Commit Graph

46 Commits

Author SHA1 Message Date
null 4040abbf28 refactor(functions): B1 migrate 13 Firestore triggers to v2 + harden
Migrate all Firestore triggers off the v1 API to firebase-functions/v2/firestore
(onDocumentCreated/Updated/Written); context.params→event.params, snap→event.data,
change.before/after→event.data.before/after. Region stays us-central1 (global option).

Hardening folded in (all reuse in-repo patterns):
- Adopt the shared sendPushToUser()/getUserTokens() helper in every trigger, removing
  ~7 copied token readers and the copied send/prune blocks. FCM tokens are no longer
  logged in plaintext anywhere here (redacted inside push.ts).
- console.* → firebase-functions/logger (structured).
- Idempotency: new claimOnce() (atomic create-if-absent marker under
  couples/{id}/notif_marks) dedupes at-least-once redelivery on the non-idempotent
  senders (onAnswerWritten/Revealed, onMessageWritten, onCoupleLeave, onEntitlementChanged,
  onDateReflectionWritten/Revealed, onDateHistoryCreated). Fail-open. onGameSessionUpdate/
  onGamePartFinished/notifyOnDateMatch already had transactional claim-flags — preserved.
- onRestoreRequested: the plan's "claim" is implemented as the existing 60s time-WINDOW
  (lastRestorePartnerAlertAt), not a permanent recipientUid marker — a permanent marker
  would wrongly block legitimate re-requests (restore docs are deleted+recreated by design).

Faithful port of onGameSessionUpdate/onGamePartFinished (broad wildcard + allowlist kept);
the trigger split and read reorder are deferred to B6 as separate commits.

Build clean; 70 tests green (+ new idempotency.test.ts, push token/prune tests). Emulator
discovery loads all triggers as v2 in us-central1. firebase-functions still v5.1.1 (v6 bump
deferred to B6). dist rebuilt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:46:17 -05:00
null fbf4e7957c build(functions): B0 v2 foundation — global options, shared push helper, structured logging
Groundwork for the v1→v2 Cloud Functions migration; no function is migrated yet
(all 35 still load as v1, verified via emulator discovery).

- options.ts: setGlobalOptions({ region: 'us-central1', maxInstances: 20 }), imported
  first in index.ts so it applies before any v2 function is defined. Region pin is
  load-bearing — the Android client uses the default region.
- notifications/push.ts: single canonical getUserTokens() + sendPushToUser() that
  batches via messaging.sendEachForMulticast() and prunes dead tokens, to replace the
  ~10 copied token readers and ~19 copied send/prune blocks in later batches.
- log.ts: firebase-functions/logger re-export + redactToken() (FCM tokens are secrets).
- push.test.ts: 9 unit tests (token merge/dedupe, BatchResponse→dead-token mapping,
  send/prune/no-op/whole-batch-failure paths). 67 tests green.

firebase-functions stays at v5.1.1 for the migration (supports both the root v1 API and
the /v2 subpaths); bump to v6 is deferred to the final batch once nothing references the
root namespace, so the build stays green at every step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:36:16 -05:00
null 3acba138a3 chore(functions): rebuild dist for deployed daily-question + game-copy changes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 22:31:02 -05:00
null 89cbd7cb55 refactor(functions): type callable payloads instead of `any`
Change the 5 https.onCall handlers from `data: any` to
`data: Record<string, unknown>`, so payload fields are `unknown` and must go
through the existing validators rather than being implicitly-typed. No behavior
change (every field was already validated); tsc + 53 function tests green.

