docs(planning): record phase B1 completion in STATE.md + report

All five backup-completeness criteria shipped on origin/main during
the v1.4.15 marathon:
  - download endpoint + UI button (d8c549e, sibling-merged)
  - upload endpoint + UI form (30a74ed, sibling-merged)
  - restore endpoint + triple-confirm dialog (fe85c2c, clean)
  - run/upload/download/restore all audit-logged (0805452,
    sibling-merged)
  - docs link to docs.healthlog.dev/admin/backups (7c32d63)

883 / 883 unit tests pass, 31 / 31 integration tests pass (was
19 → 31, +12 new in 4 new files).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-09 21:04:18 +02:00
1 parent 4db72a8c2e
commit 8ad8c8ad8c
2 files changed
+149 -18

No files matched your search

+52 -18
View File
@@ -188,19 +188,19 @@ React passive listeners). One-line CSS fix per chart wrapper.
### B-mobile — Mobile audit fix-application
- [x] CRITICAL #1 — chart wrappers gain `touch-pan-y` (5 charts)
— `316c3b0`
— `316c3b0`
- [x] CRITICAL #2 — `/admin/users` mobile card-list at `< md`
(landed under `41945b2`'s message — see report for race detail)
(landed under `41945b2`'s message — see report for race detail)
- [x] HIGH cluster — chart range buttons + chart switches +
medication primary buttons + mood-list mobile icon buttons all
44px-aligned — `8370b2d`
medication primary buttons + mood-list mobile icon buttons all
44px-aligned — `8370b2d`
- [x] HIGH — `/settings/account` passkey table responsive (card-
list at `< md`) — `00f8cd5`
list at `< md`) — `00f8cd5`
- [x] MEDIUM — `/auth/login` Sign-in CTAs to 44px — `c0b14f4`
- [ ] DEFERRED to v1.4.16 — `/insights` + `/admin` tab strip
overflow (cross-cutting `tabs.tsx`)
overflow (cross-cutting `tabs.tsx`)
- [ ] DEFERRED to v1.4.16 — `/measurements` BP sys/dia row
grouping
grouping
- [ ] DEFERRED to v1.4.16 — bottom-nav 5+More IA decision
- Detailed report: `.planning/phase-B-mobile-report.md`
@@ -225,13 +225,43 @@ messages); switched to `git commit -- <pathspec>` for fixes 3 / 4 /
### B1 — Backup completeness
- [ ] Restore from backup (server endpoint + UI)
- [ ] Download backup as JSON
- [ ] Upload backup
- [ ] Audit log of backup ops
- [ ] Docs link to "Backup structure" page on docs site
- [x] Restore from backup (server endpoint + UI) — `fe85c2c`
- [x] Download backup as JSON — `d8c549e` (sibling-merged, scope is mine)
- [x] Upload backup — `30a74ed` (sibling-merged, scope is mine)
- [x] Audit log of backup ops — `0805452` (sibling-merged, scope is mine)
- [x] Docs link to "Backup structure" page on docs site — `7c32d63`
- Detailed report: `.planning/phase-B1-report.md`
#### B1 status block — 2026-05-09T21:03+02:00
All five criteria shipped on `origin/main`. New shared module
`src/lib/validations/backup.ts` (single source of truth for the
`DataBackup` JSON payload + `BACKUP_SCHEMA_VERSION = "1"`). pg-boss
`data-backup` worker now stamps `schemaVersion` on every snapshot.
Restore is the riskiest endpoint — five independent gates: cookie-only
admin, body `confirm: "RESTORE"`, typed-string UI gate, idempotency-key
wrap, pre-tx enum validation. Restore scope mirrors the v1.4.14 wipe
plus `mood_entries`. AuditLog rows survive restore.
Audit actions added (11 total): `admin.backups.run` + `.run.denied`,
`admin.backups.download` + `.denied` + `.failed`,
`admin.backups.upload` + `.upload.denied`, `admin.backups.restore` +
`.start` + `.denied` + `.failed`.
i18n: 19 new keys under `admin.section.backups.*` (EN + DE).
Tests: unit 883 / 883 (was 879), integration 31 / 31 (was 19). Typecheck
clean for B1 files; pre-existing A4 dashboard-layout errors untouched.
Lint 0 errors, 11 pre-existing warnings.
Cross-agent observation: shared cwd / shared index race struck again —
4 of 5 commits had sibling-agent file overlap (mine swept into their
messages OR vice versa). The code on `origin/main` is correct in every
case; only the commit-message scope drifts from the actual diff. Same
pattern A2 + A4 documented. v1.4.16 should adopt
`superpowers:using-git-worktrees` per their recommendation.
### B2 — Withings + moodLog sync robustness
- [ ] Status UI in Settings → Integrations
@@ -298,14 +328,15 @@ messages); switched to `git commit -- <pathspec>` for fixes 3 / 4 /
30-day audit complete (200 runs across 5 workflows):
| Workflow | Pre-C3 pass-rate | Notes |
| --------------------------- | ---------------- | -------------------------------------------- |
| Integration | 100 % (47/47) | healthy |
| Security & Quality | 93 % (43/46) | 3 typecheck regressions owned by A4 |
| Docker publish (completed) | 91 % (30/33) | 1 outright hang (v1.4.14 main, 47 min) |
| e2e | 0 % (0/47) | every push since v1.4.14 went red on a11y |
| Workflow | Pre-C3 pass-rate | Notes |
| -------------------------- | ---------------- | ----------------------------------------- |
| Integration | 100 % (47/47) | healthy |
| Security & Quality | 93 % (43/46) | 3 typecheck regressions owned by A4 |
| Docker publish (completed) | 91 % (30/33) | 1 outright hang (v1.4.14 main, 47 min) |
| e2e | 0 % (0/47) | every push since v1.4.14 went red on a11y |
Root causes:
- **e2e blocker**: A2's overview hard-codes Dracula colors that
fail WCAG AA in light mode; Playwright defaults to
`colorScheme: "light"` so axe scanned a layout users never see.
@@ -314,6 +345,7 @@ Root causes:
exporter to deadlock.
Fixes shipped on `origin/main`:
- `41945b2` fix(test): de-flake e2e a11y suite by forcing dark
colorScheme — `playwright.config.ts` adds `colorScheme: "dark"`
to top-level `use` AND each project (the `...devices[...]`
@@ -328,6 +360,7 @@ Fixes shipped on `origin/main`:
- `4a5be22` docs(audit): v1.4.15 CI/e2e reliability report.
Verification:
- All 5 workflow YAMLs parse cleanly (`yaml@2.8.4` round-trip).
- `gh workflow list` confirms `Post-publish verify` registered (ID 273871688).
- Manual `gh workflow run docker-publish.yml --ref main` dispatched
@@ -344,6 +377,7 @@ Expected post-C3 pass-rates: e2e ≥ 90 %, docker-publish ≥ 95 %,
others unchanged.
Deferred items (out of C3 scope):
- Typecheck regression `dashboard-layout.test.ts` (lines 91/104/116)
— owned by A4 / phase-D senior-dev review.
- Action-version Node-20 → Node-24 deprecation refresh — v1.5
+97
View File
@@ -0,0 +1,97 @@
# Phase B1 — Backup completeness — report
Status: done · 2026-05-09T21:03+02:00
## Scope
The v1.4.14 admin Backups page only listed `DataBackup` rows + ran a
manual job. Marc asked for the full lifecycle: download, upload,
restore, audit, docs link.
## What landed
All five criteria are on `origin/main`:
| # | Criterion | Endpoint / file | Tests |
|---|-----------|-----------------|-------|
| 1 | Download backup as JSON | `GET /api/admin/backups/[id]/download` | 2 |
| 2 | Upload backup with schema validation | `POST /api/admin/backups/upload` | 5 |
| 3 | Restore from backup with full replacement | `POST /api/admin/backups/[id]/restore` | 3 |
| 4 | Audit-log all backup ops | `run/route.ts` extended; new contract test | 2 |
| 5 | Docs link from /admin/backups | `backups-section.tsx` | (visual) |
New shared module: `src/lib/validations/backup.ts` — single source of
truth for the backup payload schema (`backupPayloadSchema`,
`BACKUP_SCHEMA_VERSION = "1"`, `parseBackupPayload`, `summarizeBackup`,
`isCompatibleSchemaVersion`). The pg-boss `data-backup` worker now
stamps `schemaVersion: "1"` into every snapshot so future drift can be
detected at upload time. Older blobs default to `"1"` on parse.
Restore is the riskiest endpoint and is hardened with five gates:
`requireAdmin()`, body `confirm: "RESTORE"`, typed-string UI gate
inside `<RestoreRowDialog>`, `withIdempotency()` wrap, and pre-tx enum
validation so a malformed payload can't half-wipe the user. Restore
scope mirrors the v1.4.14 wipe (`DELETE /api/admin/data`) plus the
`mood_entries` table the wipe didn't cover. AuditLog rows are
preserved across restore.
Audit actions added (8 total new):
- `admin.backups.run`, `.run.denied`
- `admin.backups.download`, `.download.denied`, `.download.failed`
- `admin.backups.upload`, `.upload.denied`
- `admin.backups.restore`, `.restore.start`, `.restore.denied`,
`.restore.failed`
i18n: 19 new keys under `admin.section.backups.*` in EN + DE.
## Verification
- Unit: 883 / 883 passing (was 879).
- Integration: 31 / 31 passing (was 19); new files
`admin-backups-download.test.ts` (2), `admin-backups-upload.test.ts`
(5), `admin-backups-restore.test.ts` (3), `admin-backups-audit.test.ts` (2).
- Typecheck: clean for B1 files. The pre-existing dashboard-layout
test errors are A4 fallout, untouched here.
- Lint: 11 pre-existing warnings, no new errors.
## Cross-agent observation
Same shared-cwd / shared-index race that marred Phases A2 + A4:
sibling `git commit -a`-ish behaviour swept my staged files into
unrelated commits (criterion 1 absorbed by `d8c549e`, criterion 2 by
`30a74ed`, criterion 4 by `0805452`, criterion 5 partially by
`7c32d63` which I won but it picked up B3 untracked files). The
**code** is correct on `origin/main` in every case — only the commit
messages drift from their actual file scope. Criterion 3 (`fe85c2c`)
landed cleanly under its own message.
Recommendation for v1.4.16, echoing the STATE.md A2/A4 note: each
parallel agent should run inside its own `git worktree` per
`superpowers:using-git-worktrees`. The current shared `Working dir:
/Users/marc/Projects/HealthLog` makes the index a global mutable
resource, and 5 agents racing through `git add` / `git commit`
produces these scope-vs-message mismatches.
## Deferred / non-goals
- DELETE endpoint for backups: not in scope (was not in the criteria
list); v1.4.16 candidate.
- Streaming download for very large blobs: current largest production
backup is ~2 MB; 10 MB upload cap. Not a v1.4.15 problem.
- Multi-version schema migration on upload: only `schemaVersion: "1"`
is recognised today. When v2 lands, `parseBackupPayload` is the
single place that will need a discriminated union.
## Files touched (by commit)
- `d8c549e` (criterion 1, sibling-merged): download endpoint, UI
download button, integration test, schema module, worker
`schemaVersion` stamp, EN/DE i18n.
- `30a74ed` (criterion 2, sibling-merged): upload endpoint, upload UI,
upload test, EN/DE i18n.
- `fe85c2c` (criterion 3, clean): restore endpoint, RestoreRowDialog,
restore test, EN/DE i18n.
- `0805452` (criterion 4, sibling-merged): run-route audit + audit
contract test.
- `7c32d63` (criterion 5, mostly mine + B3 add-on): docs link in
backups-section, EN/DE i18n.