4.1 KiB
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 IDname,aliases: local identity onlyrelationship: user-facing relationship categoryaffinityScore: rough closeness scorenextMoment: next planned contact or relationship momenttags,notes,location: user-authored contextlastUpdatedAt,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 payloadreceivedAt: when the app received/imported the sharesharedMessageDateTime: 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, miscsourceKind: manual, shareSheet, or shareInboxsharedMessageIdorinboxEntryId: provenanceneedsReviewandisSensitive: 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:
- Add nullable/defaulted fields where possible.
- Update
toJson,fromJson, andcopyWith. - Increase
_schemaVersiononly when a migration has meaning beyond default compatible parsing. - Add repository and serialization tests.
- Verify legacy/missing field behavior.
The current fromJson patterns are intentionally tolerant for many optional
lists and fields. Keep that property.