This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Data Model
|
||||
|
||||
The app stores most relationship data in `LocalDataState`, persisted by
|
||||
`LocalRepository`.
|
||||
|
||||
## Aggregate State
|
||||
|
||||
Source: `lib/app/state/local_data_state.dart`
|
||||
|
||||
| Field | Type | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `people` | `List<PersonProfile>` | primary relationship profiles |
|
||||
| `moments` | `List<RelationshipMoment>` | interaction and capture history |
|
||||
| `ideas` | `List<RelationshipIdea>` | gift, activity, and follow-up ideas |
|
||||
| `reminders` | `List<ReminderRule>` | local reminder rules |
|
||||
| `tasks` | `List<DashboardTask>` | dashboard task surface |
|
||||
| `dismissedSignalIds` | `List<String>` | dismissed generated signal IDs |
|
||||
| `sourceLinks` | `List<SourceProfileLink>` | external sender/thread to profile mapping |
|
||||
| `sharedMessages` | `List<SharedMessageEntry>` | imported shares attached to profiles |
|
||||
| `sharedInbox` | `List<SharedInboxEntry>` | unresolved or ambiguous shares |
|
||||
| `personFacts` | `List<PersonFact>` | structured relationship facts |
|
||||
| `importantDates` | `List<PersonImportantDate>` | birthdays, anniversaries, events |
|
||||
| `preferenceSignals` | `List<PersonPreferenceSignal>` | inferred/confirmed likes/dislikes |
|
||||
| `aiSuggestionDrafts` | `List<AiSuggestionDraft>` | pending AI review items |
|
||||
|
||||
## Profile Model
|
||||
|
||||
Source: `lib/features/people/domain/person_models.dart`
|
||||
|
||||
`PersonProfile` is the stable profile root. Important fields:
|
||||
|
||||
- `id`: internal local ID
|
||||
- `name`, `aliases`: local identity only
|
||||
- `relationship`: user-facing relationship category
|
||||
- `affinityScore`: rough closeness score
|
||||
- `nextMoment`: next planned contact or relationship moment
|
||||
- `tags`, `notes`, `location`: user-authored context
|
||||
- `lastUpdatedAt`, `lastInteractedAt`: operational recency fields
|
||||
|
||||
`SourceProfileLink` maps an external source to a local profile. It is used by
|
||||
share intake to avoid asking again after the user resolves a source identity.
|
||||
|
||||
## Share Models
|
||||
|
||||
Source: `lib/features/share_intake/domain/share_models.dart`
|
||||
|
||||
`SharedPayload` is normalized input from share sheets, action extensions, or
|
||||
simulation tools.
|
||||
|
||||
Key timestamp fields:
|
||||
|
||||
- `createdAt`: when the app created the normalized payload
|
||||
- `receivedAt`: when the app received/imported the share
|
||||
- `sharedMessageDateTime`: best-effort original message timestamp extracted
|
||||
from shared text, or null
|
||||
|
||||
Use `sharedMessageDateTime` as temporal evidence. Do not assume it exists. Do
|
||||
not infer it from arbitrary content dates such as "birthday is May 20".
|
||||
|
||||
`CapturedFactDraft` is the review/edit draft before a share becomes a durable
|
||||
fact or important date.
|
||||
|
||||
`SharedMessageEntry` is the durable record attached to a person. Its `sharedAt`
|
||||
getter prefers `sharedMessageDateTime` when present.
|
||||
|
||||
`SharedInboxEntry` is unresolved intake. Reasons include missing identity,
|
||||
ambiguous profile match, near-profile conflict, and manual selection needs.
|
||||
|
||||
## Facts, Dates, And Signals
|
||||
|
||||
`PersonFact` is durable structured context:
|
||||
|
||||
- `type`: note, like, dislike, importantDate, giftIdea, placeIdea,
|
||||
activityIdea, misc
|
||||
- `sourceKind`: manual, shareSheet, or shareInbox
|
||||
- `sharedMessageId` or `inboxEntryId`: provenance
|
||||
- `needsReview` and `isSensitive`: prompt and UI filtering controls
|
||||
|
||||
`PersonImportantDate` is a dated profile-owned record. It can come from manual
|
||||
input, share review, or AI-assisted extraction.
|
||||
|
||||
`PersonPreferenceSignal` is inferred or confirmed preference evidence. It
|
||||
tracks first/last seen timestamps, occurrence count, source apps, message IDs,
|
||||
and evidence snippets.
|
||||
|
||||
## AI Suggestion Drafts
|
||||
|
||||
Source: `lib/features/ai_digest/domain/ai_digest_models.dart`
|
||||
|
||||
AI suggestions are saved as drafts first. Accepted drafts can become local
|
||||
ideas, reminders, or tasks. Dismissed drafts stay in history so future digest
|
||||
prompts can avoid repeats.
|
||||
|
||||
## Schema Versioning
|
||||
|
||||
`LocalRepository` owns `_schemaVersion`. When adding persisted fields:
|
||||
|
||||
1. Add nullable/defaulted fields where possible.
|
||||
2. Update `toJson`, `fromJson`, and `copyWith`.
|
||||
3. Increase `_schemaVersion` only when a migration has meaning beyond default
|
||||
compatible parsing.
|
||||
4. Add repository and serialization tests.
|
||||
5. Verify legacy/missing field behavior.
|
||||
|
||||
The current `fromJson` patterns are intentionally tolerant for many optional
|
||||
lists and fields. Keep that property.
|
||||
Reference in New Issue
Block a user