Two problems on fresh install with pic_ngo mode:
1. Caddy crashed at startup because ddns.token was empty (registration
hadn't completed yet), producing a bare `token` keyword in the
Caddyfile that Caddy rejects with "wrong argument count".
Fix: fall back to lan mode in _caddyfile_pic_ngo when the token is
empty so Caddy always starts cleanly. The Caddyfile is regenerated
once registration completes and the token is persisted.
2. DDNS registration failures were silently swallowed — the wizard
showed "Setup complete!" with no indication that HTTPS wouldn't work.
This made it look like everything was fine when the subdomain was
never registered (e.g. name already taken from a previous install,
or transient network error).
Fix: capture the exception, classify it (name_taken vs transient),
and return it as a `warnings` list in the setup response. The wizard
done screen now shows amber warning cards with actionable text instead
of auto-redirecting, giving the user a "Continue to login" button and
a clear explanation of what went wrong.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Services are now installed post-setup from the Store page, so the
wizard step that let users pre-select email/calendar/files is removed.
Reduces wizard from 5 steps to 4 (Step4Services deleted, Step5Review
renamed to Step4Review). Backend drops services_enabled validation,
background install thread, and service_store_manager dependency.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
For pic_ngo: name must be confirmed available (not just format-valid).
For cloudflare/duckdns: token is auto-verified on Next if not already
done — invalid or unreachable service blocks proceeding. Only lan and
http01 (no external dependency) allow Next without a live check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The availability check was only triggered onBlur, so clicking Next
without blurring the field skipped the DDNS request entirely. Now
handleNext awaits the check and blocks with an error if the name is
taken. Unknown/unreachable DDNS is treated as available to avoid
blocking the wizard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Domain name is now the cell identity (no separate cell name step).
All 5 providers (pic_ngo, cloudflare, duckdns, http01, lan) are
first-class options in a single Domain step. pic.ngo availability
is checked live via backend proxy to ddns.pic.ngo. Cloudflare and
DuckDNS tokens are verified via backend before proceeding.
cell_name is derived automatically from the chosen domain.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs:
1. AttributeError: AuthManager.update_password does not exist — the
fallback when create_user fails should call set_password_admin().
This caused a 500 on every setup submit when an admin user already
existed (e.g. from a previous install attempt).
2. Wizard was jumping to step 2 and skipping domain steps 3-4 when
preconfigured data existed in cell_config.json. Since the installer
no longer sets that data, and the wizard must always show all steps,
the installerConfigured state and all step-skipping navigation is
removed. Values are still pre-filled if found in config.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
install.sh no longer prompts for anything. It installs packages (with sudo),
creates the system user, clones the repo, and runs 'make install' — all as
the invoking user. Only package installs and system-level ops use sudo.
All folder creation happens under the user's own account, no chown needed.
/setup wizard gains the missing validation that was previously in install.sh:
- Step 1: checks pic.ngo name availability via backend (non-blocking)
- Step 4: 'Verify token' button for Cloudflare and DuckDNS tokens,
validated server-side through new /api/setup/validate steps
API changes (routes/setup.py):
- validate step 'pic_ngo_available': proxy check to ddns.pic.ngo
- validate step 'cloudflare_token': verify via Cloudflare tokens API
- validate step 'duckdns_token': verify via DuckDNS update endpoint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the bash installer collects cell name and domain mode, the first-run
wizard's /setup should only ask for a password, service selection, and
timezone. Previously the wizard pre-filled those fields but still showed
all 7 steps.
- useEffect fetches /api/setup/status on mount; if preconfigured.cell_name
and preconfigured.domain_mode are both set, sets installerConfigured=true
and jumps to step 2 (password)
- handleStep2Next → step 5 when installerConfigured (skips domain steps 3+4)
- handleStep2Back → step 1 when installerConfigured (review cell name)
- handleStep5Back returns to step 2 when installerConfigured
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DDNS registration (setup_cell.py):
- Replace pyotp dependency with stdlib TOTP (HMAC-SHA1, RFC 6238)
pyotp is only available inside the Docker container, not on the host
where setup_cell.py runs — registration was silently skipped every time
- OTP header still sent if generation succeeds; omitted gracefully if not
Wizard pre-fill (setup_manager + Setup.jsx):
- GET /api/setup/status now returns 'preconfigured' dict with cell_name,
domain_mode, domain_name, and provider tokens from installer-written config
- Setup.jsx fetches status on mount and pre-fills all form state so the
user only needs to set password, services, and timezone — not re-enter
the identity they already configured in the bash installer
- Fails silently so wizard still works on fresh installs with no config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Password:
- Add lowercase to strength scoring; "Good" now requires all API criteria
(12 chars, upper, lower, digit) — no more submitting passwords the API rejects
- isReady gates the Next button on meeting API requirements, not just length
Domain steps 3 + 4:
- Step 3: choose pic_ngo / custom / lan (sends valid API domain_modes)
- Step 4 (pic.ngo): shows derived [cellName].pic.ngo domain preview
- Step 4 (custom): domain name field + TLS method selector
(Cloudflare DNS-01 + API token, DuckDNS + token, HTTP-01 + port-80 warning)
- Step 4 skipped entirely for LAN-only
- Review step shows actual domain string and TLS method instead of opaque codes
Cell name:
- Description and preview hint make clear it becomes the pic.ngo subdomain
- Step 1 shows live "name.pic.ngo" preview as you type
Backend:
- setup_manager now accepts and stores domain_name, cloudflare_api_token,
duckdns_token for Phase 3 DDNS registration use
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The wizard was sending domain_type and services but the API expected
domain_mode and services_enabled, causing a validation error on submit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>