Today the public surface (landing, docs, in-app quickstart) is live, but signup
is gated: SIGNUP_ALLOWLIST lets only known emails/domains create accounts. The
landing reads as open ("Sign up" CTA, no waitlist) — the allowlist enforces
server-side. The page being open and signup being open are deliberately separate.
Opening signup is the final, manual step, and it's gated on three things being true. Do them together — flipping one without the others ships a hole.
- Enforcement is live (PRD-B). The counter actually blocks Free past the limit and bills Pro overage on Stripe Meters. Verify a Free project is refused past 1,000 MTU and a Pro project records overage. Without this, an open signup hands out unmetered usage.
- Live Stripe keys. Swap
STRIPE_SECRET_KEY/STRIPE_PUBLIC_KEY/STRIPE_PRICE_PRO/STRIPE_WEBHOOK_SECRETfromsk_test_…to live values (dashboard env). Re-create the webhook endpoint against live mode and confirmcheckout.session.completed+customer.subscription.*reach/api/stripe/webhook. Run one real upgrade end-to-end. - Email verification on. Set
requireEmailVerification: trueinapps/dashboard/lib/auth.ts(currentlyfalse). Requires thebismite.devsender domain verified in Resend and a confirmed delivery test — otherwise new users can't verify and are locked out.
Once the gates pass:
- Clear the allowlist — unset
SIGNUP_ALLOWLISTin the dashboard prod env (empty/unset ⇒ open, persignupAllowedinapps/dashboard/lib/auth.ts). requireEmailVerification: truecommitted and deployed.- Live Stripe keys set in prod env.
- Deploy (
vercel --prod) and run prod DB migrations. - Smoke test from a fresh, non-allowlisted email: sign up → verify email → create project → upgrade through Checkout → confirm the plan flips.
Re-set SIGNUP_ALLOWLIST to lock signup again. Sign-IN is never gated, so existing
users keep working regardless.