Supabase runbook (condensed)
The full copy-pasteable version lives in the repo at product-docs/05_RUNBOOK.md. This is the condensed operator summary: demo deploy → Supabase + real providers in about an hour.
| Step | What | Budget |
|---|---|---|
| 1 | Push repo to GitHub | 5 min |
| 2 | Vercel import, DEMO deploy | 10 min |
| 3 | Supabase project + migrate + seed | 15 min |
| 4 | Flip env to postgres + provider keys, redeploy | 10 min |
| 5 | Enable durable run execution | 10 min |
| 6 | Post-swap checklist | 8 min |
1–2. GitHub + demo deploy
Push the repo (git remote add origin … && git push -u origin main), import it into Vercel (Next.js auto-detected, all defaults). Env for the demo deploy: DEMO_MODE=1, SESSION_SECRET (openssl rand -base64 32), OPERATOR_EMAIL, OPERATOR_PASSWORD. Deploy, then verify /api/health shows "demoMode":true. This deploy is also your one-minute rollback target.
3. Supabase
Create a project and copy both connection strings: the transaction pooler (port 6543) becomes DATABASE_URL; the direct connection (port 5432) becomes DIRECT_URL. Locally set DB_DRIVER=postgres plus both URLs, then:
pnpm exec drizzle-kit migrate # runs against DIRECT_URL, TLS forced by drizzle.config.ts
OPERATOR_EMAIL=you@… OPERATOR_PASSWORD=… pnpm seed
Migrations go through DIRECT_URL only: DDL through the transaction pooler is unreliable (it multiplexes sessions across backends). The app itself always uses the pooled URL.
4. Flip the deploy
In Vercel env vars: remove DEMO_MODE; add DB_DRIVER=postgres, DATABASE_URL, DIRECT_URL, DATAFORSEO_LOGIN, DATAFORSEO_PASSWORD, PERPLEXITY_API_KEY. Redeploy. Verify /api/health shows "driver":"postgres" and Settings → Engines shows every engine configured.
5. Run execution
Immediately: run pnpm worker anywhere with the Supabase env — it claims queued runs safely (90-second stale-claim protocol) and executes them. Durable end state: wire the Vercel Workflows entrypoint (app/workflows/run.ts, one step per batch around the same shared executor) — the workflow package is installed; see runbook step 5 for exactly where to flip.
6. After the swap
- Sign in as your real operator; create your first real agency. There is no demo data to clean up — pre-Supabase data was in-memory/local and disposable by design.
- RLS: tables ship with RLS disabled; isolation is app-layer (session-scoped DAL, e2e-tested). Never add
supabase-jsor expose the anon key. The dashboard linter will complain — acknowledge it, don't enable RLS (without policies it adds no protection). - Demo-period access requests: retrieve
ACCESS_REQUESTlog lines from Vercel Logs now — Hobby retention is short. From here on, requests persist in the database and appear at/requests. - Custom domain: add it in Vercel; nothing in the app hardcodes a URL.
- Password recovery: Forgot your password? on the sign-in card emails a one-hour, single-use link (and still asks for a code when the second sign-in step is on).
pnpm user:set-password <email>is the backstop for a lost mailbox, a lost authenticator plus recovery codes (--reset-mfa), or a deployment with no email key set. - Email is optional. Set
RESEND_API_KEYandEMAIL_FROMwith a sending domain verified in Resend; leave them unset and nothing is sent, with every surface falling back to a stated alternative. Setting the key adds a sub-processor, which the security page lists.
Rollback: re-add DEMO_MODE=1, redeploy — back on the self-contained demo while Supabase keeps your data untouched.