mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(notifications): opt-in clientManaged flag to suppress server MEDICATION_REMINDER
Closes GH #206. Server-side APNs reminder for a dose now skips when the user's notification_prefs.medication.clientManaged is true — set by the iOS client once it confirms local SpeziScheduler banners are wired. Default false so existing users see no change until the iOS client opts them in. PATCH + GET endpoints land at /api/auth/me/notification-prefs with deep-merge semantics so future categories can slot in next to `medication` without overwriting siblings. Cron emits a wide-event annotation per suppressed dose so the operator can audit the skip path.
This commit is contained in:
1 parent
8956bd22af
commit
d49fd2bc4c
7 files changed
+785
No files matched your search
@@ -0,0 +1,41 @@
|
||||
-- v1.4.49 M-DOUBLE-REMINDER — per-user notification preferences blob.
|
||||
--
|
||||
-- iOS v0.6.0.7 wires local SpeziScheduler banners for medication doses.
|
||||
-- Once the client has confirmed (a) APNs permission = `.authorized`,
|
||||
-- (b) Spezi reminders are actively scheduled, and (c) the binary is
|
||||
-- >= v0.6.0.7, it flips `notification_prefs.medication.clientManaged`
|
||||
-- to true via `PATCH /api/auth/me/notification-prefs`. The server-side
|
||||
-- MEDICATION_REMINDER cron then suppresses the redundant APNs push for
|
||||
-- that user so the dose only buzzes once.
|
||||
--
|
||||
-- Shape (additive — future categories slot in next to `medication`):
|
||||
-- {
|
||||
-- "medication": { "clientManaged": boolean }
|
||||
-- }
|
||||
--
|
||||
-- Default `NULL` (the column itself), which the application layer
|
||||
-- resolves to `{ medication: { clientManaged: false } }` so every
|
||||
-- existing user keeps the legacy server-side push until the iOS app
|
||||
-- explicitly opts them in. This preserves UX for clients that don't
|
||||
-- have working local reminders yet (e.g. the
|
||||
-- `healthlog-iOS#10` notification-permission-stuck-`notDetermined`
|
||||
-- scenario).
|
||||
--
|
||||
-- Idempotent guard (`IF NOT EXISTS`) matches the 0067 / 0070 / 0071 /
|
||||
-- 0075 / 0078 pattern so reruns are safe on prod where the migration
|
||||
-- has already been applied.
|
||||
--
|
||||
-- Reversibility: down migration is
|
||||
-- ALTER TABLE "users" DROP COLUMN IF EXISTS "notification_prefs";
|
||||
-- A roll-back loses opt-in state for every user that had flipped
|
||||
-- `clientManaged` (they fall back to server-side reminders) but the
|
||||
-- application reads tolerate a missing column / null row and default
|
||||
-- to `clientManaged: false`, so a partial deploy where the schema is
|
||||
-- rolled back ahead of the app code keeps working.
|
||||
|
||||
-- No additional index — reads at cron time are per-user
|
||||
-- (`WHERE id = $1`), matching the convention set by
|
||||
-- `source_priority_json` and `doctor_report_prefs_json` on the same
|
||||
-- table (no GIN index on either).
|
||||
ALTER TABLE "users"
|
||||
ADD COLUMN IF NOT EXISTS "notification_prefs" JSONB;
|
||||
@@ -223,6 +223,30 @@ model User {
|
||||
// payload when the toggle is off so the data never leaves the DB row.
|
||||
doctorReportPrefsJson Json? @map("doctor_report_prefs_json")
|
||||
|
||||
// v1.4.49 M-DOUBLE-REMINDER — per-user notification preferences blob.
|
||||
//
|
||||
// Opt-in suppression for redundant server-side pushes. Shape:
|
||||
// { "medication": { "clientManaged": boolean } }
|
||||
//
|
||||
// When `medication.clientManaged === true`, the reminder cron skips
|
||||
// the APNs `MEDICATION_REMINDER` for this user — iOS v0.6.0.7+
|
||||
// schedules local SpeziScheduler banners that cover the same dose.
|
||||
// The iOS app flips the flag to true on first launch after it has
|
||||
// confirmed (a) APNs permission = `.authorized`, (b) local Spezi
|
||||
// reminders are actively scheduled, and (c) the binary is
|
||||
// >= v0.6.0.7. Default `null` (resolved as `clientManaged: false`)
|
||||
// so existing installs see zero regression — server reminders flow
|
||||
// unchanged until the iOS client explicitly opts the user in.
|
||||
//
|
||||
// Only `MEDICATION_REMINDER` is gated by this flag; MOOD_REMINDER,
|
||||
// PERSONAL_RECORD, SYSTEM_ALERT, and anomaly pushes flow unchanged.
|
||||
//
|
||||
// Persisted via `PATCH /api/auth/me/notification-prefs` with
|
||||
// deep-merge semantics so future categories (e.g. mood,
|
||||
// personal_records) slot in next to `medication` without
|
||||
// overwriting siblings.
|
||||
notificationPrefs Json? @map("notification_prefs")
|
||||
|
||||
// v1.4.47 W3 — per-user Coach opt-out (privacy-leaning users).
|
||||
//
|
||||
// When `true`, every Coach mount point on the web client renders
|
||||
|
||||
Reference in new issue
Block a user