Overview
UniSave uses delta sync to keep clients in sync with the server. Instead of fetching all data on every sync, clients request only what changed since their last sync using an opaque cursor.Cursor Design
| Property | Detail |
|---|---|
| Format | Opaque string — clients must not parse it |
| Internal encoding | (updated_at, client_id) composite key |
| Ordering | Ascending by updated_at, then by client_id for ties |
| Stability | Deterministic — same cursor always returns same page boundary |
Tombstones
Deleted records aren’t removed from the database — they’re soft-deleted with adeleted_at timestamp. This is essential for sync:
Tombstones appear in delta responses alongside upserts. A record’s
deleted_at timestamp determines its position in the sync stream — it’s treated like any other update.Client Sync Algorithm
Apply upserts
For each record in
upserts:- If it exists locally → update local fields
- If it’s new → insert into local store
- Always merge server-authoritative fields (enrichment data)
Apply tombstones
For each record in
tombstones:- Mark the local record as deleted
- Remove from UI but optionally keep in local store for undo
Conflict Resolution
UniSave uses server last-write-wins (LWW):- The server sets
updated_at = now()on every successful write - When two clients modify the same record, the most recent server-side write wins
- Clients don’t need to implement complex merge logic
Enrichment Merge Exception
Enrichment data (summary, tags, saveWhy, enrichmentStatus) is always server-authoritative. Even if a client’s local copy has a newerupdated_at, enrichment fields from the server should always be accepted:
Offline Queue
When a client is offline, writes are queued locally:- User saves/edits/deletes a bookmark → written to local store + offline queue
- UI updates immediately from local store
- When connectivity resumes, the offline queue replays writes to the server
- Server applies LWW — if the record was modified on another device, the most recent write wins
- Delta sync fetches any server-side changes missed during offline period
Sync Triggers
Clients trigger delta sync in these situations:| Trigger | Context |
|---|---|
| App launch | Initial catch-up sync |
| Pull to refresh | User-initiated |
| WebSocket nudge | bookmarks_changed event (when available) |
| Background sync | iOS BGTaskScheduler periodic refresh |
| After offline queue flush | Ensure local and server are consistent |
Data Consistency Guarantees
- Eventual consistency — all clients converge to the same state, given connectivity
- No data loss — offline writes are queued and replayed; tombstones ensure deletes propagate
- Idempotent upserts — PUT operations can be safely retried without side effects
- Monotonic cursors — cursors always move forward; replaying a cursor never skips records