Left as-is deliberately: `catch (err: unknown)` narrowing (churn, marginal) and
the untyped Tink handles in wrapReleaseKeyCallable (the crypto lib ships no types).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:06:45 -05:00
null eeac3c9383 build(functions): compile dist for outcome aggregation
Tracked dist output rebuilt to match src (aggregateOutcomeStats export +
aggregateOutcomes module), keeping the deployed bundle in sync with source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:10:02 -05:00
null 896bf26b28 feat: date reflection reveal, UI upgrade plan, seed updates, ime-scan script 2026-07-01 04:12:58 -05:00
null d8408a2c44 chore(functions): rebuild dist with pruneDeadTokens wired into all 19 push sites 2026-06-30 23:45:42 -05:00
null 37815af781 chore: rebuild functions dist (add onRestoreRequested + onRestoreFulfilled exports) 2026-06-30 20:43:58 -05:00
null 4dd60a6a4d chore(date-memories): add compiled onDateReflectionWritten 2026-06-30 18:14:54 -05:00
null 2c47c222de chore(date-memories): add compiled onDateHistoryCreated 2026-06-30 18:14:52 -05:00
null d4cedaf304 chore(date-memories): update compiled function index 2026-06-30 18:14:50 -05:00
null 6dddac4615 Revert "feat(date-memories): add onDateHistoryCreated + onDateReflectionWritten Cloud Functions (batch 5/8)"
This reverts commit 8829cffa7e.
2026-06-30 18:13:00 -05:00
null 8829cffa7e feat(date-memories): add onDateHistoryCreated + onDateReflectionWritten Cloud Functions (batch 5/8) 2026-06-30 16:51:59 -05:00
null d87603211a feat(activity): ActivityScreen timeline, HomeScreen activity feed, HomeViewModel wiring, PartnerNotificationManager, sendThinkingOfYouCallable Cloud Function 2026-06-30 03:54:01 -05:00
null e74b6f59af feat(cloud-functions): onEntitlementChanged, acceptInviteCallable, onGameSessionUpdate, onAnswerRevealed, onMessageWritten — FirestoreUserDataSource E2EE, AppMessagingService, EditProfileScreen, iOS plan 2026-06-30 02:38:31 -05:00
null 2a5c40508e feat(notifications): QuietHoursManager + NotificationSettingsScreen rewrite, Cloud Functions (streakReminder, quietHours, reengagement, gameRetention), UserRepository E2EE wiring, SettingsDataStore, firestore rules, wiring-scan 2026-06-30 00:38:06 -05:00
null f51a55743c feat(games): partner game-session push orchestration — in-app notification banner, Firestore rules, Cloud Function, QA docs 2026-06-28 22:24:46 -05:00
null 37ed7cebec feat: quiet hours notifications, settings UI, game session updates, docs 2026-06-28 10:00:25 -05:00
null 4eed0a8115 feat(premium): couple-shared unlock notification + reveal retry + users update allowlist + brand glyphs
- New Cloud Function: onEntitlementChanged (Firestore onWrite on entitlements/premium) — edge-triggered inactive→active, notifies the OTHER partner so couple-shared unlock isn't silent
- New notification type SUBSCRIPTION_CHANGED → routes to SUBSCRIPTION
- AnswerRevealViewModel: re-issue markRevealed if best-effort failed (offline/transient) so partner_opened_answer push eventually fires
- firestore.rules: harden users/{uid} update allowlist (defense-in-depth; no live hole)
- 18 new brand glyph vector drawables (drawable-nodpi/)
- SettingsScreen / PlayHubScreen / WaitingForPartnerScreen: swap Material icons for new brand glyphs
- ClaudeQA docs + Future.md updated
2026-06-27 16:35:41 -05:00
null 2cd0af65a8 chore: working tree changes — QA docs, app tweaks, Cloud Functions updates 2026-06-27 13:31:09 -05:00
null 6e79cd9704 fix(notif): replace status-diff with idempotent flag-claim for game start/finish pushes (F-RACE-001) 2026-06-26 20:04:05 -05:00
null 47867b5663 feat(notif): onAnswerWritten detects both-answered — send 'unlocked' notification instead of 'go answer' 2026-06-26 12:40:41 -05:00
null 8b4c5ba005 feat(notif): add onAnswerRevealed cloud function — notify partner when answers are opened 2026-06-26 12:40:36 -05:00
null 765916a8ef build(functions): recompile dist for E-OBS + E-003 results-ready changes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 12:40:38 -05:00
null 29beff1702 build(functions): rebuild dist from source — revenueCatWebhook ack-after-process, acceptInvite strict E2EE, onMessageWritten conversations path, onGameSessionUpdate both-partner notify 2026-06-24 16:15:30 -05:00
null 7d3b47b3ba fix(firestore): handle Timestamp type for lastAnsweredAt/createdAt in Android + Cloud Function 2026-06-23 12:40:00 -05:00
null 658ead38cd security: App Check enforcement on all callables, fail-closed device integrity, no raw code in logs; release signing config; iOS RevenueCat log level 2026-06-23 10:56:42 -05:00
null 5e16177eb2 feat: code push -- notifications, cloud functions, iOS updates 2026-06-22 08:53:23 -05:00
null af70280daa feat: E2EE recovery flow, iOS parity updates, onboarding + pairing polish 2026-06-21 11:20:48 -05:00
null 0a377ecdda fix(accept-invite): dynamic encryptionVersion, Firestore TTL on attempt docs, wipe recoveryPhrase on accept 2026-06-21 09:13:29 -05:00
null 26419ce08d feat: remove email invite screen, add accept-invite rate limiting, clean up iOS pairing (v0.2.2) 2026-06-21 08:55:43 -05:00
null 57a3e35359 feat(outcomes): add 30/60/90 day check-in flow with baseline + reminders 2026-06-20 23:59:24 -05:00
null 1f777e827d feat: add onMessageWritten cloud function, notification settings screen, user repo cleanup 2026-06-20 18:25:05 -05:00
null 4dad0e774e refactor: update crypto, invite flow, and account screen patterns 2026-06-20 18:09:46 -05:00
null 0e75b3b536 feat: add gentle reminder callable and wire into HomeViewModel (batch v1.0.12)
- GENTLE_REMINDER notification type with warm copy
- sendGentleReminderCallable Cloud Function
- HomeViewModel.sendGentleReminder() calls function, shows snackbar
- Snackbar event consumed after display
2026-06-19 23:47:01 -05:00
null 39255c8733 fix: prevent invite code enumeration via Cloud Function (batch v0.2.18)
- Remove client-side read access to invites (only inviter can read own invite)
- Deny direct client update to invites (server-side only via Admin SDK)
- Add acceptInviteCallable Cloud Function: validates code, creates couple,
  updates user docs, marks invite accepted, returns wrapped key for local decryption
