Files
familysync/.planning/milestones/v1.1-phases/12-initial-setup-wizard/12-05-SUMMARY.md
T
2026-06-18 22:21:38 -04:00

6.2 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, decisions, metrics
phase plan subsystem tags requires provides affects tech-stack key-files decisions metrics
12-initial-setup-wizard 05 setup-wizard-frontend
setup
pwa
uat-gap-closure
a11y
GET /api/setup/status { setupComplete, dbName } (Plan 06)
SetupStatusResponse.dbName?: string | null typed field (Plan 06)
Instance step intro copy trimmed (no DB-vs-env-file aside)
Read-only, disabled DB-name field under App URL, populated from status dbName
Instance field values lifted to SetupPage so Back navigation preserves them
apps/pwa setup wizard Instance step (SetupPage.tsx)
added patterns
useQuery({ queryKey: ['setupStatus'], queryFn: fetchSetupStatus }) reads non-secret dbName into a read-only field
Step-level field values lifted to the parent (SetupPage) so step unmount no longer drops entries
Sensitive app password deliberately NOT lifted — stays in Step3 local state, cleared on unmount (T-12-15)
created modified
apps/pwa/src/routes/SetupPage.tsx
apps/pwa/src/routes/SetupPage.test.tsx
D-12-05-LIFT: only the four non-secret Instance fields are lifted to SetupPage; the Fastmail app password is never lifted or persisted (T-12-15 preserved).
D-12-05-DBNAME: DB-name field renders the dbName value only; DB_HOST/DB_PORT/DB_USER/DB_PASSWORD appear solely as static env-var names in helper text, never as values (T-12-3DB).
D-12-05-VALSTATE: Step2 validation state (db/oidc/vapid pass flags) is intentionally NOT lifted — only field values persist across Back; operator re-runs Save & Validate after returning.
duration_minutes completed
9 2026-06-16

Phase 12 Plan 05: Instance-Step Gap Closure (copy trim, DB-name field, Back persistence) Summary

Closed UAT gaps 1, 3 (frontend half), and 4 on the PWA Instance step (SetupPage.tsx): dropped the confusing DB-vs-env-file implementation aside, added a read-only env-derived DB-name field so the "database connection verified" row has an on-screen referent, and lifted the four Instance field values into SetupPage so navigating Back from the Calendar step no longer wipes entered config.

What Was Built

Task 1 — Drop DB-vs-env aside + add read-only DB-name field (gaps 1, 3-frontend)

Commit 35db5c5.

  • Gap 1: Removed the sentence "These are written to the database — not your environment file." from the Instance step intro <p>, keeping the first sentence ("Enter your instance's connection details.").
  • Gap 3 (frontend): Added a labelled, readOnly + disabled input ("Database") directly under the App URL field, populated from fetchSetupStatus().dbName via useQuery({ queryKey: ['setupStatus'], staleTime: 0, retry: false }). The field is greyed out (--color-surface-dim background, --color-text-secondary text), carries aria-readonly="true" and tabIndex={-1}, and shows while loading/null. Helper text explains the DB is configured via the server's Docker environment (DB_HOST/DB_PORT/DB_USER/DB_PASSWORD as static names) and is not entered here. The existing "Database connection verified." ValidationRow is unchanged.
  • Tests assert the dropped sentence is absent, the DB field renders readOnly/disabled/aria-readonly with the mocked dbName: 'familysync', and the existing DB validation row still appears on Save & Validate.

Task 2 — Preserve Instance fields across Back navigation (gap 4)

Commit a13fc11.

  • Introduced an InstanceFields shape (appUrl, oidcIssuer, oidcClientId, vapidPublicKey) owned by SetupPage (instanceFields / setInstanceFields), passed to Step2Config as fields / setFields props. Step2Config now reads/writes these through the lifted setters instead of its own local useState. Validation/mutation logic is unchanged.
  • The Fastmail app password (Step 3) is not lifted — it remains in Step3Credential local state and is cleared on unmount when navigating away (T-12-15 preserved).
  • Tests: filling the Instance step, validating to GREEN, advancing to the Calendar step, then clicking Back restores all four Instance values; a second test confirms a typed app password is empty after Back→forward (Step 3 re-mounts fresh).

Verification

  • cd apps/pwa && pnpm test -- SetupPage263 passed (22 files).
  • cd apps/pwa && pnpm typecheck → clean (tsc + e2e tsconfig).
  • grep -c "not your environment file" apps/pwa/src/routes/SetupPage.tsx0.
  • grep -c "dangerouslySetInnerHTML" apps/pwa/src/routes/SetupPage.tsx0.
  • grep -nE "sessionStorage|localStorage" apps/pwa/src/routes/SetupPage.tsxno matches (no client-side persistence of any field, secret or otherwise).
  • grep -c "readOnly" apps/pwa/src/routes/SetupPage.tsx1 (the DB-name field).
  • DB_HOST/DB_PORT/DB_USER/DB_PASSWORD appear only as static env-var names in helper/error copy — never fetched or rendered as values.

Deviations from Plan

None — plan executed exactly as written. Implementation note: the two tasks both restructure the Step2Config signature/body and the same intro paragraph, so they were authored together and then committed as two atomic, individually-GREEN commits (Task 1 commit verified GREEN with 261 tests before Task 2's state-lifting and Back-navigation tests were added).

Threat Surface

Threat ID Disposition Outcome
T-12-15 (app password disclosure) mitigate Preserved — password stays in Step3 local state, type="password", NOT lifted, NOT persisted to storage; cleared on unmount. Test asserts it is empty after Back→forward.
T-12-14 (XSS in Instance/DB copy) mitigate All new copy + dbName rendered as plain-text JSX children; dangerouslySetInnerHTML grep = 0.
T-12-3DB (DB secret/topology disclosure) mitigate Only dbName value is fetched and rendered; DB_HOST/DB_PORT/DB_USER/DB_PASSWORD appear solely as static env-var names in helper text.

No new security-relevant surface introduced beyond the planned threat_model.

Known Stubs

None.

Self-Check: PASSED

  • apps/pwa/src/routes/SetupPage.tsx — modified, exists.
  • apps/pwa/src/routes/SetupPage.test.tsx — modified, exists.
  • Commit 35db5c5 (Task 1) — FOUND in git log.
  • Commit a13fc11 (Task 2) — FOUND in git log.