77 lines
4.4 KiB
Markdown
77 lines
4.4 KiB
Markdown
# Phase 18 — Plan Index & Coverage Audit
|
|
|
|
**Created:** 2026-06-15
|
|
**Plans:** 4 (3 waves)
|
|
**Mode:** standard · TDD mode ON · MVP off
|
|
|
|
---
|
|
|
|
## Wave Structure
|
|
|
|
| Wave | Plans | Autonomous | Files (disjoint per wave) |
|
|
|------|-------|------------|----------------------------|
|
|
| 1 | 18-01 (accessor + IANA validator, TDD) | yes | `lib/householdTimezone.ts` (+test) |
|
|
| 2 | 18-02 (admin endpoints, TDD), 18-03 (broker wiring, TDD) | yes, yes | 02: `routes/admin.ts` (+test); 03: `broker/reminderScheduler.ts` + `broker/outboxWorker.ts` (+tests) — no overlap with 02 |
|
|
| 3 | 18-04 (PWA picker UI) | no (human-verify checkpoint) | `pwa/api/client.ts`, `pwa/routes/AdminPage.tsx` |
|
|
|
|
Dependency rationale: 02 and 03 both depend only on the Wave-1 accessor and touch disjoint files →
|
|
parallel in Wave 2. 04 depends on the 02 endpoint contract → Wave 3.
|
|
|
|
---
|
|
|
|
## Artifacts This Phase Produces (MANDATORY)
|
|
|
|
| Symbol / Artifact | Kind | File | Plan |
|
|
|-------------------|------|------|------|
|
|
| `getHouseholdTimezone(db)` | function (async, → Promise<string>) | `apps/api/src/lib/householdTimezone.ts` | 01 |
|
|
| `isValidIanaTimezone(tz)` | function (→ boolean) | `apps/api/src/lib/householdTimezone.ts` | 01 |
|
|
| `'household_timezone'` | app_config key string (new additive row, no migration) | `apps/api/src/db/schema.ts` appConfig (existing table) | 01/02 |
|
|
| `GET /api/admin/config/timezone` | route | `apps/api/src/routes/admin.ts` | 02 |
|
|
| `PUT /api/admin/config/timezone` | route | `apps/api/src/routes/admin.ts` | 02 |
|
|
| `POST /api/admin/config/timezone/seed` | route (no-overwrite seed, D-02/D-03) | `apps/api/src/routes/admin.ts` | 02 |
|
|
| `timezoneSchema` | Zod schema | `apps/api/src/routes/admin.ts` | 02 |
|
|
| `fetchAdminTimezone()` | client fn | `apps/pwa/src/api/client.ts` | 04 |
|
|
| `setAdminTimezone(timezone)` | client fn | `apps/pwa/src/api/client.ts` | 04 |
|
|
| `AdminTimezoneResponse` | interface | `apps/pwa/src/api/client.ts` | 04 |
|
|
| Timezone section (`aria-label="Timezone"`) | UI component/section | `apps/pwa/src/routes/AdminPage.tsx` | 04 |
|
|
| `apps/api/tests/lib/householdTimezone.test.ts` | new test file | — | 01 |
|
|
|
|
Test files extended (not new): `apps/api/tests/routes/admin.test.ts` (02),
|
|
`apps/api/tests/broker/reminderScheduler.test.ts` + `apps/api/tests/broker/outboxWorker.test.ts` (03).
|
|
|
|
---
|
|
|
|
## Multi-Source Coverage Audit
|
|
|
|
### GOAL (ROADMAP Phase 18 goal)
|
|
"Auto-detect the household timezone and allow changing it" → COVERED: detection seed (D-02, Plans 02 seed
|
|
endpoint + 04 detected-zone affordance); change (D-04, Plans 02 PUT + 04 picker); behavioral wiring
|
|
(D-05, Plan 03).
|
|
|
|
### REQ (phase_req_ids from REQUIREMENTS.md)
|
|
No REQ-IDs are mapped to Phase 18 in ROADMAP.md (confirmed: "Requirements: TBD"). Per the planning
|
|
context, the D-01..D-07 decision set is the coverage contract — see CONTEXT below. Not a gap.
|
|
|
|
### RESEARCH (18-RESEARCH.md features/constraints)
|
|
- Single accessor `getHouseholdTimezone` + IANA validator → Plan 01.
|
|
- GET/PUT endpoints on adminRouter, no new router → Plan 02.
|
|
- Seed endpoint, additive/non-blocking (Phase 12 not yet executed) → Plan 02.
|
|
- Rewire reminderScheduler:247 + outboxWorker:501,607 → Plan 03.
|
|
- PWA picker, no new package, Intl-based → Plan 04.
|
|
- No new npm installs (Package Legitimacy Audit: zero) → honored across all plans; T-18-SC = no-op.
|
|
|
|
### CONTEXT (D-01..D-07 — the trackable decision contract)
|
|
|
|
| Decision | Covered by | Where |
|
|
|----------|-----------|-------|
|
|
| D-01 single household app_config key `household_timezone` | Plan 01 (key literal), Plan 02 (upsert) | accessor + endpoints |
|
|
| D-02 browser-detect + seed at first run | Plan 02 (seed endpoint), Plan 04 (detected-zone affordance) | endpoints + UI |
|
|
| D-03 no auto-overwrite after seed | Plan 02 (seed writes only if unset) | seed endpoint |
|
|
| D-04 change via role-gated /admin Settings | Plan 02 (requireAdmin endpoints), Plan 04 (Timezone section) | endpoints + UI |
|
|
| D-05 stored TZ = source of truth, single accessor at both scheduler sites | Plan 01 (accessor), Plan 03 (both sites route through it) | accessor + broker |
|
|
| D-06 fallback chain when unset | Plan 01 (verbatim fallback), Plan 03 (existing tests stay green) | accessor + broker |
|
|
| D-07 do not touch display/timed-write path | Plan 03 + Plan 04 (boundary as acceptance criterion) | broker + UI |
|
|
|
|
**No unplanned items.** Deferred Ideas (per-member timezones; driving display/timed off stored TZ) are
|
|
correctly absent from all plans.
|