- Update Android client: FirestoreInviteDataSource calls callable function,
  InviteConfirmViewModel uses acceptInvite + unwrapAndStore flow
- Deprecate CoupleRepositoryImpl.createCouple (client-side path removed)
- Update Firestore rules tests: unpaired read now denied, direct update now denied
- 118/118 tests passing
2026-06-19 21:46:12 -05:00
null 6828be72fc feat: Cloud Functions — leaveCoupleCallable, onUserDelete cascade (batch v0.2.8)
- Add leaveCoupleCallable: HTTPS callable that atomically unlinks couple via Admin SDK (clears both user coupleIds, recursiveDelete couple doc)
- Add onUserDelete: Auth deletion trigger that cascades cleanup — unpairs partner, sends FCM notification, deletes Storage objects, recursiveDelete user doc
- Replace client-side batch leaveCouple with callable invocation (Firestore rules prevent cross-user writes)
- Remove CoupleRepository/UserRepository from DeleteAccountViewModel — cleanup now handled by onUserDelete trigger
- Wire new functions into index.ts exports
2026-06-19 20:04:18 -05:00
null 0e0a33a6dd feat: add FCM game retention notification functions, messaging service updates, ThisOrThat screen fixes 2026-06-19 02:23:52 -05:00
null 2b8e05b29b fix: address Neo review — fix cloud function partnerName scope, WheelCompleteScreen session ID, polling isActive, navigateTo reset 2026-06-18 01:28:43 -05:00
null c0696cfb80 feat: partner leave notification, real-time couple state sync, in-app unpair alerts 2026-06-18 00:25:52 -05:00
null eaac8ffcc9 feat: couple-scoped daily question, answer sync, partner notifications, and answer review 2026-06-18 00:18:05 -05:00
null c816033e74 feat: cloud function for date match cleanup, ViewModel and repo improvements 2026-06-17 20:26:24 -05:00
null ec315c63e0 feat: add App Integrity + device attestation modules 2026-06-17 19:37:19 -05:00
null 534bb076c7 feat: implement Ed25519 RevenueCat webhook signature verification 2026-06-17 19:08:53 -05:00
null f3bad90ec6 feat(notifications): FCM token registration, quiet hours, notification permission helper, reminder Cloud Functions (batch 11) 2026-06-17 01:30:04 -05:00
null b9ad713ddb feat(billing): server-side entitlement sync — RevenueCat webhook handler, entitlement logic, Firestore EntitlementChecker, Hilt DI, callable sync function (batch 10) 2026-06-17 01:25:51 -05:00