Commit Graph

402 Commits

Author SHA1 Message Date
null 95c3bc21fa feat(dates): Firestore-backed date catalog + sponsored ideas
- DateIdea gains sponsored/sponsorName/externalUrl (native, clearly-labeled ads
  — no tracking SDK).
- FirestoreDateIdeaDataSource reads the server-curated date_ideas collection
  (defensive: malformed docs skipped, https-only externalUrl); DateMatchRepo
  serves remote first, falling back to the shipped static seed when empty/failed
  so the feature always has content. Fallback verified live (Date Match renders
  the seed) + unit-tested (remote-present / empty / failure).
- Date card shows a "Sponsored · <name>" pill and a "Learn more" link (opened via
  the system browser, https-only, no click IDs).
- Local admin seeder (functions/scripts/seedDateIdeas.ts + date_ideas_seed.json,
  generated from the Kotlin seed + 1 sponsored example) — idempotent by id, has a
  --dry-run; NOT a deployed endpoint. Verified: 38 docs upserted to the emulator,
  1 sponsored, tsc builds.

Owner: run the seeder against prod (GOOGLE_APPLICATION_CREDENTIALS) to populate
date_ideas; add real sponsor content.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:02:22 -05:00
null 6ecc98eec2 feat(paywall): free-trial/intro pricing, gift framing, one-time SKUs
- PaywallPricing turns a RevenueCat Package into a headline price + an offer line
  (free trial, intro price, or one-time), so a dashboard-configured trial or a
  lifetime SKU renders without an app release; unknown shapes degrade to the
  plain price. Pure formatting is unit-tested (PaywallPricingTest); the SDK
  extraction is type-checked against purchases 8.20.
