Pre-Dashboard Onboarding Wizard — Expected Output Spec
Why this spec exists
On 2026-05-25 Anthony (founder's nephew, IT professional) signed up for a free trial and described the existing onboarding as "a huge list of things to do for a free trial." The current SetupGuide.tsx renders an 8-required-step checklist inline above the empty dashboard on /admin/[token]/#home — the customer sees TODOs before they ever see an AI working.
Industry benchmarks (2026): >10-step wizards drop completion 30–50%; blank-state dashboards lose 84% of users in session 1; the top-quartile time-to-WOW is 2–5 minutes (knowledge/processes/seo-traffic-strategy-2026.md, see the SaaS onboarding research synthesis from the May 26 design proposal).
This spec defines the pre-dashboard guided wizard that replaces the long inline checklist for first-time customers. It ends at the customer interacting with their own AI agent — the "Meet Your Agent" reveal — and only then drops them into the dashboard.
Core UX promise
From magic-link click to hearing your own AI in under 10 minutes. Six short steps. Skip anytime. We'll do it for you if you'd rather (Phase 4 concierge fork).
The wizard is the FIRST surface the customer sees after the magic link. The existing dashboard-inline SetupGuide still exists for post-wizard finer tweaks (Pro Website hero images, FAQs, sharing) but is no longer the first impression.
The 6-step journey
| # | Step id | Title | Type | Form component | What saves it | Est. time |
|---|---|---|---|---|---|---|
| 1 | welcome | Welcome | static + concierge fork | n/a | Click "Let's go" or "Train it for me ($99)" | 30s |
| 2 | church-profile | Your church | reuse ChurchProfileForm | ChurchProfileForm | "Save profile" | 2 min |
| 3 | what-to-expect | What visitors will hear | reuse WhatToExpectForm | WhatToExpectForm | "Save" | 3 min |
| 4 | office-hours | Your hours | reuse OfficeHoursForm | OfficeHoursForm | "Save hours" | 1 min |
| 5 | theology | Your tradition | reuse TheologySettings | TheologySettings | "Save tradition" | 30s |
| 6 | meet-your-agent | Meet your AI agent | NEW MeetYourAgentStep | n/a | "Take me to my dashboard" | 2 min |
Total target time: ~9 minutes. Each step's estimate is displayed on its own header so the customer can pace themselves.
Step 1 — welcome (the concierge fork)
Layout
┌─────────────────────────────────────────────────────────────┐
│ ChurchWiseAI •━━━━━━━━━━━━━━━━━━━━━━• Step 1 of 6 │
│ │
│ │
│ Welcome, Pastor John. │
│ │
│ Your AI agent for Grace Community is almost │
│ ready. We'll be done in about 9 minutes. │
│ │
│ │
│ ┌──────────────────────────┐ ┌──────────────────────┐ │
│ │ [Let's set it up │ │ [Train it for me │ │
│ │ together — 9 min] │ │ — $99 setup] │ │
│ │ │ │ │ │
│ │ You answer 5 short │ │ Send us your church │ │
│ │ questions. We do the │ │ website + a sermon. │ │
│ │ rest. Free for 14 days. │ │ Agent ready in 24h. │ │
│ └──────────────────────────┘ └──────────────────────┘ │
│ │
│ Skip — let me explore the dashboard first │
└─────────────────────────────────────────────────────────────┘
Behaviors
- B1.1 — Greeting interpolates
{member_name || 'there'}and{church_name}from thepremium_churchesrow. - B1.2 — "Let's set it up together" advances to Step 2 + sets
setup_current_step='church-profile'. - B1.3 — "Train it for me ($99 setup)" — Phase 4 wires this to Stripe + intake form. In Phase 2, the button renders as a disabled "Coming soon" pill with copy "We're launching this in the next few days — for now, please reach out at hello@churchwiseai.com." (The DRAFT button is present in the DOM but disabled, so Phase 4 can swap behavior without re-cutting the layout.)
- B1.4 — "Skip — let me explore the dashboard first" sets
setup_current_step='skipped'and navigates to/admin/[token](the legacy dashboard, where the inline SetupGuide still renders for completeness). - B1.5 — No header chrome (no marketing nav, no chat widget) — bare wizard shell only. Reuses
LayoutShellforceBarepattern.
Steps 2–5 — data collection (reuse existing forms)
Each step renders inside a StepShell component that provides:
- Top-left logo + step indicator
Step N of 6+ estimated time - Progress bar (
N/6filled) - Center: the reused form component
- Bottom-right:
[Save & continue →](the form's existing save button) - Bottom-left:
Skip this step(sets the step as skipped, advances to next) - Top-right:
Skip — take me to my dashboard(setssetup_current_step='skipped', hard exit)
Save discipline
- Every form save updates
premium_churches.setup_current_step = '<next-step-id>'andsetup_resumed_at = now()server-side BEFORE returning success to the client. - If the customer closes the tab mid-step, returning to
/admin/[token]redirects them back to/admin/[token]/welcomewith the saved step pre-selected. - Required fields enforced by the form components themselves (see existing spec at
pro-website-setup-wizard.md§B5).
Vertical-aware copy
VerticalProvider.wizardCopy (NEW context field) supplies per-vertical labels:
| Vertical | Step 2 title | Step 3 title | Step 4 title | Step 5 title |
|---|---|---|---|---|
| church | Your church | What visitors will hear | Your hours | Your tradition |
| funeral | Your funeral home | What families need to know | Your hours | Your tradition (denomination context) |
| vet | Your clinic | What pet owners will hear | Your hours | (skip — no theological lens) |
| local_business | Your business | What customers will hear | Your hours | (skip) |
For verticals that skip Step 5, the wizard renders 5 steps total. Step indicator shows Step N of 5 for those.
Step 6 — meet-your-agent (the WOW reveal)
Layout
┌─────────────────────────────────────────────────────────────┐
│ ChurchWiseAI ●━━━━━━━━━━━━━━━━━━━━━━● Step 6 of 6 │
│ │
│ │
│ Pastor John, meet Grace's AI receptionist. │
│ │
│ Your agent is trained on Grace Community's beliefs, │
│ service times, and visitor experience. Try it now. │
│ │
│ ┌──────────────────────────┐ ┌──────────────────────┐ │
│ │ 💬 Chat with your agent │ │ 📞 Call your number │ │
│ │ │ │ │ │
│ │ [Embedded chat widget │ │ +1 (xxx) xxx-xxxx │ │
│ │ pre-loaded with their │ │ │ │
│ │ live data] │ │ [Copy number] │ │
│ │ │ │ │ │
│ │ Try: "What time is │ │ Voice plans only — │ │
│ │ Sunday service?" │ │ hidden for chat- │ │
│ │ │ │ only customers. │ │
│ └──────────────────────────┘ └──────────────────────┘ │
│ │
│ [Take me to my dashboard] │
└─────────────────────────────────────────────────────────────┘
Behaviors
- B6.1 — Greeting interpolates
{contact_name}+{church_name}+{vertical_term}(e.g., "AI receptionist" for churches, "intake assistant" for funeral homes, "front desk" for vets). - B6.2 — Chat card always present for any plan with chat enabled (Starter Chat, Pro, Suite, Pro Website). Renders
ChatWidgetin inline mode (not floating). Pre-seeded with the customer'schurch_idso the agent answers using their data. - B6.3 — Voice card present only for plans with voice (Starter Voice, Pro Voice, *_both, Suite). Voice card hidden for chat-only plans; chat card spans full width when voice is hidden.
- B6.4 — Phone number resolved from
church_voice_agents.twilio_phone_number(ortelnyx_phone_numberfor new provisions). If voice agent is not yet provisioned (e.g., still in 24h Telnyx setup window), the voice card renders a "Your number arrives by email when ready" placeholder with[Notify me]button. - B6.5 — "Take me to my dashboard" button sets
setup_current_step='complete'and navigates to/admin/[token]. The dashboard renders normally with the inlineSetupGuide's celebration card ANDOptimizationTips(the post-wizard finer tweaks). - B6.6 — Confetti animation fires once on first arrival at this step (
framer-motionconfetti, dismissible by clicking anywhere). Persisted inlocalStorage.cwai-wizard-confetti-shown=trueso it doesn't repeat on re-entry. - B6.7 —
Skip — take me to my dashboard(top-right) is hidden on Step 6 because the user is already at the destination — the only forward action is "Take me to my dashboard."
Redirect logic on /admin/[token]
Server-side, in the page component:
GET /admin/[token]:
load premium_churches row for token
if premium.setup_current_step is null:
redirect 302 → /admin/[token]/welcome
if premium.setup_current_step is one of (church-profile, what-to-expect, office-hours, theology, meet-your-agent):
redirect 302 → /admin/[token]/welcome (wizard resumes at saved step)
if premium.setup_current_step in ('complete', 'skipped'):
render dashboard normally (existing behavior unchanged)
A ?bypass=true query param skips the redirect (useful for QA + the "Skip" actions in the wizard which set state before navigating away).
DB schema
Migration 2026-05-26-premium-churches-setup-current-step.sql:
ALTER TABLE premium_churches
ADD COLUMN IF NOT EXISTS setup_current_step text NULL,
ADD COLUMN IF NOT EXISTS setup_resumed_at timestamptz NULL;
COMMENT ON COLUMN premium_churches.setup_current_step IS
'Pre-dashboard wizard cursor. NULL = never started (force-redirect to wizard). '
'One of: welcome, church-profile, what-to-expect, office-hours, theology, '
'meet-your-agent, complete, skipped. complete/skipped are terminal — '
'the customer is no longer force-redirected.';
COMMENT ON COLUMN premium_churches.setup_resumed_at IS
'Last time the wizard saved progress. Used for the 3-email recovery sequence '
'(immediate / +24h / +7d) when a customer abandons mid-wizard.';
Backfill: existing customers (i.e., setup_completed = true OR there are dashboard activity rows) are set to setup_current_step='complete' so they are never redirected to the wizard.
Save & continue later — recovery emails
When setup_resumed_at has been older than 24h AND setup_current_step is not in ('complete', 'skipped'), the lifecycle cron sends a "Pick up where you left off" email with a deep link /admin/[token]/welcome. Three emails total: +24h, +3d, +7d. After +7d the cron stops nagging and the customer is left alone.
(Lifecycle email plumbing already exists at src/app/api/cron/lifecycle-emails/route.ts — this spec just defines a new trigger condition.)
What this spec does NOT cover (deferred)
- Concierge fork ($99 setup) full wiring — Phase 4. This spec only requires the disabled-button placeholder.
- WiseAI Agency
/business/[token]bridge — Phase 5. The wizard works for/admin/[token]plans (church, funeral, vet) only in Phase 2. - Pastor + tone slider — deferred. The agent uses default tone tied to the picked theological lens. A future spec can add tone customization inside the existing AgentPersonality form on the Training tab.
- Pro Website hero photo upload — stays in the post-wizard inline SetupGuide (Pro Website plans still use the existing 8-step Pro Website wizard there).
- Embed widget snippet display — stays on the dashboard Home tab share card.
- Pastor View vs Tech View dashboard toggle — Phase 3.
- Per-step analytics events — wire after first founder walkthrough confirms the step set is final (don't bake events into a moving target).
Acceptance criteria (Given/When/Then)
Wizard rendering
- Given
premium_churches.setup_current_step IS NULLAND token matches an active row, when GET/admin/[token]runs, then HTTP 302 redirect to/admin/[token]/welcomeand the wizard renders at Step 1. - Given
setup_current_step='theology', when GET/admin/[token]runs, then redirect to/admin/[token]/welcomeand the wizard opens directly at Step 5 (theology). - Given
setup_current_step='complete', when GET/admin/[token]runs, then no redirect — the dashboard renders normally. - Given
setup_current_step='skipped', when GET/admin/[token]runs, then no redirect — dashboard renders + inline SetupGuide visible.
Step progression
- Given the wizard is at Step 2 (
church-profile), when the customer fills the form and clicks "Save profile", thensetup_current_stepupdates towhat-to-expectserver-side BEFORE the client receives success, and the wizard advances to Step 3 client-side. - Given the wizard is at any step 2–5, when the customer clicks "Skip this step" at the bottom-left, then
setup_current_stepadvances to the next step (the skipped step's form data stays whatever it was — usually empty), but the form is NOT marked complete. - Given the wizard is at any step 1–5, when the customer clicks "Skip — take me to my dashboard" (top-right), then
setup_current_step='skipped'and HTTP redirect to/admin/[token]?bypass=true.
Vertical-aware copy
- Given a
cwa_starter_chatplan withvertical='funeral', when the wizard renders Step 2, then the title is "Your funeral home" not "Your church". - Given
vertical='vet', when the wizard renders, then Step 5 (theology) is absent from the step list and the indicator readsStep N of 5notStep N of 6.
Meet Your Agent (Step 6)
- Given a chat-only plan, when Step 6 renders, then the Voice card is absent from the DOM and the Chat card spans the full row width.
- Given a voice-or-both plan with a provisioned
twilio_phone_number, when Step 6 renders, then the Voice card displays the number, aCopy numberbutton, and a "Try calling now" hint. - Given a voice-or-both plan WITHOUT a provisioned phone yet, when Step 6 renders, then the Voice card shows the "Your number arrives by email when ready" placeholder with a
Notify mebutton (no-op in Phase 2 — Phase 4 wires a real notification preference). - Given the customer arrives at Step 6 for the first time, when the page mounts, then a confetti animation fires once and
localStorage.cwai-wizard-confetti-shownis set totrue. - Given the customer arrives at Step 6 a second time (e.g., refreshes), when the page mounts, then no confetti.
- Given the customer clicks "Take me to my dashboard" on Step 6, then
setup_current_step='complete'server-side and the browser navigates to/admin/[token](no redirect-back-to-wizard loop).
Embedded chat reveal
- Given Step 6 renders the Chat card, when the customer types "What time is your service?" and submits, then the agent responds using THIS customer's
church_iddata (verified by intercepting the/api/chatbot/streamrequest and assertingchurch_idin the payload).
Recovery emails
- Given
setup_resumed_atis 24h old ANDsetup_current_stepis not terminal, when the lifecycle-emails cron runs, then a "Pick up where you left off" email is sent (template covered by a separate flow spec underknowledge/flows/onboarding-wizard-recovery.md— to be added in the same PR).
Regression hazards (what to verify in the Playwright spec)
- Redirect loop — if Step 6 sets state correctly but the redirect logic on
/admin/[token]doesn't match the terminal state, customers loop back into the wizard forever. Test 15 covers. - Cross-vertical breakage — change to VerticalProvider's wizardCopy must not regress existing dashboard tab labels (the same provider drives both). Test the funeral and vet variants of every step.
- Form save partial state — if a form save updates DB but the server response races the client step advance, the customer might see Step 2 finish but the redirect logic thinks they're still on Step 2 → infinite loop on refresh. Server MUST update
setup_current_stepBEFORE the response returns. - Pro Website wizard collision — the old
pro-website-setup-wizard.md8-step spec runs INLINE on/admin/[token]/#homeAFTER this wizard completes. Verify the dashboard SetupGuide does NOT auto-pop on first visit if our wizard just completed (would feel like a second tax).
Change-management rules
- When
premium_churches.setup_current_stepenum gains a new value (e.g., Phase 4 addsconcierge-purchased), update §"Redirect logic" in the SAME PR and add the enum to the DB column comment. - When VerticalProvider.wizardCopy adds a new vertical, add a row to the §"Vertical-aware copy" table here.
- When the Meet Your Agent step gains a new action (e.g., "Share your number with your office" SMS test), add an acceptance criterion AC18+ here BEFORE writing the Playwright assertion.
End of spec. This document is the test target for e2e/onboarding-wizard.spec.ts and the expected-output contract for every wizard feature built in Phase 2.