Key takeaways
- Your Lovable app works in the preview because nothing is attacking it, paying through it, or depending on it. Production is a different sport.
- The three launch-blocking fixes: Row Level Security on every table, secrets moved off the client, and auth verified on the server.
- Step zero most founders skip: get the code into Git you own and stop letting prompts overwrite your hand-written security fixes.
- The 48-hour launch sequence — redirect URLs, webhook targets, env parity, migrations on prod — is where AI-built apps most often break on day one.
- If more than a few of these fail, pause growth spend and harden first. That is what our rescue audits are for.
You prompted your way to a working app. The demo looked great. Someone asked when it launches, and a quiet worry crept in: is this thing actually safe to put real users and real money through?
Good instinct. AI builders like Lovable, v0, and Bolt are excellent at shipping a working prototype and terrible at the boring production work that keeps you out of trouble. The gap between "works in preview" and "production-ready" is not one big rewrite. It is a stack of small, unglamorous fixes nobody prompted the AI to make.
This is the exact audit we run at Lynxwell on every AI-built app before we call it ready. We have done this enough times to know where the bodies are buried.
What the AI builder did for you — and what it skipped
Be fair to the tool: it gave you UI, flows, and a working database in days instead of months. That is real value. But it optimized for the demo, not for strangers. Here is the honest ledger:
| The AI builder did this | Production needs this instead |
|---|---|
| Generated a database with tables | Row Level Security policies on every table, tested user-vs-user |
| Wired up a login screen | Verified signups, expiring sessions, server-side identity checks |
| Pasted API keys where they were needed | Secrets in server env vars only, never in the browser bundle |
| Connected Stripe | Webhook signature verification, idempotent handlers, refund paths |
| Deployed to a preview URL | Staging and production environments with env parity and real DNS/SSL |
| Fetched data for one user | Indexed, paginated queries that survive 100 users at once |
None of this means your app is bad. It means it is unfinished in exactly the ways AI builders always leave things unfinished.
Step zero: stop letting the AI undo your fixes
This is the step no ranking checklist covers, and it is the one that burns founders first.
Here is what happens: you (or an engineer) hand-write proper security fixes — RLS policies, a server-side payment route, rate limiting. Then you go back to the builder, prompt "add a dark mode toggle," and the AI cheerfully regenerates files and overwrites your fixes. You are now less secure than before you started, and nothing tells you.
Fix this before you fix anything else:
- Get the code into a Git repo you own. Not just the builder's cloud — GitHub or GitLab, under your account. If you cannot clone it and deploy it without the builder, you do not own your product.
- Make Git the source of truth. Security-sensitive files get edited by hand (or by your engineer) in the repo. The builder's chat becomes a UI-and-copy assistant, not the codebase owner.
- Separate environments. Preview, staging, production — separate projects, separate databases. Migrations run against staging first, then production. Never test a schema change on the live database.
- Write down how to run it. If a new engineer cannot clone, install, and deploy in under an hour, your "production" setup is one laptop failure away from a crisis.
The most expensive bug in AI-built apps is not a bug at all. It is a workflow: every prompt is a chance for the builder to quietly revert the security work you already paid for.
The security pass: the part that keeps you out of headlines
A December 2025 audit by HackNope, cited across the industry, found that 10.3% of Lovable apps had data-exposure vulnerabilities. A separate 2025 audit found 170 of 1,645 Lovable apps shipping live vulnerabilities, with missing or misconfigured Row Level Security the most common cause. These are not exotic attacks. They are missing guardrails.
Run these in order:
- Turn on Row Level Security on every table with user data. With RLS off, your database trusts the browser — any logged-in user can request any row. Write policies so a user can only read and change their own rows, then prove it: log in as user A in one browser and user B in another, and try to touch each other's data.
- Move every secret server-side. Open dev tools on your live site, search the built JavaScript for sk_live_, sk_test_, or anything labeled service or secret. If a key is in the bundle, it is public. Supabase URL and anon key are fine in the client by design — the anon key is only safe because RLS exists. Everything else goes behind a server route or edge function.
- Make auth real. Preview auth often accepts any email and never verifies anything. Production needs verified signups, sessions that expire (short-lived access tokens, longer refresh tokens), and — critically — the server reading identity from the verified session instead of trusting a user ID the browser sends it.
- Lock CORS to your domains. Prototypes ship with wildcards that let any website call your backend from a browser. Restrict it to your production domain and staging. Five minutes of work.
- Rate-limit anything that costs money. Signup, password reset, email sending, and any endpoint that calls a paid API. Without limits, one script can run up your bill in an afternoon.
Your anon key is in every visitor's browser by design. That is fine — but only if RLS is doing its job. Without RLS, the anon key is a master key to your database.
Payments: where demos become liabilities
The builder connected Stripe. It did not build you a payments system. There is a difference, and the difference is where money gets lost.
- Verify webhook signatures. Your webhook endpoint must confirm each event actually came from Stripe (via constructEvent or your provider's equivalent). Without this, anyone can POST fake "payment succeeded" events to your app and get the product for free.
- Make webhooks idempotent. Stripe retries events. If your handler creates two orders for one payment because it ran twice, you have a reconciliation mess. Guard with the event ID.
- Re-point everything at production. Preview webhooks aimed at a preview URL do not fire on your real domain. This is the single most common "payments worked in testing" failure we see.
- Build the refund path before you need it. If you cannot issue a refund without touching the database by hand, you are not ready to take money.
The 48-hour launch sequence
This is the unglamorous checklist that decides whether launch day is boring (good) or a fire drill. Do it in this order, about two days before real users arrive:
- OAuth redirect URLs: update every provider (Google, GitHub, etc.) from localhost and preview URLs to your production domain. Login breaking on launch morning is a classic.
- Webhook targets: confirm Stripe and every other webhook points at production, and fire a test event end to end.
- Environment parity: list every env var the app needs, and confirm each exists in production with production values. AI builders are notorious for env vars that lived in the preview and never traveled.
- Migrations on prod: run your database migrations against the production database explicitly, then verify the schema matches. Never assume the builder did this.
- DNS and SSL: confirm the certificate is valid on the real domain and there are no mixed-content warnings.
- Backups — and one restore: confirm automated backups exist, then actually restore one to a scratch database. A backup you have never restored is a hope, not a backup.
- Error tracking and uptime: wire up error monitoring and an uptime check that alerts a human — not an inbox nobody reads.
- One full pass as a stranger: sign up, pay, break things, reset your password, all on production, from a browser that has never seen your app.
Launch day failures are never mysterious in hindsight. They are always a URL that still said localhost, a webhook aimed at a preview, or a migration that never ran. Boring causes, boring prevention.
What breaks at 100 users
Your app works for one user: you. At a hundred simultaneous users, a different set of problems appears, and they are almost all database problems.
- Missing indexes. The queries that were instant on 200 rows crawl on 200,000. Index the columns you filter and sort by. Cheap to add now, painful later.
- Unbounded queries. If any screen loads "all records" with no pagination, it will freeze the moment real data arrives. Paginate every list.
- Silent failures. When a call fails in production, the user sees a frozen screen and you see nothing — unless you added real error handling that shows the user a clear message and logs what happened on the server.
- No visibility. You cannot fix what you cannot see. Uptime checks and error tracking are not enterprise luxuries; they are how you learn your app is down before your customers tell you.
You do not need caching layers, read replicas, or a bigger server on day one. You need clean queries and eyes on the system. Scale problems at this stage are discipline problems, not infrastructure problems.
What to fix yourself vs. what needs an engineer
Honest split. Some of this is an afternoon's work for a confident builder; some of it is where DIY becomes risky.
| Fix yourself in an afternoon | Get an engineer |
|---|---|
| Search the built bundle for leaked keys | Write and adversarially test RLS policies |
| Turn on email verification | Move secrets server-side and reroute the calls |
| Lock CORS to your domains | Harden sessions and server-side auth checks |
| Update OAuth redirect and webhook URLs | Make webhooks idempotent and refunds safe |
| Add pagination to long lists | Set up CI, error tracking, and the indexing strategy |
If the security column makes you nervous, trust that instinct. Getting data isolation wrong is the kind of mistake that stays invisible until it is a headline.
When to stop prompting and get help
There is a point where more prompts stop helping. If your checklist fails on security or ownership — RLS you cannot verify, secrets you cannot fully trace, no repo you own — another round of "fix the auth" in the builder chat is not the move. You need an engineer to do a proper hardening pass, lock the fixes into Git, and hand you back something you can keep building on safely.
That hardening pass is exactly what our AI app rescue service does: we take Lovable, Bolt, and v0 apps, run the full production audit, close the gaps, and return a codebase you own outright. If you want to see how we think about this work, browse our services — or just get a second pair of eyes on what you built.
Start with our free site audit — send us the app and we will tell you what is actually broken, no pitch attached. Or book a call and we will walk through the checklist against your app together.