Document the cross-device settings-sync contract

Shared reference for Web/iOS/Android: canonical keys, default flags, the
GET/PUT sync_flags API, and the pull/push rules each client implements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-14 20:46:23 +02:00
parent 91ae434e7c
commit 3d58e8fef8

60
backend/SETTINGS_SYNC.md Normal file
View File

@@ -0,0 +1,60 @@
# Settings sync contract (Web / iOS / Android)
Per-setting, cross-device synchronisation of user settings. The **server is the
sole authority** for *which* settings sync; clients must not duplicate that logic.
This document is the shared contract all three clients implement identically.
## Canonical keys & default flags
Source of truth: `DEFAULT_SYNC` in `backend/routers/settings_router.py`. Keys use
the server's snake_case field names.
| Key | Kind | Default sync |
|---|---|---|
| `default_view` | enum | ON |
| `week_start_day` | enum | ON |
| `dim_past_events` | bool | ON |
| `hour_height` | enum(int) | ON |
| `primary_color` `accent_color` `today_color` `text_color` `line_color` `bg_color` `month_divider_color` `month_label_color` | color hex | ON |
| `default_event_duration_minutes` | enum(int) | ON |
| `default_reminder_minutes` | enum(int, null=off) | ON |
| `language` | enum | **OFF** |
| `share_calendar_icon` | icon key | **OFF** |
| `cache_months` | enum(int) | **OFF** |
| `month_view_paged` | bool | **OFF** |
Settings **not** in this list are never synced by this mechanism:
- Account-wide settings (`private_event_visibility`, `group_visible_calendar_id`,
`directory_hidden`) — one value per account, always identical everywhere; they
keep their existing dedicated endpoints/UI, not a sync toggle.
- Platform-exclusive device prefs (e.g. iOS `liquid_glass`) — stay device-local.
- Identity/security, calendar/account management, admin.
## API
- `GET /api/settings/` returns every value **plus** `sync_flags`: a fully-resolved
`{key: bool}` map covering exactly the keys above (stored overrides on top of
`DEFAULT_SYNC`). Clients read this map verbatim — no client-side defaults.
- `PUT /api/settings/` accepts a partial `sync_flags` map (merged account-wide,
unknown keys ignored, untouched flags preserved) and partial value fields
(`exclude_unset`; `text_color`/`line_color`/`bg_color`/… treated as
nullable-reset per `NULLABLE_OVERRIDES`).
## Client rules
Each client keeps a **local copy** of every syncable value (UserDefaults /
DataStore-SharedPreferences / localStorage) so that "not synced" works per device.
1. **On login / launch / foreground:** `GET /api/settings/` → values + `sync_flags`.
2. **Pull:** for each syncable key, if `sync_flags[key]` is ON, adopt the server
value into the local copy; if OFF, keep the local value.
3. **Push (debounced, read-modify-write):** start from the current server snapshot,
overwrite only keys whose flag is ON with the local value, `PUT`. Never push a
key whose flag is OFF.
4. **Toggle a flag ON:** set the flag true **and** push this device's current local
value (it becomes the shared value). **OFF:** set false; keep the local value.
5. **Global "share everything":** set all syncable flags true and push all local
values. Global off: set all false.
The flag map itself is always account-wide and always fetched fresh; it is what a
client consults to decide what to send/receive.