Routiq Labs · Field Guide № 001Est. reading time. One honest coffee

You commented. This is the full plan.

Build it properly. the second time.

The skill isn't getting AI to write code anymore. It's knowing how to build it properly. Below: the five mistakes that quietly wreck AI-built apps, the six-stage plan that fixes them, and the exact books, talks and templates to steal. No theory. This is the system behind a real rebuild.

Daniel Welsh@danielwelsh_routiq9,354 commits · 4 apps · 1 rebuild

Part I. The damage

Five mistakes that wreck AI-built apps

Each one feels fine on the day. Each one compounds. How it shows up, why it happens, and the fix. With the receipt that says we're not guessing.

  1. 01

    GitHub as a save button

    Shows up asNo repo, or one giant “updates” commit a week. Then the AI breaks something and there's no yesterday to go back to.

    WhyAI makes code feel disposable — you can always “just ask again.” You can't. You get a different wrong answer.

    The fixRepo before the first prompt. Commit every working change, small. Branch before experiments. Git isn't backup — it's the undo button for AI mistakes.

    9,354 commits behind the clinic app. The habit is the receipt.

  2. 02

    Secrets in the code

    Shows up asAPI keys pasted into frontend files, or a committed .env. Scanners find hundreds of thousands of live keys on GitHub every month; one sweep of 20k+ indie launches found 11% exposing database credentials in the frontend.

    WhyThe AI optimises for “it works” — and pasting the key into the file works. Anything in the browser bundle is readable by anyone who opens dev tools.

    The fix.gitignore and .env before the first secret exists. .env.example for the shape. A secret scanner (gitleaks) on pre-commit, so a key physically can't get in. Server-only keys stay server-only.

    Confession: v1 shipped a committed encryption key. Fixing it is a pre-day-1 item of the rebuild plan. Not preaching — recovering.

  3. 03

    Everything in one file

    Shows up asThe 2,000-line page.tsx. The AI happily keeps appending until it can't safely edit its own file — and neither can you.

    WhyEvery prompt is “add X,” and adding in place is the path of least resistance. Nobody prompts “reorganise.”

    The fixThe folder skeleton before the first feature — AI reads structure and imitates it. Plus a file-size budget (600 lines) enforced as a check, so bloat bounces automatically.

    Confession: v1's front door was one 2,535-line function. The brain was 4,830. Nobody could read either — that's why there's a rebuild.

  4. 04

    The database is public and nobody checked

    Shows up asSupabase or Firebase with row-level security off — any user can read every row. A 2026 audit found 88% of vibe-coded apps had RLS entirely disabled; one incident confirmed 170+ production apps exposed.

    WhyThe app works without it. Nothing visibly breaks. Security that's invisible when missing never gets built.

    The fixRLS on from day one. An ownership policy per table. The two-account test before launch. The prompt that matters: “show me the exact rule that enforces ownership” — if the AI can't point to it, it doesn't exist.

    This one gets its own episode — “Your data might be public” is already in the series.

  5. 05

    Design as an afterthought

    Shows up asTwo flavours. Visually: every AI app looks identical, because the model defaults to the internet's average. Structurally: screens before deciding what the app is, so the data model changes weekly and every screen breaks.

    WhyThe demo looks 80% done in an hour, and the pretty parts are the fun parts. Both flavours are the same mistake: taste and scope were never written down, so the AI supplied defaults.

    The fixThe one page first — what it does, who it's for, what done means. A taste file of apps you love, so the AI copies your taste, not the average. Data model before screens; migrations as the truth.

    Stages 1 and 2 below exist because of this one.

Part II. The receipts

Same app. Two histories.

Two real repos of the same clinic booking app. One built the way the five mistakes build it, one built on the plan below. These are the props from the reel.

✗ the-mess✓ built-properly
History1 commit — “updates”, 9:47pm18 small commits + a merged feature branch
Biggest filepage.tsx — 2,535 linesevery file under the 600-line budget
Secrets.env committed, keys inside.env invisible to git status; .env.example holds the shape
DatabaseRLS disabled in schema.sqlRLS + ownership policy in migration 001
Versions“utils copy 2.js” · “final-final-v3.js”one utils — git holds the history
Dependenciesnode_modules committedlockfile only

▸ Both parse clean. Both run. Only one of them can still be changed safely.

Part III. The plan

The six stages

One question per stage. If you can answer it honestly, move on. Every stage carries one renowned book. The deep end, when you want it. Plus a companion.

Stage 1 of 6

The one page and the workspace

Could a stranger say what this app is?

Before any code: write one page — what it does, who it's for, what “done” means, what it will not do. Then the empty folder skeleton and CLAUDE.md, before the first feature prompt.

Folders
The skeleton is the first prompt — the AI reads structure and imitates it.
Tools
Git and GitHub from commit 1. .gitignore and .env.example before any secret exists.
Architecture
None yet, on purpose. The one-pager is the first architecture decision: scope.
Readability
CLAUDE.md written like onboarding notes for a new hire — it's how every future session inherits the project.

