Security
Generate new JWT RSA key pair
Change default admin credentials
Admin123! to something secure. Do not skip this — the default password is the same for every scaffolded project.Verify ENVIRONMENT=Production
Confirm Swagger is not accessible
https://api.yourdomain.com/swagger — it should return 404, not the Swagger UI.Verify HTTPS is configured
- HTTP requests should redirect to HTTPS
- SSL certificate is valid (not self-signed in production)
- HSTS header is present:
Strict-Transport-Security: max-age=31536000
Verify no secrets are in code or config files
Stripe
Switch to live Stripe keys
STRIPE_SECRET_KEY must start with sk_live_, not sk_test_. Check in your environment variables.Webhook endpoint is registered in Stripe Dashboard
All five required events are selected
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_failedinvoice.payment_succeeded
Webhook signing secret is the live endpoint secret
STRIPE_WEBHOOK_SECRET must start with whsec_ and come from the live endpoint, not from the Stripe CLI. The CLI secret and the Dashboard endpoint secret are different values.Complete a real test checkout
Sending domain is verified in Resend
EMAIL_FROM_ADDRESS uses your verified domain
noreply@yourdomain.com or similar. Not onboarding@resend.dev.Send a test email and check deliverability
Database
Migrations applied to production database
No pending migrations. when complete.Seed data applied
make seed or the equivalent command against the production database once.Database backups are configured
pg_dump via cron.OAuth
Production redirect URIs configured in Google Cloud Console
https://api.yourdomain.com/api/v1/auth/google/callback. Not localhost.Production callback URL configured in GitHub OAuth App
https://api.yourdomain.com/api/v1/auth/github/callback. Not localhost.Frontend
VITE_API_URL points to production API URL
https://api.yourdomain.com, not http://localhost:5000.Frontend build uses production environment variables
VITE_API_URL=https://api.yourdomain.com npm run build. Verify the built JavaScript files do not contain localhost.Notifications and Redis
Redis is running and accessible