Demo vs production: what your vibe-coded app is missing
Your Lovable / Bolt / Cursor / Replit / v0 build looks great in the preview link. Shipping it to paying users is a different product. This checklist is about gaps we see between “works in the demo” and “won’t lose people’s data or money.” It is not a certification checklist and it does not replace a full security review.
1. Identity that survives a refresh
- Sign-up / login works on the production domain, not only
localhostor the builder preview URL. - Auth redirect URLs and site URL settings include that production domain.
- A second browser (or incognito) cannot see the first user’s private screens without signing in.
- Password reset and magic-link emails arrive from a domain you control (or you accept the provider’s defaults knowingly).
2. Data rules, not “demo trust”
- Every table with user content has row-level security on (and forced) if you use Supabase or similar.
- No
using (true)“enable all access” policies left from the scaffold. - Anonymous visitors get empty results on private tables; user A cannot read user B’s rows.
- File storage buckets are not public unless the files are meant to be public.
See: Supabase RLS for Lovable apps.
3. Secrets that never board the browser
- Server secrets live in the host’s env / secret store — not in
VITE_…(or equivalent) client env vars. - Production bundles have been grepped for
sk_live_,sk_test_, andservice_roleJWTs. - Anything that ever leaked is rotated, not just deleted from the repo.
See: Remove leaked VITE_ keys and the free scanner.
4. Money path you can explain
- Stripe (or other processor) is in live mode only when you intend to charge real cards.
- Checkout success does not trust the browser alone — a verified webhook updates order state on the server.
- Webhook signing secret is set in production env; forged test posts are rejected.
- Refund / failed-payment paths do not leave “paid” flags stuck on.
See: Stripe webhook signature verification.
5. Deploy, domain, and config
- App is on a host you can redeploy from git (not only “publish” from a chat session you might lose).
- Custom domain + HTTPS;
wwwand apex both behave (redirect or serve, on purpose). - Production env vars are set in the host dashboard; build-time vs runtime vars are understood.
- Database migrations are applied to production (dashboard clicks alone are easy to forget).
6. Operations when something breaks
- You can restore from a backup or point-in-time recovery for the database.
- You know who has admin access (Supabase, Stripe, GitHub, DNS) and can revoke a contractor.
- Error tracking or at least access to host logs — “it failed for one user” is diagnosable.
- A simple status plan: how you tell users if checkout or login is down.
7. Legal and product basics (still not legal advice)
- Privacy and terms pages that match what you actually collect and who operates the app.
- A support email that you read.
- Clear pricing and cancellation if you charge subscriptions.
Demo-ready vs production-ready (honest bar)
| Area | Often fine in a demo | Needed before real users / payments |
|---|---|---|
| Auth | Works in preview | Production URLs, session isolation |
| Database | Seed data, open RLS | RLS + verified isolation |
| Keys | Whatever the AI pasted | No secrets in the client; rotated if leaked |
| Payments | Test card screenshots | Live mode + verified webhooks |
| Hosting | Builder URL | Your domain, env, migrations, rollback |
| Ops | Restart the preview | Backups, access control, logs |
If several rows still look like the left column, fix those before marketing a launch — or book a Rescue / Launch Kit for a scoped fix with a verification report. The report covers only the checks we list at delivery; it is not a promise the whole internet cannot break your app.