05 — Engineering notes
Offline-first answer sync for an exam app
Working notes on buffering answers in IndexedDB without letting the client become the authority.
/ This is a working draft. The structure is here; the details are still being verified and filled in.
The constraint
Exam rooms have unreliable networks. A participant in the middle of a listening section cannot be asked to reconnect before the next question, and an answer cannot be lost because a request timed out.
The tempting solution is to let the client own the exam state and sync everything at the end. That fails the moment the server needs to decide whether a section is still open.
The model
Three layers, with a clear owner for each:
| Layer | Owns | Does not own |
|---|---|---|
| IndexedDB (Dexie) | Draft answers, local queue | Final submission state |
| Client app | Rendering, navigation | Scoring, timing authority |
| Server | Timing, submission, scoring | Offline availability |
The write path:
- The answer is written to IndexedDB immediately.
- A sync job sends it with a client-generated identifier.
- The server upserts by that identifier, so retries are safe.
- The local entry is marked acknowledged.
- On reload, unacknowledged entries are replayed.
Why idempotency is the core
Networks fail in the ambiguous window: the request may have arrived and the response may have been lost. Without an idempotency key, a retry creates a duplicate answer and the participant’s score is wrong.
With one, the server can process the same write twice and end up in the same state. That property is more important than any particular sync interval.
Open questions to verify
- How the client timer and the server timer are reconciled at section boundaries.
- Whether a late answer arriving after submission is rejected or recorded for review.
- How much of the queue needs to survive a browser restart versus a tab refresh.
- What the operator sees when a participant has unsynced answers at the end of a session.
What I would write next
A worked example of the upsert endpoint and the Dexie table definition, plus a failure table: network drop, tab close, server restart, and clock skew.