Commit Graph

696 Commits

Author SHA1 Message Date
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 b115cd2f66 chore(seed): update daily question content 2026-07-01 02:55:34 -05:00
null e1a8528489 docs: restructure README screenshot table to daily-question stages + core screens 2026-07-01 02:55:30 -05:00
null d49d67ecbd docs: add reveal-ready brand art + screenshot 2026-07-01 02:55:24 -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 b19394b900 chore(seed): update daily question content to v61 weekly format 2026-07-01 02:20:09 -05:00
null a1b77f6786 docs: update README home screenshot alt text 2026-07-01 02:20:04 -05:00
null 18490f990e docs: update home screenshots (ready + your-turn states) 2026-07-01 02:19:57 -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 2ecff95c12 docs: update home-dark screenshot 2026-07-01 01:50:54 -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 7aa72532b7 docs: update home-dark screenshot 2026-07-01 00:21:54 -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 b15e696388 docs(questions): v6 — patch_policy and mass_rewrite_policy metadata fields 2026-06-30 23:48:23 -05:00
null 8897e103b6 docs(questions): v6 — Patch Mode Required, Mass Rewrite Exception 2026-06-30 23:48:18 -05:00
null 3b49b76b33 docs(questions): v7 — Patch Discipline Checks, Fun But Grounded Checks 2026-06-30 23:48:14 -05:00
null 1bdbed4fbc docs(questions): v8 — Daily Patch Discipline, Fun But Grounded 2026-06-30 23:48:10 -05:00
null 7f20fa8ee7 docs(questions): v6 — Patch Discipline, Fun But Grounded gate 2026-06-30 23:48:05 -05:00
null 94a7feeb43 docs(questions): add Daily Patch Review Loop Policy v1 and Research Notes v2 2026-06-30 23:48:01 -05:00
null fd5fae7444 docs: update README with E2EE chat, backup, and partner-assisted restore 2026-06-30 23:46:02 -05:00
null 39be5dd238 docs: R25-d entry for pruneDeadTokens implementation 2026-06-30 23:45:52 -05:00
null 1daf0c2bf5 docs(questions): v5.1 — Research-Informed Fun Rules, Daily Game Mechanics, Daily Content Metadata 2026-06-30 23:45:47 -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 afd1eab299 feat(users): wire pruneDeadTokens into onUserDelete 2026-06-30 23:45:36 -05:00