Stage 2 of 6

Rules the AI can't argue with

Can a bad commit physically get in?

Gates before features. Every push runs them; a failing check bounces the commit — the AI's included.

Folders
A CI workflow, lint and format config at root, one config file validating every env var at boot.
Tools
TypeScript strict. Linter and formatter. Test runner. Gitleaks on pre-commit. CI on every push. A 600-line file budget as a check.
Architecture
Fail-loud config: the app never half-boots.
Readability
The size budget is readability enforced mechanically — no file the AI can quietly bloat.

Stage 3 of 6

One core, thin edges

Does every integration have an exam and a mock?

Decide the boundaries before the features. One domain core. One adapter per outside service. Channels — web, API, phone — as thin shells over the same core.

Folders
src/core/ holds types and logic and imports no vendors. src/lib/ holds one adapter per service. Channels never import vendors directly.
Tools
A contract test suite per integration — the exam every adapter must pass — plus a mock adapter passing the same exam, so the AI iterates all day without touching anything real.
Architecture
Ports and adapters. One shared definition per noun. For AI features: the model picks the words, a table picks the outcomes.
Readability
The state table fits on one screen. An unreadable brain is unreviewable — and unsafe to let AI extend.

Stage 4 of 6

The smallest complete slice, with receipts

Can anything happen twice?

One user journey end-to-end — ugly but live. Then every action that touches the outside world gets a receipt before it happens.

Folders
The ledger-table migration lands with the first write path, not later.
Tools
Deploy pipeline from week one. Idempotency keys on every external write. A dead-letter path for failures.
Architecture
The walking skeleton kills integration risk first. Effects go through the ledger, so “it sent twice” is a constraint violation, not a code-review hope.
Readability
One job per module. After each slice, the AI explains its own diff as if to someone who didn't write it. Long explanation = wrong code.

Stage 5 of 6

Watch it — errors, usage, evals, a stranger

Does the system tell you what it did?

Wire observability while it's small, then hand it to someone who isn't you.

Folders
tests/evals/ with golden transcripts for every AI behaviour. Diagnostics as structured events, not print statements.
Tools
Sentry — did it break. PostHog — did anyone use it. An eval harness with deterministic replay: the scoreboard that turns “seems fine” into a number.
Architecture
Built to be watched: the system tells you what it did.
Readability
The stranger test: README to running in ten minutes, no help — or it isn't finished.

Stage 6 of 6

Widen only when the core proves it

Did channel #2 take days or months?

Now — and only now — the second channel, the second integration. Through the same contracts and the same core.

Folders
One new adapter file plus its contract-suite run. No new architecture.
Tools
The existing exam grades the new integration. Decision records in docs/ so future sessions inherit the why.
Architecture
The proof: channel #2 in days validates stage 3; months falsifies it — found out cheap. The old system migrates by parallel-run, through the same front door as a stranger.
Readability
The gates never stop: any file that outgrows the budget gets split. Properly built means stays readable.

Part IV. The library

Twelve books, in build order

Concepts attributed, never excerpted. These are the originals. Read one per stage; the companion when the stage bites you. Covers link to Open Library.

  • Cover of The Pragmatic Programmer by David Thomas & Andrew Hunt

    Stage 1 · primary

    The Pragmatic Programmer

    David Thomas & Andrew Hunt

    The mindset the whole plan borrows — tracer bullets, DRY, fix broken windows before they spread.

  • Cover of The Mythical Man-Month by Frederick P. Brooks Jr.

    Stage 1 · companion

    The Mythical Man-Month

    Frederick P. Brooks Jr.

    Why one page from one mind beats ten from a committee — and why adding people (or agents) to a late project makes it later.

  • Cover of Continuous Delivery by Jez Humble & David Farley

    Stage 2 · primary

    Continuous Delivery

    Jez Humble & David Farley

    The case for gates on every push — releases so boring they're a non-event.

  • Cover of Accelerate by Forsgren, Humble & Kim

    Stage 2 · companion

    Accelerate

    Forsgren, Humble & Kim

    The data behind the gates — small batches and fast feedback beat heroics, measurably.

  • Cover of Clean Architecture by Robert C. Martin

    Stage 3 · primary

    Clean Architecture

    Robert C. Martin

    Dependencies point inward; vendors stay at the edge where they can be swapped.

  • Cover of Domain-Driven Design by Eric Evans

    Stage 3 · companion

    Domain-Driven Design

    Eric Evans

    One shared language per noun, so the code matches the business it runs.

  • Cover of Designing Data-Intensive Applications by Martin Kleppmann

    Stage 4 · primary

    Designing Data-Intensive Applications

    Martin Kleppmann

    What actually happens to your data under failure — and why 'it sent twice' is a design problem.

  • Cover of Growing Object-Oriented Software, Guided by Tests by Steve Freeman & Nat Pryce

    Stage 4 · companion

    Growing Object-Oriented Software, Guided by Tests

    Steve Freeman & Nat Pryce

    The walking skeleton — one journey end-to-end first, features second.

  • Cover of Don't Make Me Think by Steve Krug

    Stage 5 · primary

    Don't Make Me Think

    Steve Krug

    Usability you can apply in an afternoon — including the test where a stranger uses your app while you stay silent.

  • Cover of The Lean Startup by Eric Ries

    Stage 5 · companion

    The Lean Startup

    Eric Ries

    Measure what people do, not what they say — the difference between shipped and used.

  • Cover of Refactoring by Martin Fowler

    Stage 6 · primary

    Refactoring

    Martin Fowler

    How to change code without breaking it — the strangler fig migration lives here.

  • Cover of Building Microservices by Sam Newman

    Stage 6 · companion

    Building Microservices

    Sam Newman

    When to split and when not to — plus the parallel-run migration pattern.

