How apps and servers should talk
REST or GraphQL
REST is our default. It is simple to cache, easy to debug and every mobile HTTP library handles it well. GraphQL earns its place when screens combine many related objects and the app team wants to request exactly the fields each screen needs, or when several clients with different needs share one backend. Either way, the rules for mobile are the same: small payloads, cursor pagination, a stable error envelope with machine-readable codes, and an API description that both sides generate code from so the app and the server cannot quietly disagree.
Login that is safe and stays out of the way
For sign-in we use the OAuth2 authorization code flow with PKCE, or tokens issued by your own backend when no external identity provider is involved. Access tokens are short-lived. Refresh tokens rotate on use and are stored in the iOS Keychain or behind the Android Keystore, never in plain preferences. Face or fingerprint login does not replace any of this. Biometrics release a credential held on the device, and the server still validates the token. The detail that causes most random logouts is concurrency: when several requests find the token expired at once, only one may refresh while the others wait.
Offline-first means the server is not the first stop
In an offline-first app the screen reads from a local database and the network updates that database in the background. Writes go into an outbox and are sent when a connection exists, each with an idempotency key so a retry cannot create a duplicate. Then comes the hard part: two people changed the same record. Last write wins is acceptable for a profile photo and dangerous for an inspection report. We agree the rule per data type with you, whether that is server authority, field-level merge or asking the user, and we test it by scripting conflicts on purpose. Deletions are synced as markers, otherwise removed items come back from the dead.
Push, payments and other moving parts
Push notifications pass through FCM on Android and APNs on iOS, often with FCM in front of both. Your server needs to store a token per device, replace it when it changes and drop it when the provider reports it invalid. Delivery is best effort, so nothing important should exist only in a notification. Payments follow a similar principle. The app starts the payment, but the server confirms it from the gateway's webhook or the store's server notification before granting anything. Map and analytics keys are restricted to your app, and real secrets stay on the server.
Old app versions never fully go away
Once an app is in the stores, some users will run a months-old build for a long time. The API has to keep answering them. We version endpoints, make additive changes where possible, send the app version with every request and keep a minimum-supported-version switch that can show an update screen when a release truly must be retired. Usage by version is tracked, so an old endpoint is removed when the numbers say it is safe.