Designed for Tier 2/3 India — kirana shops, freelancers on mobile data, restaurants on overloaded routers. Vouchers post optimistically, queue locally, sync when connectivity returns. Conflict resolution is built in — nothing gets silently dropped.
We didn't build offline mode for an enterprise tick-box. We built it because every field test in non-metro India proved the same thing: connectivity is the single biggest cause of abandoned voucher entries.
BSNL goes down twice a day. The owner keeps posting receipts on the phone — Tab to party, Enter to save, next voucher. No spinner, no error toast. When the signal returns 40 minutes later the queue replays in order with idempotency keys so the books match what was typed.
Train tunnel cuts the 4G. The freelancer is mid-invoice with five line items. They tap Save → optimistic success → router push. The invoice sits in the queue with a server-side `idempotency-key`; when the tunnel ends, it posts exactly once even if the browser retries.
Wi-Fi drops every Friday at 8 PM when 200 phones hit the router. The cashier keeps swiping bills. Master data (items, parties, accounts) is served from IndexedDB so dropdowns still populate, voucher posts queue, the rest of the world keeps moving.
Four stages. Every stage maps to a real file in our repo — open it if you're evaluating us against another vendor that just says "cloud-native".
Master data (parties, items, accounts, voucher classes) is cached in IndexedDB with explicit TTLs. The hot path always tries network first, falls back to IndexedDB on failure, and tags the response so the UI can show "as of 12 minutes ago" when stale.
When `navigator.onLine === false` (or the fetch itself blows up), the voucher post lands in an IndexedDB queue with a client-generated idempotency key. The caller gets optimistic success — the UI moves on instantly. No spinner held hostage by a missing tower.
On the `online` event (and on every page load if items are queued), the queue replays in FIFO order with the cached Supabase auth token. Each request carries its idempotency key so the server collapses retries safely.
If the server rejects an entry (duplicate number, deleted party, period locked), the row stays in the queue with a `conflict` flag instead of being silently dropped. The Sync console shows a side-by-side diff and a suggested resolution from the pure conflict-resolver.
We refuse to claim "100% offline-capable" — some things genuinely need a live connection. Better you know which is which up front than discover it during a stock-take.
Sign up free, open the app, turn off Wi-Fi, post ten vouchers. Watch them queue. Turn Wi-Fi back on. Watch them sync. If anything feels slow or weird, mail us — we ship offline-mode fixes every week.