This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user