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:
60
backend/SETTINGS_SYNC.md
Normal file
60
backend/SETTINGS_SYNC.md
Normal 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.
|
||||
Reference in New Issue
Block a user