Restored onto phase-12 branch — discuss-phase originally committed the context (dc41073) on the phase-18 branch by mistake. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.8 KiB
Phase 12: Initial Setup Wizard - Discussion Log
Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
Date: 2026-06-15 Phase: 12-initial-setup-wizard Areas discussed: Wizard nature, Restart & resume, Credential + admin, Guard
Wizard nature
Q1 — Does the wizard write config, or validate-only?
| Option | Description | Selected |
|---|---|---|
| Validate-only (UI-SPEC) | Wizard never writes config; checks env, generates secrets to paste, validates, flips setup_complete | |
| Collect-and-write some | Wizard accepts some config via fields and persists it; contradicts the no-input UI-SPEC | ✓ |
User's choice: Collect-and-write some — "I'm okay to migrate away from a .env file entirely if that helps. The wizard could supersede it and config values live in the DB."
Q2 — Which config to collect-and-write?
| Option | Description | Selected |
|---|---|---|
| App / external URL | Non-secret runtime URL → app_config | (folded into D-02) |
| OIDC client_id + issuer | Non-secret OIDC identifiers (caveat: boot-time read) | (folded into D-02) |
| VAPID public key | Non-secret half of keypair → app_config | (folded into D-02) |
| Nothing — reconsider | Keep validate-only after all |
User's choice (free text): "I want the env variables to come through from docker or fall back to that .env file" + (Q3) "minimal kernel + db config."
Q3 — How far to push config-into-DB?
| Option | Description | Selected |
|---|---|---|
| Minimal kernel + DB config | Env keeps bootstrap kernel only; wizard writes non-secret config to app_config | ✓ |
| Wizard validates env, writes only credential | Smallest, matches UI-SPEC | |
| Full DB-config migration | Move everything + refactor all consumers; scope risk |
User's choice: Minimal kernel + DB config; env from Docker, .env fallback.
Notes: Hard floor surfaced and accepted: DB connection + ENCRYPTION_KEY + VAPID_PRIVATE_KEY + SESSION_SECRET + OIDC client_secret cannot leave env (chicken-and-egg / key-beside-ciphertext / SC-3).
Restart & resume
Q1 — How to handle re-entry after the post-secrets restart?
| Option | Description | Selected |
|---|---|---|
| Live re-detection, world is the state | No cursor; each step re-checks live env/DB; skip satisfied steps | |
| Persisted step cursor in app_config | Store setup_step; can drift from reality | |
| Always restart from Step 1 | Simplest but breaks the un-re-showable secrets step |
User's choice (free text / reframe): "No, I'm envisioning an Unraid template or clear instructions to bootstrap the image and all of those variables should be defined before first boot." Notes: This designs OUT the mid-wizard restart entirely — kernel is complete at first boot; the generate-secrets step leaves the wizard.
Q2 — Where do the secret values come from before first boot?
| Option | Description | Selected |
|---|---|---|
| Documented commands in template/README | openssl + npx web-push generate-vapid-keys | |
| Helper script in the repo | npm run generate-secrets prints all four, VAPID via web-push lib | ✓ |
| Pre-boot generator endpoint/mode | App boots unconfigured to generate; reintroduces complexity |
User's choice: Helper script in the repo.
Credential + admin
Q1 — How is the first Fastmail credential handled with no user row?
| Option | Description | Selected |
|---|---|---|
| Validate in wizard, store post-login via self-service | CalDAV-validate only; store later via SetupBanner; double-entry | |
| Store against a pending/first user row | Wizard reserves a user row + credential, reconcile at login | ✓ (refined) |
| No credential in wizard at all | Drops the CalDAV step; fails SC-2 |
User's choice (free text): "When we switch from Fastmail to generic provider, the first user who gets provisioned will need to enter this. … we need a local user who will get merged into an OIDC user once that's set up." Notes: Refined into the local-user → claim-at-first-login model (D-07/D-08); provider-agnostic framing.
Q2 — How is the first OIDC login matched to the pending local user?
| Option | Description | Selected |
|---|---|---|
| First-login-claims | First OIDC login after setup_complete adopts the local user | ✓ |
| Match by email claim | Couples identity to email (fights D-10) | |
| Explicit claim code | One-time code; strongest but extra friction |
User's choice: First-login-claims. Notes: User added a deferred capability — a fully local (no-OIDC) operating mode, wiring OIDC in later — to be captured as its own future phase.
Guard
Q1 — What does the 423 guard trust per invocation?
| Option | Description | Selected |
|---|---|---|
| Flag OR live-config (defense in depth) | Lock if setup_complete OR (creds row + VAPID env), re-evaluated every call | ✓ |
| Flag only, read fresh each call | Single setup_complete flag, re-read per call | |
| Live-computed only (no flag) | No persisted flag; risks premature mid-flow lock |
User's choice: Flag OR live-config (defense in depth).
Claude's Discretion
- Exact reworked step list and per-step field grouping (consistent with the revised UI-SPEC).
- Exact
/api/setup/*route paths and newapp_configkey names. - Migration packaging for the nullable-OIDC-identity + claimed-marker schema change.
- Whether
app_configruntime reads are per-process cached or per-request.
Deferred Ideas
- Local-auth / no-OIDC operating mode — run entirely on local DB users, wire OIDC in later; its own future phase, built atop Phase 12's local-user foundation (D-07).