1282 lines
50 KiB
Markdown
1282 lines
50 KiB
Markdown
# Relationship Saver Progress Log
|
||
|
||
Updated: 2026-02-22
|
||
|
||
## Collaboration Rule (Carry Forward)
|
||
|
||
- After every sensible code/documentation change set, create a git commit as
|
||
the last step so the next agent session can pick up from clean checkpoints.
|
||
|
||
## Latest Milestone (2026-02-22): MVP Chat Preference Extractor + Ingest Enrichment
|
||
|
||
Implemented the first local semantic-enrichment pass so shared chat messages can
|
||
start building inferred person preferences automatically.
|
||
|
||
- `lib/features/local/chat_preference_extractor.dart` (new)
|
||
- added a pure Dart, local-first rule-based extractor
|
||
- extracts evidence-backed preference candidates from message text:
|
||
- `prefer X over Y` (creates like/dislike pair)
|
||
- `favorite ... is ...`
|
||
- `I love/like/enjoy ...`
|
||
- `I hate/dislike/don’t like ...`
|
||
- `allergic to ...`
|
||
- adds category heuristics (e.g. drink/food/hobby/environment/health)
|
||
- returns confidence-scored candidates with evidence snippets
|
||
|
||
- `lib/features/local/local_repository.dart`
|
||
- integrated extractor into resolved shared-message ingest flow
|
||
- when a chat share is imported and linked to a profile:
|
||
- store raw shared message + capture moment (existing behavior)
|
||
- extract preference candidates from message text
|
||
- upsert local inferred preference signals with evidence + source metadata
|
||
|
||
- Tests
|
||
- `test/features/local/chat_preference_extractor_test.dart` (new)
|
||
- extractor unit coverage for positive/negative/comparative/allergy patterns
|
||
- `test/features/local/local_repository_test.dart`
|
||
- added ingest test proving shared chat import creates inferred signals
|
||
|
||
- Validation
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-22): Local Preference Signal Scaffolding (Inferred/Confirmed)
|
||
|
||
Added a local-first data model and repository APIs for chat-derived preference
|
||
signals so the app can gradually build profile context from shared messages.
|
||
|
||
- `lib/features/local/local_models.dart`
|
||
- new enums:
|
||
- `PreferenceSignalPolarity` (`like`, `dislike`, `neutral`)
|
||
- `PreferenceSignalStatus` (`inferred`, `confirmed`, `dismissed`)
|
||
- new model:
|
||
- `PersonPreferenceSignal`
|
||
- key/category/label
|
||
- confidence
|
||
- status
|
||
- first/last seen timestamps
|
||
- occurrence count
|
||
- evidence message ids/snippets
|
||
- source apps
|
||
- `LocalDataState` now stores `preferenceSignals`
|
||
- added `copyWith`, `toJson`, `fromJson` support (backward-compatible with
|
||
existing stored state)
|
||
|
||
- `lib/features/local/local_repository.dart`
|
||
- added local-only repository APIs:
|
||
- `upsertInferredPreferenceSignalObservation(...)`
|
||
- aggregates repeated observations
|
||
- merges evidence and source apps
|
||
- updates confidence and occurrence count
|
||
- `upsertPreferenceSignal(...)`
|
||
- `setPreferenceSignalStatus(...)`
|
||
- `confirmPreferenceSignal(...)`
|
||
- `dismissPreferenceSignal(...)`
|
||
- updated person lifecycle consistency:
|
||
- deleting a person removes linked preference signals
|
||
- merging profiles rebinds source preference signals to target
|
||
- remote person delete application also removes preference signals
|
||
- intentionally local-only for now (not yet mapped to backend sync envelopes)
|
||
|
||
- `test/features/local/local_repository_test.dart`
|
||
- added coverage for inferred signal upsert aggregation + status transitions
|
||
|
||
- Validation
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-22): Person Editor Inline Validation + Duplicate Warning
|
||
|
||
Improved the People add/edit profile experience to make validation explicit and
|
||
support safer profile creation in a sharing-first workflow.
|
||
|
||
- `lib/features/people/people_view.dart`
|
||
- added inline required-field validation for `Name` and `Relationship`
|
||
(no more silent no-op when save is pressed with empty required fields)
|
||
- added live duplicate-name warning banner in add/edit form:
|
||
- checks normalized profile names against existing local profiles
|
||
- excludes the current profile during edit
|
||
- warns before save while still allowing save (with follow-up merge flow)
|
||
- routed existing profile list into the responsive editor panel/sheet so
|
||
duplicate detection works on mobile + desktop/web
|
||
|
||
- Validation
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-22): Responsive People Add/Edit Form (Sheet + Dialog)
|
||
|
||
Aligned the People profile creation/edit flow with the newer insights-style UI
|
||
language and improved platform-specific presentation behavior.
|
||
|
||
- `lib/features/people/people_view.dart`
|
||
- replaced the old `AlertDialog` person editor with a shared responsive form
|
||
panel:
|
||
- mobile (`<720px`): `showModalBottomSheet` with a rounded sheet layout
|
||
- desktop/web/tablet: larger custom dialog panel
|
||
- added richer form UX with:
|
||
- hero preview (avatar + live preview chips for name/relationship/location/tags)
|
||
- grouped sections (`Identity`, `Context`) matching the People/Insights card
|
||
style
|
||
- preserved existing labels and `Save` action text for test compatibility
|
||
- kept add/edit repository behavior unchanged (local-first)
|
||
- fixed narrow-width section header overflow discovered by widget test
|
||
|
||
- Validation
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-22): People Page UX Redesign (Insights-Aligned)
|
||
|
||
Reworked the `People` page to feel closer to the graph long-press `Person
|
||
Insights` experience and improved the compact/mobile interaction flow.
|
||
|
||
- `lib/features/people/people_view.dart`
|
||
- redesigned the selected person detail area into an insights-style workspace:
|
||
- hero summary card with quick actions (`Capture`, `Idea`, menu + edit/delete)
|
||
- stats tiles (affinity, next moment, captures, ideas)
|
||
- section cards for:
|
||
- profile context (relationship/location/tags/source links + notes)
|
||
- ideas
|
||
- moments
|
||
- reminders
|
||
- shared message history
|
||
- added richer person list cards:
|
||
- next moment pill
|
||
- optional location pill
|
||
- tag pills
|
||
- added People list controls:
|
||
- search
|
||
- relationship filter chips
|
||
- sort menu (affinity / next / A-Z)
|
||
- empty state when filters yield no results
|
||
- improved compact/mobile flow:
|
||
- selected profile workspace now renders above the full list (instead of
|
||
after all profiles)
|
||
- explicit `All profiles` section header with count
|
||
- improved add-person flow UX:
|
||
- newly created person is automatically selected/focused immediately
|
||
- also fixed the mobile CRUD widget test expectation after layout changes
|
||
- migrated page-local filter state to Riverpod 3 `Notifier` providers
|
||
(instead of unavailable legacy `StateProvider` API)
|
||
|
||
- Validation
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-18): Quick-Add Actions on Graph Person Insights
|
||
|
||
Closed a UX gap where long-pressing a graph node opened person insights without
|
||
the expected context add action.
|
||
|
||
- Added `Quick add` menu to person profile header in graph-based insights page:
|
||
- `lib/features/dashboard/dashboard_view.dart`
|
||
- supports:
|
||
- Add Capture
|
||
- Add Note
|
||
- Add Idea
|
||
- Add Reminder
|
||
- Wired actions directly to `LocalRepository` so entries are immediately written
|
||
to local-first state and reflected in insights sections.
|
||
- Added local dialogs for quick idea/reminder creation in insights flow.
|
||
- Updated dashboard interaction coverage:
|
||
- `test/features/dashboard/dashboard_graph_interactions_test.dart`
|
||
- now asserts `Quick add` is present after opening `Person Insights`.
|
||
- Added visible floating `+` button on `Person Insights` for mobile-first
|
||
discoverability:
|
||
- opens a bottom sheet with the same quick actions as the header menu
|
||
- tooltip: `Add to person`
|
||
|
||
## Latest Milestone (2026-02-18): Duplicate Profile Merge + Share Deep-Link Polish
|
||
|
||
Improved identity continuity from WhatsApp intake with merge tooling and direct
|
||
navigation:
|
||
|
||
- Added duplicate-profile merge operation in local repository:
|
||
- `lib/features/local/local_repository.dart`
|
||
- new `mergePersonProfiles(sourcePersonId, targetPersonId)`:
|
||
- merges target profile metadata (tags/notes/location/affinity/next moment)
|
||
- rebinds related records from source -> target:
|
||
- moments
|
||
- ideas
|
||
- reminders
|
||
- source links
|
||
- shared message history
|
||
- unresolved inbox candidate IDs
|
||
- enqueues sync envelopes for merged target + source delete + rebounded
|
||
related entities
|
||
- Added merge action in People UX:
|
||
- `lib/features/people/people_view.dart`
|
||
- new `Merge` / `Merge duplicates` action in People header
|
||
- duplicate-name detection and merge dialog for selecting source/target
|
||
- Share destination deep-link polish:
|
||
- `lib/features/share_intake/whatsapp_share_listener.dart`
|
||
- initial app launch from share intent now auto-opens destination context:
|
||
- `Share Inbox` for unresolved imports
|
||
- `People` with selected imported profile for resolved imports
|
||
- snackbar action updated to `Open Profile` / `Open Inbox`
|
||
- `lib/features/settings/settings_view.dart`
|
||
- simulated share snackbar now offers direct navigation to profile/inbox
|
||
- Added merge test coverage:
|
||
- `test/features/local/local_repository_test.dart`
|
||
- verifies merge rebinding across related records
|
||
|
||
## Latest Milestone (2026-02-18): Stable Share Fingerprints + Near-Match Conflict Detection
|
||
|
||
Strengthened WhatsApp identity mapping to reduce accidental mis-links:
|
||
|
||
- Added stable source fingerprint strategy:
|
||
- `lib/features/local/local_models.dart`
|
||
- `SourceProfileLink` now stores optional `sourceFingerprint`
|
||
- `SharedInboxEntry` also keeps the same fingerprint when unresolved
|
||
- fingerprint is derived from stable source identifiers (`sourceApp` +
|
||
source user/thread ids)
|
||
- Updated ingest matching order:
|
||
- `lib/features/local/local_repository.dart`
|
||
- fingerprint match is now the primary lookup path
|
||
- backward-compatible fallback to existing user/thread/display matching
|
||
- legacy links without stored fingerprint still match by derived fingerprint
|
||
- Added near-match conflict handling:
|
||
- new inbox reason: `nearProfileConflict`
|
||
- fuzzy name similarity heuristic (edit-distance + containment) now detects
|
||
likely profile conflicts and routes to Share Inbox for explicit user choice
|
||
- Updated Share Inbox UI reason labels:
|
||
- `lib/features/share_intake/share_inbox_view.dart`
|
||
- Added test coverage:
|
||
- `test/features/local/local_repository_test.dart`
|
||
- verifies:
|
||
- fingerprint persistence on source links
|
||
- near-match conflict queueing
|
||
- follow-up routing succeeds via fingerprint after manual resolution
|
||
|
||
## Latest Milestone (2026-02-18): Share Inbox Conflict Review UX
|
||
|
||
Upgraded unresolved-share resolution from a basic picker to guided review:
|
||
|
||
- Added conflict review modal in Share Inbox:
|
||
- `lib/features/share_intake/share_inbox_view.dart`
|
||
- new flow:
|
||
- tap `Review & Match`
|
||
- inspect side-by-side comparison:
|
||
- incoming share identity panel (sender, source ids, fingerprint, message)
|
||
- selected profile panel (name, relationship, tags/location, confidence)
|
||
- review candidate list with confidence percentages and suggestion marker
|
||
- confirm explicit link with `Confirm Match`
|
||
- Added confidence scoring + rationale hints:
|
||
- combines normalized-name similarity, prior candidate suggestion, and source
|
||
identity signals into a 1-99% confidence display
|
||
- shows short rationale bullets to make matching decisions transparent
|
||
- Added widget coverage:
|
||
- `test/features/share_intake/share_inbox_view_test.dart`
|
||
- verifies conflict review dialog opens and confirm mapping resolves inbox item
|
||
|
||
## Latest Milestone (2026-02-18): Share Inbox Resolution Flow
|
||
|
||
Added manual resolution UX and data paths for ambiguous/unidentifiable WhatsApp
|
||
shares:
|
||
|
||
- Introduced unresolved-share queue model:
|
||
- `lib/features/local/local_models.dart`
|
||
- new `SharedInboxEntry` + `SharedInboxReason`
|
||
- persisted in `LocalDataState.sharedInbox`
|
||
- Extended ingest result + repository APIs:
|
||
- `lib/features/local/local_repository.dart`
|
||
- `SharedMessageIngestResult` now reports imported vs queued-for-resolution
|
||
- ambiguous/missing-identity shares are routed to inbox instead of forced
|
||
auto-link
|
||
- added resolution actions:
|
||
- resolve inbox item to existing profile
|
||
- resolve inbox item by creating a new profile (with optional location)
|
||
- dismiss inbox item
|
||
- Added dedicated Share Inbox view:
|
||
- `lib/features/share_intake/share_inbox_view.dart`
|
||
- shows unresolved items, suggested matches, create-profile dialog, dismiss
|
||
- Wired entry points:
|
||
- `lib/features/share_intake/whatsapp_share_listener.dart`
|
||
- snackbar now routes unresolved imports to Share Inbox
|
||
- `lib/features/settings/settings_view.dart`
|
||
- added `Open Share Inbox` action and updated simulation feedback
|
||
- Added tests:
|
||
- `test/features/local/local_repository_test.dart`
|
||
- unresolved queue behavior
|
||
- resolve-to-existing-profile flow
|
||
- `test/features/share_intake/share_inbox_view_test.dart`
|
||
- inbox render + dismiss behavior
|
||
|
||
## Latest Milestone (2026-02-17): WhatsApp Share Intake + Profile Quick Actions
|
||
|
||
Implemented the next major usage-flow slice focused on capture-to-action speed:
|
||
|
||
- WhatsApp share intake pipeline (MVP):
|
||
- `lib/features/share_intake/whatsapp_share_listener.dart`
|
||
- `lib/features/share_intake/whatsapp_share_parser.dart`
|
||
- listener now ingests shared WhatsApp text into local state while
|
||
authenticated
|
||
- parser resolves sender-prefixed message shapes (including timestamped
|
||
export line format)
|
||
- Source identity linking for repeat routing:
|
||
- `lib/features/local/local_models.dart`
|
||
- `lib/features/local/local_repository.dart`
|
||
- added persisted source->profile link records and shared-message history
|
||
- repeated shares with same source identity resolve to the same profile
|
||
- Auto profile creation on first unresolved share:
|
||
- `LocalRepository.ingestSharedMessage(...)`
|
||
- creates profile (when needed), writes/updates source link, and appends
|
||
WhatsApp moment capture to that profile history
|
||
- Profile model enhancement:
|
||
- added optional `location` field on `PersonProfile`
|
||
- wired into serialization, repository payload mapping, and People editor UI
|
||
- People context quick-add:
|
||
- `lib/features/people/people_view.dart`
|
||
- profile detail now includes `+` quick actions:
|
||
- Add Capture
|
||
- Add Note
|
||
- Add Idea
|
||
- Add Reminder
|
||
- each action is person-scoped and writes directly to local state
|
||
- Settings support for dev/testing:
|
||
- `lib/features/settings/settings_view.dart`
|
||
- added `Simulate WhatsApp Share` flow to test ingestion without OS share UI
|
||
- App bootstrap wiring:
|
||
- `lib/main.dart` wraps authenticated shell with `WhatsAppShareListener`
|
||
- runtime flag in `lib/core/config/app_config.dart`:
|
||
`ENABLE_WHATSAPP_SHARE_INTAKE`
|
||
- Added tests:
|
||
- `test/features/share_intake/whatsapp_share_parser_test.dart`
|
||
- `test/features/local/local_repository_test.dart` share-ingest/link reuse case
|
||
- updated migration expectation in
|
||
`test/features/local/storage/local_repository_hive_migration_test.dart`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-17): Interactive Relationship Graph + Person Insights Drilldown
|
||
|
||
Upgraded the dashboard graph from static visualization to interactive
|
||
navigation:
|
||
|
||
- Graph interactions:
|
||
- `lib/features/dashboard/dashboard_view.dart`
|
||
- graph area now supports:
|
||
- pan by drag gesture
|
||
- pinch-to-zoom scaling
|
||
- long-press on person bubbles
|
||
- Long-press drilldown behavior:
|
||
- opens a dedicated person insights page with back navigation to the graph
|
||
- page sections are category-separated:
|
||
- Ideas
|
||
- Promotions & Signals
|
||
- Moments
|
||
- Reminders
|
||
- Tasks & Follow-Ups
|
||
- includes profile summary (relationship type, affinity, tags, notes)
|
||
- Added interaction test coverage:
|
||
- `test/features/dashboard/dashboard_graph_interactions_test.dart`
|
||
- verifies:
|
||
- graph contains interactive viewer
|
||
- long-press on a person node opens insights screen
|
||
- back button returns to graph
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-17): Obsidian-Style Relationship Graph on Dashboard
|
||
|
||
Reworked the initial Dashboard section to lead with a relationship network
|
||
visual:
|
||
|
||
- Replaced the old top summary-only start with a graph-first hero:
|
||
- `lib/features/dashboard/dashboard_view.dart`
|
||
- new `Relationship Graph` card renders:
|
||
- center `YOU` node
|
||
- surrounding person bubbles from local people data
|
||
- custom-painted connection edges (radial + mesh links)
|
||
- relationship-type icon badges + color-coded edge/node styling
|
||
- Added relationship-type visual mapping for labels such as:
|
||
- spouse, fiance, partner/girlfriend/boyfriend, friend, bestie, family,
|
||
sister, brother, fallback connection
|
||
- Added adaptive layout behavior:
|
||
- compact/mobile and wide/web radius/node limits
|
||
- hidden-node indicator for large lists
|
||
- relationship legend chips under the graph
|
||
- Preserved existing dashboard flow below the graph:
|
||
- stats cards and `Next Moves` tasks remain available
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-17): Connectivity Event-Driven Background Sync
|
||
|
||
Implemented online-transition-triggered sync so background sync reacts faster
|
||
when network returns:
|
||
|
||
- Added connectivity stream support to reachability abstraction:
|
||
- `lib/core/network/reachability/network_reachability.dart`
|
||
- new `watch(...)` API for reachability change events
|
||
- Added IO implementation using connectivity plugin + internet probe:
|
||
- `lib/core/network/reachability/network_reachability_io.dart`
|
||
- `connectivity_plus` integrated as transport signal source
|
||
- Updated background runner:
|
||
- `lib/features/sync/sync_background_runner.dart`
|
||
- now listens for offline -> online transitions and triggers immediate sync
|
||
- keeps existing startup/resume/periodic behavior
|
||
- Added coverage:
|
||
- `test/features/sync/sync_background_runner_test.dart`
|
||
- verifies transition-trigger behavior and avoids duplicate triggers when
|
||
already online
|
||
- Updated setup docs:
|
||
- `docs/SETUP.md` background sync section now includes connectivity-return
|
||
behavior note
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-17): Sync Repair Test Stability + Mobile CRUD/Sync Flow Coverage
|
||
|
||
Completed two test-depth upgrades:
|
||
|
||
- Stabilized rejected-sync repair widget flow:
|
||
- `test/features/sync/sync_rejection_repair_flow_test.dart`
|
||
- fixed viewport-aware assertions/actions for `ListView` content by
|
||
scrolling before interacting with rejection controls
|
||
- verifies rejected item -> open related repair screen -> save ->
|
||
local state mutation applied
|
||
- Added mobile-first integration-style flow:
|
||
- `test/features/app/app_mobile_crud_sync_flow_test.dart`
|
||
- covers compact-shell path: sign-in -> People -> add person -> sync queue
|
||
envelope asserted -> open Sync from `More` menu
|
||
- validates both UI behavior and queued backend envelope side effect in
|
||
`SyncQueueRepository`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Direct Entity Repair Forms From Sync
|
||
|
||
Implemented deep-link repair forms for rejected sync items:
|
||
|
||
- Updated `lib/features/sync/sync_view.dart`:
|
||
- `Open Related Screen` now routes into dedicated entity-specific repair
|
||
forms, not just general list screens
|
||
- supported entity repair forms:
|
||
- `person`
|
||
- `capture`
|
||
- `giftIdea`/`eventIdea`
|
||
- `reminderRule`
|
||
- each form updates local state via `LocalRepository` directly
|
||
- focus banner keeps exact `entityType:entityId` context with copy action
|
||
- Added widget flow coverage:
|
||
- `test/features/sync/sync_rejection_repair_flow_test.dart`
|
||
- verifies reject -> open repair form -> save -> local state updated
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Notification Tap Routing
|
||
|
||
Implemented initial in-app routing for reminder notification taps:
|
||
|
||
- Added notification intent bus:
|
||
- `lib/features/reminders/scheduling/reminder_notification_intent_bus.dart`
|
||
- Wired local notifications scheduler to emit tap payloads:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler_local_notifications.dart`
|
||
- Added app-level intent listener wrapper:
|
||
- `lib/features/reminders/scheduling/reminder_notification_listener.dart`
|
||
- opens reminder management screen when a reminder notification is tapped
|
||
- Mounted listener in authenticated app shell path:
|
||
- `lib/main.dart`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Sync Rejection Repair Navigation
|
||
|
||
Added direct repair navigation from rejected sync items:
|
||
|
||
- Updated `lib/features/sync/sync_view.dart`:
|
||
- each rejected item now includes `Open Related Screen`
|
||
- routes user to a relevant maintenance screen based on entity type:
|
||
- `person` -> People
|
||
- `capture` -> Moments
|
||
- `giftIdea`/`eventIdea` -> Ideas
|
||
- `reminderRule` -> Reminders
|
||
- keeps existing payload inspect + requeue/dismiss actions
|
||
- opened repair screen now shows exact `entityType:entityId` focus banner
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Notification Permission UX
|
||
|
||
Added runtime notification permission flow through the product UI:
|
||
|
||
- Extended reminder scheduler interface:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler.dart`
|
||
- new `requestPermissions()` API
|
||
- Implemented permission handling in local notifications scheduler:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler_local_notifications.dart`
|
||
- Android: `requestNotificationsPermission()`
|
||
- iOS/macOS: `requestPermissions(alert/badge/sound)`
|
||
- Added settings action:
|
||
- `lib/features/settings/settings_view.dart`
|
||
- `Request Notification Access` button with result feedback snackbar
|
||
- Added test coverage:
|
||
- `test/features/reminders/scheduling/reminder_scheduler_local_notifications_test.dart`
|
||
- verifies permission delegation behavior
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Local Notifications Reminder Runtime
|
||
|
||
Implemented reminder delivery with local notifications runtime integration:
|
||
|
||
- Added dependency:
|
||
- `flutter_local_notifications`
|
||
- Added concrete scheduler:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler_local_notifications.dart`
|
||
- `LocalNotificationsReminderScheduler`
|
||
- reconciles local reminders into platform notification schedule
|
||
- supports recurring cadence mapping:
|
||
- daily -> `DateTimeComponents.time`
|
||
- weekly -> `DateTimeComponents.dayOfWeekAndTime`
|
||
- monthly -> `DateTimeComponents.dayOfMonthAndTime`
|
||
- web/linux gracefully no-op (scheduling fallback)
|
||
- Provider wiring now defaults to local notifications scheduler:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler_provider.dart`
|
||
- gated by `ENABLE_LOCAL_NOTIFICATIONS`
|
||
- Added config flag:
|
||
- `lib/core/config/app_config.dart` -> `enableLocalNotifications`
|
||
- Added tests:
|
||
- `test/features/reminders/scheduling/reminder_scheduler_local_notifications_test.dart`
|
||
- Updated setup docs:
|
||
- `docs/SETUP.md`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Sync Rejection Payload Inspection
|
||
|
||
Improved conflict handling UX in Sync view:
|
||
|
||
- Updated `lib/features/sync/sync_view.dart`:
|
||
- each rejected mutation now supports payload inspect/expand
|
||
- shows formatted local envelope payload JSON for failed mutations when
|
||
available
|
||
- keeps requeue/dismiss actions for operator control
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Reachability-Gated Auto Sync
|
||
|
||
Added connectivity-aware gating to background sync auto-triggers:
|
||
|
||
- Added network reachability abstraction:
|
||
- `lib/core/network/reachability/network_reachability.dart`
|
||
- `lib/core/network/reachability/network_reachability_provider.dart`
|
||
- platform impls:
|
||
- `network_reachability_io.dart`
|
||
- `network_reachability_web.dart`
|
||
- `network_reachability_stub.dart`
|
||
- Integrated into background sync runner:
|
||
- `lib/features/sync/sync_background_runner.dart`
|
||
- auto-triggers now skip when reachability gate reports offline (REST mode)
|
||
- fake backend mode bypasses reachability gate
|
||
- Extended sync trigger controller:
|
||
- `lib/features/sync/sync_auto_trigger_controller.dart`
|
||
- added trigger gate callback support
|
||
- Added tests:
|
||
- `test/features/sync/sync_auto_trigger_controller_test.dart`
|
||
- validates denied-trigger behavior
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): App Session Flow Test Coverage
|
||
|
||
Added higher-level widget coverage for a core authenticated user journey:
|
||
|
||
- New test:
|
||
- `test/features/app/app_auth_flow_test.dart`
|
||
- validates end-to-end path:
|
||
- sign-in screen shown by default
|
||
- sign-in transitions into app shell
|
||
- navigate to settings and sign out
|
||
- sign-out returns to sign-in screen
|
||
- Uses deterministic in-memory overrides for token, local data store, sync state
|
||
store, and backend gateway fake.
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Rejected-Mutation Requeue Flow
|
||
|
||
Extended sync conflict handling so rejected mutations can be retried after local
|
||
fixes:
|
||
|
||
- Expanded sync state model:
|
||
- `lib/features/sync/sync_state.dart`
|
||
- stores `lastRejectedChanges` alongside rejection reasons
|
||
- Updated sync queue repository:
|
||
- `lib/features/sync/sync_queue_repository.dart`
|
||
- captures rejected envelopes during push
|
||
- adds `requeueRejectedChanges()` to move rejected envelopes back into pending
|
||
queue
|
||
- keeps clear/dismiss behavior for rejected metadata
|
||
- Updated sync UX:
|
||
- `lib/features/sync/sync_view.dart`
|
||
- rejected section now includes:
|
||
- entity context (`entityType:entityId`)
|
||
- `Requeue` action for manual retry flow
|
||
- existing `Dismiss` action
|
||
- Added/updated tests:
|
||
- `test/features/sync/sync_queue_repository_test.dart`
|
||
- verifies rejected envelope capture and requeue behavior
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Sync Auto-Trigger Backoff
|
||
|
||
Improved sync trigger resilience for repeated failures:
|
||
|
||
- Updated `lib/features/sync/sync_auto_trigger_controller.dart`:
|
||
- tracks consecutive sync failures
|
||
- applies exponential cooldown backoff before auto-trigger retries
|
||
- resets backoff after a successful sync run
|
||
- Added coverage:
|
||
- `test/features/sync/sync_auto_trigger_controller_test.dart`
|
||
- validates cooldown behavior after failures
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Reminder Delivery Interface Wiring
|
||
|
||
Implemented the notification scheduling boundary and connected it to local data
|
||
state transitions:
|
||
|
||
- Added reminder scheduler abstraction:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler.dart`
|
||
- `ReminderScheduler` + `NoopReminderScheduler`
|
||
- Added provider wiring:
|
||
- `lib/features/reminders/scheduling/reminder_scheduler_provider.dart`
|
||
- Integrated schedule reconciliation with local repository:
|
||
- `lib/features/local/local_repository.dart`
|
||
- reconcile runs on repository boot and each persisted state update
|
||
- failures are swallowed to preserve offline-first behavior
|
||
- Added tests:
|
||
- `test/features/local/local_repository_test.dart` now verifies reminder
|
||
schedule reconciliation calls
|
||
- Updated setup docs:
|
||
- `docs/SETUP.md` now documents reminder scheduler scaffold
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Sync Hardening + CI Baseline
|
||
|
||
Implemented the next production-readiness slice:
|
||
|
||
- Added lifecycle-aware background sync runner:
|
||
- `lib/features/sync/sync_auto_trigger_controller.dart`
|
||
- `lib/features/sync/sync_background_runner.dart`
|
||
- mounted while authenticated in `lib/main.dart`
|
||
- behavior: one trigger on app startup, trigger on app resume, periodic sync
|
||
ticks (default every 180s), cooldown/concurrency guarded
|
||
- Added runtime config flags:
|
||
- `ENABLE_BACKGROUND_SYNC` (default `true`)
|
||
- `BACKGROUND_SYNC_INTERVAL_SECONDS` (default `180`)
|
||
- in `lib/core/config/app_config.dart`
|
||
- Added user-facing rejected mutation handling:
|
||
- `lib/features/sync/sync_queue_repository.dart` -> `clearRejections()`
|
||
- `lib/features/sync/sync_view.dart` now renders a `Rejected Changes` section
|
||
with dismiss action
|
||
- Added tests:
|
||
- `test/features/sync/sync_auto_trigger_controller_test.dart`
|
||
- `test/features/sync/sync_queue_repository_test.dart` rejection clear case
|
||
- Added CI workflow:
|
||
- `.github/workflows/flutter_ci.yml` (`flutter pub get`, `flutter analyze`,
|
||
`flutter test`)
|
||
- Updated setup docs:
|
||
- `docs/SETUP.md` with background sync flags
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
### Open Phases (Current)
|
||
|
||
1. Reminder delivery runtime integration:
|
||
- implemented for Android/iOS/macOS/windows with web/linux safe fallback.
|
||
- permission UX implemented in settings.
|
||
- notification tap routing implemented for reminder screen handoff.
|
||
2. Conflict resolution UX:
|
||
- reject/requeue + payload inspect + direct entity repair forms implemented.
|
||
- future enhancement: auto-select and highlight the exact row in main feature
|
||
screens after save.
|
||
3. Sync trigger maturity:
|
||
- implemented via reachability gating + online-transition event triggers.
|
||
- future: add richer platform-specific network quality awareness if needed.
|
||
4. Test depth:
|
||
- expanded with mobile compact CRUD+sync flow and rejected-repair flow.
|
||
- future: add desktop + web-specific end-to-end sync error/retry scenario.
|
||
|
||
## Latest Milestone (2026-02-15): Sync Queue Storage Adapter + Hive Migration
|
||
|
||
Extended the storage abstraction approach to sync queue persistence:
|
||
|
||
- Added sync storage abstraction:
|
||
- `lib/features/sync/storage/sync_state_store.dart`
|
||
- Added concrete sync stores:
|
||
- `lib/features/sync/storage/sync_state_store_shared_prefs.dart`
|
||
- `lib/features/sync/storage/sync_state_store_hive.dart`
|
||
- `lib/features/sync/storage/sync_state_store_in_memory.dart`
|
||
- provider wiring: `lib/features/sync/storage/sync_state_store_provider.dart`
|
||
- Refactored sync queue repository:
|
||
- `lib/features/sync/sync_queue_repository.dart`
|
||
- no direct `shared_preferences` dependency
|
||
- store-agnostic read/write path via `SyncStateStore`
|
||
- one-time migration path from legacy shared prefs sync payload into Hive
|
||
- Updated tests to use explicit in-memory store overrides where deterministic:
|
||
- `test/features/sync/sync_queue_repository_test.dart`
|
||
- `test/features/sync/sync_coordinator_test.dart`
|
||
- `test/features/local/local_repository_test.dart`
|
||
- `test/features/responsive/responsive_views_smoke_test.dart`
|
||
- Added migration coverage:
|
||
- `test/features/sync/storage/sync_queue_hive_migration_test.dart`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Local Store Adapter Layer (DB Migration Scaffold)
|
||
|
||
Implemented a persistence boundary so local app state is no longer tightly coupled to `shared_preferences` internals:
|
||
|
||
- Added local persistence abstraction:
|
||
- `lib/features/local/storage/local_data_store.dart`
|
||
- `LocalDataStore` + `LocalDataRecord`
|
||
- Added concrete store implementations:
|
||
- `lib/features/local/storage/local_data_store_shared_prefs.dart`
|
||
- `lib/features/local/storage/local_data_store_hive.dart`
|
||
- `lib/features/local/storage/local_data_store_in_memory.dart`
|
||
- provider wiring: `lib/features/local/storage/local_data_store_provider.dart`
|
||
- Refactored local repository to use store adapter:
|
||
- `lib/features/local/local_repository.dart`
|
||
- build/read/write/migration paths now go through `LocalDataStore`
|
||
- schema migration hook retained and now store-agnostic
|
||
- Added config flag for local backend selection:
|
||
- `lib/core/config/app_config.dart` -> `USE_HIVE_LOCAL_DB`
|
||
- default now set to Hive (`true`)
|
||
- Added one-time migration path from legacy shared prefs into Hive:
|
||
- `lib/features/local/local_repository.dart`
|
||
- when Hive is active and empty, legacy payload is imported then cleared
|
||
- Added setup docs for switching local persistence backend:
|
||
- `docs/SETUP.md`
|
||
- Added migration/storage tests:
|
||
- `test/features/local/storage/local_data_store_shared_prefs_test.dart`
|
||
- `test/features/local/storage/local_repository_store_override_test.dart`
|
||
- `test/features/local/storage/local_repository_hive_migration_test.dart`
|
||
|
||
This prepares the app for a true DB migration path while keeping existing UX and tests stable.
|
||
|
||
## Latest Milestone (2026-02-15): Cross-View Responsive Pass
|
||
|
||
Audited and adjusted the main product views for mobile-first behavior while preserving desktop/web UX:
|
||
|
||
- Updated responsive behavior and compact spacing for:
|
||
- `lib/features/dashboard/dashboard_view.dart`
|
||
- `lib/features/moments/moments_view.dart`
|
||
- `lib/features/ideas/ideas_view.dart`
|
||
- `lib/features/reminders/reminders_view.dart`
|
||
- `lib/features/signals/signals_view.dart`
|
||
- `lib/features/settings/settings_view.dart`
|
||
- `lib/features/sync/sync_view.dart`
|
||
- `lib/features/auth/sign_in_view.dart`
|
||
- `lib/features/people/people_view.dart`
|
||
- Removed narrow-width overflow hotspots:
|
||
- stacked compact headers/actions instead of single fixed rows
|
||
- converted key action rows to `Wrap`/column where needed
|
||
- improved list-item text constraints (`maxLines`, `ellipsis`)
|
||
- made editor dialogs width-safe using max-width constraints
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
### Breakpoint QA follow-up
|
||
|
||
Ran targeted responsive smoke checks for:
|
||
|
||
- iPhone SE (`320x568`)
|
||
- iPhone Pro Max (`430x932`)
|
||
- iPad portrait (`768x1024`)
|
||
- Web/desktop (`1280x800`)
|
||
|
||
Follow-up fixes from QA:
|
||
|
||
- `lib/features/auth/sign_in_view.dart`
|
||
- added scroll-safe container for short-height screens to prevent vertical overflow
|
||
- `lib/features/home/app_shell.dart`
|
||
- made sidebar brand text ellipsize-safe to prevent horizontal overflow
|
||
- Added automated responsive regression suite:
|
||
- `test/features/responsive/responsive_views_smoke_test.dart`
|
||
- validates `AppShell` + all primary views across the breakpoints above
|
||
|
||
## Latest Milestone (2026-02-15): People Mobile Layout Fix
|
||
|
||
Fixed the `People` view so it is mobile-friendly and no longer overflows on iOS narrow screens:
|
||
|
||
- `lib/features/people/people_view.dart`
|
||
- added responsive breakpoint logic (`LayoutBuilder`)
|
||
- desktop keeps split-pane list/detail layout
|
||
- mobile now uses a single-column flow (header, people list, selected person detail)
|
||
- improved text safety with `maxLines`/`ellipsis` and compact detail action row
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Sync Queue + Orchestrator
|
||
|
||
Implemented the next sync phase so local mutations are now queued and synced through a real coordinator flow:
|
||
|
||
- Added persisted sync queue state:
|
||
- `lib/features/sync/sync_state.dart`
|
||
- `lib/features/sync/sync_queue_repository.dart`
|
||
- stores pending `ChangeEnvelope`s, cursor, last attempt/sync, and rejection info
|
||
- Added sync orchestration service:
|
||
- `lib/features/sync/sync_coordinator.dart`
|
||
- supports `pushPending`, `pullRemote`, and `syncNow`
|
||
- keeps offline-first behavior by recording failures without blocking local usage
|
||
- Wired local CRUD to sync envelopes:
|
||
- `lib/features/local/local_repository.dart`
|
||
- all person/moment/idea/reminder mutations now enqueue typed change envelopes
|
||
- added `applyRemoteChanges(...)` to apply pulled backend envelopes into local state
|
||
- Upgraded Sync UI:
|
||
- `lib/features/sync/sync_view.dart`
|
||
- now shows queue/cursor/error status and provides real sync actions (sync/push/pull/clear)
|
||
- Added sync tests:
|
||
- `test/features/sync/sync_queue_repository_test.dart`
|
||
- `test/features/sync/sync_coordinator_test.dart`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Auth Session UX
|
||
|
||
Implemented app-level authentication/session flow so navigation is now session-aware:
|
||
|
||
- Added session lifecycle controller:
|
||
- `lib/features/auth/session_controller.dart`
|
||
- bootstraps from token store on app startup
|
||
- supports sign-in, sign-out, and profile refresh
|
||
- enforces offline-safe sign-out (always clears local session)
|
||
- Added sign-in experience:
|
||
- `lib/features/auth/sign_in_view.dart`
|
||
- supports Password / Magic Link / OIDC request shapes
|
||
- shows mode status (Fake/REST)
|
||
- Updated app bootstrap:
|
||
- `lib/main.dart` now gates between `SignInView` and `AppShell` based on session state
|
||
- Updated settings with session actions:
|
||
- `lib/features/settings/settings_view.dart`
|
||
- shows current identity and provides `Sign Out` + `Refresh Profile`
|
||
- Added auth tests:
|
||
- `test/features/auth/session_controller_test.dart`
|
||
- updated `test/widget_test.dart` for sign-in default route
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Ideas + Reminders Phase
|
||
|
||
Implemented the next Phase 2 slice by introducing Ideas and Reminder Rules as first-class local features.
|
||
|
||
- Expanded local domain/state:
|
||
- `IdeaType`, `ReminderCadence`, `RelationshipIdea`, `ReminderRule`
|
||
- `LocalDataState` now persists `ideas` and `reminders`
|
||
- Expanded local repository CRUD:
|
||
- ideas: add/update/archive/delete
|
||
- reminders: add/update/toggle/delete
|
||
- people deletion now cascades to moments/ideas/reminders
|
||
- Added new feature views:
|
||
- `lib/features/ideas/ideas_view.dart`
|
||
- `lib/features/reminders/reminders_view.dart`
|
||
- Updated shell navigation:
|
||
- desktop sidebar now includes `Ideas` and `Reminders`
|
||
- mobile keeps compact primary tabs and exposes `Ideas`/`Reminders` under `More`
|
||
- Expanded local repository tests for new CRUD surface:
|
||
- `test/features/local/local_repository_test.dart`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Latest Milestone (2026-02-15): Local Persistence + CRUD Baseline
|
||
|
||
Implemented the first real local data foundation pass (replacing static demo-only reads):
|
||
|
||
- Added persisted local state using `shared_preferences`:
|
||
- `lib/features/local/local_repository.dart`
|
||
- schema key/version scaffold + seed fallback + persistence logic
|
||
- Upgraded local models with serialization/copy methods:
|
||
- `lib/features/local/local_models.dart`
|
||
- Added local CRUD operations:
|
||
- people: add, edit, delete
|
||
- moments: add, delete
|
||
- dashboard tasks: done/undone toggle
|
||
- Wired views to async persisted state:
|
||
- `DashboardView`, `PeopleView`, `MomentsView`
|
||
- Updated signals fallback to read from persisted local state:
|
||
- `lib/features/signals/signals_controller.dart`
|
||
- Added local repository tests:
|
||
- `test/features/local/local_repository_test.dart`
|
||
|
||
Validation for this milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Workflow Rule
|
||
|
||
- After every sensible change, the final step is a Git commit with a clear message.
|
||
- Keep changes in small, logical commits so future sessions can revert or continue safely.
|
||
|
||
## Latest Milestone (2026-02-15): Product UI Flow Implemented
|
||
|
||
The app now has a real multi-screen user experience on macOS (and other platforms), not just a placeholder screen.
|
||
|
||
Delivered UI architecture:
|
||
|
||
- App shell with responsive navigation:
|
||
- desktop: left sidebar + content pane
|
||
- compact: bottom navigation (reduced to 4 primary tabs)
|
||
- compact secondary actions (`Sync`, `Settings`) moved into a `More` menu to avoid tab overload on iOS/mobile
|
||
- Views implemented:
|
||
- Dashboard
|
||
- People
|
||
- Moments
|
||
- Signals
|
||
- Sync
|
||
- Settings
|
||
- Reference-aligned visual style:
|
||
- WorkSans typography (copied from the UI reference assets)
|
||
- soft gradients, rounded glass-like cards, accent palette similar to the reference repo
|
||
- Offline-safe UX:
|
||
- fake backend mode now defaults to `true` unless overridden via `--dart-define=USE_FAKE_BACKEND=false`
|
||
- signals view gracefully falls back to local recommendations when backend calls fail
|
||
|
||
Key new files:
|
||
|
||
- `lib/features/home/app_shell.dart`
|
||
- `lib/features/dashboard/dashboard_view.dart`
|
||
- `lib/features/people/people_view.dart`
|
||
- `lib/features/moments/moments_view.dart`
|
||
- `lib/features/signals/signals_controller.dart`
|
||
- `lib/features/signals/signals_view.dart`
|
||
- `lib/features/sync/sync_view.dart`
|
||
- `lib/features/settings/settings_view.dart`
|
||
- `lib/features/shared/frosted_card.dart`
|
||
- `lib/features/local/local_models.dart`
|
||
- `lib/features/local/local_repository.dart`
|
||
- `assets/fonts/WorkSans-*.ttf`
|
||
|
||
Other updates:
|
||
|
||
- `lib/main.dart` now launches the new app shell.
|
||
- `lib/core/config/app_theme.dart` updated to a stronger visual system.
|
||
- `pubspec.yaml` includes local WorkSans font family.
|
||
- `test/widget_test.dart` updated for the new flow.
|
||
|
||
Validation status after UI milestone:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Current Gap Analysis (2026-02-15)
|
||
|
||
### What we have now
|
||
|
||
- Backend gateway architecture with REST + fake implementations, typed DTOs, retries, refresh, and tests.
|
||
- OpenAPI + ADR documentation baseline.
|
||
- Product UI shell with responsive desktop/mobile navigation and key views.
|
||
- Offline-safe default behavior with fake backend mode.
|
||
|
||
### What is still missing
|
||
|
||
- Local database persistence and repository wiring (currently demo in-memory data).
|
||
- Full CRUD flows (create/edit/delete) for people, captures, reminder rules, gift/event ideas.
|
||
- Auth UX flows (sign-in, session-expired recovery, sign-out confirmation).
|
||
- Conflict policy UI and merge/resolution UX for rejected remote/local mutations.
|
||
- Notifications/reminders delivery and scheduling integration.
|
||
- End-to-end and integration tests for app flows beyond unit/widget basics.
|
||
|
||
## Implementation Plan (Next)
|
||
|
||
### Phase 1: Data Foundation
|
||
|
||
1. Introduce local DB schema + repository interfaces for core entities.
|
||
2. Replace `LocalRepository` demo data with persisted data access.
|
||
3. Add migration/test coverage for DB reads/writes.
|
||
|
||
### Phase 2: Core Product Flows
|
||
|
||
1. Build People CRUD and detail editing screens.
|
||
2. Build Moments/Captures create-and-list workflows.
|
||
3. Add Ideas and Reminder Rule management.
|
||
|
||
### Phase 3: Sync + Auth UX
|
||
|
||
1. Add background sync scheduling/triggers (app start, manual retry, connectivity hooks).
|
||
2. Add conflict handling strategy and user-facing UI states for rejected mutations.
|
||
3. Add session-expired recovery UX and guarded routes for protected actions.
|
||
|
||
### Phase 4: Quality + Release Readiness
|
||
|
||
1. Add CI for analyze/test and optional build smoke checks.
|
||
2. Expand widget/integration tests for primary user journeys.
|
||
3. Add observability hooks and production hardening pass.
|
||
|
||
## Current Status
|
||
|
||
The Flutter app now includes a production-grade backend integration scaffold with an offline-first posture:
|
||
|
||
- Local/offline UX remains primary; backend is optional for core usage.
|
||
- A transport-agnostic gateway interface is in place.
|
||
- REST implementation with auth refresh/retry/error mapping is implemented.
|
||
- Deterministic fake gateway is available for local/dev without backend.
|
||
- OpenAPI contract + ADR + setup docs + unit tests are in place.
|
||
- `flutter analyze` and `flutter test` are passing.
|
||
|
||
## What Was Implemented
|
||
|
||
### 1. Core Config + Theme Shell
|
||
|
||
- Added backend config with build-time + runtime override:
|
||
- `lib/core/config/app_config.dart`
|
||
- Added lightweight app theme aligned with reference style direction:
|
||
- `lib/core/config/app_theme.dart`
|
||
- Updated app entry shell and Riverpod root:
|
||
- `lib/main.dart`
|
||
|
||
### 2. Network Foundation
|
||
|
||
Implemented a Dio stack with request metadata, auth, refresh, retry, and error mapping:
|
||
|
||
- `lib/core/network/dio_factory.dart`
|
||
- `lib/core/network/network_constants.dart`
|
||
- `lib/core/network/backend_exception.dart`
|
||
- `lib/core/network/dio_error_mapper.dart`
|
||
- Interceptors:
|
||
- `lib/core/network/interceptors/request_metadata_interceptor.dart`
|
||
- `lib/core/network/interceptors/auth_interceptor.dart`
|
||
- `lib/core/network/interceptors/refresh_token_interceptor.dart`
|
||
- `lib/core/network/interceptors/retry_interceptor.dart`
|
||
|
||
Behavior implemented:
|
||
|
||
- Adds per-request `X-Request-Id`.
|
||
- Adds `Authorization: Bearer <token>` when session exists.
|
||
- On `401`, attempts one refresh (`/v1/auth/refresh`) then retries original request.
|
||
- If refresh fails, session is cleared and `AuthExpiredException` surfaced.
|
||
- Retry policy (max 2 retries, exponential backoff):
|
||
- Retry transient failures (`timeouts`, `connection`, `5xx`).
|
||
- Safe methods (`GET/HEAD/OPTIONS`) retry automatically.
|
||
- Non-idempotent endpoints only retry when `Idempotency-Key` exists.
|
||
- Maps Dio failures into typed backend exceptions with metadata.
|
||
|
||
### 3. Auth Token Storage
|
||
|
||
- Interface:
|
||
- `lib/core/auth/token_store.dart`
|
||
- Production implementation:
|
||
- `lib/core/auth/secure_token_store.dart`
|
||
- Test/dev implementation:
|
||
- `lib/core/auth/in_memory_token_store.dart`
|
||
|
||
### 4. Backend Integration Layer
|
||
|
||
Domain boundary and implementations:
|
||
|
||
- Interface:
|
||
- `lib/integrations/backend/backend_gateway.dart`
|
||
- REST:
|
||
- `lib/integrations/backend/backend_gateway_rest.dart`
|
||
- Fake:
|
||
- `lib/integrations/backend/backend_gateway_fake.dart`
|
||
- Optional Riverpod providers:
|
||
- `lib/integrations/backend/backend_gateway_provider.dart`
|
||
- Sync validation:
|
||
- `lib/integrations/backend/sync_envelope_validator.dart`
|
||
|
||
Implemented methods:
|
||
|
||
- sign-in/out + me
|
||
- sync pull/push (with idempotency key on push)
|
||
- signals feed + ack
|
||
- upload init + download URL scaffold
|
||
|
||
Offline-first hardening:
|
||
|
||
- `signOut()` clears local token store in `finally`, even when network call fails.
|
||
|
||
### 5. Typed Models (Freezed + JSON)
|
||
|
||
- `lib/integrations/backend/models/backend_models.dart`
|
||
- Generated files:
|
||
- `backend_models.freezed.dart`
|
||
- `backend_models.g.dart`
|
||
|
||
Includes DTOs/enums for:
|
||
|
||
- Auth (`SignInRequest`, `AuthSession`, refresh request/response, `UserProfile`)
|
||
- Sync (`ChangeEnvelope`, push/pull requests/results, ack/rejection)
|
||
- Signals (`SignalsFeed`, `SignalItem`, ack request/action)
|
||
- Uploads (`UploadInitRequest/Result`, `DownloadUrl`)
|
||
|
||
### 6. Contract + Architecture Docs
|
||
|
||
- OpenAPI spec:
|
||
- `docs/api/openapi.yaml`
|
||
- ADR:
|
||
- `docs/ADR/0002-backend-protocol-rest-openapi.md`
|
||
- Setup instructions:
|
||
- `docs/SETUP.md`
|
||
- Previous concise checklist log:
|
||
- `docs/PROGRESS.md`
|
||
|
||
### 7. Tooling + Quality
|
||
|
||
- Strict analyzer/lints:
|
||
- `analysis_options.yaml`
|
||
- Dependencies added in `pubspec.yaml`:
|
||
- runtime: `dio`, `freezed_annotation`, `json_annotation`, `flutter_secure_storage`, `uuid`, `clock`, `flutter_riverpod`
|
||
- dev: `freezed`, `json_serializable`, `build_runner`, `mocktail`
|
||
|
||
### 8. Test Coverage Added
|
||
|
||
Core network and model tests:
|
||
|
||
- `test/core/network/token_refresh_interceptor_test.dart`
|
||
- `test/core/network/dio_error_mapper_test.dart`
|
||
- `test/core/network/retry_interceptor_test.dart`
|
||
- `test/integrations/backend/backend_models_serialization_test.dart`
|
||
- `test/integrations/backend/sync_envelope_validator_test.dart`
|
||
- helper adapter: `test/helpers/queue_http_client_adapter.dart`
|
||
- updated smoke widget test: `test/widget_test.dart`
|
||
|
||
## Verification Snapshot
|
||
|
||
Most recent local checks:
|
||
|
||
- `flutter analyze` -> pass
|
||
- `flutter test` -> pass
|
||
|
||
## Known Gaps / Intentional Scope Limits
|
||
|
||
- No realtime transport yet (SSE/WebSocket intentionally deferred).
|
||
- No backend-generated client code from OpenAPI yet.
|
||
- No persistence layer wiring to local DB yet (gateway is ready to plug in).
|
||
- No UI features using backend gateway yet beyond app shell readiness.
|
||
- Fake gateway data is deterministic sample content, not scenario-configurable yet.
|
||
|
||
## Handoff Plan For Next Agent Sessions
|
||
|
||
### Priority 1: Repository Hygiene + CI
|
||
|
||
1. Add CI workflow for `flutter analyze` + `flutter test`.
|
||
2. Add branch protections / PR template if desired.
|
||
3. Keep generated files committed policy explicit in README.
|
||
|
||
### Priority 2: Local DB Integration (Offline-First Core)
|
||
|
||
1. Define local domain entities and repositories for `person`, `capture`, `giftIdea`, `eventIdea`, `tag`, `reminderRule`.
|
||
2. Map local mutations to `ChangeEnvelope` and enqueue for sync.
|
||
3. Create sync orchestrator service that:
|
||
- pushes pending local mutations,
|
||
- applies pull changes with conflict policy,
|
||
- stores/advances cursor.
|
||
4. Add tests for conflict handling and cursor progression.
|
||
|
||
### Priority 3: App Wiring + UX
|
||
|
||
1. Replace local demo repository data with actual local DB repositories.
|
||
2. Add create/edit flows for people, captures, reminders, and ideas (forms + validation).
|
||
3. Add session state and auth entry screens (sign-in, expired-session recovery).
|
||
4. Add explicit offline badges and sync conflict resolution UI.
|
||
|
||
### Priority 4: Security + Hardening
|
||
|
||
1. Add central log redaction helper for headers/bodies.
|
||
2. Add token-expiry pre-check strategy (optional proactive refresh).
|
||
3. Evaluate secure storage behavior on web target and fallback policy.
|
||
4. Add tests for concurrent 401 refresh race conditions.
|
||
|
||
### Priority 5: API Evolution
|
||
|
||
1. Version strategy in OpenAPI (`/v1` already set).
|
||
2. Define backend error payload schema formally in OpenAPI.
|
||
3. Add capabilities endpoint for future realtime negotiation.
|
||
4. Add SSE/WebSocket design ADR when backend is ready.
|
||
|
||
## How To Continue Quickly
|
||
|
||
1. Run: `flutter pub get`
|
||
2. If models change: `dart run build_runner build --delete-conflicting-outputs`
|
||
3. Validate: `flutter analyze && flutter test`
|
||
4. Start from:
|
||
- gateway surface: `lib/integrations/backend/backend_gateway.dart`
|
||
- sync transport: `lib/integrations/backend/backend_gateway_rest.dart`
|
||
- contract: `docs/api/openapi.yaml`
|
||
|
||
## Important Notes
|
||
|
||
- Current default base URL is placeholder (`https://api.example.com`).
|
||
- Use fake mode for local iteration:
|
||
- `flutter run --dart-define=USE_FAKE_BACKEND=true`
|
||
- Build-time URL override:
|
||
- `flutter run --dart-define=BACKEND_BASE_URL=<your-url>`
|