# Relationship Saver Progress Log Updated: 2026-02-18 ## 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-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 ` 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=`