feat: streak-loss reminder notification#168
Open
code418 wants to merge 1 commit into
Open
Conversation
Add a scheduled gameplay notification that nudges players who are about to break their daily claim streak. - New scheduled function `streakReminder` (functions/src/streakReminder.ts): polls every 15 min from 17:00–20:45 Europe/London and fires once per day at a random slot within that window, so the reminder lands at an unpredictable time between 5pm and 9pm UK time. Recipients are users whose `lastClaimDate == yesterday` (claimed yesterday, not yet today), so they still have a streak to lose. - Dispatch bookkeeping (random target slot + sent marker) is persisted in a server-only `notificationState/streakReminder` doc, gated in a transaction so overlapping invocations can't double-send. - Export `sendToUser` from `_notifications.ts` for reuse. - Add `previousDay` and `getLondonHourMinute` helpers to `_dateUtils.ts`. - New opt-out pref `streakReminder` (default on): defaulted in `onUserCreated`, gated with the existing `=== false` convention, and surfaced as a Switch in the Settings notifications section. - firestore.rules: explicit server-only block for `notificationState`. - Unit tests for the slot maths, the pure fire-decision logic, pref gating, recipient query, and fan-out send. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S9hCUG7puzA94Ed46oJASU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Expands the notification system with the first gameplay push (the existing ones are all social). Once a day, at an unpredictable time between 5pm and 9pm UK time, we remind players who claimed yesterday but haven't claimed today that they'll lose their daily streak unless they claim before midnight.
How it works
New scheduled function
streakReminder(functions/src/streakReminder.ts), mirroring thenewDayScoreboardpattern (thinonSchedulewrapper + exported, unit-tested helpers):*/15 17-20 * * *,Europe/London) across a 16-slot window (17:00 … 20:45). On the day's first run it rolls a random target slot and fires once when that slot is reached — giving an unpredictable send time that's guaranteed to land inside the 5–9pm window. Firing onslot >= target(not==) keeps it robust to a skipped scheduler run.{ day, targetSlot, sentDay }) lives in a server-onlynotificationState/streakReminderdoc, read-and-written inside a transaction so two overlapping invocations can't double-send.users where lastClaimDate == yesterday— sincelastClaimDateadvances to today the moment a user claims, this is exactly "claimed yesterday, not yet today" (and impliesstreak >= 1).Supporting changes:
_notifications.ts: export the existingsendToUserFCM helper for reuse._dateUtils.ts: addpreviousDayandgetLondonHourMinutehelpers.streakReminder(default on): defaulted inonUserCreated, gated with the existing=== falseconvention, and surfaced as a Switch in the Settings → Notifications section (lib/settings_screen.dart).firestore.rules: explicit server-only block fornotificationState(consistent withreportQuotas/trustScores).CLAUDE.md: documented the new function, helpers, and pref.Tests
Added unit tests (
functions/src/test/test.index.ts) for the slot maths (slotForLondonTime), the pure fire-decision (decideFire— random roll, fires at/after target, never twice/day, drops stalesentDay), pref gating (shouldNotifyStreakReminder), thepreviousDay/getLondonHourMinutehelpers, the recipient query (mock Firestore), and the fan-out send (opt-out + allSettled). The region-pinning loop auto-covers the new export (europe-west2). All 33 new/related assertions pass;npm run buildandeslintare clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01S9hCUG7puzA94Ed46oJASU
Generated by Claude Code