setup-guides

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).

MigrationWhat it addsRequired for
368_dreampro_coaching_foundation.sqlchannel_partners, coaches, referral codes, memberships, cohort_team_ideverything
369_dreampro_coaching_seats.sqlcoaching_seats + decisions + goalsthe AI coach
370_dreampro_coaching_channel_economics.sqlrevenue policies + earnings source_kindsthe split
371_dreams_public_slug.sqldreams.public_slug/start/<slug>
372_coaching_links.sqldurable /go/<id> redirect + QRprint/QR links
373_coach_interest.sql/for-coaches lead capturecoach recruitment
374_coaching_clickbank_affiliate.sqlclickbank_affiliate on referral codesClickBank affiliate attribution
375_workout_window_battles_cohort.sqlworkout_window_battles.cohort_team_id + partial uniquescohort weekly battles

⚠️ 375 is the newest. Until it's applied, GET /api/workout-window/battle/current errors on the missing cohort_team_id column 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."

  1. As a super-admin, open /dashboard/coaching.
  2. 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).
  3. 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:

  1. 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
    
  2. Vercel — add dreampro.io + www.dreampro.io to the frontend project (Settings → Domains); TLS auto-provisions.
  3. 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.
  4. (optional) NEXT_PUBLIC_GA_MEASUREMENT_ID_DREAMPRO for 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/dreampro to openenergy.* (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:

  1. Stripe Dashboard → create a recurring Price for DreamPro Coaching (e.g. $29/mo). Copy the price id.
  2. Backend env (Railway):
    STRIPE_PRICE_COACHING=price_…
    
  3. Stripe Dashboard → Webhooks — on the existing /api/payment/webhook endpoint, ensure invoice.payment_succeeded is enabled (plus checkout.session.completed + customer.subscription.*). Signing secret unchanged.
  4. 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.

  1. 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 stay pending).
  2. Flip the money gate (backend env, Railway):
    COACHING_PAYOUTS_ENABLED=true
    
  3. Enable the cron toggle — super-admin → /dashboard/admin/crons → turn on coaching_payouts (default off). It runs daily; it's a no-op while COACHING_PAYOUTS_ENABLED is unset, so BOTH must be on for transfers.
  4. (optional) trigger a manual run from the super-admin "Run payouts" button on /dashboard/coaching to 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 the coach_brief cron at /dashboard/admin/crons so 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> (or DREAMPRO_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-end ref.)
  • 30-Day Reset audiobook — once a narrated edition is produced in EmberKiln, set NEXT_PUBLIC_RESET_AUDIOBOOK_SEASON_ID=<season id> and /30-day-reset swaps its "coming soon" teaser for the real /seasons/<id>/embed player.

Env var quick reference

VarWherePurposeRequired?
NEXT_PUBLIC_DREAMPRO_HOUSE_REFfrontendHouse coach code for the native funnelYes (Part B)
STRIPE_PRICE_COACHINGbackendThe coaching subscription priceYes for money-in (D)
COACHING_PAYOUTS_ENABLEDbackendMaster gate for real Connect transfersYes for payouts (E)
COACH_BRIEF_ENABLEDbackendAI coach daily-brief cron gateOptional (F)
DREAMPRO_COACH_PERSONA_ID / _NAMEbackendDefault AI seat holderOptional (F)
NEXT_PUBLIC_RESET_AUDIOBOOK_SEASON_IDfrontend30-Day Reset audiobook embedOptional (F)
NEXT_PUBLIC_GA_MEASUREMENT_ID_DREAMPROfrontendSeparate GA4 for dreampro.ioOptional (C)

Cron toggles (super-admin UI, /dashboard/admin/crons): coaching_payouts, coach_brief.


Smoke-test checklist (after each part)

  • Aworkout_window_battles.cohort_team_id exists in prod.
  • B/30-day-reset → "Start free" enrolls a real client (no ref error).
  • Cdreampro.io/ serves the coaching landing; signup tagged 🏋️.
  • D — test-mode subscription records coaching_subscription + coaching_override earnings (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_id set).
  • Cohort flow — create a cohort on /dashboard/coaching, assign a client, confirm they appear on their cohort leaderboard (/dashboard/my-coaching → "Your cohort").
DREAMPRO COACHING GO LIVE — Docs | HiveJournal