204 lines
7.0 KiB
Markdown
204 lines
7.0 KiB
Markdown
# Relationship Saver Progress Log
|
|
|
|
Updated: 2026-02-14
|
|
|
|
## 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. Wire `BackendGateway` into app services/use cases (not UI widgets directly).
|
|
2. Add session state provider (signed in / expired / signed out).
|
|
3. Add explicit offline indicators and non-blocking sync status UI.
|
|
4. Start consuming fake gateway in feature screens before live backend.
|
|
|
|
### 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>`
|