Companion plan: [email-settings.md](email-settings.md) (admin UI for email config)
## Context
The setup wizard requires email verification (magic link) to create the admin account. This doesn't work for self-hosted users without email configured. The fix: auto-confirm and auto-login the first admin during setup, gated by a setup secret in prod. Also adds env var SMTP support and a warning banner when email isn't configured.
## UX flow
### Screen states
| Context | What they see |
|---------|---------------|
| Prod, no admin, no secret entered | Secret gate only (single input + submit) |
| Prod, no admin, secret verified | All 3 cards (card 1 active with email field) |
| Dev, no admin | All 3 cards (card 1 active, no secret gate) |
| Admin exists, not logged in | Redirect to `/users/log-in` |
| Logged in, setup incomplete | All 3 cards (card 1 done with checkmark, cards 2+3 active) |
| Setup complete | Redirect to `/admin` |
| Site live | Redirect to `/` |
### Prod first-run flow
1. Server logs: `Setup secret: abc123-def456 — visit /setup to create your admin account`
2. Visit `/setup` -> see only a setup secret input
3. Enter correct secret -> LiveView assigns `secret_verified: true` -> template reveals all 3 cards
4. Card 1 "Create admin account" has email field -> submit -> account created, auto-confirmed, token generated, redirect to `/setup/login/:token` -> controller sets session cookie -> redirect back to `/setup` -> card 1 shows done, cards 2+3 active
### Dev first-run flow
1. Visit `/setup` -> all 3 cards visible immediately (no secret gate)
2. Card 1 has email field -> submit -> same auto-confirm + redirect flow
## Changes
### 1. Setup secret (`lib/berrypod/setup.ex`)
Add to existing file:
-`setup_secret/0` — returns `SETUP_SECRET` env var, or auto-generates via `:crypto.strong_rand_bytes/1` on first call and stores in `:persistent_term`. Not stored in DB (bootstrap credential needed before admin exists).
-`require_setup_secret?/0` — `true` in prod when no admin exists. `false` in dev.
### 2. Log setup secret on boot (`lib/berrypod/application.ex`)
In `start/2`, after children are started: if no admin exists, call `Setup.setup_secret/0` and log it:
```
[info] Setup secret: <token> — visit /setup to create your admin account
- **Setup secret** prevents unauthorized admin creation on fresh instances. Only someone with server log access or the `SETUP_SECRET` env var can proceed.
- **Not stored in DB** — it's a bootstrap credential needed before the admin exists. `:persistent_term` for auto-generated, env var for explicit.
- **Skipped in dev** — no friction during local development.
- **Skipped when logged in** — hosted platform users are already authenticated.
- **Auto-login token** is same-origin (never emailed), single-use (consumed immediately by controller), with 15-minute expiry as safety net.
- **Race-safe** — `register_and_confirm_admin/1` checks `has_admin?()` inside a DB transaction.
- **Removes info leak** — old check_inbox phase exposed admin email to unauthenticated visitors.
## Verification
1.`mix precommit` passes
2. Dev fresh install: visit `/setup`, enter email only, immediately on configure phase