---
title: "Vibe-Coded App Production Checklist (Lovable, Bolt, v0)"
description: "A vibe coding production checklist for apps built with Lovable, Bolt, v0 or Cursor: exposed keys, Supabase RLS, payments, tests, backups and GDPR."
canonical_url: "https://liviu.dev/blog/7/vibe-coded-app-production-checklist"
---

> Index of every page on this site: [llms.txt](https://liviu.dev/llms.txt)

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:

```bash
# 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:

```sql
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:

```bash
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.

<table>
<thead>
  <tr>
    <th>
      Area
    </th>
    
    <th>
      Usually refactor
    </th>
    
    <th>
      Consider a rebuild
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Security
    </td>
    
    <td>
      Loose policies, but every row records its owner
    </td>
    
    <td>
      Ownership isn't modelled; roles live in the front end
    </td>
  </tr>
  
  <tr>
    <td>
      Data model
    </td>
    
    <td>
      Naming, missing constraints, duplicated columns
    </td>
    
    <td>
      The business needs teams, but everything belongs to one user
    </td>
  </tr>
  
  <tr>
    <td>
      Code
    </td>
    
    <td>
      Duplicated components and scattered queries
    </td>
    
    <td>
      Every change breaks something else
    </td>
  </tr>
  
  <tr>
    <td>
      Payments
    </td>
    
    <td>
      Missing signature checks or duplicate handling
    </td>
    
    <td>
      Payment state is decided in the browser
    </td>
  </tr>
</tbody>
</table>

If an audit lands in the right-hand column, [SaaS & MVP development](https://liviu.dev/services/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](https://liviu.dev/blog/10/nuxt-2-vue-2-to-nuxt-4-migration).

## 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](https://liviu.dev/services/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](https://liviu.dev/services/maintenance-support) keeps the app stable, and if you want it usable from ChatGPT or Claude, see [building an MCP server for your SaaS](https://liviu.dev/blog/8/mcp-server-for-saas-chatgpt-claude).

Send me a link to the app and what it was built with through [the hire me page](https://liviu.dev/hire-me), 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](https://liviu.dev/services/ai-prototype-to-production) 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.

## Sitemap

See the full [sitemap](https://liviu.dev/sitemap.md) for all pages.
