In progress
Ada Lovelace
September 30
48 minutes ago
This page is the source of truth for offline mode. If it disagrees with a ticket, the page wins.
The problem
Half our traffic is on a connection that drops for twenty seconds at a time. Today that is indistinguishable from the app being broken: the spinner never resolves, the form loses what was typed, and the retry button retries into the same hole.
Offline is not a state the app enters. It is a property of every request the app makes.
The shape of the fix
Every write goes into a local queue first and is replayed in order when the connection comes back. Reads come from a cache that knows how stale it is, and the UI says so rather than pretending.
The write queue
type Queued = { id: string; op: 'create' | 'update' | 'delete'; body: unknown; at: number };export async function flush(queue: Queued[]) { for (const item of queue.sort((a, b) => a.at - b.at)) { await send(item); // ordered, not parallel }} Saying how stale
A cached row carries the time it was fetched. Anything older than five minutes gets a quiet marker rather than a modal — the point is to keep working, not to interrupt.
Open questions
What happens to a queued write whose row was deleted on the server?
Do we surface the queue to the user, or only its length?
Is there a size at which we stop queueing and start refusing?