Deploy to Vercel
Production is mostly an env-parity problem.
The most common mistake is getting Vercel, Clerk, Convex, and Stripe individually “working” while the cross-system values still drift.
Before the first deploy
Prepare production values in your hosting dashboards and provider dashboards. Mirror the same categories you use locally and verify they match across systems:
- Clerk publishable and secret keys
- Clerk frontend API URL
- Convex client URL (
NEXT_PUBLIC_CONVEX_URL) - Convex HTTP-actions URL (
NEXT_PUBLIC_CONVEX_SITE_URL) when the deployment serves HTTP actions on.convex.site - any deployment values your Convex environment writes
- Stripe secret key, product id, price id
- live
STRIPE_WEBHOOK_SECRET APP_BASE_URLOBSERVABILITY_INGEST_TOKENOBSERVABILITY_INCIDENT_CONTROL_TOKENCLERK_WEBHOOK_SIGNING_SECRETOBSERVABILITY_VERCEL_WEBHOOK_SECRETTELEGRAM_BOT_TOKENTELEGRAM_CHAT_ID
Vercel checklist
- deploy as a normal Next.js app
- keep the project linked to
ParkerRex/mma-shipbysunday - keep Vercel’s production branch on
main - let Preview continue to handle unassigned git branches such as
devand feature branches - keep the package manager pinned to the repo version
- use real production Clerk env values
- use real production Stripe live keys
- if the app uses observability or any other Convex HTTP actions, set
NEXT_PUBLIC_CONVEX_SITE_URLto the matching.convex.sitehost
Do not make Vercel responsible for production Convex deploys in this repo. The frontend should build on Vercel, but Convex production promotion now happens from GitHub Actions on main through .github/workflows/convex-production-deploy.yml.
CONVEX_DEPLOY_KEY belongs in GitHub repository secrets for that workflow, not in the Vercel project.
Convex checklist
Convex production must match the same production auth and Stripe values used by the app.
Do not leave Convex pointed at:
- an old Clerk instance
- a dev Clerk instance
- an outdated Stripe webhook secret
- a mismatched Stripe secret key
- a deployment that does not have the current
observabilityfunctions pushed
Post-deploy verification
After a release merge to main, confirm all of this with a real test flow:
- signed-out visitor hits a protected route and is pushed to sign-in
- signed-in user without access reaches
/startand sees inline recovery - live checkout returns to
/checkout/success - webhook grants access
- newly granted user reaches
/start - signed Clerk and Vercel observability webhooks persist incidents and deliver Telegram packets
- the public incident status route can
acka live incident and keep repeat delivery suppressed - Vercel attributes the production web deploy to
main - GitHub Actions reports a matching
Convex Production Deployrun for the same release
Use the QA control-plane command for the authenticated production pass:
PLAYWRIGHT_BASE_URL=https://www.man-meets-ai.com QA_ENV_FILE=apps/web/.env.production bun run qa:run-pack -- --pack=default_shipThat command assumes:
qa/personas.local.jsoncontains the real QA account emails and passwords- the file referenced by
QA_ENV_FILEcontains the production Clerk and Convex env values - the production Clerk instance matches the target site
If persona prep fails with a Clerk publishable-key mismatch, stop there. That means the loaded env file does not match the production site, so any later authenticated browser result would be invalid.
What success looks like
Production is healthy when payment, access, route protection, observability, and deployment provenance all agree on the same release. In this repo that means the web app came from Vercel main, the backend came from the Convex production workflow on main, and both use the same production env values.
If payment completes but access does not, debug env parity before you rewrite application code.