When the demo meets real users
Your AI-built app works. Then it doesn't.
Lovable, Bolt and v0 get you to something real in an afternoon, and that is not a trick — the screens are genuinely there. What follows are the five things that break first when actual people start using it, why each one happens, and how to fix it. Several of them you can do yourself this week.
Free 1-minute fit check · no equity · no retainer
Before anything else
None of this means you were wrong to build it that way. Getting to a working screen fast is the right first move, and the product decisions you made along the way are the expensive part — they survive all of this. What breaks is plumbing, and plumbing is quick to redo once the decisions exist.
01
Anyone can read anyone else's data
- What you see
- Nothing looks wrong. The screens show each person their own rows, because the query filters by user id.
- Why it happens
- The filter lives in the page, not in the database. Change the id in the URL, or call the API directly, and the rows come back. AI builders generate the filter in the query because that is what makes the screen correct, and the screen is what you asked for.
- The fix
- Turn on row-level security and write a policy per table, then try to break it on purpose: sign in as A and fetch B's row. If it comes back, the policy is not doing what you think. This is the one test that should block a release.
Fixable yourself, and worth doing today even if you change nothing else.
02
Two people act at once and the data goes wrong
- What you see
- Two bookings for the same slot. Stock going negative. A counter that drifts. Rare at first, constant once you have users in different time zones.
- Why it happens
- The code reads a value, decides, and writes it back. Between the read and the write, somebody else did the same. On a demo with one user this never happens. With twenty it happens weekly.
- The fix
- Do the check and the write in one statement, or take a lock on the row inside a transaction. A unique constraint in the database is often the whole fix, and it is five minutes of work.
Fixable yourself if you know which write is the dangerous one. Finding it is the hard part.
03
Money moves and the app does not notice
- What you see
- Somebody pays and stays on 'pending'. Or a card is declined and they keep access. Support email starts with 'I already paid'.
- Why it happens
- The app updates its own state on the success page instead of listening to the payment provider. If the customer closes the tab, the page never runs. Webhooks are the boring, invisible half and they get skipped.
- The fix
- Treat the provider's webhook as the only source of truth, and make the handler safe to run twice — the same event will arrive twice sooner or later. Never decide anything on the redirect.
Fixable yourself. Tedious, not difficult.
04
It gets slow at a number of rows that is not impressive
- What you see
- Fine with your test data. Crawls at a few thousand rows. Everyone assumes it needs a bigger server.
- Why it happens
- Missing indexes, and queries inside loops. A list screen that runs one extra query per row is invisible with ten rows and fatal with two thousand.
- The fix
- Turn on slow query logging and look at the worst one. Usually it is one missing index and one loop. It is almost never the server.
Fixable yourself, and cheaper than the upgrade you were about to buy.
05
Nobody can tell you what it is supposed to do
- What you see
- A change breaks something unrelated. Two people disagree about how it 'always worked'. Nobody wants to touch the part that runs payroll.
- Why it happens
- Prompting your way to an app leaves no written statement of intent. The code is the only record of what was decided, and code cannot tell you what was deliberate and what was an accident.
- The fix
- Write down, per screen, what must be true after each action. That list is what tests get written from, and it is what makes the next change safe. It is also most of what a build specification is.
This is the one that compounds. Everything above gets worse while this is missing.
The order to do them in
Access rules first. Always.
Slow pages annoy people. A customer reading another customer's data is the one you do not recover from, and it is the failure that gives you no warning at all — everything looks correct right up until somebody notices. If you only do one thing from this page, do number one, and try to break it yourself afterwards.
If you would rather not
What we would do with it.
We rebuild the layer underneath and keep the product you already designed: the access rules enforced in the database, the writes made safe, payments driven by webhooks, and a written statement of what every screen must do — which is what stops the next change from breaking the last one.
If you want to see the shape of that before spending anything, run your product through the generator: it comes back with the data model, who is allowed to read which row, and the places a product like yours tends to break. Free, no email.
Questions
What people ask us about this.
Is the app I built with an AI builder worth keeping?
Usually the screens are. What normally has to be rebuilt is the data layer: access rules, the shape of the tables and the places where two users can collide. That is where AI builders take shortcuts that only show up under real use.
Can I fix these myself?
Several of them, yes, and this page says how. Access rules enforced in the database and race conditions on writes are the two that most often need somebody who has done it before, because the failure is silent until it is not.
Do I have to start over?
Almost never. The product decisions you made are the expensive part and they survive. What gets rebuilt is plumbing, and plumbing is fast when the decisions are already made.
Next step
Find out if your idea fits in 10 working days.
Tell us what you want to build. We reply the same day with a straight yes, no, or here is what we would cut.