Part V. The watchlist

Watch these before you prompt

Every link verified. The 100-second ones cost you five minutes total. The talks are for the stage you're standing in. Not homework, ammunition.

Start here. Under five minutes total

The full talks. One per stage, when you're in it

Part VI. Steal these

The templates, verbatim

The most giveable pieces of the plan. Copy them into your project today. They work before you've read a single book above.

The one page

Stage 1's first artifact. If you can't fill this in, the AI can't build it — it'll supply defaults for everything you left blank.

docs/one-page.md
# <app name> — the one page

**What it does (one sentence):**

**Who it's for:**

**What "done" means (3 checks):**
1.
2.
3.

**What it will NOT do (v1):**
-

**The first slice (one user journey, end to end):**

The folder skeleton

Create this empty, before the first feature prompt. The AI reads structure and imitates it — the skeleton is the prompt.

the shape of the repo
src/
  app/          # routes / screens
  components/
  lib/          # ONE file per external service (stripe.ts, twilio.ts…)
  hooks/
  core/         # domain logic — imports no vendors
supabase/migrations/   # schema as code, the only truth
tests/
scripts/        # one-off automation, never in src
docs/           # the one-pager + decision records
CLAUDE.md       # the project constitution

CLAUDE.md starter

The project constitution — written like onboarding notes for a new hire. Every future AI session inherits it.

CLAUDE.md
# <App name>

<One sentence on what this app is — written for a new hire.>

## Commands
- npm run dev / build / test / lint

## Rules
- Migrations are the only truth for the schema. Never edit the DB by hand.
- One file per external service in src/lib/. Core logic in src/core/ imports no vendors.
- No file over 600 lines. Split before you add.
- Secrets live in .env (gitignored). .env.example holds the shape. Never print or commit a key.
- Commit small, after every working change. Branch before experiments.

## Gotchas
- <the things that bit you — keep this list honest>

The ownership prompt

The one that catches mistake #4 before your users do. If the AI can't point to the policy, it doesn't exist.

paste into your AI session
Show me the exact rule that enforces ownership on this table.
Point to the policy file and the line. If it doesn't exist,
write the migration now — and then walk me through the
two-account test to prove it holds.

The two-account test

Five minutes, before launch, every time the schema changes. This is the whole test.

the ritual
1. Sign up as user A. Create a record.
2. Sign up as user B in an incognito window.
3. As B, try to read A's record — through the UI, then through
   the network tab (copy the request, replay it).
4. If anything of A's comes back, the policy is wrong.
   Nothing else ships until this passes.

The taste prompt

The fix for mistake #5. Written taste beats supplied defaults — otherwise every AI app looks like the internet's average.

paste into your AI session
Here are screenshots of three apps whose design I love.
Write me a design guide from them — type scale, spacing,
color, density, tone — and follow it for every screen
from now on. Never fall back to defaults. When in doubt,
ask the guide, not the internet's average.

The 600-line budget

Readability enforced mechanically. Wire it into pre-commit or CI and the 2,535-line file physically can't happen again.

scripts/check-file-budget.mjs
import { readdirSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";

const BUDGET = 600;
const walk = (dir) =>
  readdirSync(dir).flatMap((f) => {
    const p = join(dir, f);
    return statSync(p).isDirectory() ? walk(p) : [p];
  });

const over = walk("src")
  .filter((f) => /\.(ts|tsx|js|jsx)$/.test(f))
  .map((f) => [f, readFileSync(f, "utf8").split("\n").length])
  .filter(([, lines]) => lines > BUDGET);

if (over.length) {
  console.error(`Over the ${BUDGET}-line budget:`);
  for (const [f, lines] of over) console.error(`  ${f} — ${lines} lines`);
  process.exit(1);
}

The plan, run in public

This isn't theory. The rebuild is happening now.

Robyn. The AI receptionist behind those 9,354 commits. Is being rebuilt from scratch on this exact plan, one stage per episode. Each stage ships with its own deep-dive. Leave an email and get each one as it drops. Nothing else, ever.

Or just follow along. @danielwelsh_routiq . The next episode is already in progress.