Vibe coding to production: what has to change before real customers use the app
Vibe coding means describing what you want to an AI tool and accepting the code it writes, usually judging the result by running it rather than reading it. That is a sound way to find out whether an idea is worth building. It is not a sound way to hold customer data or run a team's day, because nobody has yet decided who may see what, and nobody has read the code that enforces it. This article lists what has to change before real users arrive, in the order the failures tend to cost money, and says when to harden what you have and when to rewrite it.
By Saveez IrfanUpdated
In short
- A prototype proves the idea works for the person who built it. Production has to survive strangers, mistakes and the builder being away. That is a different job, and often different code.
- Start with who can see and change what. Authentication says who someone is; authorisation says what they may touch. Hiding a button is not authorisation. The rule has to be enforced where the data lives.
- Keep secrets on the server, rotate any key that has ever been pasted into a chat, a screenshot or a commit, and put access rules in the database (row-level security on Postgres or Supabase), not only in the screens.
- Test the money and permission paths before anything else: charge, refund, change a role, read someone else's data, delete. Coverage figures matter far less than those five.
- Harden if you can explain where each permission is enforced and the data model is sound. Rewrite the data and permission layer if you cannot, and keep the prototype as the specification.
- Before launch, make sure you can restore a backup, go back to the last good version, and cap what a stranger can spend through your AI and API keys.
What is vibe coding, and is it the problem?
Vibe coding is building software by telling an AI tool what you want (Cursor, Lovable, Bolt, Claude Code and similar) and accepting what it produces, judging the result by running it rather than reading the code. The term is also used loosely for any AI-assisted coding. Here it means the narrower sense: the code is accepted without being understood.
It is not the problem. It is a fast, cheap way to learn whether people want the thing, and a working prototype is a better specification than any document. The problem is the gap it leaves: unread code, rules nobody decided, and no record of why anything is the way it is. Even the vendor-side guidance says the user carries that responsibility. Claude Code's own security page states that you are responsible for reviewing proposed code and commands for safety before approval. The tools help you write the code; they do not take over the reading.
Nothing below depends on which tool wrote the app. It depends on what the app now has to do.
Why is a working prototype not a production app?
A prototype is judged by whether it works for its author on a good day. A production app is judged by what happens on a bad day, to someone who is not the author. Almost every item on the checklist further down is one row of this table turned into a task.
| Prototype | Production | |
|---|---|---|
| Users | You and a friendly few | Strangers, some careless and a few hostile |
| Data | Test data you can recreate | Real personal or financial data you cannot recreate and may be legally responsible for |
| Failure | You notice and restart it | It fails at night, and a customer or a bill tells you |
| Change | Edit the live copy until it works | Changes are reviewed, tested and reversible |
| Cost | Free tiers and pennies | Usage-based bills that grow with abuse as well as with use |
| Ownership | A chat history only the author remembers | Someone who can explain how it works, and accounts you own |
What has to change before real customers use it?
Ten areas, ordered roughly by how expensive the failure is. Each row names the question to answer and the evidence that it is answered. 'It seems to work' is not evidence.
| Area | The question to answer | Evidence it is done |
|---|---|---|
| Authentication and authorisation | What stops user A reading or changing user B's data? | Two test accounts fail to reach each other's records through the API directly, not only through the screens |
| Secrets and environment variables | Which keys exist, where do they live, and could a visitor see any? | No secret in the browser bundle or the repository history; separate keys for test and live; a rotation done once |
| Database access rules | Who can read and write each table, and where is that enforced? | Row-level security on every table that holds user data, with policies read by a person and tested with real roles |
| Input validation | What happens when the input is wrong, huge or hostile? | Server-side validation against a schema; uploads limited by type and size; webhooks verified |
| Error handling and logging | When something fails, who finds out, and can you tell what happened? | Errors reach a person; sensitive actions leave a record of who did what; no secrets or personal data in logs |
| Backups | If the database is damaged tonight, what do you lose? | A restore performed into a scratch copy, with the result checked |
| Dependencies and licences | What is the app built from, and may you ship it? | A reviewed package list, a committed lockfile, a vulnerability scan, and the licences of direct dependencies recorded |
| Tests for money and permission paths | Which five failures would hurt most, and does a test fail when each happens? | Tests whose expected outcomes a person wrote or approved, running on every change |
| Deployment and rollback | How does a change reach customers, and how do you undo it? | Separate staging and live environments; deploys from version control; a rehearsed way back |
| Cost limits on AI and API calls | What is the most a single visitor, bug or loop can spend? | Server-side keys, per-user limits, provider spend caps where offered, and an alert |
Authentication and authorisation
Use a managed sign-in provider rather than hand-built login code, and check the dull parts: password reset, session expiry, email verification, what an administrator is and how someone becomes one. An admin flag that the browser sends and the server trusts is not a role.
Authorisation is where AI-built apps most often fail, because the screen looks right. A button that is hidden for ordinary users protects nothing if the endpoint behind it answers anyone who asks. The test is quick: sign in as two different users, copy a request for one user's record from the browser's network panel, and replay it as the other. If it succeeds, you have found the first thing to fix.
Secrets and environment variables
In most front-end frameworks, variables with a public prefix are compiled into the code sent to every visitor, so check the name of each one before you decide it is safe. Anything that can spend money or read all the data belongs on the server only. Treat a key as burned if it has ever been pasted into a chat with an AI tool, shown in a screenshot or committed to version control, because deleting the commit does not delete it from history. Rotate it, use separate keys for test and live, and turn on secret scanning in your code host if it offers it.
Database access rules
Many AI-built apps use a hosted Postgres such as Supabase, where the browser talks to the database through an automatically generated interface using a public key. In that design the access policies are the only barrier between a visitor and every row, so a table without row-level security, or with a policy that allows everything, is open. The privileged service key bypasses those policies and must never reach the browser. Supabase's own documentation is the authority on the details and it changes, so confirm them for your own project rather than relying on this paragraph.
Read every policy. The quickest fix for a permission error is to loosen the rule, and a tool aiming at 'it works now' can do exactly that, so search for policies that are simply true. Write select, insert, update and delete separately, and test them as an anonymous visitor, as an ordinary user, and as an administrator. On the school ERP we built, row-level security policies carry both role and branch, so a branch administrator's queries return their branch's rows regardless of which screen asked. On the consent-scoped health app, per-category sharing is enforced in the database, not the interface. The principle is the same in both: the interface reflects the rules, and the database enforces them.
Input validation
Validate on the server, against a schema, whatever the form already checks in the browser. Never assemble database queries by joining strings. Decide where uploaded files go, who can open them, and whether the storage bucket is public. Verify the signature on any incoming webhook, or anyone can post fake payment confirmations to you. Rate-limit sign-up, login and every endpoint that sends email or calls a model.
Error handling and logging
Search the code for empty catch blocks and for errors that are logged and then ignored. A failure that is swallowed is worse than a crash, because nothing tells you. Users should see a plain message and never a stack trace, and a person should be told about the real error. For anything sensitive, such as changing a role, issuing a refund or exporting data, keep a record of who did it and when. On the trading ERP we built, every write appends a field-level entry to an audit table that staff can add to but never edit, so the trail cannot be rewritten through the API. Keep secrets and personal data out of the logs themselves.
Backups
A backup you have never restored is a hope. Find out what your database plan includes, how far back it goes and how to restore, then do a restore into a scratch copy and check the result. Keep the code in version control in an account you own, not only inside the AI tool's workspace, and keep a separate export of anything customers upload.
Dependencies and licences
AI tools add packages freely. List what the app depends on, remove what it does not use, commit the lockfile and run your package manager's vulnerability audit. Check that each package is the one you think it is: a name the tool mistyped or invented can be registered by someone else. Record the licences of the direct dependencies, because some constrain how you may distribute a commercial product, and read the AI tool's own terms on who owns what it generates. If either matters to your business, ask a lawyer; this article is not legal advice.
Tests for the money and permission paths
Do not chase a coverage figure. Pick the handful of failures that would hurt most: charging the wrong amount, a refund that does not reverse, a user promoted without approval, one customer reading another's records, data deleted that should not be. Write those tests first, and run them against a real database where you can. State the expected outcome in plain English before any code, because tests the tool writes to match its own code will pass whether or not the code is right.
Deployment and rollback
Give staging and live their own database and their own keys, and deploy from version control through a repeatable step instead of editing the only copy. Know how to go back to the last good version, and rehearse it once when nothing is on fire. Database changes are the hard part of rolling back, so apply them to a copy first and keep them small. For anything that acts on its own, such as sending messages or moving orders, run it in a mode that records what it would have done before you let it do it. We used that shadow-mode approach on the fleet order automation before go-live.
Cost limits on AI and API calls
An unauthenticated endpoint that calls a model is a public line of credit. Keep the key on the server, require sign-in, set a per-user limit, cap the length and number of calls per request, and set a spend cap and an alert at the provider if one is offered. If the app runs an agent in a loop, cap the steps. Our article on AI agents for operations covers cost control in more depth. We do not quote prices here, because they change; use the provider's current published rates for your own estimate.
Should you harden the app or rewrite it?
Ask one question: can someone other than the AI tool explain where each permission is enforced? If yes, harden. If the honest answer is 'somewhere in the screens, probably', the data and permission layer needs rewriting, and that usually costs less than finding every gap in code nobody understands.
| If this is true | Then |
|---|---|
| The data model maps to real things (customers, orders, jobs) and the tables are related sensibly | Harden. A sound schema is the expensive part to get right |
| Sign-in uses a managed provider and access rules sit in the database | Harden. Fix the policies, add tests, add the missing operations |
| The app runs locally from a README, in separate files that a developer recognises | Harden. It can be reviewed and changed by a person |
| Permissions are checked only in the interface, or the same logic is copied in many places | Rewrite the permission layer, and keep the screens |
| The schema is duplicated, unrelated or stores the same fact in several places | Rewrite the data layer, migrate the data, keep the flows |
| It cannot run outside the tool that generated it, or nobody can say how it is deployed | Rebuild the delivery path first; decide on the code after reading it |
| It is an internal tool for a few colleagues with non-sensitive data behind your company sign-in | Keep it, with the minimum below |
The middle route is often the right one. Keep the prototype as the specification, because its screens and flows are what users reacted to, and rebuild the layer beneath them. That is the reverse of a classic rewrite, which throws away what was learned.
For a small internal tool, the minimum is still real: sign-in in front of it, secrets off the client, a backup you have restored, and the code in an account you own. The rest of the checklist scales with how bad a leak or a wrong number would be.
What does a review and handover look like?
- 01Read-only access first: the repository, the database schema and policies, the deployment settings and a list of third-party accounts. No access to live customer data and no ability to change anything.
- 02A map of what the app does, who uses it, what data it holds and what a failure would cost. The consequences set the priorities.
- 03Findings ranked by consequence, each pointing to a file or a policy and showing how to reproduce it. A finding nobody can reproduce is an opinion.
- 04A decision on harden, rewrite part, or rewrite, with the reasons written down.
- 05The fixes that block launch, tests on the money and permission paths, a staging environment, deployment from version control, restored backups and spend caps.
- 06A handover: the repository, hosting and database accounts in your name, and a short runbook covering how to deploy, roll back, rotate a key and restore a backup, plus a list of known gaps.
A review is not a penetration test, a certification or legal advice, and it cannot make an app compliant with data-protection or financial rules on its own. Apps that handle health or payment data need specialist assessment on top. The same applies to anything the review did not look at, which the handover should list.
Our own track record: the closest published example is the materials marketplace, an app first generated on an AI app builder that we audited and moved onto its own database. It was a migration, not a measured before-and-after, so treat this checklist as a method. It rests on the controls in systems we wrote and reviewed by hand, such as the school ERP, the trading ERP and the fleet order automation, and on the reading of vendor documentation we cite below. Our vibe-coding-to-production page describes the review we offer; our custom development page covers a full rebuild.
Common questions
Not as it stands, and not because AI wrote it. Nobody has yet shown that one user cannot reach another's data, that no key is exposed, that a backup restores, or that spend is capped. Work through the checklist, and expect the access rules to need the most attention.
Access control. The screens look right, but the endpoint or database table behind them answers anyone who asks. Exposed keys come second. Both can be tested with two accounts and a look at the browser's network panel.
Often only part of it. If the data model is sound and permissions are enforced in the database, harden it. If permissions live only in the interface or the schema is tangled, rebuild that layer and keep the screens as the specification. Read the code before deciding.
It is a Postgres feature that decides, per row, which signed-in user can read or change it. If your app lets the browser reach the database directly, as many Supabase apps do, you need it on every table holding user data, with policies a person has read and tested.
It depends on the tool's terms and the law where you are, so read the terms and ask a lawyer if it matters to you. Whatever the answer, keep the repository and the hosting accounts in your own name so you are never locked out.
It depends on what the review finds, so we will not quote a timeline in the abstract. A small internal tool with sound foundations is a short job; a customer-facing app with tangled permissions is closer to a rebuild of one layer. We quote after reading the code.
Sources
Statements about what a platform does are checked against the vendor’s own documentation as of 2026-10-10. Vendors change things, so check the current page before you rely on a limit or a price.
- Security · Anthropic
Drafted with AI assistance (Claude). Published under Saveez Irfan’s name, who is accountable for it. Editorial policy