feat(sync): opt-in consent layer — per-user, per-product, per-data-class sync preferences #57

Open
opened 2026-04-26 09:06:07 -07:00 by pyr0ball · 0 comments
Owner

Context

Circuit-Forge/circuitforge-core#56 defines the sync service API (push/pull/delete endpoints for localStorage-keyed blobs). This ticket covers the consent and preference layer that sits in front of it.

What to build

Sync preference model

Each user has a set of sync preferences stored in their account, keyed by {product_slug}:{data_class}:

kiwi:cook_log         → enabled | disabled
kiwi:bookmarks        → enabled | disabled
kiwi:dismissed        → enabled | disabled
peregrine:dismissed   → enabled | disabled
...

Default: all disabled (local-first, no sync until user opts in).

cf-core module: sync_prefs

  • get_sync_prefs(user_id, product) → dict of data_class → bool
  • set_sync_pref(user_id, product, data_class, enabled: bool) → updates preference
  • get_all_sync_prefs(user_id) → full cross-product preference map (for account page)
  • wipe_sync_data(user_id, product=None) → deletes synced blobs; if product=None, wipes all

API endpoints (shared, mounted by each product)

  • GET /api/v1/sync/prefs — returns current sync preferences for this product
  • PATCH /api/v1/sync/prefs — update one or more preferences {data_class: bool}
  • DELETE /api/v1/sync/data — wipe all synced data for this product (keeps preferences)
  • DELETE /api/v1/sync/all — wipe all synced data + reset preferences to disabled
  • Opt-in is per data class, not a single blanket toggle — users can sync cook log without syncing dismissed recipes
  • Plain-language labels required (defined per product, not by cf-core)
  • No pre-checked boxes. No opt-out flow. Opt-in only.
  • Deletion must be immediate and irrevocable (no "we'll process this in 30 days")

References

  • circuitforge-core#56 — sync service architecture (parent)
  • Website account page ticket: Circuit-Forge/website (filed separately)
## Context Circuit-Forge/circuitforge-core#56 defines the sync service API (`push`/`pull`/`delete` endpoints for localStorage-keyed blobs). This ticket covers the **consent and preference layer** that sits in front of it. ## What to build ### Sync preference model Each user has a set of sync preferences stored in their account, keyed by `{product_slug}:{data_class}`: ``` kiwi:cook_log → enabled | disabled kiwi:bookmarks → enabled | disabled kiwi:dismissed → enabled | disabled peregrine:dismissed → enabled | disabled ... ``` Default: **all disabled** (local-first, no sync until user opts in). ### cf-core module: `sync_prefs` - `get_sync_prefs(user_id, product)` → dict of data_class → bool - `set_sync_pref(user_id, product, data_class, enabled: bool)` → updates preference - `get_all_sync_prefs(user_id)` → full cross-product preference map (for account page) - `wipe_sync_data(user_id, product=None)` → deletes synced blobs; if product=None, wipes all ### API endpoints (shared, mounted by each product) - `GET /api/v1/sync/prefs` — returns current sync preferences for this product - `PATCH /api/v1/sync/prefs` — update one or more preferences `{data_class: bool}` - `DELETE /api/v1/sync/data` — wipe all synced data for this product (keeps preferences) - `DELETE /api/v1/sync/all` — wipe all synced data + reset preferences to disabled ### Consent requirements (non-negotiable) - Opt-in is **per data class**, not a single blanket toggle — users can sync cook log without syncing dismissed recipes - Plain-language labels required (defined per product, not by cf-core) - No pre-checked boxes. No opt-out flow. Opt-in only. - Deletion must be immediate and irrevocable (no "we'll process this in 30 days") ## References - circuitforge-core#56 — sync service architecture (parent) - Website account page ticket: Circuit-Forge/website (filed separately)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/circuitforge-core#57
No description provided.