Add wizard-flow spec with locked tech picks
8-screen first-boot installer spec extending Robert's 4-screen wireframe with the YunoHost-style post-install pattern (domain, SSL, diagnostic, confirm). Covers: - Entry point via https://proksi.local with local CA cert install - Screens S1-S8, each mapped to archinstall config fields or side effects (SSL cert issuance, DNS delegation, diagnostic gates) - Data model mapping wizard fields to user_configuration.json + user_credentials.json - Locked tech picks with rejected alternatives: Caddy (reverse proxy), Authentik (SSO), NS delegation (managed gateway DNS), local CA (HTTPS on proksi.local) - Open questions for Robert: Backend on/off meaning, local CA vs Tailscale ACME, UI framework choice, language list, S2 auto-setup branch behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1f0abc464a
commit
f06d32989d
1 changed files with 190 additions and 0 deletions
190
docs/wizard-flow.md
Normal file
190
docs/wizard-flow.md
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# Installer Wizard Flow
|
||||
|
||||
End-to-end spec for the Homebase first-boot installer. Extends Robert's wireframes in [installer-wireframes.md](./installer-wireframes.md) with the post-install pattern proven by YunoHost (see [competitors.md](./competitors.md#yunohost)). Concrete tech picks are locked in at the bottom so Robert has unambiguous targets for the next coding session.
|
||||
|
||||
**Status:** Draft spec 2026-04-13. Not implemented yet. Open questions for Robert at the end.
|
||||
|
||||
---
|
||||
|
||||
## Goals
|
||||
|
||||
1. **Your dad can install this.** Boot USB, answer plain-language questions, get a working server. No terminal required on the happy path.
|
||||
2. **HTTPS from boot #1.** No plaintext admin UI at any stage — unlike Umbrel ([#546](https://github.com/getumbrel/umbrel/issues/546)) and CasaOS. Even the pre-install wizard uses HTTPS via a local CA.
|
||||
3. **No post-install CLI required.** By screen S8 (confirm), the user has a reachable domain, valid TLS, admin credentials, and the base OS installing. Everything else is reachable from the web UI.
|
||||
|
||||
---
|
||||
|
||||
## Entry point
|
||||
|
||||
1. User flashes ISO to USB (Etcher / `dd` / Rufus).
|
||||
2. Boots target machine from USB into a **headless live environment**.
|
||||
3. Live image auto-starts:
|
||||
- `webinstaller` Flask app on port 443 with TLS
|
||||
- mDNS advertising `proksi.local`
|
||||
- Local CA cert generated on first boot, served at `http://proksi.local/ca.crt` (plaintext port 80 serves **only** the CA cert download and a redirect to HTTPS — nothing else)
|
||||
4. User opens `https://proksi.local` on any device on the same LAN.
|
||||
5. **First screen before S1:** browser warning page with a one-click "Download Homebase CA" button and OS-specific install instructions (macOS Keychain, Windows cert store, iOS profile, Android). After install, user clicks "Continue" and proceeds to S1 with no further warnings.
|
||||
|
||||
> **Why not self-signed (YunoHost model)?** Users learn to click through warnings, which kills trust. A single one-time CA install gives clean green padlocks for every Homebase service after.
|
||||
|
||||
---
|
||||
|
||||
## Wizard screens
|
||||
|
||||
Each screen is one Flask route under `/install/<step>`. The Flask `settings` dict in `webinstaller/app.py` accumulates answers and is flushed to `user_configuration.json` + `credentials.json` at S8.
|
||||
|
||||
### S1 — Welcome / Account
|
||||
|
||||
From Robert's wireframe Screen 1, trimmed.
|
||||
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| Hostname | text | Default `furtka`. Becomes `hostname` in archinstall config. |
|
||||
| Admin username | text | Becomes first entry in `users[].username`. |
|
||||
| Password | password | |
|
||||
| Password (confirm) | password | Must match. |
|
||||
| Language | select | Sets `archinstall-language` + `locale_config.locale`. |
|
||||
|
||||
**Dropped from wireframe:** "Backend on/off" and "Backend address" — meaning is unclear, see open questions.
|
||||
|
||||
### S2 — Drive Selection
|
||||
|
||||
From Robert's wireframe Screen 2.
|
||||
|
||||
- Lists drives via `webinstaller/drives.py::list_scored_devices()` (already implemented — do not duplicate).
|
||||
- Each row shows: device path, size, score, SMART status.
|
||||
- Radio selection for boot drive, with highest-score drive pre-selected.
|
||||
- **"Auto setup" button** — accepts the recommendation, jumps past S3.
|
||||
- Remaining drives carried into S3.
|
||||
|
||||
| Field | Type | Maps to |
|
||||
|-------|------|---------|
|
||||
| Boot drive | radio | `disk_config.device` |
|
||||
|
||||
### S3 — Per-Device Purpose
|
||||
|
||||
From Robert's wireframe Screen 3. One screen per non-boot drive.
|
||||
|
||||
| Purpose | Action at install time |
|
||||
|---------|------------------------|
|
||||
| Mass storage (default for large HDDs) | Added to a shared data pool mounted at `/mnt/data`. |
|
||||
| App storage (default for fast drives) | Mounted at `/var/lib/docker/homebase-apps`, used for container volumes. |
|
||||
| Backup target | Formatted and scheduled in the backup service (deferred). |
|
||||
| I don't know | Same as "Mass storage" — safe fallback. |
|
||||
|
||||
Radio buttons; default is `I don't know`.
|
||||
|
||||
### S4 — Network
|
||||
|
||||
From Robert's wireframe Screen 4.
|
||||
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| Network mode | radio | DHCP (default) / static |
|
||||
| Static config | group | IP, gateway, DNS — shown only if "static" picked |
|
||||
| VPN | toggle | Deferred — stub this out in v1; no VPN config in the wizard yet |
|
||||
|
||||
### S5 — Domain (NEW)
|
||||
|
||||
The YunoHost-style domain picker. Three paths:
|
||||
|
||||
| Option | What it does | Who it's for |
|
||||
|--------|--------------|--------------|
|
||||
| **Free `*.homebase.cloud` subdomain** | User picks `myname.homebase.cloud`. DNS is ours, wildcard cert via DNS-01 issued automatically. Managed gateway path. | The "your dad" default. |
|
||||
| **Bring your own domain** | User enters e.g. `example.com`. Wizard shows two NS records (`ns1.homebase.cloud`, `ns2.homebase.cloud`) to paste at their registrar. We handle the rest. | Users who already have a domain. |
|
||||
| **Skip — LAN only** | No public domain. Apps accessible as `<app>.proksi.local` via mDNS, with certs from the local CA. | Paranoid users / offline networks. |
|
||||
|
||||
Screen validates propagation in the background (NS query every 5s, green check when `nslookup` resolves to our NS). User can click "Next" past yellow, but not past red.
|
||||
|
||||
### S6 — SSL / Gateway (NEW)
|
||||
|
||||
Auto-configured based on S5.
|
||||
|
||||
| S5 choice | S6 behavior |
|
||||
|-----------|-------------|
|
||||
| Free subdomain | Silent — wildcard cert already issued by our infra, Caddy picks it up. One line: "✅ TLS ready for `*.myname.homebase.cloud`." |
|
||||
| BYO domain | Waits for NS propagation (can take minutes–hours). Page auto-refreshes. Shows "⏳ Waiting for `example.com` to point to us…" → green check. |
|
||||
| LAN only | Local CA cert used for `*.proksi.local`. One line: "✅ Local TLS ready." |
|
||||
|
||||
User can't advance past S6 until cert is ready (or they go back to S5 and pick a different option).
|
||||
|
||||
### S7 — Diagnostic (NEW)
|
||||
|
||||
YunoHost-style health check before confirming. Runs in parallel, shows results as they land.
|
||||
|
||||
| Check | Green | Yellow | Red |
|
||||
|-------|-------|--------|-----|
|
||||
| DNS resolves target domain | `nslookup` succeeds | Succeeds but propagation incomplete | Fails |
|
||||
| Ports 80 + 443 reachable from WAN | Inbound probe succeeds | CGNAT detected (fallback to Tailscale/Cloudflare tunnel suggested) | Blocked |
|
||||
| Boot drive mounted | — | — | Fails |
|
||||
| Docker available | — | — | Missing |
|
||||
| SMART healthy (all drives) | PASSED | No SMART data | FAILED |
|
||||
| Admin password strength | ≥12 chars, mixed | 8–11 chars | <8 chars |
|
||||
|
||||
**Rules:** user can continue past yellow with a "I understand" checkbox. Red blocks Next and offers a fix-it shortcut back to the relevant screen.
|
||||
|
||||
### S8 — Overview + Confirm
|
||||
|
||||
Shows the full `user_configuration.json` and `credentials.json` side by side (credentials masked, with a "show" toggle). User clicks **Install** → wizard POSTs to `/install/run`, which:
|
||||
|
||||
1. Writes the two JSON files to `/tmp/homebase/`.
|
||||
2. Fires `archinstall --config /tmp/homebase/user_configuration.json --creds /tmp/homebase/user_credentials.json --silent`.
|
||||
3. Streams output to a log pane on-screen.
|
||||
4. On success: shows "🎉 Install complete. Remove USB and reboot. After reboot, log in at `https://<your-domain>`."
|
||||
|
||||
---
|
||||
|
||||
## Data model
|
||||
|
||||
The wizard accumulates answers in the Flask `settings` dict at `webinstaller/app.py:6`. At S8, two JSON files are written. The mapping:
|
||||
|
||||
| Wizard field | Target file | Target path |
|
||||
|--------------|-------------|-------------|
|
||||
| `hostname` | `user_configuration.json` | `hostname` |
|
||||
| `language` | `user_configuration.json` | `archinstall-language` |
|
||||
| `language` (derived) | `user_configuration.json` | `locale_config.locale` |
|
||||
| S2 `boot_drive` | `user_configuration.json` | `disk_config.device` |
|
||||
| S3 per-device mounts | `user_configuration.json` | `disk_config.additional_mounts` (new field; extend archinstall profile) |
|
||||
| S4 `network_mode` | `user_configuration.json` | `network_config.type` |
|
||||
| S5 `domain` | — | Stored in Homebase state (`/etc/homebase/domain.conf`), read by Caddy + Authentik at first boot post-install |
|
||||
| S5 `domain_mode` | — | Same |
|
||||
| `admin_username` | `user_credentials.json` | `users[0].username` |
|
||||
| `admin_password` | `user_credentials.json` | `users[0].password` |
|
||||
| `admin_password` (hash) | — | Also pushed to Authentik bootstrap config |
|
||||
|
||||
**New archinstall fields** (beyond what's in the current `archinstall/user_configuration.json`):
|
||||
- `disk_config.additional_mounts` — list of `{device, mountpoint, purpose}` — needs a custom archinstall profile script.
|
||||
- Bootstrap script hook to deploy Caddy + Authentik + Homebase admin UI containers on first boot.
|
||||
|
||||
---
|
||||
|
||||
## Tech decisions (locked)
|
||||
|
||||
| Decision | Choice | Why | Rejected |
|
||||
|----------|--------|-----|----------|
|
||||
| Reverse proxy | **Caddy** | Automatic Let's Encrypt built-in. Caddyfile is the simplest config of any reverse proxy — matches the "simple" ethos. Auto-reloads on config change. | Traefik (label-based config is elegant for Docker but overkill and Kubernetes-flavored), nginx (battle-tested but manual SSL = every competitor's failure mode). |
|
||||
| Identity provider | **Authentik** | Bundled SSO from day one — every app template wires to it at install (YunoHost's best move). Active development, clean admin UI, OIDC + SAML + LDAP. | Authelia (lighter but worse UI and no built-in user management — needs external LDAP), external-only (loses the YunoHost wedge of SSO-by-default). |
|
||||
| Managed gateway DNS | **NS delegation** to `ns1.homebase.cloud` / `ns2.homebase.cloud` | User delegates once at registrar; we handle wildcard cert via Let's Encrypt DNS-01, subdomain creation, propagation. The single biggest UX cliff every competitor dies on. | CNAME-per-subdomain (clunky, users see our hostnames in records), manual A records (the exact pain point we're solving). |
|
||||
| Local HTTPS | **Local CA** generated at first boot | Single cert install in browser → green padlock for every service, no warnings ever. | Self-signed (YunoHost's model — users learn to click through warnings), public CA for `.proksi.local` (impossible — `.local` is reserved for mDNS), Tailscale-style ACME (good but adds a vendor dependency). |
|
||||
| Base OS | **Arch** (confirmed) | Rolling releases, Robert's existing Proxmox work. No user-visible difference. | Debian fallback remains documented in README. |
|
||||
| Container runtime | **Docker + Compose** | Confirmed in README. Authentik and Caddy ship as Compose stacks. | Podman (cleaner rootless story, but Compose ecosystem is smaller and Authentik ships Docker-first). |
|
||||
|
||||
---
|
||||
|
||||
## What this spec does NOT cover (deferred)
|
||||
|
||||
- App store UI and install flow (separate spec after bootable ISO lands).
|
||||
- Backup target scheduling (S3 stub points to this).
|
||||
- VPN configuration (S4 stub points to this).
|
||||
- Multi-node / cluster setup (not v1).
|
||||
- Update mechanism (rolling updates via Arch pacman + `docker compose pull`).
|
||||
|
||||
---
|
||||
|
||||
## Open questions for Robert
|
||||
|
||||
1. **"Backend on/off" and "Backend address" fields** in your Screen 1 wireframe — what do these configure? Dropped from S1 above until this is clear. If it's "connect to Homebase cloud for managed gateway," that's already covered by the S5 "free subdomain" path.
|
||||
2. **Local CA vs Tailscale-style ACME** — I locked in local CA because it's self-contained and works offline. Tailscale's approach (public cert for `*.ts.net`) is smoother but requires Tailscale. Your call.
|
||||
3. **Wizard UI framework** — currently Jinja templates + plain HTML (see `webinstaller/templates/`). If you want HTMX or Alpine for the async parts (S6 cert wait, S7 diagnostics), decide now so the templates don't need rework later.
|
||||
4. **Language list** — which languages ship in v1? Defaulting to English + German + Polish would cover us; anything else up to you.
|
||||
5. **Auto-setup branch from S2** — should it skip S3 entirely (purpose auto-assigned by drive type) or still show S3 with pre-filled defaults for confirmation?
|
||||
Loading…
Add table
Reference in a new issue