Commit Graph

504 Commits

Author SHA1 Message Date
null 935aee5ec5 feat: add partner-trigger notifications with rate limits and quiet hours (batch v1.0.4)
- PartnerNotificationManager: 6 notification types, static copy only
- NotificationRateLimiter: max 2 partner/day, 1 reminder/day, 4/week
- QuietHoursManager: default 10pm-8am, user-configurable
- NotificationChannelSetup: partner-actions channel (HIGH importance)
- PartnerNotificationScheduler: routes FCM events through manager
- AppMessagingService: safe static copy, drops unknown types
- Deep link navigation for all notification targets
- 3 test files covering quiet hours, rate limits, notification types
2026-06-19 22:34:42 -05:00
null 9828e73171 feat: add 'Waiting for you' unfinished business dashboard (batch v1.0.3)
- PendingActionCard data class with priority-ordered cards
- 6 card types: reveal ready, partner answered, game, challenge, date, capsule
- Max 3 cards, highest priority first, deep link to correct screen
- Placeholder guards for game/challenge/date/capsule (wired in later batches)
- Compact cards with purple/pink palette, no private text leaked
2026-06-19 22:31:11 -05:00
null c38e83b8ee feat: add streak calculator with couple/personal/weekly streaks and repair (batch v1.0.2)
- Streak data models: Couple, Personal, WeeklyRhythm streaks
- StreakCalculator: pure Kotlin, no Android deps, deterministic
- Milestone copy at 1/3/7/14/30 days
- Streak repair: 1 missed day per 7-day window, requires both partners
- 23 unit tests covering all streak types, milestones, repair, timezone
2026-06-19 22:25:47 -05:00
null 0b619ee7ba feat: improve daily question habit loop with 5 UI states (batch v1.0.1)
- Add DailyQuestionState enum to HomeViewModel with 5 states
- Real-time Firestore listener for partner's daily answer
- Home card shows correct copy/CTA per state
- CTAs: answer, gentle reminder (no-op), reveal, follow-up (placeholder)
- Cleanup listener on onCleared()
2026-06-19 22:23:24 -05:00
null aff1150295 feat: add retention events and analytics wrapper (batch v1.0.0)
- RetentionEvent sealed class with 19 event types (metadata only, no answer text)
- RetentionAnalytics interface + LogcatRetentionAnalytics (debug-only, hashed IDs)
- NoopRetentionAnalytics for tests/disabled state
- Hilt AnalyticsModule binding as singleton
- Couple IDs SHA-256 hashed before logging
2026-06-19 22:20:49 -05:00
null 1441dcaebc chore: add retention loops build plan to project root and gitignore 2026-06-19 22:15:41 -05:00
null 700201bbd6 refactor: extract EncryptedSharedPreferences into SecurePreferencesFactory with auto-recovery (batch v0.2.21)
- New SecurePreferencesFactory handles EncryptedSharedPreferences creation
- Auto-resets and recreates on corruption (unreadable prefs)
- CoupleKeyStore and SharedPreferencesLocalAnswerRepository use the factory
- Removes duplicated EncryptedSharedPreferences boilerplate
2026-06-19 22:06:52 -05:00
null 8be7b7da0e chore: update couple create rule comment to reflect server-only flow (batch v0.2.20) 2026-06-19 21:52:19 -05:00
null c31177d52b chore: remove dead invite code after Cloud Function migration (batch v0.2.19)
- Remove unused markAccepted from InviteRepository/Impl
- Remove unused loadedInvite field from InviteConfirmViewModel
- Fix deprecated getHttpsCallable result access
- Remove unused SetOptions import
2026-06-19 21:50:29 -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 749d3aa6fd test: add Firestore rules extra-field injection tests (batch v0.2.17)
- Add extra-field injection tests for daily answers, thread answers, messages (create + update), and reactions
- Fix existing message update test: use setDoc instead of updateDoc (hasOnly(['text']) requires full replacement)
- Fix existing reaction test: remove targetUserId (not in whitelist)
- Add seedThread() to reaction allowed test for consistency
- 118/118 tests passing
2026-06-19 21:29:42 -05:00
null 2e2c79be3d fix: remove android.util.Base64 from RecoveryKeyManager for portability (batch v0.2.16)
- Replace android.util.Base64 with java.util.Base64 in RecoveryKeyManager
- Crypto layer now has zero Android SDK dependencies — portable to iOS/shared testing
2026-06-19 21:26:35 -05:00
null c1f7e6f7f9 feat: daily question date key uses local timezone instead of UTC (batch v0.2.15)
- Replace SimpleDateFormat/Calendar UTC date key with java.time LocalDate in device timezone
- FirestoreAnswerDataSource: todayLocalDateString() with injectable Clock, localDateString() helper
- DailyQuestionViewModel: pass date through submit flow so sync uses same date key
- AnswerRevealViewModel: use todayLocalDateString() for partner answer lookup
- Add FirestoreAnswerDataSourceTest: verifies timezone-aware date boundaries (Chicago vs Tokyo, LA vs London)
2026-06-19 21:24:53 -05:00
null 70bb0a346c fix: normalize crypto files to plain ASCII (batch v0.2.14)
- Replace smart quotes, em dash, prime, right arrow in comments with ASCII equivalents
- Affected: CoupleEncryptionManager.kt, FieldEncryptor.kt, RecoveryKeyManager.kt
2026-06-19 21:22:27 -05:00
null 85b4eb589b feat: add 3 stronger privacy slogans to BrandMessageRotator (batch v0.2.13)
- Add to CloserBrandCopy: 'Not even Closer can read your answers.', 'End to end encrypted private responses.', 'Built for trust, not tracking.'
- Update visual-identity.md: add new slogans to approved rotation, remove migration gating note (all legacy couples migrated)
2026-06-19 21:17:59 -05:00
null 55ca3dce27 fix: Firestore rules hardening, recovery phrase strength, test cleanup (batch v0.2.12)
- Firestore rules: add isCouplesMember(coupleId) to question thread answer writes (prevents outsider writes)
- Firestore rules: allow currentIndex increment on same-status session updates (fixes thread progression)
- RecoveryKeyManager: PHRASE_WORD_COUNT 6→10 (~80 bits entropy)
- build.gradle.kts: exclude META-INF/versions/9/OSGI-INF/MANIFEST.MF (packaging conflict)
- .gitignore: add firebase-debug.log, firestore-debug.log
- firestore-tests: configurable emulator port via FIRESTORE_EMULATOR_PORT env var
- firestore-tests: fix invite outsider test (seed with different coupleId), fix non-starter session test (active→completed allowed), remove redundant beforeEach(seedThread), add outsider-write-denied test for thread answers
- visual-identity.md: update encryption claim gating note
2026-06-19 21:08:55 -05:00
null 3233c54ab2 feat: strict E2EE — encryption migration, Firestore rules enforcement, version 2 protocol (batch v0.2.11)
- Add CoupleAnswerMigrationDataSource: one-time per-user rewrite of all historical answer-bearing fields (daily answers, thread answers/messages, ThisOrThat, DesireSync, HowWell, Wheel) to ciphertext
- Add EncryptionUpgradeScreen + ViewModel: handles version-0→1→2 migration, recovery phrase display, partner coordination
- Add FieldEncryptorTest: round-trip, cross-couple binding, null-key, plaintext-not-leaked
- CoupleEncryptionManager: STRICT_ENCRYPTION_VERSION=2, requireAead() throws on missing key, setupLegacyCouple, pendingRecoveryPhrase/acknowledge
- CoupleKeyStore: pending recovery phrase storage/clear
- FieldEncryptor: switch from android.util.Base64 to java.util.Base64
- All data sources: use requireAead() (throws instead of silent plaintext fallback), encrypt all answer-bearing writes
- FirestoreCoupleDataSource: beginEncryptionMigration (atomic version-0→1 claim), markEncryptionMigrationComplete (per-user + version-2 promotion)
- CoupleRepositoryImpl: require wrappedKey on invite acceptance (no more optional)
- HomeScreen/ViewModel: route to EncryptionUpgradeScreen for version-0 or unmigrated version-1 couples
- Firestore rules: isCiphertext validator, isEncryptedAnswerPayload, isStartingEncryptionMigration, isCompletingOwnEncryptionMigration, isUpdatingRecoveryWrap, isUpdatingCoupleRhythm; enforce ciphertext on all answer/message writes; game collection rules (this_or_that, desire_sync, how_well, wheel) with per-user answer ownership; couple doc update split into 4 mutually exclusive paths; invite doc requires createdAt + wrappedKey fields; isImmutable uses diff().hasAny() instead of field equality
- Firestore rules tests: encryption migration scenarios, plaintext rejection, per-user answer ownership, game collection ciphertext enforcement
- firebase.json: emulator port 8180
- .gitignore: firestore-tests/node_modules
2026-06-19 20:53:52 -05:00
null e7b45cc84f fix: profile photo temp dir, Firestore rules field-level lockdown (batch v0.2.10)
- Move temp profile photos to filesDir/photos/ subdirectory with mkdirs
- Update file_paths.xml to scope FileProvider to photos/ subdirectory
- Firestore rules: restrict couple doc updates to only mutable fields (streakCount, lastAnsweredAt, wrappedCoupleKey, kdfSalt, kdfParams, encryptionVersion) — prevents client from overwriting currentQuestionId, activePackId, id
2026-06-19 20:33:08 -05:00
null 9a0b2b6a3d feat: BrandMessageRotator — rotating privacy copy across screens (batch v0.2.9)
- Add CloserBrandCopy with 6 approved privacy messages
- Add BrandMessageRotator composable: animated fade rotation every 4.5s, reduced-motion support
- Integrate rotator into: OnboardingScreen (CTA + auth check), LoginScreen, LoadingState, AnswerRevealScreen (waiting card), WaitingForPartnerScreen, DesireSync/HowWell/ThisOrThat waiting screens
- Add CloserBrandCopyTest for uniqueness and length validation
- Update visual-identity.md with approved rotation and security-claim publishing rules
2026-06-19 20:24:50 -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 cbaa68ef2e feat: account deletion with re-authentication flow (batch v0.2.7)
- Add reauthenticateWithEmail to AuthRepository + FirebaseAuthDataSource
- DeleteAccountScreen: re-auth dialog for email users (password prompt), Google user guidance
- DeleteAccountViewModel: handle FirebaseAuthRecentLoginRequiredException, re-auth submission
- Reorder delete flow: auth account deleted first, then couple leave + user data cleanup
2026-06-19 19:57:07 -05:00
null 30fddcc2df feat: E2EE — Tink AEAD, Argon2id KDF, recovery phrase, encrypted Firestore fields (batch v0.2.6)
- Add crypto module: CoupleKeyStore (EncryptedSharedPreferences), RecoveryKeyManager (Argon2id + AES-256-GCM key wrap), FieldEncryptor (AEAD per-field), CoupleEncryptionManager (orchestration)
- Add Tink + Bouncy Castle dependencies to build.gradle.kts, register AeadConfig in CloserApp
- Encrypt answer fields (writtenText, selectedOptionIds, scaleValue) on write, decrypt on read
- Encrypt DesireSync, HowWell, WheelAnswer, QuestionThread fields via CoupleEncryptionManager
- Generate recovery phrase during invite creation, display in CreateInviteScreen
- Add recovery phrase input to InviteConfirmScreen for encrypted invites
- Add RecoveryScreen + RecoveryViewModel for post-pairing key recovery
- Update Couple model with encryptionVersion, wrappedCoupleKey, kdfSalt, kdfParams
- Update Firestore rules: allow couple doc creation by members, fcmTokens path, encryptionVersion monotonic check, invite doc extended fields
2026-06-19 19:52:35 -05:00
null 5caae523e7 feat: app icon redesign, store assets, brand identity docs (batch v0.2.5)
- Redraw adaptive icon layers (background + foreground) with Closer palette colors
- Add monochrome icon layer for Android 13+ themed icons
- Add mipmap-anydpi-v33 adaptive icon configs (round + standard)
- Add store assets: 512px app icon, 1024x500 feature graphic, source SVGs
- Add docs/brand/visual-identity.md with brand mark, color palette, store voice, asset rules
- Update store-assets.md checklist to reflect completed items
2026-06-19 19:10:03 -05:00
null 7256a71bdf feat: dark mode support — ThemeMode setting, dynamic colors, status bar sync (batch v0.2.4)
- Add ThemeMode enum (DEVICE/LIGHT/DARK) with DataStore persistence
- SettingsScreen: appearance section with radio buttons for Device/Light/Dark
- SettingsViewModel: observe and persist theme mode
- MainActivity: read theme setting, apply dark theme, sync status bar icons
- Replace hardcoded Color.White references with MaterialTheme.colorScheme.surface across auth, onboarding, settings, and theme
- Convert AuthVisuals, SettingsVisuals, CloserPalette brushes to @Composable getters using dynamic scheme colors
- Add values-night/themes.xml for dark theme manifest entry
- Add ThemeModeTest unit test for fromStorageValue parsing
2026-06-19 19:00:37 -05:00
null c878a9be1f feat: Firebase project config — Firestore, Storage rules, Functions setup (batch v0.2.3)
- .firebaserc: default project set to couples-connect-dev
- firebase.json: Firestore rules/indexes, Storage rules, Functions source config
- storage.rules: profile photo write/read rules (5MB cap, image-only, owner-scoped)
- firestore.indexes.json: empty (no custom indexes yet)
2026-06-19 18:46:25 -05:00
null 7552c451db feat: notification copy, error messages, animations, reduced-motion support (batch v0.2.2)
- Rewrite all notification titles/bodies + channel descriptions to warmer, partner-centric tone
- Update error messages across all screens for clarity and consistency
- Add AnimatedVisibility + reduced-motion detection (Settings.Global.ANIMATOR_DURATION_SCALE) to AnswerRevealScreen and LocalQuestionContent
- Polish settings copy (quiet hours, partner activity labels, info footer)
- Update all game error states with actionable language ('Go back and try again')
- Refresh docs screenshots
2026-06-19 04:20:08 -05:00
null 79a63629f1 refactor: CloserPrimitives design system, PairPromptScreen, state component overhauls (batch v0.2.1)
- Add CloserPrimitives (CloserCard, CloserActionButton, CloserSpacing, CloserButtonStyle, SkeletonLine)
- Refactor EmptyState, ErrorState, LoadingState to use primitives with closer design tokens
- Add PairPromptScreen + nav route for post-signup partner invitation
- Update SignUpScreen onboarding copy to mention partner invite flow
- HomeScreen and PlayHubScreen layout/structure refinements
2026-06-19 04:04:52 -05:00
null 164e0e47ca feat: update AnswerHistory, BucketList, DateMatches, Onboarding, LocalQuestionContent, WheelHistory screens 2026-06-19 03:53:43 -05:00
null 803b681d06 feat: update PrivacyScreen, add Firestore test scripts, gitleaks audit artifacts 2026-06-19 03:45:53 -05:00
null 9e587a23dd feat: update question thread data source, repository, ViewModel, and Firestore security rules 2026-06-19 03:19:58 -05:00
null 927e930b79 feat: add SessionLength model, update game screens with session length awareness 2026-06-19 02:50:58 -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 70e7c66cd6 feat: add game history screen, shared session state, updated navigation + PlayHub 2026-06-19 01:43:06 -05:00
null 3ba6c659dd feat: add partner-waiting flow across all game screens with QuestionSession model updates 2026-06-19 01:14:04 -05:00
null 733c0967c2 fix: Q2 grammar quality pass on emotional_intimacy, parenting, stress questions + app.db rebuild 2026-06-19 00:50:23 -05:00
null 8cfcb6d51f chore: update Q1 scripts with minor fixes 2026-06-19 00:38:43 -05:00
null a13167dc3e feat: Q1 question variety improvement across all categories, app.db rebuild 2026-06-19 00:35:00 -05:00
null 93813255fd chore: Q3 asset DB cleanup (remove 300 dead rows), Q5 grammar fix for depth-5 questions in emotional_intimacy + stress 2026-06-18 22:03:52 -05:00
null 5ad1456adb feat: update desire sync question bank, degender scripts, app.db rebuild 2026-06-18 21:41:14 -05:00
null 473feb78a9 feat: add DesireSync + HowWell Firestore data sources, update screens with cloud-backed answering 2026-06-18 20:47:18 -05:00
null 97cc334136 feat: add Firestore wheel answer data source, update wheel screens with logging + answer history 2026-06-18 20:10:08 -05:00
null 408a2f24ba feat: add ThisOrThat Firestore data source, updated screen with question answering flow 2026-06-18 19:53:17 -05:00
null af06cb2123 feat: add Time Capsule feature with Firestore data source, model, and MemoryLane UI screens 2026-06-18 04:14:12 -05:00
null 4e871f8e4f feat: add Connection Challenge system with game routing, Firestore data source, ChallengeGameScreen in PlayHub 2026-06-18 04:03:57 -05:00
null 574fed27f7 refactor: replace raw string game types with GameType constants, remove unused feature flag module 2026-06-18 03:51:12 -05:00
null debc6aed02 fix: handle partner_active_session error in SpinWheelViewModel, navigate to waiting screen 2026-06-18 03:46:34 -05:00
null 1b344e7220 fix: filter out empty-text/unknown-category questions from all DAO queries, regenerate app.db, handle deleted cloud question by falling back to random 2026-06-18 03:43:24 -05:00
null 606d724f12 feat: add answer history filter pills with reveal/private badges, DesireSync progress meter and reveal UI, HowWell ring progress and privacy tiles, Paywall feature scavenger hunt, category screen grid polish 2026-06-18 03:26:12 -05:00
null 15c1fbdda0 feat: replace PlaceholderScreen with FinishedEmptyStateScreen across PartnerHome, EmailInvite, QuestionComposer, Subscription 2026-06-18 03:20:13 -05:00
null 8b394ab40f fix: use UTC dates for daily question keys across all date consumers 2026-06-18 03:11:22 -05:00