When Vibe Coding Breaks Down
The boundary between vibe-code-it and build-it-properly. What to notice on this side of the line — and what to expect in Project 2.
You will hit moments in Project 1 where Lovable simply cannot do what you want, or does it in a way that feels broken. These moments are the entire reason this project exists. They show you, in real time, where the ceiling is — and why Project 2 starts.
This page catalogues the most common ones.
Signal 1 — The Same Prompt, Different Results
You ask Lovable: "Add a 'Sign in' button to the navigation."
It adds it. You like it. You ask for an unrelated change to the footer.
Now there are two "Sign in" buttons, in different styles, in different places. Or the original one disappeared. Or the navigation regenerated and lost the order you carefully arranged.
What's happening: Lovable doesn't have stable identity for elements. Each prompt re-renders parts of the page from scratch, and the AI's idea of "the right place for Sign In" might drift.
In Project 2: every component has a file, a name, and a stable position in the code. Moving "Sign in" requires you to edit the file. It cannot drift on its own.
Signal 2 — You Need Exact Data Behaviour
You want the contact form to:
- Accept a name, email, child's grade, and message.
- Validate the email is real.
- Send an email to admissions@aurora-school.com.
- Show "Thanks, we'll be in touch within 2 business days" on success.
- Save the inquiry to a database so you can review submissions later.
You can describe this to Lovable. It might even generate code that looks like it does all five things. But:
- The validation might let through
notanemailbecause the regex is too loose. - The "email to admissions" code is there but no API key is configured, so it silently fails.
- The success message shows even when the email didn't send.
- There is no database — Lovable might fake one with localStorage, which loses data on every refresh.
What's happening: AI is excellent at the shape of code. It is unreliable at the exact wiring — API keys, environment variables, database schemas, network reliability. These are the things that break in production.
In Project 2: you wire each piece by hand (or with Claude Code's help, with you reviewing). You see the API key in .env. You see the validation Zod schema. You see the Supabase insert. If something breaks, you know where to look.
Signal 3 — The Codebase Becomes Hard to Reason About
By prompt 40, if you click "View code" in Lovable, you will likely see:
- Component files with 600+ lines because Lovable kept adding to one file rather than splitting.
- Three different ways the indigo colour is declared (
bg-indigo-700,#4338CA,bg-[#4338CA]). - Two unused components left over from earlier iterations.
- A
BranchesSectionV2.tsxnext to aBranchesSection.tsx, both used.
What's happening: Lovable optimises for what looks right in the preview, not for what is clean in the code. Three months later, when someone (or you) wants to change the indigo, you have to find and update all three places.
In Project 2: colours live in one place (Tailwind config). Components are small (under 200 lines). Removing a component means deleting its file. Code review — even self-review — becomes possible.
Signal 4 — You Want Two Pages to Share Something
You add the branches list to the home page. Looks great. Then you add a /branches page. Lovable rebuilds the branches list there. Now you have two definitions of the same branches. You update Powai's phone number on the home page; it stays old on /branches.
What's happening: Vibe coding tools don't naturally factor shared things into one source. Each prompt is local — the AI works on what's in front of it.
In Project 2: the branch list is a single TypeScript constant imported by both pages. Update once, both update.
Signal 5 — Real Users with Real Devices
You publish. You proudly send the URL to your spouse, who opens it on an iPhone. The hero photo overlaps the headline. The navigation menu is broken. The "Plan a Visit" button is hidden behind the keyboard.
What's happening: Lovable previews show desktop by default. It writes responsive code, but the responsive parts are often the first to break on real devices because the AI couldn't test them.
In Project 2: you'll use the same useIsMobile hook from the global standards, you'll resize the browser yourself, and you'll add explicit sm: and md: Tailwind breakpoints that you understand. The site looks right because you saw it look right.
Signal 6 — Something Needs to Change in Many Places at Once
The school decides to add a fourth branch — Vashi. You ask Lovable to add it.
- The home page gets a 4th card. Good.
- The
/branchespage still shows 3. You forgot to mention it. - The footer mentions "3 campuses across Mumbai." Still says 3.
- The hero copy says "spanning Andheri, Powai, and Thane." Still does.
- A photo gallery has 3 buildings. Still 3.
You spend 20 minutes prompt-by-prompt fixing each occurrence and you still miss something.
What's happening: There is no "branches" data anywhere — there is just prose mentioning the branches in 7 different places. Adding a branch is a 7-place edit.
In Project 2: there is a BRANCHES constant. You add { name: 'Vashi', ... } to the array. Every page that renders branches picks up the new one automatically. Even the footer count BRANCHES.length is correct without thinking about it.
This is the single biggest reason real projects need real code. Data should have one source.
Signal 7 — A Concept the AI Doesn't Understand
You ask: "Add Row Level Security to the database so only branch admins can see their own students."
Lovable might generate something. It will almost certainly be wrong, or just code that looks like RLS without enforcing anything.
What's happening: RLS is enforced at the Supabase / Postgres layer, not in front-end code. Lovable lives in the front-end world. It doesn't have the tools to set up RLS policies or test them.
In Project 3: you'll set RLS in Supabase directly. You'll test it with the RLS Shield playground from Phase 2. You'll know exactly which policy applies to which role. This is foundational for a real school system — no parent should see another child's records.
The Boundary, Stated Simply
Vibe coding is appropriate when all three of these are true:
- The output is mostly visual.
- There's no exact data correctness requirement.
- You can throw it away and rewrite later if needed.
Vibe coding is not appropriate when any of these is true:
- The thing must keep working in 2 years' time.
- There are real users entering real data that must be preserved.
- Money, security, or compliance is involved.
- Multiple people need to maintain the code.
A school brochure hits all three "vibe coding OK" criteria. A school system hits the "vibe coding not OK" criteria immediately.
What Project 2 Will Do Differently
The exact school landing site you built in Project 1 gets rebuilt in Project 2. Same content. Same look. But:
- You build it in VS Code, looking at real code, line by line.
- You use Next.js instead of Lovable — the same framework that powers Sahinov.com.
- You style with Tailwind CSS directly — same library Lovable uses under the hood, but you write the classes yourself.
- Photos live in a real
/publicfolder. - Pages are real files in a real
/appfolder. - The code goes to GitHub every time you commit.
- The site deploys to Vercel with a custom domain (or a free vercel.app URL).
- The contact form actually sends an email — via Resend, with the API key in
.env.
Project 2 will feel slower at first. You will type things Lovable would have generated. But by the end of Project 2, you will understand what is actually happening on the school website you already built once.
That understanding is the foundation for Project 3 — where you build the actual school system, not just the brochure.