docs: add project orientation notes

This commit is contained in:
Rijad Zuzo
2026-05-17 00:17:03 +02:00
parent 6c4a139448
commit dab50abf0e
6 changed files with 701 additions and 12 deletions
+128
View File
@@ -0,0 +1,128 @@
# AGENTS.md
This file is the fastest orientation doc for future coding agents working in
this repository.
## Project Summary
`relationship_saver` is a Flutter app for capturing and maintaining
relationship context locally. The app already supports:
- people profiles with aliases, notes, tags, facts, important dates, and
preference signals
- moments, ideas, reminders, and dashboard tasks
- Android/in-app share-intake flows with inbox-first review for ambiguous
content
- local notification scheduling for reminders
- fake-backend auth/sync flows and REST/OpenAPI scaffolding for later backend
work
The current product posture is local-first and prototype-oriented, not a fully
server-backed production app.
## Canonical Code Paths
Start here before changing behavior:
- `lib/main.dart`: app entry
- `lib/app/relationship_saver_app.dart`: root widget, auth gate, global
listeners
- `lib/app/presentation/app_shell.dart`: responsive shell and navigation
- `lib/app/data/relationship_repository.dart`: aggregate local-first write
boundary
- `lib/features/sync/data/sync_queue_repository.dart`: queued mutation store
- `lib/integrations/backend/backend_gateway_provider.dart`: fake vs REST
gateway selection
- `lib/core/config/app_config.dart`: runtime flags
## Architecture Reality
The repo is in a vertical-slice migration.
- Canonical structure is `lib/app`, `lib/features`, `lib/core`,
`lib/integrations`
- Many older files at slice roots are compatibility exports
- Prefer editing canonical files under:
- `presentation/`
- `application/`
- `domain/`
- `data/`
- Avoid expanding legacy compatibility files unless the task is specifically
about keeping old imports working
Useful orientation docs:
- `lib/README.md`
- `lib/app/README.md`
- `lib/features/README.md`
- `lib/core/README.md`
- slice READMEs inside `lib/features/*`
## Main Product Slices
- `people`: primary relationship workspace and richest data model
- `share_intake`: normalized shared payloads, review flows, inbox routing
- `sync`: queued changes, push/pull orchestration, rejection repair
- `reminders`: local reminder rules and notification scheduling
- `dashboard`: overview metrics and graph preview/explorer
- `settings`: trust/privacy copy, AI config, share simulation, environment
diagnostics
- `auth`: sign-in UI and session lifecycle
## Storage And Data Flow
- Local state is centered on `LocalDataState` in `lib/app/state/`
- `LocalRepository` persists a mostly single aggregate snapshot
- Default local store is Hive; shared preferences remains as legacy fallback
and migration path
- Sync queue state is persisted separately through the sync store abstraction
- The app is intentionally offline-safe in fake-backend mode
## Runtime Flags
Defined in `lib/core/config/app_config.dart`:
- `USE_FAKE_BACKEND=true` by default
- `BACKEND_BASE_URL`
- `USE_HIVE_LOCAL_DB=true` by default
- `ENABLE_BACKGROUND_SYNC=true` by default
- `BACKGROUND_SYNC_INTERVAL_SECONDS=180` by default
- `ENABLE_LOCAL_NOTIFICATIONS=true` by default
- `ENABLE_WHATSAPP_SHARE_INTAKE=true` by default
If behavior seems surprising, check the active `--dart-define` values first.
## Backend Boundary
- Transport contract is documented in `docs/api/openapi.yaml`
- Architectural rationale lives in
`docs/ADR/0002-backend-protocol-rest-openapi.md`
- `BackendGatewayFake` is still the default development path
- `BackendGatewayRest` is the real transport boundary when fake mode is off
## Known Limitations
- iOS share extension work is deferred; see `docs/open-tasks.md`
- Native share-entry support is stronger on Android than iOS
- Sync scaffolding exists, but not all newer local entities are mapped to the
backend protocol yet
- The repo currently contains a lot of in-flight migration work and
compatibility exports
## Working Guidance
- Read the relevant slice README before changing a feature
- Treat existing uncommitted changes as user work unless you created them
- Prefer canonical slice files over compatibility exports
- Keep docs aligned with the verified code, not with older plans
- When changing architecture-level behavior, update the nearest README or this
file if it affects future orientation
## Useful Commands
```bash
flutter pub get
flutter test
flutter analyze
dart run build_runner build --delete-conflicting-outputs
```
+114 -11
View File
@@ -1,17 +1,120 @@
# relationship_saver # Relationship Saver
A new Flutter project. `relationship_saver` is a local-first Flutter app for managing relationship
context: people, moments, ideas, reminders, share-intake, and lightweight
signals that can later support sync and AI-assisted workflows.
## Getting Started The app currently runs as a prototype-friendly single-client build:
This project is a starting point for a Flutter application. - Flutter + Material UI
- Riverpod for app state
- Hive-backed local persistence by default
- fake backend enabled by default for offline-safe development
- REST/OpenAPI scaffolding for future auth + sync work
- local notifications for reminders
- Android text-share entry and in-app share simulation tools
A few resources to get you started if this is your first Flutter project: ## Current Architecture
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter) The codebase is mid-migration from an older horizontal structure to a
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) vertical-slice layout.
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
For help getting started with Flutter development, view the - `lib/app/`: app bootstrap, shell navigation, aggregate persistence, shared
[online documentation](https://docs.flutter.dev/), which offers tutorials, app state
samples, guidance on mobile development, and a full API reference. - `lib/features/`: product slices such as `people`, `share_intake`, `sync`,
`reminders`, `dashboard`, and `settings`
- `lib/core/`: cross-cutting primitives like config, auth, networking, theme,
and shared presentation helpers
- `lib/integrations/backend/`: backend-facing gateway contracts, REST/fake
implementations, DTOs, and mappers
Many older root-level files under `lib/features/*` still exist as compatibility
exports. New work should generally target the canonical files in `app/`,
`core/`, or slice subfolders such as `presentation/`, `application/`,
`domain/`, and `data/`.
## Key Runtime Behavior
- Entry point: `lib/main.dart`
- Root widget: `lib/app/relationship_saver_app.dart`
- Authenticated shell: `lib/app/presentation/app_shell.dart`
- Local-first aggregate repository:
`lib/app/data/relationship_repository.dart`
- Queued sync persistence:
`lib/features/sync/data/sync_queue_repository.dart`
Notable build-time flags live in `lib/core/config/app_config.dart`:
- `USE_FAKE_BACKEND` defaults to `true`
- `BACKEND_BASE_URL`
- `USE_HIVE_LOCAL_DB`
- `ENABLE_BACKGROUND_SYNC`
- `BACKGROUND_SYNC_INTERVAL_SECONDS`
- `ENABLE_LOCAL_NOTIFICATIONS`
- `ENABLE_WHATSAPP_SHARE_INTAKE`
## Run
Install packages:
```bash
flutter pub get
```
Run with the default fake backend:
```bash
flutter run
```
Run against a REST backend:
```bash
flutter run \
--dart-define=USE_FAKE_BACKEND=false \
--dart-define=BACKEND_BASE_URL=https://api.example.com
```
Run tests:
```bash
flutter test
```
Generate code:
```bash
dart run build_runner build --delete-conflicting-outputs
```
## Current Product Areas
- `Dashboard`: overview cards and relationship graph preview/explorer
- `People`: primary workspace for profiles, notes, facts, dates, tags, and
preference signals
- `Moments`: interaction/capture history
- `Signals`: lightweight prompts derived from local relationship context
- `Ideas`: follow-up and gift/activity/place ideas
- `Reminders`: reminder rules plus local notification scheduling
- `Sync`: queued change diagnostics and repair surface
- `Settings`: environment flags, trust/privacy copy, AI config, share
simulation, and notification permission actions
## Docs
- [Setup](docs/SETUP.md)
- [Progress Log](docs/progress.md)
- [Open Tasks](docs/open-tasks.md)
- [Client Audit](docs/client-audit-relationship-app.md)
- [Client Implementation Plan](docs/client-implementation-plan.md)
- [Client Iteration Summary](docs/client-iteration-summary.md)
- [Backend ADR](docs/ADR/0002-backend-protocol-rest-openapi.md)
- [OpenAPI Contract](docs/api/openapi.yaml)
- [Contributor Notes](AGENTS.md)
## Known Gaps
- iOS share-sheet integration is still deferred; see `docs/open-tasks.md`
- sync/backend contracts exist, but the product remains primarily local-first
- the repository layer still persists one aggregate snapshot for most local
state while the slice migration continues
+139
View File
@@ -0,0 +1,139 @@
# Client Audit: Relationship Assistant App
Date: 2026-04-01
## Current implementation summary
The client is a Flutter app using Riverpod for state management and a single
`MaterialApp` rooted at `lib/main.dart`. Authenticated users land in a custom
shell with index-based navigation across dashboard, people, moments, signals,
ideas, reminders, sync, and settings.
The app is already local-first in practice. Product state lives in
`LocalRepository` and is persisted through a `LocalDataStore` abstraction with
Hive as the default backend and shared preferences as a fallback/migration
path. There is also background sync scaffolding, notification scheduling, and a
fake backend mode for offline development.
Share intake exists, but the implementation is narrow. Flutter-side logic
supports a WhatsApp-oriented share parser, source-link resolution, and a manual
share inbox. Native platform wiring is incomplete for production-grade cross-app
sharing, especially on iOS and likely also on Android for text share intents.
## A. Current implementation inventory
| Feature Area | Current State |
| --- | --- |
| Client technology | Flutter |
| State management | Riverpod (`Notifier`, `AsyncNotifier`, provider overrides in tests) |
| Navigation | Single `MaterialApp`, custom shell, route pushes for secondary flows |
| Local persistence | Hive by default, shared preferences fallback/migration |
| Auth | Local/fake-friendly sign-in flow with token-store abstractions |
| People list/detail | Implemented, responsive, searchable, editable |
| Person creation/editing | Implemented with validation and duplicate-name warning |
| Notes/profile context | Implemented as a single freeform notes field plus tags |
| Moments/captures | Implemented |
| Ideas | Implemented |
| Reminders | Implemented with local notification scaffold |
| Shared message history | Implemented per profile |
| Share intake | Implemented in Flutter, but WhatsApp-specific and not fully generalized |
| Share inbox | Implemented for unresolved profile matching |
| Source linking | Implemented for repeated source-to-profile matching |
| Preference inference | Implemented locally from shared chat text |
| Search/filtering | Implemented for people; limited elsewhere |
| Theming/design system | Implemented via `AppTheme`, custom frosted cards, responsive layouts |
| Tests | Good targeted widget/unit coverage, no true end-to-end native share tests |
| Backend sync readiness | Good scaffolding, still fake/offline-friendly |
| Privacy/trust UX | Limited; local-first behavior exists more in code than in user-facing copy |
| Cross-platform share viability | Partial; Flutter layer exists, native integration incomplete |
## B. Grading
| Feature Area | Status | Grade | Notes | Risk / Missing Pieces | Recommended Next Step |
| --- | --- | --- | --- | --- | --- |
| App architecture | Present | B | Clear enough separation between UI, local repository, sync, and integrations | Some large UI files, especially `PeopleView` | Add smaller share/fact modules instead of broad refactors |
| Local-first persistence | Present | A- | Hive-backed state with migration path and test coverage | Still JSON-in-Hive rather than richer queryable store | Keep current approach for this iteration |
| People management | Present | B | Good responsive UI, editing, duplicate warning, merge flow | Person model is too thin for relationship intelligence | Extend model with aliases, facts, dates, timestamps |
| Moments / history | Present | B | Useful local activity log | History is not yet strongly typed for preferences/dates/fact provenance | Add structured facts on top rather than replacing moments |
| Ideas / reminders | Present | B | Solid founder-mode utility already | Not tightly connected to share capture | Reuse future share classification to feed these areas later |
| Share intake pipeline | Partial | C | Flutter-side ingest and inbox exist | WhatsApp-specific, no generic text/URL pipeline, native wiring incomplete | Generalize payload normalization and improve clarification UX |
| Person resolution | Partial | B- | Exact/near-match logic and source links already exist | Resolution is tied to sender matching and not broader share assignment | Add explicit assign/create/save-to-inbox review flow |
| Inbox / triage | Partial | C+ | Resolves ambiguous source matching | Cannot yet classify into structured facts/dates/preferences | Add fact classification and later reassignment/edit support |
| Search / discoverability | Partial | C+ | People search/filter exists | No real inbox/fact/date search | Keep scope limited; prepare data for later search expansion |
| Privacy / trust UX | Weak | D | Local-first architecture exists | App does not clearly explain on-device storage or future AI sharing controls | Add clear local-first settings copy and sensitive-data affordances |
| Cross-platform share readiness | Weak | D | Plugin added, listener implemented | Android manifest missing share intent filters; iOS share extension not configured | Fix Android now, document iOS as deferred native work |
| Test posture | Present | B+ | Good unit/widget coverage for local repo and share inbox | Missing tests for generalized share parsing and structured triage | Add targeted parser/repository/widget tests |
## C. Product readiness assessment
### Solo founder daily use
Current usefulness is moderate. The app already supports keeping people,
captures, reminders, and ideas locally, which is enough for founder testing.
However, the most important real-world capture path, sharing snippets from other
apps, is not yet strong enough to rely on daily.
### Friction of data entry
Manual entry is acceptable. Cross-app capture still has too much friction
because it is optimized around one parser path instead of a general intake
flow. Ambiguous content can be saved, but not yet shaped into structured,
reviewable facts.
### Trust / privacy feel
The implementation is local-first, but the UX does not communicate that clearly
enough. For a relationship app, trust is part of the product. The app should
say what stays on device, what is not yet shared, and how users can correct or
delete imported facts.
### Extensibility for future LLM support
Reasonably good. The repository pattern, fake backend mode, and local inferred
preference signals create a workable foundation. The main gap is data shape:
profile context is still too flat, and shared content is not normalized into a
recommendation-ready structure.
### Cross-platform viability
Good at the Flutter layer, incomplete at the native share-entry layer. Android
needs explicit share intent wiring. iOS still lacks a real share extension.
### Likely adoption blocker
The biggest blocker is not “AI quality”; it is capture friction. If sharing a
snippet from WhatsApp, Safari, Notes, or Messages into the app is unreliable or
too manual, the product will not accumulate enough high-value context to become
habit-forming.
## D. Top implementation priorities
1. Generalize share capture into a platform-aware text/URL pipeline with a
clear internal payload model and Android native entry wiring.
2. Add an inbox-first clarification flow that lets the user assign to an
existing person, create a new person quickly, or save unresolved data for
later.
3. Extend the local person knowledge model with aliases, structured facts,
important dates, timestamps, and source traceability.
4. Upgrade the inbox from “resolve person only” to “triage into note / like /
dislike / date / idea-ish fact”.
5. Improve privacy/trust wording and make correction paths more obvious.
## Recommended scope for this iteration
Implement a disciplined client-only slice:
- generic shared text / URL normalization
- Android text share intent support
- share clarification sheet for assign/create/inbox
- richer local fact/date models with provenance
- inbox triage into structured facts or important dates
- person detail UI for reviewing captured facts/dates
- targeted tests
Explicitly defer:
- native iOS share extension target work
- real backend sync of new fact/date entities
- real LLM or recommendation calls
- large navigation or persistence rewrites
+173
View File
@@ -0,0 +1,173 @@
# Client Implementation Plan
Date: 2026-04-01
## Chosen scope for this iteration
This iteration focuses on the smallest slice that materially improves founder
testing:
1. Generalize intake from WhatsApp-only text import to a broader shared payload
pipeline that supports:
- plain text
- URL
- text + URL
2. Add an explicit clarification flow for ambiguous shares:
- assign to existing person
- create person quickly
- save to inbox for later
3. Improve the local person knowledge model with:
- aliases
- structured captured facts
- important dates
- timestamps
- source/provenance metadata
4. Upgrade inbox triage so unresolved shares can be converted into:
- note
- like
- dislike
- important date
- gift idea
- place idea
- activity idea
- misc fact
5. Add trust-facing settings copy and targeted tests.
## Why this scope
- It directly improves the most important product workflow: fast capture from
outside the app.
- It stays client-side and local-first.
- It does not require a storage rewrite or backend coupling.
- It produces data structures that future LLM/recommendation work can consume.
- It keeps risk contained by extending the existing repository and views rather
than replacing them.
## Affected files / modules
### Expected to change
- `lib/main.dart`
- `lib/features/local/local_models.dart`
- `lib/features/local/local_repository.dart`
- `lib/features/people/people_view.dart`
- `lib/features/settings/settings_view.dart`
- `lib/features/share_intake/share_inbox_view.dart`
- `lib/features/share_intake/whatsapp_share_listener.dart` or replacement
- `android/app/src/main/AndroidManifest.xml`
- `test/features/local/local_repository_test.dart`
- `test/features/share_intake/share_inbox_view_test.dart`
### Expected to add
- generic share payload parser / models
- share review sheet / dialog component
- parser unit tests
- iteration summary doc
## Architecture decisions
### 1. Keep `LocalRepository` as the orchestration layer
Reason:
- It already owns local persistence, entity updates, and ingestion logic.
- Extending it is safer than introducing a second persistence coordinator.
Tradeoff:
- The file remains large.
Mitigation:
- Add focused helpers/models for share parsing and captured-fact typing rather
than pushing more UI logic into the repository.
### 2. Add structured fact/date entities instead of overloading `notes`
Reason:
- Future recommendation features need provenance, timestamps, and type-safe
context.
- Users need auditability and correction, not just a bigger notes blob.
Tradeoff:
- More model surface area now.
Mitigation:
- Keep entity types intentionally small and local-only for this iteration.
### 3. Prefer inbox-first safety over aggressive auto-assignment
Reason:
- Wrong person attachment is worse than extra triage work in this domain.
Decision:
- Only auto-assign when confidence is genuinely high.
- Otherwise open clarification UI or save to inbox.
### 4. Fix Android share entry now, defer iOS native extension
Reason:
- Android manifest support is low-cost and unblocks real testing.
- Proper iOS share extension work is native-project-heavy and should be treated
as a separate scoped task.
## UX flows
### Flow A: direct share received with high-confidence target
1. Normalize incoming share into `SharedPayload`.
2. If a stable source link or clear unique alias/name match exists, allow direct
save to the person.
3. Persist the payload history plus a structured fact defaulting to `note`
unless a better classification is explicitly chosen.
4. Show confirmation snackbar and navigate to the relevant destination on cold
start.
### Flow B: share received without safe target
1. Normalize into `SharedPayload`.
2. Open a lightweight review sheet when possible.
3. Offer:
- recent people / candidate people
- quick create person
- save to inbox
4. If the user saves to inbox, persist payload + draft classification and leave
the item unresolved.
### Flow C: inbox triage later
1. Open `Share Inbox`.
2. Review the preview text/URL and suggested candidates.
3. Choose person or create one.
4. Choose classification and edit the extracted content.
5. Save as structured fact/date.
## Risks
### Risk: model expansion causes migration issues
Fallback:
- Keep new JSON fields backward-compatible with defaults in `fromJson`.
### Risk: generic share parsing creates false confidence
Fallback:
- Default to inbox / manual clarification for unclear payloads.
### Risk: too much UI churn in `PeopleView`
Fallback:
- Add new review sections for facts/dates without reworking the whole people
editor architecture.
### Risk: native plugin behavior differs across platforms
Fallback:
- Keep settings-based share simulation path for deterministic local testing.
## Intentionally deferred
- iOS share extension target creation and App Group setup
- image/file share support
- sync mapping for new fact/date entities
- AI-driven classification/recommendations
- full-text search across inbox/facts/dates
- notification engine hooks for new entities
+146
View File
@@ -0,0 +1,146 @@
# Client Iteration Summary
Date: 2026-04-01
## What was implemented
This iteration focused on client-side share capture, local-first structure, and
safer person assignment.
Implemented:
- generic shared payload normalization for:
- plain text
- URL
- text + URL
- a review-first share capture sheet for:
- assign to existing person
- create person quickly
- save to inbox
- richer local person model support:
- aliases / nicknames
- last updated / last interacted timestamps
- richer local knowledge entities:
- structured captured facts
- important dates
- source/provenance metadata
- sensitive flag scaffolding
- inbox triage improvements:
- draft mapping to note / like / dislike / date / gift / place / activity / misc
- create person directly from inbox
- resolve to existing person with fact mapping
- people profile UI improvements:
- aliases visible in profile context
- captured facts section
- important dates section
- edit/delete support for facts and dates
- Android native text share entry:
- `ACTION_SEND` text intent filter added to `AndroidManifest.xml`
- trust/privacy wording:
- clearer local-first copy in settings
- tests:
- generic share payload parser tests
- repository tests for inbox-to-fact and date persistence
- updated share inbox widget test flow
## Architecture decisions
### Kept the existing repository-centered local architecture
`LocalRepository` remains the orchestrator for local persistence and ingest.
This avoided a risky refactor and let the new share pipeline build on existing
person/source-link/moment infrastructure.
### Added structured fact/date entities instead of overloading notes
This creates a cleaner bridge to future recommendation, summarization, and sync
work. Shared captures can now produce auditable, typed local knowledge instead
of only raw note blobs.
### Used a review-first share flow for safety
Rather than silently guessing in generic share cases, the app now asks for a
target person or lets the user save to inbox. This is the safer default for a
relationship product.
## Known limitations
- iOS still does not have a real share extension target configured. The Flutter
share logic exists, but native iOS share-sheet presence remains deferred.
- Android share support added here is text-focused only.
- Generic share flows do not infer advanced semantic structure automatically
beyond the existing preference extractor.
- Captured facts and important dates are local-only and not yet mapped into the
backend sync protocol.
- Inbox triage currently converts one structured draft per inbox item. It does
not yet split a single payload into multiple facts.
- Search is still strongest in People and not yet expanded across facts/dates/
inbox.
## What should happen next in a backend / LLM session
1. Define backend entity contracts for:
- person aliases
- structured facts
- important dates
- shared payload provenance
2. Add sync-envelope mappings for the new local entities.
3. Introduce optional AI-assisted extraction that proposes:
- multiple facts from one payload
- date detection
- confidence scoring
- recommendation context packaging
4. Add server-compatible merge/reconciliation rules for conflicting profile
facts and dates.
5. Implement explicit privacy controls for any future cloud or AI sharing.
## Manual walkthrough
### 1. Create person
- Open `People`.
- Tap `Add person`.
- Enter:
- `Name`
- `Relationship`
- optional `Aliases`
- optional notes/tags/location
- Save.
### 2. Share text into app
- On Android, share any text snippet into the app from another app.
- Or use `Settings` -> `Simulate Share Capture`.
- The review sheet should open showing the parsed text/URL preview.
### 3. Resolve ambiguity
- In the review sheet, choose a fact type such as `Like` or `Note`.
- Pick an existing person from recent chips or the full dropdown.
- Save to that person.
### 4. Save to inbox
- Repeat with another shared snippet.
- In the review sheet, choose `Save To Inbox`.
- Open `Share Inbox`.
### 5. Assign later
- In `Share Inbox`, open the queued item.
- Confirm or change the fact mapping.
- Choose `Review & Save` to match an existing person, or `Create Person`.
- Complete the flow.
### 6. Edit captured fact
- Open `People`.
- Select the person.
- In `Captured facts`, tap `Edit` on the new fact.
- Change the text/label/type or sensitive flag and save.
### 7. Edit captured date
- If the capture was saved as a date, open `Important dates`.
- Tap `Edit`.
- Adjust label/classification/date and save.
+1 -1
View File
@@ -1,6 +1,6 @@
# Relationship Saver Progress Log # Relationship Saver Progress Log
Updated: 2026-02-22 Updated: 2026-02-23
## Collaboration Rule (Carry Forward) ## Collaboration Rule (Carry Forward)