DreamPro Coaching — Go-Live Checklist
One ordered runbook to take DreamPro Coaching from "merged but inert" to "live and taking money." All the code is shipped (PRs #592 + #593); what remains is configuration only — migrations, a house coach, DNS, a Stripe price, and flipping the money switches when you're ready.
Deep dives this consolidates: DREAMPRO_IO_DOMAIN.md (DNS), DREAMPRO_COACHING_STRIPE.md (Stripe), DREAMPRO_COACHING_SYSTEM.md (the whole system).
Order matters where noted. Parts A–B are required for the funnel to work at all; C is the public front door; D is money-in; E is money-out (do last, behind the gates). F is optional polish.
Part A — Apply the database migrations
The coaching system spans migrations 368–375. Apply any not yet on prod (file-based migrations are applied via your own process per CLAUDE.md — they do not auto-apply on merge).
| Migration | What it adds | Required for |
|---|---|---|
368_dreampro_coaching_foundation.sql | channel_partners, coaches, referral codes, memberships, cohort_team_id | everything |
369_dreampro_coaching_seats.sql | coaching_seats + decisions + goals | the AI coach |
370_dreampro_coaching_channel_economics.sql | revenue policies + earnings source_kinds | the split |
371_dreams_public_slug.sql | dreams.public_slug | /start/<slug> |
372_coaching_links.sql | durable /go/<id> redirect + QR | print/QR links |
373_coach_interest.sql | /for-coaches lead capture | coach recruitment |
374_coaching_clickbank_affiliate.sql | clickbank_affiliate on referral codes | ClickBank affiliate attribution |
375_workout_window_battles_cohort.sql | workout_window_battles.cohort_team_id + partial uniques | cohort weekly battles |
⚠️
375is the newest. Until it's applied,GET /api/workout-window/battle/currenterrors on the missingcohort_team_idcolumn for everyone (not just coaching users). Apply it before/with the deploy of #593.
Verify: in prod, select column_name from information_schema.columns where table_name='workout_window_battles' and column_name='cohort_team_id'; returns a row.
Part B — Provision the house coach + house referral code (required for the native funnel)
enrollClient() requires a real, non-seed coach referral code. Until one
exists, the native "Start free" CTAs on /30-day-reset (and the /start/<slug>
links) fail with "invalid or inactive referral code."
- As a super-admin, open
/dashboard/coaching. - In the "Super-admin · house coach" card, set a code (default
HOUSE) and tap Provision house coach. This idempotently creates a channel partner → coach (active) → coach referral code, all real (is_seed=false). - Set the frontend env var to the returned code and redeploy the frontend:
NEXT_PUBLIC_DREAMPRO_HOUSE_REF=HOUSE
Verify: https://<host>/30-day-reset → "Start the Reset free" → enrolls
(clones the 30-Day Reset, lands on /dashboard/my-coaching) instead of erroring.
Part C — Point dreampro.io at the coaching front door (the public brand)
The host-aware middleware already rewrites dreampro.io/ → /coaching and tags
signups brand='dreampro'. Activation is DNS/Vercel/Supabase config only.
Full guide: DREAMPRO_IO_DOMAIN.md. In brief:
- DNS — point the apex + www at Vercel:
dreampro.io CNAME → cname.vercel-dns.com (A/ALIAS for the apex per registrar) www.dreampro.io CNAME → cname.vercel-dns.com - Vercel — add
dreampro.io+www.dreampro.ioto the frontend project (Settings → Domains); TLS auto-provisions. - Supabase Auth — add the dreampro.io redirect URLs (Auth → URL Configuration):
https://dreampro.io/auth/callback,https://www.dreampro.io/auth/callback,https://dreampro.io/start/*— else confirm links fall back to the canonical Site URL. - (optional)
NEXT_PUBLIC_GA_MEASUREMENT_ID_DREAMPROfor a separate GA4 property.
Verify: https://dreampro.io/ shows the coaching landing (URL stays on
dreampro.io); a new signup there shows the 🏋️ surface icon on the admin Users card.
Not in scope here: migrating Citizen Science off
hivejournal.com/dreamprotoopenenergy.*(separate effort — see SYSTEM.md §6) and dedicated DreamPro nav chrome.
Part D — Stripe: turn on the coaching subscription (money-in)
The checkout + the invoice.payment_succeeded → split webhook are shipped but
inert until a price exists. Full runbook + test plan:
DREAMPRO_COACHING_STRIPE.md. In brief:
- Stripe Dashboard → create a recurring Price for DreamPro Coaching (e.g. $29/mo). Copy the price id.
- Backend env (Railway):
STRIPE_PRICE_COACHING=price_… - Stripe Dashboard → Webhooks — on the existing
/api/payment/webhookendpoint, ensureinvoice.payment_succeededis enabled (pluscheckout.session.completed+customer.subscription.*). Signing secret unchanged. - The client-facing surfaces already exist:
/coaching/subscribe(kicks off Checkout) — it 503s with a friendly message until the price is set.
Test (Stripe test mode): enroll a non-seed client via /start/<slug>?ref=<code>
→ subscribe with 4242 4242 4242 4242 → confirm creator_earnings gets a
coaching_subscription row (coach + platform) and a coaching_override row
(partner), both pending, same stripe_invoice_id. Replaying the webhook must
not duplicate (idempotency), and a seed/persona membership must record
nothing (money guard). The split shows in the earnings panel on /dashboard/coaching.
No real money moves yet at this stage — earnings only accrue
pending. Transfers are Part E.
Part E — Payouts: actually move the money (money-out — do last, behind the gates)
Earnings accrue pending; the coaching_payouts cron transfers them to
coaches' + the partner's Stripe Connect accounts. Doubly gated so nothing moves
by accident.
- Coaches onboard Connect — each coach taps the "Get paid" card on
/dashboard/coaching→ Stripe Connect Express onboarding (reuses the creator-payout rails). Until a coach finishes onboarding, the cron skips them (their earnings staypending). - Flip the money gate (backend env, Railway):
COACHING_PAYOUTS_ENABLED=true - Enable the cron toggle — super-admin →
/dashboard/admin/crons→ turn oncoaching_payouts(default off). It runs daily; it's a no-op whileCOACHING_PAYOUTS_ENABLEDis unset, so BOTH must be on for transfers. - (optional) trigger a manual run from the super-admin "Run payouts" button on
/dashboard/coachingto settle immediately the first time.
Verify: with both gates on + at least one onboarded coach holding pending
earnings, a run reports transferred > 0; those creator_earnings rows flip
pending → transferred with a stripe_transfer_id. The partner dashboard
(/dashboard/coaching/partner)
shows the paid totals.
Part F — Optional toggles
- AI coach daily brief — set
COACH_BRIEF_ENABLED=true(backend) and enable thecoach_briefcron at/dashboard/admin/cronsso each active AI-held seat gets a drafted between-session note daily. Off → the review queue only fills from manual "generate brief" actions. - Default the new seats to an AI coach — set
DREAMPRO_COACH_PERSONA_ID=<ai_persona id>(orDREAMPRO_COACH_PERSONA_NAME=<display name>) so a deliberate coaching persona holds each new client's seat. Unset → seats default to human-held (the coach holds it) rather than a random persona. - ClickBank affiliate attribution — map a ClickBank affiliate nickname to a coach
code via the "ClickBank affiliate map" mini-form on
/dashboard/coaching, so buyers their HopLink sent earn the recurring back-end override too. (Front-end commission stays ClickBank's HopLink; this is the back-endref.) - 30-Day Reset audiobook — once a narrated edition is produced in EmberKiln,
set
NEXT_PUBLIC_RESET_AUDIOBOOK_SEASON_ID=<season id>and/30-day-resetswaps its "coming soon" teaser for the real/seasons/<id>/embedplayer.
Env var quick reference
| Var | Where | Purpose | Required? |
|---|---|---|---|
NEXT_PUBLIC_DREAMPRO_HOUSE_REF | frontend | House coach code for the native funnel | Yes (Part B) |
STRIPE_PRICE_COACHING | backend | The coaching subscription price | Yes for money-in (D) |
COACHING_PAYOUTS_ENABLED | backend | Master gate for real Connect transfers | Yes for payouts (E) |
COACH_BRIEF_ENABLED | backend | AI coach daily-brief cron gate | Optional (F) |
DREAMPRO_COACH_PERSONA_ID / _NAME | backend | Default AI seat holder | Optional (F) |
NEXT_PUBLIC_RESET_AUDIOBOOK_SEASON_ID | frontend | 30-Day Reset audiobook embed | Optional (F) |
NEXT_PUBLIC_GA_MEASUREMENT_ID_DREAMPRO | frontend | Separate GA4 for dreampro.io | Optional (C) |
Cron toggles (super-admin UI, /dashboard/admin/crons): coaching_payouts,
coach_brief.
Smoke-test checklist (after each part)
- A —
workout_window_battles.cohort_team_idexists in prod. - B —
/30-day-reset→ "Start free" enrolls a real client (no ref error). - C —
dreampro.io/serves the coaching landing; signup tagged 🏋️. - D — test-mode subscription records
coaching_subscription+coaching_overrideearnings (pending); replay doesn't duplicate; seed membership records nothing. - E — with both gates on, a payout run transfers an onboarded coach's pending
earnings (
pending → transferred,stripe_transfer_idset). - Cohort flow — create a cohort on
/dashboard/coaching, assign a client, confirm they appear on their cohort leaderboard (/dashboard/my-coaching→ "Your cohort").