ADR 0006 — iOS Offline Posture: Read-Only Cached State
Status: Accepted
Date: 2026-04-22
Deciders: software-architect
Scope: Raxx iOS app behavior when the device has no network connectivity
Context
Options trading requires real-time market data and a live connection to the broker API. The iOS app must have a defined posture when the user is offline: does it queue actions, show stale data without labeling it, show a hard error screen, or display a read-only snapshot with clear staleness labeling?
Decision
Read-only cached state with explicit staleness disclosure. On network loss, the app:
Displays the last successfully fetched portfolio snapshot, positions list, and fill history.
Shows a persistent banner: "No connection — data last updated at [timestamp]."
Disables all write controls: order entry, settings changes, credential management. Tapping a disabled control shows an explanatory prompt ("Connect to the internet to place orders").
Does not queue orders for deferred submission. Any pending order is cancelled and the user is informed.
On network recovery, the app refreshes immediately before re-enabling write controls.
Consequences
Positive
No risk of stale-data order submission. A queued order submitted 10 minutes after the user tapped "buy" could execute at a wildly different price. For an options trading app, this is unacceptable.
Simple to implement and reason about. No local write queue, no conflict resolution, no idempotency tokens needed.
Aligns with the audit trail invariant: no state changes occur offline, so there are no gaps in the server-side audit log.
Paper-first gating is trivially preserved — you cannot submit any order, paper or live, while offline.
Negative / risks
Users who lose connectivity during a fill event will not see the update until reconnected. Push notifications via APNs compensate for this if the device regains connectivity while the user is not in-app.
The "last updated" timestamp must be accurate. If the app silently fails to refresh (e.g. a timeout that looks like success), the displayed snapshot could be stale without the banner appearing. The refresh logic must treat timeouts as network errors.
Neutral
The cache is in-memory only in v1 (no persistent local store). On app relaunch without network, the user sees a "Connect to load your portfolio" empty state rather than a stale snapshot. This is acceptable for v1.
A persistent local cache (e.g. Core Data or SQLite) is a v2 consideration, and would need a GDPR erasure path (device data included in DSR scope).
Alternatives considered
Hard error screen on network loss
Rejected. Too disruptive for brief connectivity interruptions (subway, elevator). Showing the last known state with clear labeling is more useful.
Offline order queue with submission on reconnect
Rejected. Options prices change fast. A queued order submitted minutes or seconds late could result in significant financial harm. The paper-first gating invariant does not protect against this — it only gates live execution, not bad fill prices on paper trades. Queueing is not appropriate for this domain.
Optimistic local writes with server sync
Rejected for v1. Introduces conflict resolution complexity and a local write store that becomes PII-bearing (order intent is financial data). Out of scope for a companion app.
Compliance checklist
[x] No offline writes means no audit log gaps — every state change that affects money goes through Raptor.
[x] No local persistent store in v1 means no GDPR device-erasure surface beyond the APNs token (handled separately).
[x] Staleness disclosure directly supports the requirement to not mislead users about market state.
Revisit when
Persistent local caching is added (new ADR required with GDPR erasure design).
Watchlist / alert configuration (non-money state) could reasonably be editable offline and synced — revisit scope then.