cyberhybridhub/FLUTTER-TDD-PLAN.md
2026-05-31 11:17:12 -05:00

308 lines
8.9 KiB
Markdown

# Flutter Admin Portal TDD Plan
**Scope:** Validate the functionality defined in `FLUTTER-ADMIN-PORTAL.md` using test-first development across server API + Flutter UI/repository layers.
**Primary objective:** Ship an admin portal that reliably shows retention/cleanup/backfill history, prioritizes unresolved failures/rate limits, and presents concise expandable details.
---
## 1. Test strategy at a glance
Use a layered pyramid so core behavior is proven at the cheapest layer first:
| Layer | Purpose | Tools |
|---|---|---|
| Unit (server) | pin/severity/status logic, query mapping | `dart test` |
| Integration (server) | auth, DB query shape/order, endpoint behavior | `dart test` + Postgres test DB |
| Unit (Flutter) | DTO mapping, repository merge, parsing, formatting | `flutter test` |
| Widget (Flutter) | pinned section, newest-first list, expansion details, pagination interactions | `flutter test` |
| Optional e2e/manual | confidence pass with real API + seeded rows | local runbook |
---
## 2. Coverage targets (reasonable)
Aim for practical coverage without over-testing visual polish:
- **Server admin handler package:** >= **85% line coverage**
- **Server pin/severity helper logic:** >= **95% line coverage**
- **Flutter admin repository/models:** >= **90% line coverage**
- **Flutter admin widgets/screens:** >= **75% line coverage**
- **Critical behavior cases:** **100% scenario coverage** for:
- unresolved errors pinned
- unpin after successful retry by same `kind`
- newest-first ordering
- expanded full error text display
- no raw data fields rendered
---
## 3. Test data model fixtures
Create reusable fixture builders for `market_data_sync_runs` rows:
```text
run(id, kind, startedAt, finishedAt, rowsWritten, rowsRemoved, error)
```
Named fixture sets:
1. `all_success_recent_first`
2. `rate_limit_unresolved`
3. `failed_then_success_same_kind`
4. `partial_backfill_error`
5. `in_progress_stale`
6. `mixed_kinds_mixed_outcomes`
Keep fixtures concise; avoid raw bar payloads by design.
---
## 4. Server TDD plan
Target files (planned):
- `server/lib/handlers/market_history_admin_handler.dart`
- `server/lib/trading/market_history_admin_query.dart` (or equivalent helper)
- `server/test/integration/market_history_admin_handler_test.dart`
- `server/test/trading/market_history_admin_logic_test.dart`
### 4.1 RED: pin/severity/status logic unit tests
Write tests before implementation:
1. **Pinned unresolved failure**
- failed `backfill` with no later success => pinned
2. **Unpin after retry success**
- failed `backfill` then later successful `backfill` => old failure not pinned
3. **Pinned is per-kind**
- `cleanup` success does not clear `backfill` failure pin
4. **Rate limit classification**
- `error` containing `429` or `rate limited` => `severity=rate_limit`
5. **Partial success classification**
- `rows_written>0 && error!=null` => `status=partial`
6. **In-progress classification**
- `finished_at==null` recent => `status=in_progress`
- stale threshold exceeded => `severity=warning/error` (per chosen policy)
7. **Newest-first ordering**
- runs sorted by `started_at DESC`
### 4.2 GREEN: minimal implementation
Implement pure helper functions first:
- `deriveSeverity(error, finishedAt, startedAt, now)`
- `deriveStatus(error, finishedAt, rowsWritten, rowsRemoved)`
- `computePinned(runs)`
- `toSummary(run)`
Keep these deterministic and injectable with `clock` for testability.
### 4.3 RED: handler integration tests
`market_history_admin_handler_test.dart`:
1. **403 for non-admin token**
2. **200 + shape for admin**
3. **`runs` newest-first**
4. **`pinned` contains unresolved rate-limit row**
5. **`pinned` clears when later success seeded**
6. **`limit` respected**
7. **pagination via `before`**
8. **`kind` filter**
9. **response excludes raw fields** (no `raw`, no snapshot payload)
### 4.4 GREEN: handler + routing
Implement route:
- `GET /v1/admin/market-history/sync-runs`
Wire auth middleware with admin allowlist/claim gate.
### 4.5 REFACTOR
- Move query + transform logic out of handler into service/query class.
- Ensure all SQL is parameterized.
- Add response DTO class to reduce map-shape drift.
---
## 5. Flutter TDD plan
Planned files:
- `lib/admin/models/sync_run_event.dart`
- `lib/admin/services/market_history_admin_api.dart`
- `lib/admin/repositories/sync_run_log_repository.dart`
- `lib/admin/screens/market_history_log_screen.dart`
- `lib/admin/widgets/sync_run_expansion_tile.dart`
Tests:
- `test/admin/models/sync_run_event_test.dart`
- `test/admin/repositories/sync_run_log_repository_test.dart`
- `test/admin/services/market_history_admin_api_test.dart`
- `test/admin/widgets/sync_run_expansion_tile_test.dart`
- `test/admin/screens/market_history_log_screen_test.dart`
### 5.1 RED: model + repository unit tests
1. Parse API response into domain model
2. Severity/status mapping from API and fallback parsing
3. Merge pinned + history sections
4. Keep pinned visible above chronological list
5. Append paged results without reordering newer rows
6. Deduplicate by `id` during refresh
7. Error state handling (`401/403/500/network`)
### 5.2 GREEN: implement model/repository
- Implement immutable model objects
- Implement repository APIs:
- `loadInitial()`
- `refresh()`
- `loadMore()`
- Include simple in-memory cache for current session
### 5.3 RED: service HTTP tests
Using mocked HTTP client:
1. sends bearer token header
2. sends `limit`, `before`, `kind` query params
3. handles non-200 responses
4. parse malformed payload guardrails
### 5.4 GREEN: service implementation
Mirror existing app API style (`apiBaseUrl`, auth token retrieval, robust parse).
### 5.5 RED: widget/screen tests
1. **Pinned section shown** when pinned rows exist
2. **Pinned section hidden** when none exist
3. **Newest row at top** in history list
4. **Expansion tile details**
- shows full message text
- does not show raw data fields
5. **Severity styling** (icon/chip text present)
6. **Pull-to-refresh triggers repository refresh**
7. **Scroll-to-end triggers `loadMore()`**
8. **Loading, empty, and error states render correctly**
### 5.6 GREEN: implement UI
- Build screen with two sections:
- `Needs attention` (pinned)
- `History` (paged, newest-first)
- Use `ExpansionTile` rows with concise collapsed summary.
### 5.7 REFACTOR
- Extract common chips/icons/date formatters
- Keep widget tree shallow for testability
- Avoid business logic in widget build methods
---
## 6. API-trigger actions (optional phase C) TDD
If adding on-demand actions:
Server tests:
- `POST /v1/admin/market-data/resync` returns `202` and creates run rows
- `POST /v1/admin/market-data/cleanup` with `archive` flag routes correctly
- auth + invalid input tests
Flutter tests:
- retry button visible for pinned failures
- confirm dialog for cleanup
- action triggers refresh and shows new in-progress/success rows
This phase can be deferred without affecting MVP log validation.
---
## 7. Quality gates and CI commands
### Server
```bash
cd server && dart test test/trading/market_history_admin_logic_test.dart
cd server && dart test test/integration/market_history_admin_handler_test.dart
```
### Flutter
```bash
flutter test test/admin/models/
flutter test test/admin/repositories/
flutter test test/admin/services/
flutter test test/admin/widgets/
flutter test test/admin/screens/
```
### Coverage checks (recommended)
Server:
```bash
cd server && dart test --coverage=coverage
```
Flutter:
```bash
flutter test --coverage
```
Add CI thresholds for the targets in Section 2.
---
## 8. Risk-driven test checklist
High-priority cases to lock down early:
- [x] Pin logic regression when multiple kinds interleave
- [x] Rate-limit text variants (`429`, `rate limit`, capitalization differences)
- [x] Very long error message expansion rendering
- [x] Pagination duplicates/holes on refresh + load-more race
- [x] Timezone display mismatch (`started_at` UTC vs local display)
- [x] Empty payload safety (no crashes)
---
## 9. Definition of done
The admin portal feature is considered validated when:
1. All MVP tests listed above pass.
2. Coverage targets in Section 2 are met.
3. Automated acceptance tests (`test/admin/acceptance/`) cover:
- newest-first order,
- pinned unresolved issues,
- expandable full error detail,
- no raw payload details in UI,
- cleanup archive toggle when enabled.
4. CI includes these test suites and fails on regression.
Manual sanity pass (live server + seeded rows) remains recommended before production rollout.
---
## 10. Suggested implementation order
1. Server pure logic tests + implementation ✅
2. Server handler integration tests + endpoint ✅
3. Flutter models/repository/service tests + implementation ✅
4. Flutter widget/screen tests + UI implementation ✅
5. Optional trigger actions phase ✅
6. Risk checklist (§8) + acceptance tests (§9) ✅
This order keeps risky logic proven first and gives UI teams a stable API contract early.