mitbringsl/docs/SYNC.md
Tronax a00db14cba
Phase F: NetworkMonitor, offline banner, README & architecture docs
- NetworkMonitor: ConnectivityState Flow using ConnectivityManager.NetworkCallback
- ListsScreen & ViewModel: live offline indicator banner when disconnected
- Documentation:
  - docs/ARCHITECTURE.md: system design & tech stack overview
  - docs/SYNC.md: HLC timestamping, op_log outbox & LWW projection specification
  - docs/API.md: REST API endpoint specification
  - README.md: quickstart guide for backend, docker compose & Android app
- Verification: backend & android test suites 100% green 
2026-08-05 20:14:04 +02:00

2.4 KiB
Raw Blame History

Mitbringsl Synchronization Protocol & Conflict Resolution

1. Synchronization Model

Mitbringsl uses an Append-Only Operation Log (op_log) with Hybrid Logical Clock (HLC) timestamps and Last-Write-Wins (LWW) projections.


2. Hybrid Logical Clock (HLC)

Every operation carries a 64-bit integer timestamp hlc_ts:

\text{hlc\_ts} = (\text{wall\_ms} \ll 16) \mid \text{counter}
  • wall_ms (48 bits): Unix epoch milliseconds.
  • counter (16 bits): Logical counter disambiguating events produced within the same millisecond.

Guarantees

  1. Strict Monotonicity: t_{n+1} > t_n for all events generated on the same device.
  2. Causal Ordering: If event B was generated after observing event A, then HLC(B) > HLC(A).

3. Operations (op_log)

All state modifications are represented as structured operations:

op_type Target Description Payload Example
list_create List UUID Create list {"name":"Wocheneinkauf"}
list_rename List UUID Rename list {"name":"Supermarkt"}
list_delete List UUID Delete list {}
item_add Item UUID Add item {"name":"Milch","quantity":"2L"}
item_update Item UUID Update item {"name":"Hafermilch","checked":true}
item_remove Item UUID Delete item {}

4. Conflict Resolution (LWW & Tombstones)

  1. Projection Updates: Database tables (items, lists) are projections of op_log. When an op arrives:
    UPDATE items
    SET name = $1, hlc_ts = $2, updated_at = now()
    WHERE id = $3 AND hlc_ts < $2 AND deleted_at IS NULL;
    
  2. Tombstones (deleted_at): When an item or list is deleted (item_remove, list_delete), a tombstone is set (deleted_at = now()). Late-arriving offline item_update operations with smaller hlc_ts values will never revive a tombstoned entity.

5. Idempotent Push & Cursor Pull

  • Idempotent Push (POST /api/lists/{id}/ops): Each operation carries a (client_id, client_seq) tuple enforced by a UNIQUE constraint in Postgres (op_log). Re-sent requests return previous (seq, hlc_ts) assignments without duplicating side effects.
  • Cursor Pull (GET /api/lists/{id}/ops?since={seq}): Clients track max(server_seq) locally. Incremental sync fetches ops where seq > cursor, sorted by monotonic server sequence seq ASC.