fix(notifications): route daily_question + challenge_day_ready taps (E-001 P2)
Client fromRemoteType mapped only daily_question_reminder/challenge_waiting; functions send daily_question/challenge_day_ready too. Tapping those now deep-links to Today / Connection Challenges. Also records Pass C (main screens clean) + Pass D (security clean). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
58208fd443
commit
ce12abb1a6
|
|
@ -37,11 +37,32 @@ _(Prior games/notifications QA from 2026-06-24 was completed + verified; superse
|
||||||
|
|
||||||
**Launch/crash sweep (QA, free):** This or That ✅ (mood/length select), How Well Do You Know Me ✅ (intro), Connection Challenges ✅, Spin the Wheel ✅ — all render, **no FATAL**. Desire Sync + Memory Lane are premium-gated (covered in Pass A; gameplay needs premium toggle). Date Match: todo. Full two-device start→finish + results not exhaustively re-run this round (the prior round verified `onGameSessionUpdate` start/finish end-to-end).
|
**Launch/crash sweep (QA, free):** This or That ✅ (mood/length select), How Well Do You Know Me ✅ (intro), Connection Challenges ✅, Spin the Wheel ✅ — all render, **no FATAL**. Desire Sync + Memory Lane are premium-gated (covered in Pass A; gameplay needs premium toggle). Date Match: todo. Full two-device start→finish + results not exhaustively re-run this round (the prior round verified `onGameSessionUpdate` start/finish end-to-end).
|
||||||
|
|
||||||
## Pass C — Visual (light + dark)
|
## Pass C — Visual (light + dark) (main screens verified; deep/stateful screens pending)
|
||||||
_not started_
|
**Method:** 5554=Dark, 5556=Light; readable dark|light pair montages + a code scan for non-adapting colors.
|
||||||
|
**Verified clean (both themes, readable, no clipping):** Home, Today, Play, Messages inbox, Settings. `closerBackgroundBrush()` is theme-aware (adapts). No FATAL on these.
|
||||||
|
| ID | Area | Screen | Severity | Description | Status |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| C-OBS | Theming | ~20 screens (AnswerRevealScreen 15, WheelSessionScreen 14, DateMatchScreen 10, PaywallScreen 9, BucketListScreen 9, SettingsScreen 7, HomeScreen 5, …) | observe | Use hardcoded `Color(0x…)` literals (195 total) that don't adapt to theme — a dark-mode contrast risk to verify per-screen. Main screens checked look fine; deep/stateful screens (reveal, wheel session, dates, bucket list) still need visual verification in both themes. | Open (verify in continuation) |
|
||||||
|
|
||||||
## Pass D — Security & Encryption
|
_Deep/stateful screens (answer reveal, wheel session/complete, date match/builder/matches, bucket list, memory capsule, history, paywall, auth/onboarding/pairing) need their states set up — pending next chunk._
|
||||||
_not started_
|
|
||||||
|
## Pass D — Security & Encryption ✅ clean (no P0/P1 found)
|
||||||
|
- **D1 at-rest:** all private content is ciphertext — message `text` + `lastMessagePreview` + thread messages = `enc:v1:`; daily answers `encryptedPayload` = `sealed:v1:`. Metadata (dates, types, commitmentHash, ids) plaintext as expected. Chat media bytes = Tink ciphertext (verified prior round + unchanged code path). **No plaintext content leak.**
|
||||||
|
- **D2 rules:** no catch-all `match /{document=**}`, no blanket `if true`; **`hasPremium` server-only** (client create/update blocked, rules L172/174); entitlements `write:false`; conversations/messages/typing/reactions + entitlement partner-read scoped to members.
|
||||||
|
- **D4 key exchange:** pairing uses a **wrapped couple key** (`wrappedCoupleKey` + `kdfSalt`/`kdfParams` + `encryptedRecoveryPhrase`); invite code is the KDF seed, never stored raw; strict E2EE (invites without a wrapped key rejected) — confirmed in `acceptInviteCallable`.
|
||||||
|
- **D5 App Check/secrets:** App Check enforced (`SecurityModule`, `PlayIntegrityChecker`, `FirebaseInitializer`); both service-account JSONs gitignored **and untracked**; `allowBackup=false`.
|
||||||
|
- **D6 leak vectors:** analytics events carry only metadata (no message/answer content); `allowBackup=false`.
|
||||||
|
|
||||||
|
_Follow-ups (not blockers): live **non-member negative test** (D3) needs a fresh 3rd account (rule logic verified member-scoped); a fresh Storage-bytes spot-check of chat media._
|
||||||
|
|
||||||
## Pass E — Notifications
|
## Pass E — Notifications
|
||||||
_not started_
|
- **Copy carries no private content:** all function notification bodies are generic ("Tap to read and reply", "Answer together before it expires", etc.); `${title}` refers to public question/game titles, not user answers. ✓ (ties to D6)
|
||||||
|
- **Routing:** centralized in `PartnerNotificationType` (`fromRemoteType` → `routeFor`); chat opens the exact conversation, reveal→answerReveal(questionId), games→Play, capsule→Memory Lane, etc.
|
||||||
|
- **Foundations** (prior round, code present): FCM token registration on sign-in, POST_NOTIFICATIONS, channels.
|
||||||
|
|
||||||
|
| ID | Area | Severity | Description | Status |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| E-001 | Notification routing | **P2** | Type-string mismatch: functions send `daily_question` + `challenge_day_ready`, but client mapped only `daily_question_reminder` + `challenge_waiting` → tapping those did NOT deep-link to Today / Connection Challenges. | **FIXED** `<pending-commit>` — added `daily_question`/`challenge_day_ready` to `fromRemoteType` (build green; live tap-verify deferred). |
|
||||||
|
| E-002 | Notification routing | **P3** | `partner_left`, `partner_deleted_account`, `invite_created`, `spki` are unmapped → tap lands on default (no deep-link). Informational types; acceptable but ideally routed. | Open |
|
||||||
|
|
||||||
|
_Full live delivery matrix (17 types × foreground/background/killed) deferred — key types verified prior round; routing now code-correct._
|
||||||
|
|
|
||||||
|
|
@ -287,10 +287,12 @@ enum class PartnerNotificationType(
|
||||||
// is ready, so this maps to the results-ready copy (not "open yours when ready").
|
// is ready, so this maps to the results-ready copy (not "open yours when ready").
|
||||||
"partner_finished_game" -> GAME_RESULTS_READY
|
"partner_finished_game" -> GAME_RESULTS_READY
|
||||||
"game_results_ready" -> GAME_RESULTS_READY
|
"game_results_ready" -> GAME_RESULTS_READY
|
||||||
"challenge_waiting" -> CHALLENGE_WAITING
|
// Server emits 'challenge_day_ready'; keep the legacy 'challenge_waiting' alias too.
|
||||||
|
"challenge_day_ready", "challenge_waiting" -> CHALLENGE_WAITING
|
||||||
"memory_capsule_unlocked" -> CAPSULE_UNLOCKED
|
"memory_capsule_unlocked" -> CAPSULE_UNLOCKED
|
||||||
"gentle_reminder" -> GENTLE_REMINDER
|
"gentle_reminder" -> GENTLE_REMINDER
|
||||||
"daily_question_reminder" -> DAILY_QUESTION_REMINDER
|
// Server emits both 'daily_question' (assignment) and 'daily_question_reminder' — both open Today.
|
||||||
|
"daily_question", "daily_question_reminder" -> DAILY_QUESTION_REMINDER
|
||||||
"chat_message" -> CHAT_MESSAGE
|
"chat_message" -> CHAT_MESSAGE
|
||||||
"outcome_reminder" -> OUTCOME_REMINDER
|
"outcome_reminder" -> OUTCOME_REMINDER
|
||||||
"partner_joined" -> PARTNER_JOINED
|
"partner_joined" -> PARTNER_JOINED
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue