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

58 lines
2.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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:
```sql
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`.