8.7 KiB
8.7 KiB
Relationship Saver Progress Log
Updated: 2026-02-15
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
- 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
trueunless overridden via--dart-define=USE_FAKE_BACKEND=false - signals view gracefully falls back to local recommendations when backend calls fail
- fake backend mode now defaults to
Key new files:
lib/features/home/app_shell.dartlib/features/dashboard/dashboard_view.dartlib/features/people/people_view.dartlib/features/moments/moments_view.dartlib/features/signals/signals_controller.dartlib/features/signals/signals_view.dartlib/features/sync/sync_view.dartlib/features/settings/settings_view.dartlib/features/shared/frosted_card.dartlib/features/local/local_models.dartlib/features/local/local_repository.dartassets/fonts/WorkSans-*.ttf
Other updates:
lib/main.dartnow launches the new app shell.lib/core/config/app_theme.dartupdated to a stronger visual system.pubspec.yamlincludes local WorkSans font family.test/widget_test.dartupdated for the new flow.
Validation status after UI milestone:
flutter analyze-> passflutter test-> 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 analyzeandflutter testare 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.dartlib/core/network/network_constants.dartlib/core/network/backend_exception.dartlib/core/network/dio_error_mapper.dart- Interceptors:
lib/core/network/interceptors/request_metadata_interceptor.dartlib/core/network/interceptors/auth_interceptor.dartlib/core/network/interceptors/refresh_token_interceptor.dartlib/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
AuthExpiredExceptionsurfaced. - 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-Keyexists.
- Retry transient failures (
- 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 infinally, even when network call fails.
5. Typed Models (Freezed + JSON)
lib/integrations/backend/models/backend_models.dart- Generated files:
backend_models.freezed.dartbackend_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
- runtime:
8. Test Coverage Added
Core network and model tests:
test/core/network/token_refresh_interceptor_test.darttest/core/network/dio_error_mapper_test.darttest/core/network/retry_interceptor_test.darttest/integrations/backend/backend_models_serialization_test.darttest/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-> passflutter 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
- Add CI workflow for
flutter analyze+flutter test. - Add branch protections / PR template if desired.
- Keep generated files committed policy explicit in README.
Priority 2: Local DB Integration (Offline-First Core)
- Define local domain entities and repositories for
person,capture,giftIdea,eventIdea,tag,reminderRule. - Map local mutations to
ChangeEnvelopeand enqueue for sync. - Create sync orchestrator service that:
- pushes pending local mutations,
- applies pull changes with conflict policy,
- stores/advances cursor.
- Add tests for conflict handling and cursor progression.
Priority 3: App Wiring + UX
- Replace local demo repository data with actual local DB repositories.
- Add create/edit flows for people, captures, reminders, and ideas (forms + validation).
- Add session state and auth entry screens (sign-in, expired-session recovery).
- Add explicit offline badges and sync conflict resolution UI.
Priority 4: Security + Hardening
- Add central log redaction helper for headers/bodies.
- Add token-expiry pre-check strategy (optional proactive refresh).
- Evaluate secure storage behavior on web target and fallback policy.
- Add tests for concurrent 401 refresh race conditions.
Priority 5: API Evolution
- Version strategy in OpenAPI (
/v1already set). - Define backend error payload schema formally in OpenAPI.
- Add capabilities endpoint for future realtime negotiation.
- Add SSE/WebSocket design ADR when backend is ready.
How To Continue Quickly
- Run:
flutter pub get - If models change:
dart run build_runner build --delete-conflicting-outputs - Validate:
flutter analyze && flutter test - Start from:
- gateway surface:
lib/integrations/backend/backend_gateway.dart - sync transport:
lib/integrations/backend/backend_gateway_rest.dart - contract:
docs/api/openapi.yaml
- gateway surface:
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>