Add per-setting cross-device sync flags to user settings

Introduce an account-wide sync-flag map that is the single server-side
authority for which settings each client sends/fetches, plus value columns
for two newly-syncable device-local prefs.

- models.UserSettings: sync_flags (JSON), cache_months, month_view_paged
- main._migrate(): idempotent ALTER TABLE for the three new columns
- settings_router: DEFAULT_SYNC map + _resolve_sync_flags(); GET returns
  fully-resolved sync_flags (+ cache_months, month_view_paged); PUT accepts
  and merges a partial sync_flags map and the two new value fields

Rollout defaults: settings that already lived on the server sync ON; the
four newly-syncable prefs (language, share icon, cache range, month paging)
sync OFF until the user opts in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-14 20:44:44 +02:00
parent 1f1eb582ed
commit 91ae434e7c
3 changed files with 89 additions and 0 deletions

View File

@@ -113,6 +113,16 @@ class UserSettings(Base):
default_event_duration_minutes = Column(Integer, default=60)
# Icon key (from GROUP_ICON_KEYS) shown next to calendars this user shares with groups.
share_calendar_icon = Column(String(16), nullable=True)
# How many months around the visible range clients preload/cache. Device-local
# by default (only shared when its sync flag is on).
cache_months = Column(Integer, default=3)
# Whether the month view uses horizontal paging (swipe) instead of a vertical
# scroll feed. Device-local by default (only shared when its sync flag is on).
month_view_paged = Column(Boolean, default=False)
# Per-setting cross-device sync overrides as JSON {key: bool}. Absent keys fall
# back to settings_router.DEFAULT_SYNC. Account-wide (one map per user); it is
# the single authority for which settings each client sends/fetches.
sync_flags = Column(Text, nullable=True)
user = relationship("User", back_populates="settings")