Vibe-Coded App in Production: Launch It or Fix It
How to run a vibe-coded app in production: check access, data, payments, backups and ownership, then decide whether to launch, hold or repair it.
You built something that works. A quote form, a booking flow, a customer portal, a small internal tool. It came together in a weekend with Lovable, Replit, Bolt or Cursor and did the job you needed.
Now there are two questions. Is it ready to run in production, with real customers and real data? And if it is already live and behaving badly, can it be repaired?
Both are answered with evidence. Production readiness is not a feeling about the demo, and one failure is not proof that the whole app is worthless. The tests below support a launch, hold or repair decision, and then the choice between repairing it, rebuilding part of it or starting again.
The decision: launch, hold or repair
Apply the checks that match your app. Mark payments as inapplicable if it does not take money, and assess access and recovery against the accounts and stored data it actually has. Write down why a check does not apply.
| Decision | Evidence that supports it |
|---|---|
| Launch | Ownership, deploy and rollback are in your hands; the two-account access test refuses the wrong request; writes survive a reload; a test payment and a repeated webhook leave the correct state; a restore has been proved; alerts reach a named person |
| Hold | Any of those checks is missing or failing, especially access control, an exposed secret key or an unproven restore. A hold is a dated list of blockers, with the app kept to test users until they clear |
| Repair | The app is live or in use, faults are reproducible, and ownership and the access model are sound enough to work with |
Holding an app back is a normal engineering decision. It is not a verdict on the idea. Launching with a known access-control hole is the choice that costs customers.
None of this certifies an app as safe. The tests show that named checks were performed on a particular version. They cannot prove the absence of a defect that was not looked for.
Two different things people call an AI app
If an AI tool wrote the code and the app does not call a model when it runs, you have an ordinary web application. Review it as software: permissions, data, money, recovery. The fact that a model wrote parts of it changes how you check dependencies and tests, which is covered below. It does not change what production needs.
If the app sends data to a model while people use it, you have two systems to review: the application, and the model-dependent part inside it. Prompts, retrieved documents, tool calls, cost limits and output quality need their own evidence. Our AI proof of concept to production guide covers that second review. This article covers the first, plus the parts they share.
What production ownership requires
Before launch, establish whether you can operate the app without the person or tool that generated it. Write the answers down.
- The source code in a repository you own, with its history.
- Accounts for the repository host, hosting, database, domain name and email sender in your name.
- The ability to deploy a change yourself, from a clean clone.
- A rollback you have used at least once, back to the previous release.
- Database access and a schema dump you can keep.
- A list of every third-party service the app uses, and what each one does.
- The names of the environment variables and where each value is stored.
- A named person who receives alerts and can act on them.
Exporting code gives you a copy. It does not give you the database, the signed-in users, the uploaded files, the DNS records or the deployment credentials. A platform that hosts your backend may let you export the front end and keep the data. Find out which side of that line you are on before you plan a launch or a repair.
Production also needs a change process. Decide who can deploy, who reviews a change, how a release is announced and what happens out of hours. A small app can be run by one person, but the arrangement should be written down, agreed and checked.
Get one failure to reproduce
Fixing starts with a failure you can repeat. "It is unreliable" is a feeling. A reproduction records the steps and conditions that expose the wrong result. Intermittent failures also need logs and correlation identifiers; they remain real faults even when the same steps sometimes succeed.
Record the account, device and time, what you did, what you expected and what happened. Add a screenshot of the wrong state and any error text or request identifier the page shows. If the app has logs, note the entry for that request.
Then narrow it. Does it happen for one user or all of them? On mobile only? After a specific action? With a particular record? The smallest case that still fails is the one to fix, and it becomes the test that proves the repair.
Test access with two accounts
Broken access control is the failure that ends trust fastest, because one customer can read or change another's data. Do not launch until you have tested it. Do not test it against a real customer's account either.
- Create two test accounts you own, in an environment you own, with one record each.
- Sign in as the first account and note the identifier of your own record. In a private window, sign in as the second account and note that record's identifier.
- Using the first account's session, request the second account's record through both the page and the API. The request must be refused unless the agreed permission rules allow it. Repeat in the other direction and test signed-out access.
- Open the admin screens with the ordinary account.
- Look at what the database itself allows, including the rules that apply to signed-in users.
Hiding a button changes the screen. Calling the API directly shows what the server permits. The database check matters because some apps enforce access in the client and leave the data open.
Create records you can delete. A test that copies live personal data into a staging database has moved the problem rather than solved it.
OWASP's authorization guidance sets the standard to test against: deny by default, check permission on every request, and write unit and integration tests for the authorization logic itself.
If your app talks to Postgres through a hosted API, some of that logic lives in the database. Supabase's row level security guide is blunt about the default: a table in an exposed schema without row level security is readable and writable by any role that has a grant, and adding policies does not remove existing grants. Check the grants as well as the policies.
Find out what is public
Any value built into the browser bundle is public. Build tools publish variables with a public prefix, such as NEXT_PUBLIC_ in Next.js or VITE_ in Vite. Anyone can read them in the delivered JavaScript, so a public prefix marks a value as visible, never as safe.
That is not automatically a problem. A publishable API key is designed to be seen and reaches only what your database rules allow. For Supabase, secret/service-role keys have privileged access and must remain on the server. For other providers, check the actual key privileges; a private credential never belongs in the public bundle. Supabase's API key guidance makes the split explicit; check the current key types and privileges in your own project.
Two practical checks:
- Search the repository history and the deployed bundle for key-shaped strings, not just the current code.
- If a private or privileged credential has been exposed in client code, a public repository or a shared chat, revoke or rotate it through the provider and review its use. A deliberately public client key also needs correct access policies; its presence alone is not a secret leak. Deleting the line does not unshare the value.
An exposed secret key creates a hold. Rotate it first, then continue the review.
Check that writes survive
A screen that updates is not the same as a record that exists. Walk through the basics with a test account:
- Create a record, reload the page, open it on a second device.
- Submit the same form twice quickly.
- Interrupt the connection mid-save, then retry.
- Enter invalid data, including empty and overlong values.
- Delete something and confirm it is gone after a reload.
The failures are usually one of four: the interface shows success before the save finishes, validation exists only in the browser, retries create duplicate rows because nothing enforces uniqueness, or the write depends on the browser keeping state that a refresh discards.
Server-side validation and database constraints are the durable fix. A disabled button helps the user. It does not control the server.
Payments, webhooks and retries
Money deserves its own pass. The question is what proves a payment, and where that proof is stored.
Confirm payment on the server using the provider's supported verification flow. A browser success page alone does not prove payment. For a webhook integration, verify its signature and bind it to the expected order, amount, currency and payment state. Record processing durably so a retry cannot repeat the business action.
Webhooks arrive more than once, out of order and sometimes late. A handler that is safe to run repeatedly, keyed on the event identifier, prevents the second delivery from creating a second order, a second email or a second refund. Recording an event identifier alone is not enough: couple that record to the business state change atomically, and handle unfinished work safely. Different event IDs can also describe the same order. Test order-level transitions and fulfilment as well as duplicate event delivery.
Then reconcile. Compare the payment provider's report with your own records on a schedule, and show the differences to someone. Test all of this in the provider's test mode with test keys before taking a live card.
Prove a backup restores
A backup that has never been restored is a hypothesis. Find out what is actually backed up and how far back it goes:
- The database, including the tables the app writes to every day.
- Uploaded files, which often live in a separate storage service.
- Authentication users and their identifiers, since records usually reference them.
- Configuration and secrets, which a database backup may not include.
Restore into a separate project. Check a record within the agreed backup recovery point, a file download and a sign-in. Record the recoverable point in time and the data that would be lost; restoring an older backup cannot recover later writes. Keep an export you hold yourself, in case the provider account is the thing you lose. Record the date and the result of the restore so the next person does not have to guess.
Monitoring and dependency risk
You need to learn about failures before your customers tell you. Add error tracking and an uptime check, then make sure an alert reaches a named person and that the app records enough to answer "what happened to this order" without storing more personal data than the job needs.
Dependencies need a separate look, because AI-assisted code has two specific habits. It suggests packages that do not exist, which attackers register as lookalikes, and it suggests versions that were current when the model was trained, which may since have known vulnerabilities. OWASP's secure coding with AI guidance covers both, along with tests that pass without asserting anything. Confirm each package exists and is maintained, pin versions, keep a lockfile and run an audit as part of the build.
Generated code also tends to leave configuration files that steer later generation. Treat those files as code, review changes to them, and keep them out of reach of anyone who should not be directing the build.
Repair, selective rebuild or full rewrite
Once the tests have produced a fault list, the decision comes from evidence. Write it down before anyone quotes for the work.
| What you found | Sensible first move |
|---|---|
| A handful of local defects, with sound ownership and access control | Repair in place, with a test around each defect |
| Access control, the data model or payments are unsound while the rest works | Rebuild that subsystem behind the existing interface |
| The code cannot be obtained, run or deployed by anyone you can hire | Rebuild in stages, with the old system still serving users |
| A secret key was exposed and provider records are unclear | Contain first: rotate, revoke, then decide |
| The code is unfamiliar, undocumented and untested | Map the important flows and add representative checks before deciding what needs repair or replacement |
Repair is usually the cheapest route when the foundation is sound, because it keeps behaviour that already works and was never documented. A selective rebuild contains risk to one part. A full rewrite is the most expensive option and the one most likely to lose details your customers rely on, so it needs the clearest evidence and a staged switch with a migration, reconciliation and fallback plan suited to the data and integrations.
No responsible supplier can price a rebuild from a screenshot. An estimate needs the code, the schema, the integrations and the deployment, and it arrives after an assessment. The same applies to dates.
A pre-launch checklist you can inspect
This illustrative list is not a guarantee that a system is safe. Adapt it, and use it to ask for evidence rather than assurances.
| Area | Evidence to ask for |
|---|---|
| Ownership | Repository, hosting, database, domain and deploy access in your accounts, and a build from a clean clone |
| Rollback | A tested return to the previous release, with what happens to data written since |
| Reproduction | A written failing case, with a test that fails before the fix and passes after it |
| Access | Two owned test accounts cannot reach each other's records through the page, the API or the database |
| Public values | Bundle and repository checked; only publishable values present; exposed keys rotated |
| Data | Create, edit and delete survive a reload and a second device; duplicates and invalid input are refused |
| Payments | A test payment, a repeated webhook and an abandoned checkout each leave the correct state |
| Recovery | A restore into a separate environment recovers records to the agreed point in time, a stored file and a sign-in |
| Monitoring | A forced error appears in the tracker and reaches the named owner |
| Dependencies | A lockfile, a dependency audit and no unverified packages |
Passing a checklist like this shows that the named checks were performed. It is not a security certification, and it cannot prove the absence of defects that were not looked for.
What a repair should leave you with
- A repository you control, with history, and a build that runs from a clean clone.
- Tests for each reproduced failure and for the access rules, using your own fixtures.
- Schema changes under version control, applied by a repeatable migration.
- An environment variable inventory, with a record of any secret rotation.
- Backup and restore evidence, with dates and what was included.
- A deployment and rollback runbook, monitoring, and an owner for each alert.
- A written list of what was fixed, what was found and left, and what could not be determined.
Ask for that list in writing. A supplier who cannot describe the limits of their own review has not finished it.
What to send safely
You can get a useful first opinion without handing over live credentials or customer records:
- The stack: which builder, hosting, database and payment provider.
- Redacted screenshots, error text, request identifiers and approximate times.
- A schema dump with no rows, or a synthetic dataset you invented.
- A reproduction on a throwaway account with test data.
- A read-only repository invite, if you want someone to look before committing to anything.
Keep live keys, customer records, card details and personal data out of ordinary email, chat and web forms. Share access through a secret manager, or through a scoped invite you control and can revoke afterwards. If someone asks for a production key in a message, ask for a read-only alternative and a reason.
Where we fit
At Revitt we take on software other people built. Inovar had lost the code behind software its customers used every day, and we rebuilt it and took it live without disruption. Oldham Engineering had an ageing bespoke system that was slow and risky to change, and we modernised it in staged blocks, then helped the business hire the person who now owns it. Neither was an AI-generated app and we do not present them as one. They are evidence of taking responsibility for code we did not write, which is the relevant part.
Our development service covers defined engineering work alongside your team. Legacy software modernisation covers staged change when the existing system is the constraint.
If you want a second opinion before launch or after a failure, book a call. Bring the stack, one reproducible failure and a note of what you can access. We will say what can be determined from that, what needs deeper access, and which of launch, hold, repair or rebuild the evidence supports. That conversation does not certify the app, and it cannot price work that has not been scoped.