Offline sync
Mobile is offline-first. The server remains the source of truth. Clients keep a local SQLite/Drift cache for reads and a write outbox for offline work, then converge with pull and push.
Goals
- Keep working through long disconnects without silently losing data.
- Detect conflicts with row versions and server timestamps.
- Propagate soft deletes as tombstones.
- Keep posted financial/stock documents immutable — corrections use amend, cancel, reverse, or adjustment flows.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /v1/sync/manifest | Entity sync capabilities |
GET | /v1/sync/pull?since=<cursor> | Paginated changes since cursor |
POST | /v1/sync/push | Upload buffered local mutations |
POST | /v1/sync/reset | Rebuild local cache from server |
Business-scoped variants exist under /v1/businesses/:business_id/sync/....
How it works
- Every business resource has a
sync_versionbumped on every update (including soft delete). - Pull uses a stable opaque cursor (base64url JSON over
(updated_at, id)). - Push applies a batch of local mutations; conflicts surface deterministically.
- POS sales use an idempotent
client_sale_idso retries after reconnect are safe.
Operator tips
- Leave the Windows cashier tray process running so background sync can drain the outbox.
- After a device reset, run sync pull before taking payments.
- Never “edit” a posted invoice in place — use credit notes / reverse / adjust.
Related
- POS & cashier
- Backups
- Deep dive in the repo:
docs/sync.md