- Gift framing on the plan chooser ("One subscription covers you both — treat
  your partner"): couple-shared premium already unlocks both partners, so this
  is copy only, no billing change.

Live paywall (real offerings) still needs a real RC key + sandbox per
docs/SUBSCRIPTION_GO_LIVE.md (owner).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:53:15 -05:00
null 8464cb9219 feat(analytics): record specific notification type on push-opened
Foreground notification taps carried only app_route, so their
push_notification_opened event logged the generic "app_route" category. Also
put the notification type on the intent so the event records the specific kind
(partner_answered, reveal_ready, ...). Backgrounded taps already carry type via
the FCM data payload. Completes push-opened coverage across both tap paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:48:49 -05:00
null 368d8c455f fix(streak): gentle day-based streak with a grace day + earlier milestones
The live couple streak used a raw 48h rule that reset on any 48h gap AND
inflated the count by incrementing on every answer (several a day counted
several times). Replace with StreakCalculator.nextCount: once per calendar day,
one forgiving grace day (a single missed day still continues), reset only after
2+ missed days; skip the redundant write on a same-day answer.

Celebration milestones now include the habit-building early tiers
(1/3/7/14/30/100/365), single-sourced from StreakCalculator so the count and the
celebration can't drift; the milestone dialog handles day 1 grammatically.

Tested (StreakCountTest): same-day idempotency, consecutive, grace, reset, and
partner timezone-skew (never breaks a same-boundary streak). Existing 24
StreakCalculator tests still pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:46:14 -05:00
null f0a05f779b feat(widget): Glance "Today" home-screen widget
Content-free daily-question state + streak, mirrored from HomeViewModel via a
dedicated DataStore (TodayWidgetUpdater -> TodayWidgetState). App-lock drops it
to a generic card so partner-activity state doesn't sit on the protected home
screen; signed-out/unpaired show neutral prompts. Tapping opens the daily
question via MainActivity's app_route extra.

Verified: provider registers, state bridge writes, headline logic unit-tested
(TodayWidgetTest), no crash on launch. On-home-screen render + a Remote Config
kill switch are tracked in Future.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:40:28 -05:00
null 55699e17ed feat: security hardening, CI, analytics, invite deep links, solo mode, weekly recap
Roadmap phases 0-3.1 (see plan). Verified: unit tests, functions tests,
firestore rules 119/119, live emulator smokes.

Security + CI:
- Move App Check debug token out of committed build.gradle.kts to
  local.properties (secret() resolver: local.properties -> -P -> env);
  admin service-account key relocated outside the repo.
- Add GitHub Actions (android unit/scan/gitleaks, backend functions +
  rules emulator via emulators:exec) with a CI google-services.json stub
  and a reviewed .gitleaksignore baseline.
- Fix firestore rules tests to the current deployed contract (was 108/118,
  now 119/119).

Analytics + consent:
- FirebaseRetentionAnalytics behind a fail-safe composite sink, single-
  sourced hashing (AnalyticsHashing), Settings -> Privacy opt-out toggle
  gating Firebase + the sink, and the ~11 missing event call sites.
- NoPlaintextInAnalyticsTest guards the content-free rule at build time.

Funnel:
- Invite deep links (https App Link + closer:// fallback), JoinLink parser,
  PendingJoinCodeStore, prefilled/already-paired pairing, richer share text.
- Solo pre-pairing: UnpairedLockedCard on Play, SoloAnswerMigrator + consent
  dialog moving pre-pairing answers into Couple Lore.

Weekly recap:
- WeeklyRecapScreen driven by the existing generator from local answer data,
  Home card rewired, content-free shareable card.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:33:38 -05:00
null f68cab5cf2 feat: signup flow, age gate, user model updates, how well screen, game prompt banner 2026-07-02 02:42:55 -05:00
null 24823a39f0 feat: question discussion components, conversation VM, wheel session, settings, text input limits 2026-07-01 21:39:00 -05:00
null 09fea873e2 fix: DateReflectionScreen and FirestoreDateReflectionDataSource updates 2026-07-01 20:01:01 -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 222bbd1c57 chore(db): update seed database 2026-07-01 02:55:38 -05:00
null 31a2652e48 feat(art): add illustration_daily_reveal_ready (light + dark) 2026-07-01 02:55:20 -05:00
null d03e071098 feat(home): escalate daily-question art by state (partner prompt → reveal ready) 2026-07-01 02:55:15 -05:00
null 6d0a52641c feat(daily): rename modes to weekday theme names (Mood Check Monday, Tiny Win Tuesday, etc.) 2026-07-01 02:55:11 -05:00
null 611481786f fix(home): update PairedHomePreview to BOTH_ANSWERED state 2026-07-01 02:19:35 -05:00
null cbffaeca9f test(settings): ChangePasswordViewModelTest — validation + typed exception mapping 2026-07-01 02:19:31 -05:00
null e585856228 feat(nav): wire ChangePasswordScreen composable into AppNavigation 2026-07-01 02:19:26 -05:00
null 06c94f55f4 feat(nav): add CHANGE_PASSWORD route constant 2026-07-01 02:19:22 -05:00
null a096ca15d1 feat(settings): add Change password row to SecurityScreen (email/password accounts only) 2026-07-01 02:19:18 -05:00
null 30000e7150 feat(settings): ChangePasswordScreen + ViewModel with validation and typed error mapping 2026-07-01 02:19:14 -05:00
null 7fe095ef3b feat(auth): delegate changePassword in FirebaseAuthRepositoryImpl 2026-07-01 02:19:11 -05:00
null 54608796e1 feat(auth): add changePassword to AuthRepository interface 2026-07-01 02:19:04 -05:00
null d1e23f24ee feat(auth): wire changePassword with reauth + typed exceptions in FirebaseAuthDataSource 2026-07-01 02:19:01 -05:00
null 07eaf3c989 feat(auth): ChangePasswordException sealed class with typed failure reasons 2026-07-01 02:18:50 -05:00
null 7ff405cad6 feat(notifications): remove partner avatar from notifications (privacy) 2026-07-01 01:50:50 -05:00
null f47fa3cdbd test(auth): ForgotPasswordViewModelTest — typed exception + blank-email coverage 2026-07-01 01:50:46 -05:00
null 1a6cdaa078 feat(auth): enumeration-safe forgot-password confirmation copy 2026-07-01 01:50:40 -05:00
null 79bfea7cfb feat(auth): use typed PasswordResetException in ForgotPasswordViewModel 2026-07-01 01:50:36 -05:00
null 885af0b9e4 feat(auth): wire typed PasswordResetException into FirebaseAuthDataSource 2026-07-01 01:50:32 -05:00
null a1d2ea2db8 feat(auth): typed PasswordResetException sealed class 2026-07-01 01:50:27 -05:00
null f117da16c8 test(home): 10 unit tests for computeDailyQuestionState 2026-07-01 00:21:42 -05:00
null 0feb72eaf0 feat(home): reveal-waiting art swap, copy polish, extracted computeDailyQuestionState 2026-07-01 00:21:33 -05:00
null aa09566636 feat(backup): lock-less phrase reveal, copy-to-clipboard, partner-restore empty-state, manual helper entry (R24-d) 2026-06-30 21:24:52 -05:00
null b78dc24870 feat(backup): add back button to restore screens (R24-d) 2026-06-30 21:24:36 -05:00
null 71227561e7 feat(backup): pass recovery phrase through RestoreManager fulfill/complete (R24-c) 2026-06-30 21:24:30 -05:00
null 209ad74532 feat(backup): add ckx:v1 keybox envelope for recovery phrase transfer (R24-c) 2026-06-30 21:24:26 -05:00
null db948511fb chore: add org.json:json:20240303 test dependency for BackupCodec round-trips 2026-06-30 20:43:30 -05:00
null 139a78c222 feat(backup): add RESTORE_REQUESTED and RESTORE_SELF_ALERT notification types 2026-06-30 20:43:18 -05:00
null 72c251ae95 feat(backup): wire opportunistic backup trigger into HomeViewModel.loadHome 2026-06-30 20:43:14 -05:00
null fd854b635c feat(backup): add RESTORE_REQUEST and RESTORE_CONSENT routes + navigation 2026-06-30 20:43:10 -05:00
null df9edc1daf feat(backup): add 'Ask your partner to restore' entry to RecoveryScreen 2026-06-30 20:43:06 -05:00
null f161fa49a5 feat(backup): add RestoreViewModel + RestoreRequestScreen + RestoreConsentScreen (partner-assisted restore UI) 2026-06-30 20:43:02 -05:00
null ed3c3e4d22 feat(backup): add RestoreManager (request/fulfill/complete partner-assisted restore with OOB code gate) 2026-06-30 20:42:58 -05:00
null c8b0130f1c feat(backup): add CoupleKeyTransfer (ECIES couple-key wrap + OOB verification code) and CoupleEncryptionManager export/store methods 2026-06-30 20:42:54 -05:00
null 4ac2c8f841 feat(backup): add BackupManager (incremental append + compaction) and BackupRestoreManager (download + decrypt + upsert) 2026-06-30 20:42:50 -05:00
null f94fccfc61 feat(backup): wire ConversationCacheDatabase and DAO into DatabaseModule 2026-06-30 20:42:46 -05:00
null ab59e7e5c9 feat(backup): add ConversationCache Room DB (entity, DAO, database) 2026-06-30 20:42:42 -05:00
null 230e7f6201 feat(backup): add uploadBackupSnapshot and deleteBackupSnapshot to FirebaseStorageDataSource 2026-06-30 20:42:38 -05:00
null 909d261b6c feat(backup): add backup record reads to FirestoreConversationDataSource (getConversationsForBackup, getBackupRecords) 2026-06-30 20:42:34 -05:00
null 522823f739 feat(backup): add FirestoreBackupDataSource (manifest CAS, chunk append, snapshot compaction, restore requests) 2026-06-30 20:42:30 -05:00