The whole design, in writing
Learn AI system design by designing a prompt-to-app builder like Lovable. An interactive guide covering why rewriting a forty-file app on every change costs 20,000 tokens and 400 seconds, the brief that writes a plan before any code, a fixed starter kit, the patcher that sends a two-file change instead of the whole app, the live preview whose errors feed back to the model, the data shelf with sign-in and numbered migrations, the ship button with versions and rollback, and the lock check that stops a stranger reading every customer.
Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.
The big idea
"Design a prompt-to-app builder" — why is this even hard?
You type one sentence — a booking page for my dog-walking business — and seconds later there is a page: real code, saved data, a link you can send. A model produced that by writing text, in small pieces called tokens. Say the app is forty files at 500 tokens each. That is 20,000 tokens, and at about 50 tokens a second that is 400 seconds. And tomorrow you will want to change the button.
Never pay that twice. Write a plan first, start from a kit that already runs, send small patches that touch only the files a change needs, run the app and feed its errors back to the model, keep the data and every version, and check the locks before the link goes public.
What the new pieces do
- Userclient
- The person typing. Their sentence — “a booking page for my dog-walking business” — is the only input; everything else is the builder deciding how to turn it into a running app.
- Builder Modelmodel
- The model that writes the plan, the code and the patches. It writes about 50 tokens a second, so how much it must write per change is the whole design problem.
Step 1 · The brief
Write the plan before the program
The sentence is fuzzy: how many pages? What data? Who may see what? If the model guesses and writes all forty files, a wrong guess costs a 20,000-token rewrite. What should happen before any code exists?
What should the builder do first with the sentence?
A wrong guess is then a 20,000-token, 400-second rewrite, and the user has nothing to correct but code.
That stalls the very thing a prompt-to-app tool sells: a page in seconds. Make a sensible plan and let the user change it.
The plan is a few lines, so being wrong costs one sentence, not a rewrite. Three pages, two tables, one rule.
The Brief: from the sentence, three pages (browse walkers, book a slot, my bookings), two tables, and one rule (see only your own). It is readable, and changeable, before anything runs.
Why this piece earns its place
A plan is the cheapest place to be wrong. Changing “two tables” to “three” costs a few words; changing the same decision after forty files exist costs a rewrite. The brief also gives every later part something to agree on: the kit knows which pages to fill, the data shelf knows which tables to create, and the lock check knows which rule was promised and can later ask whether it was kept. The trade is real and worth saying out loud: an extra step before any code appears. The design bet is that a short wait for a plan is worth more than a fast first guess, because the plan is what lets every later edit stay small.
- 3pages
- 2tables
- 1rule
What the new pieces do
- Briefplan
- A short plan written from the sentence: pages, tables and who may do what. Cheap to read and cheap to change, because nothing is running yet.
Step 2 · The kit
A starter that already runs
The model has to write real code. If it chooses its own language, tools and folder layout for every app, every app is a new house with new ways to fail. What should it start from?
What should the model write code into?
Every app becomes a new, untested combination, and the model has to invent where everything lives.
A model that has seen a stack a million times knows where the button lives, and the first page is already on screen.
Some of those it will know well and some it will not. A fixed set trades reach for reliability.
The Starter Kit: one fixed stack — same language, same page tools, same folders — already running in the preview. The model fills in rooms, it does not build a house.
Why this piece earns its place
A fixed stack is a bet on familiarity. The model has read enormous amounts of code in common tools, so inside that set it is predictable: it knows where a page lives, how a button is styled, how a component is imported. The kit also means there is never an empty state; the user sees a running page immediately, and every later change is an edit to something real. The cost is honest: no exotic tools, whatever the user asked for. A builder that can do anything is a builder that fails in a hundred new ways; one that does one stack well fails in a few ways it has learned to handle. Fix the stack so that the rest of the design can be small.
- 1fixed stack
- 0empty states
- samefolders every time
What the new pieces do
- Starter Kitstore
- A fixed starter project: same language, page tools and folders every time. The model fills in its rooms instead of inventing a house.
Step 3 · The patcher
A patch, not a rewrite
The app runs. You type: make the button blue. The obvious build sends all forty files and gets all forty back: 20,000 tokens, 400 seconds. And any of those forty files might change when it should not. What should the model send instead?
How should a change be expressed?
Two files, 1,000 tokens, 20 seconds: 20× less. And if the old text no longer matches, the patch is refused rather than applied blindly.
It costs 20,000 tokens and 400 seconds, and every file written is another chance to change something unasked for.
That hands the work back to the person. The builder’s job is to make the change.
The Patcher: a patch names the file, the old text and the new text. A project map opens only 2 files. 1,000 tokens, 20 seconds, 20× less — and about 2% chance of an unrelated change against about 33%. If the old text no longer matches, it is refused.
Why this piece earns its place
There are two savings and they are different. The first is cost: write what you changed, not what you kept. The second is risk, and it is the subtler one. Suppose each file written has a 1% chance of an unintended change. Rewrite forty and the chance that at least one moves is 1 − 0.99⁴⁰, about 33%; write two and it is about 2%. So a patch is not only cheaper, it is safer, because the files you did not write cannot be altered. The refusal rule is the part that makes this robust: a patch states what it expects to find, and if the file has since changed, the match fails and the builder reads the file again rather than overwriting someone’s work. A patch that can be refused is a patch you can trust when it is accepted.
- 1,000tokens, not 20,000
- 20 snot 400 s
- 2%vs 33% surprise
What the new pieces do
- Patcherservice
- Turns a change into a patch that names the file, the old text and the new text. A project map means only the touched files are opened, and a patch is refused if the old text no longer matches.
Step 4 · The preview
The page runs, and talks back
You ask: show each walker’s free slots. The model writes a patch, and the page turns red. But the model never saw the screen, so it never saw the error. How does it find out?
How should the builder find out the code is broken?
Then the user is the test suite, and every error costs a human round trip.
The model gets the same error you would have pasted, writes a repair patch, and the loop stops at three tries.
A model reading its own code tends to agree with it. Running it is the only real test.
The Live Preview runs the app in a Sandbox, a sealed room. The error is written down and flows back to the model as if the user had pasted it, a repair patch follows, and the loop is capped at 3 tries. Then it stops and asks you.
Why this piece earns its place
Feeding errors back closes a loop that would otherwise have a human in it. The model is no longer guessing whether its code works; it is told, in text, exactly what failed. The sandbox matters twice. It lets generated code run without being able to reach anything that matters, and it makes a crash a message rather than an incident. The loop itself needs a limit, because a model that cannot fix an error will happily try again forever, spending tokens and the user’s time on the same red page. Three tries is a design choice, not a magic number: enough to fix the ordinary typo-class errors, few enough that a genuinely stuck build hands the problem to a person quickly, with the error attached.
- 0people in the loop
- 3tries, then ask
- sealedsandbox
What the new pieces do
- Live Previewservice
- The app running live beside the chat. Its errors are written down and sent back to the model, which writes a repair patch — capped at three tries.
- Sandboxexec
- Where the generated code actually runs, sealed off from everything else, so a crash or a bad program cannot reach anything that matters.
Step 5 · The data shelf
A page that remembers
The page runs and looks right. You book a walk, reload, and the booking is gone. A booking page that forgets bookings is only a drawing. Where do bookings live, and who is allowed to make them?
Where should the app’s data and users live?
Memory in a page disappears on reload and is never shared with anyone else.
Data mixed into code means every booking is a code change, and it gets overwritten by the next patch.
Real tables survive a reload, a sign-in says who is who, and a migration replays in order.
The Data Shelf: a hosted database with tables, like spreadsheets, and a sign-in. Each change to the tables is a numbered migration, so it replays in order. Book a walk, reload, and it is still there.
Why this piece earns its place
Hosting the data buys a real database with no setup, which is most of what makes a generated app a real app rather than a demo. The numbered migration is the quiet part. A change to the tables is a small, ordered, replayable step, so the database can be rebuilt from nothing and an edit to the schema is something the history can show and roll back, exactly like a code patch. The sign-in is what makes “my bookings” mean anything, and it also sets up the final step: once the page can tell users apart, the question of who may read which row becomes a rule you can state. The cost is a dependency: the app now relies on someone else’s service staying up and staying affordable.
- tableslike spreadsheets
- 1sign-in
- numberedmigrations
What the new pieces do
- Data Shelfstore
- A hosted database with tables, like spreadsheets, and a sign-in. Every change to the tables is a numbered migration, so it replays in order.
Step 6 · The ship button
Every change is a version
The model edits confidently and is sometimes wrong. Version four breaks the page. And once it works, the user needs a link to send to a first customer, and a copy of the files they actually own. What does the builder keep?
What should happen to each change the model makes?
One bad edit then has no way back except asking the model to fix its own mistake.
Any edit can be undone, the user owns the files, and one click gives a link.
That puts the burden of history on the person, and people forget.
The Ship Button: every patch is a numbered version. Version four breaks the page; one click and you are back on version three. The files can be copied to a code host so you own them, and one more click gives a public address.
Why this piece earns its place
Versions turn a confident but sometimes wrong editor into something safe to use. The history is cheap because each version is a patch, not a full copy of forty files, and a rollback is just choosing an earlier point. Exporting to a code host is a statement about ownership: the user is not locked into the builder, and can take the project somewhere else. The public address is the last gesture and the one that changes the risk. Until now the app was private: a preview only its author could see. A link to a first customer makes it public by design, which is exactly why the build is not finished when the ship button works.
- 1click to roll back
- v3the one before v4
- 1public address
What the new pieces do
- Ship Buttonservice
- Every patch is saved as a numbered version, one click rolls back, the files can be copied to a code host, and one more click gives a public address.
Step 7 · The lock check
The hidden slot: who can open the link?
Six of six parts are built, the page works, bookings save, the link is public. A stranger opens it and then the browser’s developer tools. Everything the page can fetch, they can fetch. And the customers table has no lock. What is the slot you only find when the app goes live?
The app works perfectly and the link is public. What must you check before sharing it?
A page is public by design. Row rules say who may read each row, and secret keys belong on a server.
Speed matters, but a fast page that leaks every customer is still a leak.
A model writes what works, not what is safe. An open table works perfectly and exposes everything.
The Lock Check: row rules on every table, so you see only your own rows and so does the page’s key; secret keys on a server, never in the page; and a check of what the finished app can fetch before the link is shared, not after.
Why this piece earns its place
The failure here is not a crash, and that is what makes it the interesting one. The app works perfectly. A model writes what works rather than what is safe, and an open table is the simplest thing that works. Every earlier part was about writing less or seeing more; this one is about asking who. The page runs in a stranger’s browser, so anything it can fetch, they can fetch, and anything in the page, including a secret key, is theirs to read. The remedy is dull and effective: rules attached to the rows themselves, a server for anything secret, and a habit of looking at what the published app can actually reach before the link goes out. It also closes the loop with the brief, which promised one rule: see only your own.
- every tablegets row rules
- 0secret keys in the page
- beforethe link, not after
What the new pieces do
- Lock Checkgate
- The hidden seventh slot. A published link is public by design, so every table needs row rules and every secret key belongs on a server, never in the page.
The payoff
You designed a prompt-to-app builder
From “ask for the whole app” to a build ladder: a brief that plans before code, a fixed kit that already runs, a patcher that changes only what you asked, a preview that catches errors while running, a data shelf that remembers, a ship button with versions, and a lock check, because anyone with the link can open it.
Now rewrite the whole app and watch twenty thousand tokens go by, let the repair loop run with no cap, then publish a table with no lock. Those three are the whole trade-off: writing less buys speed and safety, and every part has a price.
Everything you assembled, in order
- Brief — a plan from the sentence: pages, tables, a rule
- Starter kit — a fixed stack that already runs
- Patcher — file + old text + new text; 1,000 not 20,000 tokens
- Live preview — runs in a sandbox; errors fed back; max 3 tries
- Data shelf — hosted database, sign-in, numbered migrations
- Ship button — numbered versions, rollback, code host, public link
- Lock check — row rules on every table; secret keys on a server
- The numbers — 20,000 → 1,000 tokens · 400 → 20 s · 33% → 2% surprise
