Files
Calendarr/backend/SETTINGS_SYNC.md
Scarriffle 3d58e8fef8 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>
2026-07-14 20:46:23 +02:00

2.9 KiB

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.