📶 Built for flaky connections

Works when the signal doesn't.

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.

Start free →Install as PWA

Three places this actually matters

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.

Kirana shop in a Tier-3 town

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.

lib/offline/queue.ts — IndexedDB queue, idempotency-key dedupe

Freelancer on mobile data

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.

app/(dashboard)/dashboard/invoices/new/page.tsx — offline path

Restaurant during peak hours

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.

lib/offline/read-cache.ts — 30-min TTL for parties/items

How offline mode works

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".

01

Offline-first reads

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.

lib/offline/read-cache.ts (offlineFetchJson)
02

Writes queue locally

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.

lib/offline/queue.ts (enqueue)
03

Sync when online

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.

lib/offline/register.ts + lib/offline/queue.ts (flushQueue)
04

Conflict resolution

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.

lib/offline/conflict-resolver.ts + /dashboard/sync

What works offline. What doesn't.

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.

✓ These work offline
  • Create / record receipts
    Queued via /api/vouchers/receipt with idempotency key.
  • Create / record payments
    Queued via /api/vouchers/payment with idempotency key.
  • Post journal & contra
    Same offline path as receipts and payments.
  • Post sales / purchase invoices
    Full line-item invoice queues; replays on reconnect.
  • Look up parties, items, accounts
    Served from IndexedDB cache with 30-60 min TTL.
  • Navigate between recently-visited pages
    Service worker stale-while-revalidate cache.
⚠ These need internet
  • Real-time reports (P&L, balance sheet)
    Numbers change with every voucher; we refuse to show a number that could be off. You'll see an "offline" badge instead of a stale figure.
  • GSTR / income-tax filings
    These need a live connection to the government portal; we won't fake a confirmation receipt.
  • AI chat / agent answers
    The agent needs the model API. Offline → clean "reconnect to continue" instead of a hallucinated answer.
  • Bank feed reconciliation
    Requires fresh data from the bank aggregator. Queues your manual matches for later but won't pull new statements offline.

Try it on the worst connection you can find

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.

Start free →See the integrity guarantees