Pro Website — Pre-flight Verification — 2026-04-18T14:20Z
Call: GO for manual test. Live checkout → webhook → provisioning → dashboard → subdomain render is code-complete and infrastructure-healthy. One operational note + one blast-radius tip below.
What was verified (evidence-or-nothing)
1. Landing pages & public URLs — all 200
https://churchwiseai.com/pro-website→ 200https://churchwiseai.com/onboard?plan=cwa_pro_website→ 200https://churchwiseai.com/pricing→ 200https://churchwiseai.com/help/pro-website→ 200https://churchwiseai.com/onboard/return→ 200https://churchwiseai.com/thank-you?token=test-invalid→ 200https://the-bridge-church.john316.church(demo) → 200https://john-new-pr6o-site-j-1fa8.john316.church(founder's 2026-04-17 test) → 200
2. Stripe configuration
STRIPE_PRO_WEBSITE_MONTHLY_PRICE_IDset in Vercel production (refreshed 2d ago)- Live price
price_1TEJh4FaoK5IPzNojyaDlegM→ $19.95/mo recurring,livemode: true,active: true, productprod_UCj9DWAsREnJFK, no trial STRIPE_WEBHOOK_SECRET,STRIPE_SECRET_KEY,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,CRON_SECRETall present
3. Code paths — checkout → webhook → provisioning
OnboardForm.tsx— Pro Website branch: pinned $19.95/mo, no billing toggle, no voice, directory opt-in pre-checkedOnboardForm→/api/onboard→ stores tosessionStorage→ redirects to/onboard/checkoutCheckoutForm.tsx→/api/stripe/checkout-embedded→ui_mode: 'embedded', passes ALL onboard data inmetadata+subscription_data.metadatacheckout.session.completedwebhook →provisionNewChurch():- Creates
churchesrow (slug retry up to 3x) - Generates unique
vanity_slug(5 collision retries) - Upserts
premium_churcheswithplan: 'cwa_pro_website'(canonical, NOT normalized) — rule #22 intact (src/app/api/stripe/webhook/route.ts:1402) - Sets
website_template: 'protestant_modern',website_activated_at,directory_opt_in - Generates
admin_token - Creates primary identity + session
- Auto-provisions chatbot (
organization_settingsrow +agent_config) - Creates admin team member row
- Sends welcome email with 3 retries (magic link =
/admin/{admin_token}) - Syncs to MailerLite if opt-in
- Creates
- Legacy
activateChurch()path also preserves canonical tier inplan(lines 357, 385, 882) — regression-defense for existing customers
4. Webhook inbox health
- 12 rows total, ALL status =
succeeded - Zero
pending/processing/failed/abandoned - Last processed: 2026-04-17T13:31Z (no Stripe activity today — cron idle, healthy)
- Cron
process-stripe-webhooksruns every 1 minute (vercel.json) - Return page polls
/api/onboard/check-setupevery 2s for up to 120s → comfortably covers worst-case webhook + cron delay
5. Admin dashboard routing
AdminDashboard.tsx:209— Website tab IS shown forcwa_pro_websitecustomers despitenormalizePlanTier→ 'starter'AdminDashboard.tsx:893—isProWebsitePlan(premium.plan)routes to fullWebsiteTabEditor(design / content / settings sub-tabs, 884 lines)- Public link header uses
{vanity_slug}.john316.churchforcwa_pro_websitecustomers
6. Subdomain rendering
middleware.ts:85-101—*.john316.churchrewrites to/s/[slug](excludes static assets, APIs, root files)/s/[slug]/page.tsx— queriespremium_churchesbyvanity_slug, plans ∈{cwa_pro_website, ps_pro_website, pro_website}, status ∈{active, preview}, ISRrevalidate = 3600- Chatbot mounted with per-church UUID → church-scoped knowledge + HEAR protocol
7. DB constraints
premium_churches.planCHECK constraint acceptscwa_pro_website✅premium_churches.website_templateCHECK:{protestant_modern, catholic_liturgical, nondenominational_community}— provisioning hardcodesprotestant_modern✅vanity_slugformat regex:^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$— generator complies
8. CI state on main
- Critical Path Protection: GREEN (run 24606483266 @ 14:12:50Z) — this is the gate that matters for customer flow
Testsworkflow: red (behavioraltest_demo_data_completeness.py— demo churches missing hero videos, tracked as FA-044 P2, unrelated to live flow)Voice Behavioral — Church (STUB): red (voice-agent testing backlog, unrelated)- FA-043 (vitest import) RESOLVED via PR #52 — now uses
node:test
9. No open P0/P1 blockers
founder_action_itemsopen P0/P1: 0ops_errorsopen P0/P1 last 7d: 0
One operational note
Existing Pro Website row uses founder email john+pws2@churchwiseai.com. If you sign up with that same email, the /api/onboard endpoint returns 409 email_exists and re-sends the dashboard link (defensive, by design). To test a fresh signup, use a different +alias like john+protest@churchwiseai.com.
One blast-radius tip (optional)
To avoid real cost + real customer-facing side effects while testing the live flow, you can append ?promo=<100pct-coupon> to the checkout link — but the validation harness at /api/stripe/checkout-embedded with validation_mode: true is the cleaner way (skips MailerLite, skips voice provisioning, marks the church directory-hidden). If this is the first real payment you want through the pipe for verification, just proceed normally — $19.95 on a founder card is a fair price for end-to-end proof.
What to watch during your test
- Checkout page: Stripe EmbeddedCheckout should mount. If it spins forever → check browser console for Stripe publishable key / session client_secret errors.
- After clicking "Pay": you land on
/onboard/return?session_id=.... The spinner says "Setting Up Your Account..." for ≤120s. If it flips to "We're finishing setup — check your email" (timeout branch), the webhook cron hit ran late — refresh or check email. Provisioning still completes server-side. - Redirect: on success →
/thank-you?email=X&token=Y→ click through to/admin/{token}. - Admin dashboard: you should see the Website tab. Clicking it should render the full editor (NOT the upsell stub from
WebsiteTab.tsx). If you see the "Upgrade to Pro or Suite" stub,isProWebsitePlan(premium.plan)failed — check thatplanin DB is literallycwa_pro_website, notstarter. - Public render: after the wizard writes
vanity_slug, visithttps://{vanity_slug}.john316.church— should 200 and show the unified template + chatbot.
Path to unlock Axis A (60% cap)
This manual test, if completed with a real card (non-founder email or not attributable to the founder account), unlocks the 60% Axis A cap on the readiness score: overall would flip from NEEDS WORK → READY assuming Axis B stays where it is. Using john+...@churchwiseai.com will NOT unlock Axis A — the cap query is admin_email NOT LIKE '%@churchwiseai.com'.