From f06d32989d88a9c536b50c04784594d2f10e2059 Mon Sep 17 00:00:00 2001 From: Daniel Maksymilian Syrnicki Date: Mon, 13 Apr 2026 20:06:11 +0200 Subject: [PATCH] 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) --- docs/wizard-flow.md | 190 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/wizard-flow.md diff --git a/docs/wizard-flow.md b/docs/wizard-flow.md new file mode 100644 index 0000000..eb103ff --- /dev/null +++ b/docs/wizard-flow.md @@ -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/`. 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 `.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://`." + +--- + +## 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?