feat(engagement): localize limits and streaks

Use reported user timezones for daily response limits, expose couple streak state and reminders, and improve swipe and live-drawing synchronization with focused tests and documentation.
This commit is contained in:
jjbrunton committed 2026-08-28 20:28:31 +01:00
1 parent 61ec3692b7
commit b60c788362
42 files changed
+1308 -217

No files matched your search

@@ -0,0 +1,2 @@
ALTER TABLE "profiles" ADD COLUMN IF NOT EXISTS "timezone" text;--> statement-breakpoint
COMMENT ON COLUMN "profiles"."timezone" IS 'IANA zone reported by the client. NULL falls back to UTC when bucketing the daily response limit.';
@@ -0,0 +1,2 @@
-- The daily response limit counts a user's responses within their current local day.
CREATE INDEX IF NOT EXISTS "responses_user_created_idx" ON "responses" ("user_id", "created_at" DESC);
@@ -0,0 +1,15 @@
-- Streaks are counted in the couple's shared local day, not the server's calendar day.
-- The zone is the first reported timezone in member id order (the same ordering that
-- decides user1/user2), falling back to UTC when neither partner has reported one.
COMMENT ON COLUMN "couple_streaks"."last_active_date" IS 'Couple-local date on which either partner last answered. The answered-today flags are read as false once this is not the couple-local today.';--> statement-breakpoint
COMMENT ON COLUMN "couple_streaks"."last_completed_date" IS 'Couple-local date on which both partners last answered. The streak is alive while this is the couple-local today or yesterday.';--> statement-breakpoint
-- Prunes the evening at-risk scan to couples that actually have a streak to lose.
CREATE INDEX IF NOT EXISTS "couple_streaks_live_idx" ON "couple_streaks" ("last_completed_date") WHERE "current_streak" > 0;--> statement-breakpoint
-- The legacy data plane maintained streaks from a trigger that read auth.uid(). The API
-- owns that write now and runs it in the same transaction as the response, so drop the
-- trigger defensively in case a cutover ever carries these objects across.
DROP TRIGGER IF EXISTS "on_response_update_streak" ON "responses";--> statement-breakpoint
DROP FUNCTION IF EXISTS "update_couple_streak"();--> statement-breakpoint
DROP FUNCTION IF EXISTS "reset_daily_streak_flags"();
@@ -0,0 +1,3 @@
-- A shared streak only changes behaviour if somebody is told it is still open, so the
-- evening at-risk nudge gets its own opt-out rather than riding on milestone celebrations.
ALTER TABLE "notification_preferences" ADD COLUMN IF NOT EXISTS "streak_reminders_enabled" boolean NOT NULL DEFAULT true;
+28
View File
@@ -92,6 +92,34 @@
"when": 1787908500000,
"tag": "0012_catalogue_field_parity",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1787994900000,
"tag": "0013_daily_limit_local_reset",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1787994960000,
"tag": "0014_daily_limit_response_index",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1788081360000,
"tag": "0015_couple_streak_locality",
"breakpoints": true
},
{
"idx": 16,
"version": "7",
"when": 1788081420000,
"tag": "0016_streak_reminder_preference",
"breakpoints": true
}
]
}