From 3d58e8fef8bf9de1ad5f423acfc95faec1c39196 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Tue, 14 Jul 2026 20:46:23 +0200 Subject: [PATCH] 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 --- backend/SETTINGS_SYNC.md | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 backend/SETTINGS_SYNC.md diff --git a/backend/SETTINGS_SYNC.md b/backend/SETTINGS_SYNC.md new file mode 100644 index 0000000..31828bf --- /dev/null +++ b/backend/SETTINGS_SYNC.md @@ -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.