124 lines
4.0 KiB
Markdown
124 lines
4.0 KiB
Markdown
# Architecture
|
|
|
|
## High-Level Shape
|
|
|
|
The app is mid-migration to vertical slices.
|
|
|
|
```text
|
|
lib/
|
|
main.dart
|
|
app/ app bootstrap, shell, aggregate repository/state
|
|
core/ cross-cutting config, auth, networking, LLM, theme
|
|
features/ product slices
|
|
integrations/ backend gateway contracts and transport models
|
|
```
|
|
|
|
Canonical feature structure:
|
|
|
|
```text
|
|
lib/features/<slice>/
|
|
domain/ models and pure rules
|
|
application/ orchestration, providers, side effects
|
|
presentation/ screens, widgets, dialogs, UI state
|
|
data/ slice-owned persistence or adapters, when needed
|
|
```
|
|
|
|
Many files at `lib/features/<slice>/<name>.dart` are compatibility exports.
|
|
New implementation should go into the canonical subfolders.
|
|
|
|
## Runtime Flow
|
|
|
|
1. `lib/main.dart` initializes Flutter, Sentry/Bugsink, Workmanager, local
|
|
notifications, Hive, and Riverpod.
|
|
2. `RelationshipSaverApp` wires auth gates, share listeners, notification
|
|
listeners, and global app listeners.
|
|
3. `AppShell` owns responsive navigation between Dashboard, People, Moments,
|
|
Ideas, Reminders, Signals, Sync, and Settings.
|
|
4. `LocalRepository` exposes the aggregate `LocalDataState`.
|
|
5. Feature views read state through Riverpod providers and call repository
|
|
operations.
|
|
6. Repository writes persist state, reconcile reminder schedules, and enqueue
|
|
sync envelopes where applicable.
|
|
|
|
## State And Persistence Boundary
|
|
|
|
`LocalDataState` is the primary local aggregate. It contains:
|
|
|
|
- people
|
|
- moments
|
|
- ideas
|
|
- reminders
|
|
- dashboard tasks
|
|
- source links
|
|
- shared messages
|
|
- share inbox
|
|
- person facts
|
|
- important dates
|
|
- preference signals
|
|
- AI suggestion drafts
|
|
|
|
Most product writes should pass through `LocalRepository` because it handles:
|
|
|
|
- local state update
|
|
- persistent storage write
|
|
- reminder schedule reconciliation
|
|
- sync queue enqueue
|
|
- derived side effects such as preference extraction
|
|
|
|
The sync queue is intentionally separate from the product aggregate and lives in
|
|
`SyncQueueRepository`.
|
|
|
|
## Important Providers
|
|
|
|
| Provider | Purpose |
|
|
| --- | --- |
|
|
| `localRepositoryProvider` | primary local product state and write boundary |
|
|
| `syncQueueRepositoryProvider` | pending outbound sync mutations and sync status |
|
|
| `backendGatewayProvider` | fake vs REST backend transport selection |
|
|
| `sessionControllerProvider` | fake/REST auth session lifecycle |
|
|
| `llmConfigProvider` | LLM provider, endpoint, model, and API key state |
|
|
| `llmDigestConfigProvider` | digest cadence and grounding policy |
|
|
| `reminderSchedulerProvider` | local notification scheduler abstraction |
|
|
|
|
## Design Decisions
|
|
|
|
### Local-first aggregate first
|
|
|
|
The app persists one aggregate snapshot for product state. This is simple,
|
|
offline-safe, and pragmatic for a prototype. It also means entity-level
|
|
migrations and partial writes need care.
|
|
|
|
### Feature-owned models
|
|
|
|
Even though storage is aggregate-based, models live with features. This keeps
|
|
the migration toward vertical slices open without forcing a storage rewrite.
|
|
|
|
### Fake backend by default
|
|
|
|
Fake backend mode must stay stable because the product is not yet backend
|
|
dependent. REST transport exists behind `BackendGatewayRest`.
|
|
|
|
### Inbox-first share capture
|
|
|
|
Share intake should prefer user review when identity evidence is weak. A wrong
|
|
automatic profile match is more damaging than an extra inbox step.
|
|
|
|
### Pseudonymous AI digest
|
|
|
|
Scheduled digest prompts use person tokens and safe summaries. Identifying
|
|
details stay local. Share timestamps can be included as temporal evidence, but
|
|
raw shared text and sender identity should not be sent.
|
|
|
|
### Local notifications as best effort
|
|
|
|
Reminder and digest notifications should not block local data writes. Scheduler
|
|
errors are intentionally swallowed at the repository boundary.
|
|
|
|
## Cross-Cutting Rules
|
|
|
|
- Keep `AppConfig` flags as build-time `--dart-define` friendly values.
|
|
- Add tests around parsing, local repository state changes, and prompt payload
|
|
shape when changing sensitive flows.
|
|
- Keep docs aligned with verified code, especially native share and background
|
|
behavior.
|