docs(manual): Batch 3 — correct E2EE and Firestore data model (user fields, couple fields, date plans, preferences, bucket list, secure subdoc)
This commit is contained in:
parent
a6aa23eee2
commit
08368b3e01
|
|
@ -76,7 +76,7 @@ collection name, and architectural fact. Never assume.
|
|||
| Batch | Status | Findings | Changes made |
|
||||
|---|---|---|---|
|
||||
| 1 | ✅ done | `core/feature/` note inaccurate (dir doesn't exist); `data/questions/` listed `QuestionDao` but it's in `data/local/` | Corrected `core/feature/` note; moved `QuestionDao` to `data/local/`; kept `QuestionJsonParser` in `data/questions/`; updated older-description note. |
|
||||
| 2 | in progress | | |
|
||||
| 2 | ✅ done | No anonymous sign-in or account linking in code; Android uses legacy Google Sign-In SDK (idToken), not Credential Manager; `encryptionMigrationUsers` field does not exist | Removed anonymous auth and account-linking claims; corrected Google Sign-In description; removed `encryptionMigrationUsers` from couples model and added note that `encryptionVersion` is always `2`. |
|
||||
| 3 | todo | | |
|
||||
| 4 | todo | | |
|
||||
| 5 | todo | | |
|
||||
|
|
|
|||
|
|
@ -532,13 +532,26 @@ Thread questions follow the same sealed flow but use a different path:
|
|||
email: string
|
||||
displayName: string
|
||||
photoUrl: string | null
|
||||
sex: string # 'male' | 'female' | '' (set during onboarding)
|
||||
partnerId: string | null # deprecated mirror of the paired user's uid; prefer coupleId lookups
|
||||
coupleId: string | null
|
||||
hasPremium: bool # server-only write
|
||||
plan: string # 'free' or premium product id; client-written, not server-authoritative
|
||||
createdAt: Timestamp
|
||||
lastActiveAt: Timestamp
|
||||
fcmToken: string | null # legacy single-device FCM token; still written by older flows
|
||||
platform: 'android' | 'ios' | null
|
||||
/entitlements/premium # written by Cloud Functions only; readable by owner + current partner (see Couple-shared premium)
|
||||
notifPartnerAnswered: bool
|
||||
notifChatMessage: bool
|
||||
quietHoursEnabled: bool
|
||||
quietHoursStartMinutes: int
|
||||
quietHoursEndMinutes: int
|
||||
timezone: string
|
||||
# NOTE: hasPremium is NOT a current root field. Premium state is stored in the
|
||||
# server-only /entitlements/premium subdoc and observed by the client from there.
|
||||
/entitlements/premium # written by Cloud Functions only; readable by owner + current partner
|
||||
premium: bool
|
||||
expiresAt: Timestamp | null
|
||||
updatedAt: Timestamp # last entitlement change
|
||||
updatedAt: Timestamp
|
||||
productId: string | null # RevenueCat product identifier (e.g. 'closer_monthly')
|
||||
eventType: string # RevenueCat event type ('INITIAL_PURCHASE', 'RENEWAL', 'CANCELLATION', etc.)
|
||||
/fcmTokens/{tokenId} # owned by the user
|
||||
|
|
@ -572,12 +585,12 @@ Thread questions follow the same sealed flow but use a different path:
|
|||
id, userIds[2], inviteCode, createdAt
|
||||
streakCount, lastAnsweredAt
|
||||
currentQuestionId, activePackId
|
||||
encryptionVersion, wrappedCoupleKey, kdfSalt, kdfParams
|
||||
encryptionMigrationUsers: map<uid, bool>
|
||||
encryptionVersion (always 2), wrappedCoupleKey, kdfSalt, kdfParams
|
||||
/daily_question/{YYYY-MM-DD}
|
||||
questionId, date, assignedAt, expiresAt
|
||||
/answers/{userId} # schemaVersion 2 (enc:v1:) or 3 (sealed:v1:)
|
||||
/releaseKeys/{recipientId} # keybox:v1:
|
||||
/answers/{userId} # schemaVersion 2 metadata, or schemaVersion 3 sealed fields
|
||||
/answers/{userId}/secure/{doc} # schemaVersion 2 encryptedPayload (read-gated)
|
||||
/answers/{userId}/releaseKeys/{recipientId} # schemaVersion 3 keybox:v1:
|
||||
/threads/{threadId}
|
||||
questionId, createdAt, createdByUserId
|
||||
/messages/{userId} # schemaVersion 3 sealed
|
||||
|
|
@ -627,11 +640,18 @@ Thread questions follow the same sealed flow but use a different path:
|
|||
/couples/{coupleId}/date_matches/{matchId}
|
||||
userIds, dateIdeaId, createdAt
|
||||
/couples/{coupleId}/date_plans/{planId}
|
||||
title, dateTime, status: 'draft' | 'planned' | 'completed' # server-created by createDateMatch
|
||||
dateIdeaId, scheduledDate, scheduledTime (encrypted), status: 'draft' | 'planned' | 'completed'
|
||||
budget (encrypted), duration (encrypted)
|
||||
activity (encrypted), food (encrypted)
|
||||
conversationPrompts (encrypted), optionalChallenge (encrypted)
|
||||
createdAt, updatedAt
|
||||
/couples/{coupleId}/date_plan_preferences/{prefId}
|
||||
categories: map<category, weight> # plaintext per-user weights
|
||||
dateIdeaId, preferredDate, preferredTime (encrypted)
|
||||
budget (encrypted), duration (encrypted)
|
||||
createdAt, updatedAt
|
||||
/couples/{coupleId}/bucket_list/{itemId}
|
||||
title, category, addedByUserId, completedAt
|
||||
title, description, category, addedBy, addedAt
|
||||
completedBy, completedAt, isCompleted
|
||||
|
||||
# NOTE: this list is not exhaustive. Game-session subcollections (this_or_that, desire_sync,
|
||||
# how_well, wheel) and challenge-day / memory-lane subcollections are documented in their own
|
||||
|
|
|
|||
Loading…
Reference in New Issue