The current first-run experience is disjointed: `/users/register` is a standalone page that closes after one user, the login page still links to it, and `/admin/setup` is a 3-step wizard hardcoded to Printify that bundles "go live" into the initial setup. Research into Shopify, WooCommerce and Squarespace shows that every successful platform separates initial setup (get the plumbing working) from launch readiness (guide the owner to a shop worth opening).
## Two-phase design
### Phase A: Initial setup (`/setup`)
Quick, focused, one-time. Gets the system functional. 5-10 minutes.
- Create admin account (email + magic link)
- Connect a print provider (provider-agnostic: Printify, Printful, etc.)
- Connect payments (Stripe)
No theme customisation, no "go live", no product sync waiting. Once all three connections are made, redirect to `/admin`. The `/setup` page is never shown again.
### Phase B: Launch checklist (persistent on `/admin` dashboard)
Ongoing guidance that lives on the admin dashboard until all items are complete or dismissed. Inspired by Shopify's setup guide and WooCommerce's task list. Items auto-complete based on real state. Uses the Zeigarnik effect — seeing a partially-complete checklist motivates finishing it.
| 2 | Customise your theme | Theme preset changed from default | `/admin/theme` |
| 3 | Review your pages | At least one content page edited (future: page editor) | `/admin/settings` |
| 4 | Place a test order | At least one order exists | `/` (the shop) |
| 5 | Go live | `site_live? == true` | Button right on the checklist |
"Go live" is the final step, only enabled when at least items 1 (products synced) and the provider + Stripe connections from setup are still valid. Items 2-4 are recommended but not blocking — the admin can dismiss them or skip straight to go live.
When all items are complete (or dismissed), the checklist is replaced by the normal dashboard stats (orders, revenue, products) — same as what WooCommerce does.
### Coming-soon page (branded holding page)
Until "go live" is flipped, unauthenticated visitors see a themed page using the current theme settings (logo, colours, fonts, site name). Not a sad blank wall — a preview of the brand.
Content:
- Site name / logo
- "We're getting things ready. Check back soon."
- Optional: email signup for launch notification (future enhancement, not MVP)
The admin bypasses this and sees the full shop (existing behaviour via ThemeHook).
## Architecture
### `/setup` page
**One LiveView, one page, one URL: `/setup`.**
Not a stepper wizard — a single scrollable page with independent sections as cards. Each section can be completed in any order. Completed sections collapse to show a checkmark and summary.
**Access rules:**
- No admin exists → page is public, shows all sections including account creation
- Admin exists + logged in + setup incomplete → page is accessible, account section hidden
- Admin exists + not logged in → redirect to `/users/log-in`
- Setup complete (all three connections made) → redirect to `/admin`
- Site is live → redirect to `/`
"Setup complete" means: admin exists + provider connected + Stripe connected. Products don't need to be synced yet — that's a launch checklist item, not a setup gate.
**Why no auth gate for provider/payment setup:** Single-tenant app. During initial setup there's no data to protect. The page is only reachable before setup is complete.
**Sections:**
| Section | Shown when | Content |
|---------|-----------|---------|
| Create admin account | No admin exists | Email field, magic link flow |
| Connect a print provider | No provider connected | Provider cards (Printify, Printful, coming soon), API key form |
| Connect payments | No payment provider | Stripe API key form |
Each completed section collapses to a summary line with a checkmark (e.g. "Connected to Printify").
**No theme/style section here.** Theme customisation is a launch readiness concern, not a setup concern. Keep setup lean.
### Dashboard launch checklist
Lives on the existing `/admin` dashboard page (`lib/berrypod_web/live/admin/dashboard.ex`). Shown as a card above the stats when `site_live?` is false or when checklist items remain incomplete.
**Component:** A function component `<.launch_checklist>` that takes `@setup` assigns and renders the checklist card. Each item is a row with: checkbox/checkmark, label, description, link/button.
**Progress indicator:** "3 of 5 complete" with a simple progress bar. Shopify research shows progress bars motivate completion.
**Dismissal:** The checklist can be dismissed permanently via a "Dismiss" link. Stores `checklist_dismissed` in Settings. Once dismissed or all items complete, shows the normal stats-only dashboard.
**"Go live" button:** Inline in the checklist as the final item. Enabled when products are synced + connections valid. Clicking it sets `site_live` and shows a brief celebration state before transitioning to the normal dashboard.
### Setup status (`Setup.setup_status/0`)
Make provider-agnostic and add launch checklist fields:
```elixir
%{
# Setup phase (connections)
admin_created: boolean,
provider_connected: boolean,
provider_type: string | nil,
stripe_connected: boolean,
setup_complete: boolean, # admin + provider + stripe all connected
# Launch checklist phase
products_synced: boolean,
product_count: integer,
theme_customised: boolean,
has_orders: boolean,
site_live: boolean,
# Derived
can_go_live: boolean, # provider_connected and products_synced and stripe_connected
checklist_dismissed: boolean
}
```
## Files to create
### `lib/berrypod/providers/registry.ex`
Provider metadata. Pure data, no DB.
```elixir
@providers [
%{
type: "printify",
name: "Printify",
tagline: "Largest catalog — 800+ products from 90+ print providers",
-`handle_event("select_provider", %{"type" => type}, socket)` — expands that provider's API key form.
-`handle_event("test_connection", %{"provider" => params}, socket)` — tests API key validity.
-`handle_event("connect_provider", %{"provider" => params}, socket)` — creates connection, enqueues sync in background. Does NOT wait for sync to finish — moves on.
**Completion:** When all three sections are done (`setup_complete`), show a brief "You're all set" message with a button to go to the dashboard. Or auto-redirect after a short delay.
## Files to modify
### `lib/berrypod/setup.ex`
- Replace `Products.get_provider_connection_by_type("printify")` with `Products.get_first_provider_connection/0`
3.**Go live:** Click "Go live" on checklist → celebration → visitors see real shop.
4.**Coming soon:** Before go-live, unauthenticated visitors see branded holding page.
5.**Dismiss:** Admin can dismiss the checklist and use the normal dashboard without going live.
6.**Provider agnostic:** Connect Printful instead of Printify — works the same.
7.**Dead ends:**`/users/register` redirects to `/setup`. Login page hides "Sign up" when admin exists.
8.**`mix precommit`** passes.
## Future enhancements (not in scope)
- **Email signup on coming-soon page** — collect emails for launch notification
- **Test order detection** — auto-complete "Place a test order" when an order with a test Stripe key exists
- **Content page editing** — "Review your pages" becomes more meaningful with a page editor (Tier 4)
- **Preset picker on setup page** — considered and cut. Theme customisation belongs in the launch checklist phase, not initial setup. The theme editor is the right tool for this.
- **Onboarding tooltips** — contextual hints on first visit to admin pages (e.g. "This is where you manage your products")