Built your app with Lovable, Bolt or Cursor?

Vibe-Coded App Production Checklist (Lovable, Bolt, v0)

Vibe-Coded App Production Checklist (Lovable, Bolt, v0)

A vibe coding production checklist for apps built with Lovable, Bolt, v0 or Cursor: exposed keys, Supabase RLS, payments, tests, backups and GDPR.

Liviu Zachin

· 8 min read

You described an idea, an AI tool turned it into an app, and people are signing up. I'd never tell a founder to throw that away. But a working demo and a product that can safely hold other people's data are different things. Here's the checklist I use when someone hands me an app built with Lovable, Bolt, v0 or Cursor and asks whether it's ready.

What these tools give you, and what they don't

  • Lovable turns prompts into React and TypeScript apps, usually with Supabase for the database and auth.
  • Bolt.new, from StackBlitz, builds full-stack apps in the browser, with Bolt Cloud for hosting and a database.
  • v0, from Vercel, grew from a UI generator into a full-stack builder centred on Next.js.
  • Cursor is an AI code editor whose agents write, run and test code in your repository.

None of them know your business rules: who sees which rows, what counts as a paid order, what happens when a webhook arrives twice. And the platforms say whose job that is: Lovable disputes CVE-2025-48757 because each customer is responsible for their app's data, and Supabase leaves configuration to its customers. That's you.

Why "it works" isn't "it's ready"

In 2025, Matt Palmer scanned 1,645 apps from Lovable's public showcase and found 170, about 10%, with row-level security (RLS) settings that exposed 303 endpoints: names, emails, payment details, API keys. On one site the researchers could mark a payment as paid without going through Stripe.

In 2026, UpGuard checked around 300,000 domains that appear to use Supabase and found 16,326 databases with readable tables, more than half with signs of personal data. Their explanation: the Table Editor enables RLS by default, but tables created through the API, the way coding agents usually create them, don't get it.

And in Veracode's 2025 benchmark of over 100 language models, generated code introduced security flaws in 45% of test cases. AI output needs the review you'd give a junior developer's code, and usually nobody did it.

1. Security: secrets, RLS, auth and input

A slow app loses users; a leaky one can end the company.

Secrets and exposed keys

The Supabase publishable key (the old anon key) is meant to be public; RLS is all that limits it. The secret key (the old service_role key) bypasses RLS and must never reach a browser or the repository.

The trap is environment variables. Vite bundles anything prefixed VITE_ into client code, as do NEXT_PUBLIC_ and NUXT_PUBLIC_ in Next.js and Nuxt. An AI tool that "fixes" a permission error by moving the secret key behind one of those prefixes has just published it. I add a check like this to CI:

# Fail the build if a server-only secret reaches the client bundle
grep -rEq "sb_secret_|sk_live_|whsec_" dist/ && exit 1
grep -rEq "(VITE|NEXT_PUBLIC|NUXT_PUBLIC)_[A-Z_]*(SECRET|SERVICE_ROLE)" src/ .env* && exit 1

Rotate any key that ever sat in Git, because history keeps it. Supabase's move to new sb_publishable_ and sb_secret_ keys makes this a good moment.

Supabase row-level security

What I check on every project:

  • RLS enabled on every table in an exposed schema
  • separate policies per operation, scoped to authenticated where visitors have no business
  • with check on writes, so users can't create rows for someone else
  • no authorisation based on raw_user_meta_data, which users can edit
  • views with security_invoker = true, since by default they bypass RLS

A minimal owner-only table:

alter table public.invoices enable row level security;

create policy "Users read their own invoices"
  on public.invoices for select
  to authenticated
  using ((select auth.uid()) = user_id);

create policy "Users create their own invoices"
  on public.invoices for insert
  to authenticated
  with check ((select auth.uid()) = user_id);

-- Every policy filters on user_id, so index it
create index invoices_user_id_idx on public.invoices (user_id);

Supabase's Security Advisor and Lovable's pre-publish scan catch tables without RLS, but can't know that a team member may see invoices and not payroll. So I also test like an attacker, using the publishable key from the site's JavaScript:

curl "https://<project-ref>.supabase.co/rest/v1/profiles?select=*" \
  -H "apikey: <publishable key>"

If that returns rows while signed out, you have the CVE-2025-48757 problem. From 30 October 2026, new public tables in Supabase also aren't exposed to the API until you grant access, but grants aren't RLS: a broad grant on a table without RLS reopens the hole.

Authentication and sessions

  • Permission checks live on the server or in the database. Hiding the admin button protects nothing.
  • On the server, verify users with Supabase's getClaims() or getUser(), never getSession(), which isn't guaranteed to revalidate the token.
  • Reset and invitation links expire, and login is rate limited.

Input validation

Client-side validation is UX, not security. Validate the input of every API route and Edge Function against a schema (Zod or Valibot), and back it with database constraints. Check dangerouslySetInnerHTML and v-html on user content too: in Veracode's study, models failed to prevent cross-site scripting 86% of the time.

2. Data model and migrations

AI tools add a column whenever a prompt needs one, so I usually find duplicated fields, JSON blobs that should be tables and missing foreign keys.

  • Every row that belongs to someone has a user_id or team_id with a foreign key
  • Money is stored as integer cents or numeric, never float
  • Schema changes are migrations in Git, run on staging before production

