Mobile Backend Design: [App or product name]
Design document for the server side of a mobile app: the backend-for-frontend (BFF) layer, API
aggregation, sign-in with OAuth 2.0 for native apps (RFC 8252, BCP 212) and token handling,
offline sync and conflict resolution, push notification fan-out through Apple Push Notification
service (APNs) and the Firebase Cloud Messaging (FCM) HTTP v1 API, support for old app versions,
rate limiting, observability, security mapped to the OWASP Mobile Application Security
Verification Standard (MASVS) v2.1.0, and operations. The app-side design (modules, local
storage, UI) is covered by the Mobile architecture template (architecture/mobile-architecture).
Replace every [bracketed] value and every row marked Example.
Document control
| Field | Value |
|---|
| Document ID | [MBE-001] |
| Apps in scope | [iOS app bundle ID], [Android application ID] |
| BFF services | [Service names and repositories] |
| Identity provider | [Provider] |
| Push providers | APNs (token-based authentication), FCM HTTP v1 |
| Security baseline | OWASP MASVS v2.1.0 |
| Version | [0.1] |
| Status | [Draft / In review / Approved / Superseded] |
| Owner | [@mobile-backend-lead] |
| Approvers/reviewers | [@mobile-lead], [@security-architect], [@sre-lead], [@product-owner] |
| Last updated | YYYY-MM-DD |
| Classification | [Internal / Confidential] |
Approvals
| Role | Name | Decision | Date |
|---|
| Mobile engineering | [@name] | [Approve / Approve with conditions / Reject] | YYYY-MM-DD |
| Backend engineering | [@name] | [Decision] | YYYY-MM-DD |
| Security | [@name] | [Decision] | YYYY-MM-DD |
| Operations | [@name] | [Decision] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change summary |
|---|
| 0.1 | YYYY-MM-DD | [@name] | First draft |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved; BFF, delta sync and push live for release 5.0 |
| 1.1 | YYYY-MM-DD | [@name] | Example: Added DPoP-bound refresh tokens and minimum version enforcement |
Contents
1. Scope, clients and versions
The worked example is a field service app: technicians receive jobs, work offline on site, complete
checklists, take photos and sync when connected. Pair it with the client-side Mobile Architecture
(architecture/mobile-architecture), which owns app modules, local storage and the app release
process; this document owns everything behind the edge.
| Client | Platforms | Users | Network profile | Offline need |
|---|
| Technician app (Example) | iOS, Android | 150,000 monthly active devices | Often poor or none on site | Full working day offline |
| Supervisor app (Example) | iOS, Android, tablet layout | 8,000 | Office and vehicle | Read-only cache |
| [Client] | [Platforms] | [Users] | [Profile] | [Need] |
| App version (Example) | Share of active devices | Released | Status |
|---|
| 5.2 | 61 % | YYYY-MM-DD | Current |
| 5.1 | 24 % | YYYY-MM-DD | Supported |
| 5.0 | 11 % | YYYY-MM-DD | Supported, upgrade prompt shown |
| 4.x | 4 % | YYYY-MM-DD | Below minimum supported version from [date] |
2. Requirements and capacity
2.1 Requirements
| ID | Requirement | Priority |
|---|
| MBE-REQ-001 (Example) | A technician can complete a full day of jobs offline and sync without losing any change | Core |
| MBE-REQ-002 (Example) | First screen after app start loads in under [1.5 s] at the 90th percentile on 4G | Core |
| MBE-REQ-003 (Example) | New job assignments reach the device within [60 s] when it is online | Core |
| MBE-REQ-004 (Example) | App versions released in the last [12 months] keep working | Core |
| MBE-REQ-005 (Example) | A stolen device can be cut off within [5 min] of the report | Core |
| MBE-REQ-006 (Example) | Supervisors see live technician locations | Below the line for this release |
| [MBE-REQ-NNN] | [Requirement] | [Core / Below the line] |
2.2 Capacity estimate
Example assumptions: 60,000 daily active devices, 40 BFF calls per device per day, 25 % of daily
calls in the peak hour, each BFF call fanning out to 3 domain service calls.
| Quantity | Calculation | Result | Consequence |
|---|
| BFF calls per day | 60,000 x 40 | 2,400,000 | Modest; one small autoscaling BFF pool per region is enough |
| Peak-hour BFF rate | 2,400,000 x 25 % / 3,600 s | About 167 per second | Plan for 3x headroom: 500 per second |
| Domain calls at peak | 167 x 3 | About 500 per second | Aggregation must use parallel calls with per-call timeouts |
| Shift-start sync burst | 40,000 devices x 2 MB delta in 15 min (900 s) | About 89 MB/s (about 711 Mbit/s) | Serve photos and documents from object storage through a CDN; add random jitter of up to [10 min] to background sync |
| Push per day | 60,000 devices x 8 notifications | 480,000 | Low steady load |
| Broadcast push | 150,000 devices in 5 min (300 s) | 500 per second | Fan-out workers must respect provider throttling and retry |
3. Backend topology and BFF pattern
| Layer | Owns | Does not own |
|---|
| CDN and API gateway | TLS, coarse rate limits, request size limits, routing, static and media caching | Business decisions |
| Mobile BFF | Screen-shaped endpoints, aggregation, response shaping, app version checks, per-user rate limits | Data storage, business rules |
| Sync service | Change feeds per user scope, cursors, upload batches, conflict detection | Domain validation (delegated to domain services) |
| Domain services | Business rules, data, events | Presentation |
| Notification service | Templates, preferences, provider fan-out, delivery tracking | Deciding who must be notified |
Choose one BFF per experience (technician, supervisor) rather than per platform: iOS and Android
show the same screens, while technicians and supervisors do not. Detailed gateway design belongs in
the API gateway design (system-design/design-api-gateway).
4. API design and aggregation
| ID | Endpoint (Example) | Aggregates | Payload budget | Caching | Timeout budget |
|---|
| API-001 | GET /v1/home | Today's jobs, unread messages, alerts | Under [30 KB] compressed | Private, ETag | 800 ms total; 300 ms per dependency |
| API-002 | GET /v1/jobs/{id} | Job, customer, site, parts, checklist template | Under [50 KB] | Private, ETag | 1 s |
| API-003 | POST /v1/sync/pull | Changes since cursor for the user's scope | Pages of [500] changes | None | 5 s |
| API-004 | POST /v1/sync/push | Batch of client mutations with idempotency keys | Up to [200] mutations | None | 10 s |
| API-005 | POST /v1/media/uploads | Creates a resumable upload session in object storage | n/a | None | 2 s |
| [API-NNN] | [Endpoint] | [Aggregates] | [Budget] | [Caching] | [Budget] |
- Aggregate in parallel with a timeout per dependency and return partial results with a per-section
status when an optional dependency fails; the home screen must render without the alerts section.
- Return errors as problem details (RFC 9457) with a stable
type URI the app can map to messages.
- Use cursor pagination and
ETag or If-None-Match revalidation; compress responses.
- Accept an
Idempotency-Key header on every mutating call, so retries after a dropped connection do
not create duplicates.
- Version the BFF API in the path and keep each version for the supported app window in section 8.
- Choose REST or GraphQL per BFF with a decision record; if GraphQL, apply query cost limits and
persisted queries (see
architecture/graphql-schema-spec).
5. Authentication and token handling
| Topic | Design | Basis |
|---|
| Sign-in flow | Authorization code flow with PKCE in an external user-agent (system browser or in-app browser tab), never an embedded web view | RFC 8252 (BCP 212), RFC 7636 |
| Redirect URI | Claimed HTTPS link (universal link or app link) preferred; private-use URI scheme in reverse domain form as fallback | RFC 8252 |
| Access token | Short-lived ([10 to 15 min]), audience-restricted to the BFF | Internal policy |
| Refresh token | Rotated on every use with reuse detection, or sender-constrained with DPoP; both for high-risk apps | RFC 9700 (BCP 240), RFC 9449 |
| Token storage on device | iOS Keychain and Android Keystore-backed storage; never in plain preferences or logs | MASVS-STORAGE |
| App and device integrity | Platform attestation (App Attest on iOS, Play Integrity API on Android) checked at sign-in and on sensitive calls as a risk signal | Vendor documentation |
| Session revocation | Revoke refresh tokens per device on report of loss; BFF checks a revocation list for access tokens within [5 min] | MBE-REQ-005 |
| Offline sessions | App works offline for up to [72 h] after the last successful refresh, then requires sign-in | Business rule |
Design the customer identity side with the CIAM solution design (security/ciam-solution-design)
or, for workforce apps, the IAM solution design (security/iam-solution-design).
6. Offline sync and conflict resolution
6.1 Sync model
| Aspect | Design (Example) |
|---|
| Scope | Each device syncs the user's jobs for the past 7 days and the next 3 days, plus reference data (parts, checklist templates) |
| Change detection | Server change log with a monotonically increasing sequence per scope; the client keeps the last sequence as its cursor |
| Pull | POST /v1/sync/pull with cursor; returns changes and tombstones for deletions; client applies in order |
| Push | Client queues mutations locally, each with a client-generated ID and the base version it was made against |
| Idempotency | Server stores mutation IDs for [30 days]; a repeated mutation returns the original result |
| Ordering | Mutations for one job processed in client order; different jobs in parallel |
| Reset | If the cursor is older than the change log retention ([30 days]), the server signals a full resync of the scope |
6.2 Conflict rules per entity
| Entity | Conflict strategy | Rule | User involvement |
|---|
| Job assignment | Server wins | Dispatch decides; client change rejected with reason | Message shown |
| Job status | State machine | Only valid transitions accepted (see diagram); invalid ones rejected | Message shown |
| Checklist answers | Field-level merge | Different fields merge; same field with different values kept as a conflict | Technician chooses |
| Notes | Append only | Every note kept with author and time | None |
| Photos | Add only | Uploads never overwrite; deletions are tombstones | None |
| [Entity] | [Strategy] | [Rule] | [Involvement] |
The server validates each pushed mutation against the current state: a mutation whose base version
is older than the server version goes through the entity's conflict rule rather than being applied
blindly. Return per-mutation results so the client can mark each queued item as applied, merged or
rejected. Conflict-free replicated data types fit collaborative text; for business records with
rules, explicit per-entity strategies are easier to reason about and audit.
7. Push notification fan-out
| Topic | Design |
|---|
| Trigger | Domain events (for example JobAssigned) consumed by the notification service; the BFF never sends pushes directly |
| Payload | A short, non-sensitive alert plus an identifier; the app fetches details through the BFF |
| APNs | HTTP/2 provider API with token-based authentication (JWT signed with ES256, kid and team ID); refresh the provider token no more often than every 20 minutes and at least every 60 minutes; set apns-push-type, apns-priority, apns-expiration and, for replaceable alerts, apns-collapse-id |
| FCM | HTTP v1 API (projects/{project}/messages:send) with short-lived OAuth 2.0 access tokens from a service account; the legacy HTTP and XMPP APIs were deprecated on 20 June 2023 and shut down from 22 July 2024 |
| Token registry | Device token per installation with platform, app version, user and last-seen time; updated on every app start |
| Invalid tokens | Remove the token on APNs 410 (Unregistered) or FCM UNREGISTERED (HTTP 404); do not retry |
| Retries | Exponential backoff with jitter on provider throttling and server errors; respect provider retry hints |
| Silent pushes | Used only as a hint to sync; never relied on, because the operating system may delay or drop them |
| Preferences | Per user and per category, held by the notification service |
Design templates, preferences, provider failover and delivery tracking with the notification service
design (system-design/design-notification-service). Check payload limits and header rules on the
current Apple and Firebase documentation before each provider client upgrade.
8. Supporting old app versions
| Mechanism | Design (Example) |
|---|
| Version signal | Every request carries App-Version, App-Build and Platform headers |
| Support window | Versions released in the last 12 months are supported; older versions receive an upgrade prompt for 60 days and are then blocked |
| Minimum version | BFF configuration per platform; requests below it receive a specific problem type that the app shows as an update screen |
| Soft prompt | Remote configuration shows an upgrade suggestion from a version threshold |
| API compatibility | Additive changes only within a BFF API version; removals wait until no supported app version uses the field |
| Feature gating | Server-side flags by app version and platform; new features off for versions that cannot handle them |
| Kill switch | Ability to disable a feature for one app version within [5 min] if it misbehaves |
| Store review delay | Assume [1 to 3 days] before a fix reaches users; server fixes first where possible |
Track usage of every BFF field by app version before removing it. Publish the policy in the API
deprecation policy (architecture/api-deprecation-policy).
9. Rate limiting and abuse protection
| Layer | Key | Limit (Example) | Response |
|---|
| Edge | IP address, coarse | 1,000 requests per minute | HTTP 429 |
| BFF | User and device | 120 requests per minute; sync push 10 per minute | HTTP 429 with Retry-After |
| Sign-in | Account and device | 10 attempts per 15 minutes | Step-up or temporary lock |
| Media upload | User | 2 GB per day | HTTP 429 with problem type |
The app must honour Retry-After and use exponential backoff with jitter; a retry storm after an
outage is the most common self-inflicted load spike. Design the algorithms with the rate limiter
design (system-design/design-rate-limiter).
10. Observability
| Signal | Design |
|---|
| Trace propagation | App sends a W3C Trace Context traceparent header; the BFF continues the trace into domain services |
| Metrics dimensions | Endpoint, app version, platform, region, network type reported by the app |
| Client metrics | App start time, screen load time, sync duration, sync failures, crash-free sessions |
| Server metrics | Latency per endpoint and dependency, error rate, aggregation partial-result rate, sync conflict and rejection rates |
| Push metrics | Sent, accepted by provider, invalid-token rate, time from event to provider acceptance |
| Logs | Structured, no tokens or personal data; correlation by trace ID |
Define dashboards per app version and alert when one version's error rate exceeds the others by a
set margin. Specify the platform conventions with the observability specification
(ops/observability-spec).
11. Security and MASVS mapping
OWASP MASVS v2.1.0 (January 2024) groups controls into eight categories. The backend contributes to
the groups below; verify app-side controls with the OWASP Mobile Application Security Testing Guide.
| MASVS group | Backend contribution |
|---|
| MASVS-STORAGE | Minimise data sent to the device; short sync scope; server-driven remote wipe of local data on revocation |
| MASVS-CRYPTO | Server-side key management; no secrets shipped in the app binary |
| MASVS-AUTH | OAuth 2.0 with PKCE; authorisation enforced server-side on every call; step-up for sensitive actions |
| MASVS-NETWORK | TLS 1.2 or later only, modern cipher suites, HSTS on web endpoints; certificate rotation plan agreed with the app team |
| MASVS-PLATFORM | Deep links and push payloads carry identifiers only, never data or tokens |
| MASVS-CODE | Minimum version enforcement and input validation of every field from the app |
| MASVS-RESILIENCE | Attestation verdicts used as risk signals, not as the only control |
| MASVS-PRIVACY | Data minimisation in APIs, events and logs; consent state honoured by analytics endpoints |
Treat the app as an untrusted client: validate every input, authorise every object access (broken
object-level authorisation is the most common mobile API flaw), and never rely on hidden UI to
prevent an action. Threat-model the BFF with the threat model template (security/threat-model).
12. Reliability and operations
| Indicator | Target (Example) |
|---|
| BFF availability | 99.9 % monthly per region |
GET /v1/home latency | Under 800 ms at the 95th percentile, server side |
| Sync push success | 99.95 % of mutations applied, merged or rejected with reason (none lost) |
| Event to push acceptance | 95 % within 30 s |
Degraded modes: when a dependency fails, the BFF returns partial results with section status; when
the sync service is down, the app keeps working offline and queues changes; when push providers are
degraded, the app's foreground refresh still finds new jobs. Write runbooks for forced minimum
version changes, mass token revocation, push provider credential rotation (APNs signing key, FCM
service account) and sync change log replay.
13. Trade-offs, decisions and risks
| Decision | Options | Choice (Example) | Reason | Revisit if |
|---|
| BFF granularity | One per platform; one per experience; none | One per experience | Same screens on both platforms | Platforms diverge in features |
| API style | REST; GraphQL | REST with screen-shaped endpoints | Simple caching and versioning | Many new screens per release |
| Sync | Custom change log; vendor sync product; CRDT library | Custom change log with per-entity rules | Business rules and audit needs | Collaborative editing appears |
| Refresh token protection | Rotation; DPoP; both | Rotation now, DPoP for release 6 | Identity provider support | Provider supports DPoP for all clients |
| At 10x load (600,000 daily devices) | Scale BFF horizontally; regional sync stores | Regional sync stores and CDN for reference data | Shift-start burst grows to about 890 MB/s | Burst exceeds CDN commitment |
| At 0.1x load (6,000 daily devices) | Keep BFF; merge into one service | Keep the BFF, scale to two instances | Version handling still needed | Never merge into domain services |
| Failure mode | Effect | Mitigation |
|---|
| Change log retention shorter than offline period | Devices need full resync | Retention 30 days; full resync path tested |
| Duplicate mutations after timeouts | Duplicate records | Mutation IDs stored and checked |
| Invalid tokens accumulate | Wasted sends, provider throttling | Remove on APNs 410 or FCM UNREGISTERED (HTTP 404) |
| Old app sends removed field | Errors for a user group | Field usage tracked per version before removal |
| Retry storm after outage | Overload on recovery | Retry-After, jittered backoff, edge limits |
| ID | Risk | Mitigation | Owner |
|---|
| MBE-R-001 (Example) | Users stay on unsupported versions | Upgrade prompts, minimum version enforcement, support comms | [@mobile-lead] |
| MBE-R-002 (Example) | Push credentials expire unnoticed | Expiry monitoring and rotation runbook | [@sre-lead] |
| MBE-R-003 (Example) | Conflict rules lose data | Conflict metrics and field-level merge tests | [@mobile-backend-lead] |
| [MBE-R-NNN] | [Risk] | [Mitigation] | [@owner] |
14. Glossary and references
| Term | Meaning in this document |
|---|
| BFF | Backend for frontend: a server layer shaped for one client experience |
| Cursor | Position in a change feed from which the next pull continues |
| Tombstone | Record that tells clients an item was deleted |
| PKCE | Proof Key for Code Exchange: binds the authorization code to the app instance that requested it |
| DPoP | Demonstrating Proof of Possession: binds tokens to a key held by the client |
| Device token | Address issued by APNs or FCM for one app installation |
| Reference | Version or date checked | Use |
|---|
| RFC 8252, OAuth 2.0 for Native Apps (BCP 212) | October 2017 | Section 5 |
| RFC 7636, Proof Key for Code Exchange | 2015 | Section 5 |
| RFC 9700, Best Current Practice for OAuth 2.0 Security (BCP 240) | 2025 | Refresh token protection |
| RFC 9449, OAuth 2.0 Demonstrating Proof of Possession (DPoP) | 2023 | Sender-constrained tokens |
| RFC 9457, Problem Details for HTTP APIs | 2023 | Error format |
| Apple Developer Documentation, Sending notification requests to APNs | Checked 2026-10-23 | Section 7 |
| Firebase documentation, FCM HTTP v1 API and migration from legacy APIs | Checked 2026-10-23 | Section 7 |
| OWASP MASVS, mas.owasp.org | v2.1.0, released 18 January 2024, CC BY-SA 4.0 | Section 11 |
Standard and licence note
Based on the public IETF RFCs 8252, 7636, 9700, 9449 and 9457 and on the public Apple Push
Notification service and Firebase Cloud Messaging documentation. The security section maps backend
controls to the control group names of the OWASP Mobile Application Security Verification Standard
(MASVS) v2.1.0 by the OWASP Mobile Application Security project, licensed under CC BY-SA 4.0; only
group identifiers are used and the mapping text is original. If you adapt or redistribute OWASP
material from the MASVS itself, attribute OWASP and share your adaptation under CC BY-SA 4.0
(ShareAlike). The rest of the structure and wording is original to this collection. Check the
current official versions before use. Apple, APNs, App Attest, Google, Firebase, Android and Play
Integrity are trademarks of their owners; this template is not affiliated with or endorsed by them.
Template licence: MIT.