If you read Issue #154, you know my take on when to stop vibing and start architecting. This is the companion piece: the actual stack I'm running, and the decision tree for which layer goes where.
The premise: the model is fastest when it's writing code that has obvious shape. The model is slowest, and gets things wrong most often, when it's writing code where the shape is ambiguous. So the right stack is one where the layers have shape baked in. You don't ask the model to invent the architecture. You hand it scaffolding that already has the architecture, and let it move within the lines.
The four layers
01
★ Frontend & Scaffolding
Lovable
Initial build. Schema sketch, screens, auth wiring, the live URL. First three hours of any greenfield project — this is where I am. Cursor or v0 work the same way; Lovable is what I default to because the deploy is free and the schema editor doesn't make me hand-write SQL when I'm validating an idea.
02
★ Data & Backend
Supabase (Postgres + row-level security)
Every app that has more than one user lives on Postgres with RLS turned on from day one. Lovable Cloud abstracts this, which is good for prototyping and bad for the day you need to actually understand what's running. By app three or four I usually drop into Supabase Studio directly and write the policies myself. Two of the six rebuilds in Q2 were "I should have written the RLS first" rebuilds.
03
★ Edge & Side Effects
Cloudflare Workers (or Supabase Edge Functions)
Anything that has to be reliable. Form submissions. Webhooks. Anything that touches a payment API, an email API, or a third-party CRM. The model is happy to write fire-and-forget code that silently drops half your work (see
Issue #152). The edge layer is where I'm
least willing to vibe code and
most willing to spend an extra 20 minutes writing the contract by hand.
04
★ The Layer Most Operators Skip
The contract file (.md, in repo, next to the code)
A plain-text document that says — for each entity, each workflow, each integration — what the inputs are, what the outputs are, what's allowed to fail, and how to retry. The model reads this. You read this. New collaborators read this. When you go back to the codebase three weeks later and try to remember why a function returns an array of strings instead of a single object, the contract file is the thing that saves you. This is the layer everyone vibe-coding their way to production skips. It is the single highest-leverage 20 minutes you'll spend in any project.
The escape-hatch decision tree
The hard question isn't which tool do I use — it's when do I stop using the vibe-coding tool and switch to deterministic code. Here's how I decide.
★ Keep vibing
- You're prototyping a screen that doesn't exist yet
- The bug is visual or layout-related
- The change is < 50 lines and isolated to one file
- The data shape isn't changing — you're just rendering differently
- You can describe the desired state in one sentence
- The model fixed it correctly the last two times you prompted
★ Escape to Cursor / direct edit
- You've prompted the same fix three times and it's still almost-working
- The bug crosses three or more files and the model keeps missing one
- You're about to write something that has to handle money, identity, or sensitive data
- You can't describe the desired state in one sentence — it depends on context the model can't see
- The fix involves a database migration or RLS policy change
- You're an hour into the loop and you've made it worse, not better
What the receipts say (per layer)
★ Layer 1 · Lovable
14/14 apps started here
Every app in this quarter's batch started as a Lovable build. Average time-to-first-deployed-URL: 22 minutes. That number is the entire reason the stack starts here. Nothing else comes close.
★ Layer 2 · Supabase RLS
2 rebuilds traceable to "should have written RLS first"
In both cases the app worked fine for one user. Multi-tenant correctness was an afterthought patched in at hour four. The patch worked for the demo and broke at customer #3. Lesson: if the app has orgs, the RLS goes in before the second screen.
★ Layer 3 · Edge / Workers
3 silent-failure bugs caught in Q2
Two were the fire-and-forget pattern from
Issue #152. One was a missing idempotency key (
Issue #149) that double-charged on retry. All three would have been caught at architecture time, not at fix time, if the contract file had been written first.
★ Layer 4 · Contract files
8/14 apps had one · the other 6 are the rebuilds
The correlation is too clean to be coincidence. Eight apps had a contract file written before the second prompt. Those eight shipped without architectural rebuilds. The six that didn't have one — every single one needed work past hour four. Contract files take twenty minutes to write. They pay for themselves before the first compile.
The shape of a contract file
For anyone who wants to steal this: a contract file is not a spec doc. It's not "what the product should do." It's what each function and integration promises and is allowed to break. Three sections per entity:
- Inputs. What this thing accepts. What's required. What's optional. Defaults.
- Outputs. What this thing returns. Success shape. Failure shape. What "no result" looks like.
- Failure contract. What's allowed to fail silently (nothing, usually). What has to retry. What has to be idempotent. What has to be server-authoritative.
That's it. One sheet per entity, in plain markdown. Drop it in /docs/contracts/. Reference it in your Lovable prompts. The model gets dramatically better when it has the contract in scope, because the architecture is no longer something it has to guess.
The compounding insight
Every layer in this stack exists to make the next prompt land better. Lovable gives you the screen. Supabase gives you the data shape. Workers give you the reliability boundary. The contract file gives the model the architecture it would otherwise have to invent. When all four are aligned, vibe coding is the highest-leverage tool in the operator toolbox. When any layer is missing — usually layer four — vibe coding becomes the tax I wrote about in Issue #154.
You don't have to pick between vibe and deterministic. You pick the right layer for the right job, and you let the layers compound.
★ TL;DR · the stack in one breath
Lovable for the screen. Supabase + RLS for the data. Workers for anything reliable. A contract file for everything the model can't see. Write layer four first. The other three pay for themselves.