3. Payments and webhooks

Never mark an order as paid because the browser reached a success page. Fulfil from a verified webhook.

  • Verify the Stripe-Signature header against the raw request body.
  • Record processed event IDs: Stripe can deliver an event more than once and doesn't guarantee order.
  • Return a 2xx quickly and queue the work. Stripe retries failed live deliveries for up to three days, which only helps if your handler is idempotent.

4. Errors, monitoring and backups

  • Error tracking (Sentry or similar) on front end and back end, with alerts that reach a person
  • Uptime checks on login and webhooks, and no passwords or tokens in logs
  • Backups you've restored at least once. Supabase Pro keeps seven days of daily backups (Point-in-Time Recovery costs extra), Free projects should export their own, and Storage files aren't included.

5. Tests

You don't need 90% coverage. You need tests on the flows that cost money when they break: sign-up, checkout through to access granted, and RLS per role (user A can't read user B's rows; pgTAP with supabase test db handles this). Run them in CI on every pull request, because a prompt to tweak the pricing page can quietly rewrite the auth logic.

6. Performance, hosting and cost control

  • Index the columns your queries and policies filter on, and paginate lists; generated code often fetches whole tables.
  • Run separate staging and production environments, with automated deploys from Git.
  • Set spending limits and billing alerts on hosting, Supabase and especially LLM APIs. An endpoint that calls an LLM needs auth and rate limits, or someone else spends your credits.

7. GDPR basics

With users in the EU or UK, the minimums (not legal advice) are:

  • a privacy policy that matches what the app collects and where data goes
  • data processing agreements with your database, hosting, email, analytics and AI providers
  • a way to export and delete a user's data
  • a breach plan: under Article 33, you report a personal data breach to the supervisory authority within 72 hours of becoming aware of it, unless it's unlikely to put people at risk

8. Maintainability of AI-generated code

The code usually works; it was just written across hundreds of prompts. Typical signs: three components doing the same thing differently, queries in every component, dead files and any types silencing errors. I move the code into a Git repository you own with review on every change, put data access in one layer, turn on strict TypeScript and a linter, and delete dead code.

Refactor or rebuild?

Usually neither extreme: keep what's sound, refactor what's risky, rebuild only what's wrong at the core.

AreaUsually refactorConsider a rebuild
SecurityLoose policies, but every row records its ownerOwnership isn't modelled; roles live in the front end
Data modelNaming, missing constraints, duplicated columnsThe business needs teams, but everything belongs to one user
CodeDuplicated components and scattered queriesEvery change breaks something else
PaymentsMissing signature checks or duplicate handlingPayment state is decided in the browser

If an audit lands in the right-hand column, SaaS & MVP development is the route, and the prototype becomes an excellent spec. The same reasoning applies to older codebases; see migrating from Nuxt 2 and Vue 2 to Nuxt 4.

The short checklist

  • No secrets in the client bundle or Git history
  • RLS on every exposed table, tested with the publishable key
  • Authorisation and validation on the server, not the UI
  • Migrations in Git, run on staging first
  • Payments fulfilled from verified, idempotent webhooks
  • Error alerts that reach a person
  • Backups restored at least once
  • Tests for sign-up, payments and RLS in CI
  • Spending limits on hosting, database and AI APIs
  • Privacy policy, processor agreements and data deletion

Need a second pair of eyes?

This is what my AI prototype to production service covers. I audit the code, database and hosting, about two working days for a typical prototype, and you get a written report ranked by risk, with a keep, refactor or rebuild call for each area. Critical security problems I flag straight away. The audit starts from €960 and includes a fixed-price plan for the fixes; you choose whether I do them, your team does, or we split the work, quoted per phase or billed at €480/day.

I use Claude Code and Cursor daily, so I won't talk you out of AI tools, just set things up so you can use them safely. Afterwards, maintenance and support keeps the app stable, and if you want it usable from ChatGPT or Claude, see building an MCP server for your SaaS.

Send me a link to the app and what it was built with through the hire me page, and I'll reply within one working day.

FAQ

Is a Lovable app secure enough for production?

It can be, but not by default. Lovable apps usually run on Supabase, so your data is only as safe as your row-level security policies. Test them with the publishable key, or have them audited, before real users arrive.

How do I check if my Supabase RLS policies actually work?

Fix every table the Security Advisor flags, then query each one through the REST API with the publishable key, signed out and as two different test users. To keep them working, add pgTAP tests with supabase test db for allowed and denied cases.

Should I fix my vibe-coded app or rebuild it from scratch?

Usually fix it. Most AI-built apps have a usable interface and problems that are cheaper to refactor than to rebuild. A rebuild makes sense when the data model or the security model is wrong at the core.

How much does it cost to make an AI-generated app production-ready?

It depends on what the audit finds. My audit starts from €960 and ends with a fixed-price plan for the fixes, so you know the full cost before committing. Later work is quoted per phase or billed at €480/day.

Can I keep using Lovable, Bolt or Cursor after the app goes live?

Yes, as long as every change goes through Git, review and tests before production. The AI tool proposes, and CI catches changes that break sign-up, payments or RLS.