The QC checklist that separates hobbyists from professionals
AI has made building websites easy and finishing them exactly as hard as it always was. The projects I get asked to rescue are never broken in interesting ways — they're broken in the same ten boring ways every time: a form that fails silently, a page that scrolls sideways on a phone, a title tag that still says "Create Next App". The difference between a hobbyist and a professional isn't the build. It's what happens between "it works on my machine" and "invoice sent." I run fifteen checks in that gap, on every project, without exception. Here they are.
Why a checklist
Because judgment doesn't scale and memory doesn't either. On project one you'll remember to test the contact form. On project six, at 11 p.m., with the client waiting, you won't — unless it's written down and the rule is nothing ships until every line passes. Pilots with twenty years of experience still read the pre-flight card out loud. They aren't reminding themselves how to fly; they're removing the possibility of a skipped step. That's the entire technology of a checklist: it converts your best day's judgment into every day's baseline.
It also changes how clients experience you. "Done" delivered with a passing checklist reads as calm competence. "Done" followed by four hotfixes reads as luck. Same code, different career.
The fifteen checks
The code (1–3)
1. The build gate passes clean. Type check, lint, production build — zero errors, zero warnings I haven't explicitly accepted:
npx tsc --noEmit && npm run lint && npm run buildNot "it runs in dev". Dev mode forgives things production doesn't.
2. No placeholder text survives. Lorem ipsum, TODO, "your text here", the framework's default metadata — grep for all of it, because your eyes stopped seeing it days ago:
grep -rniE "lorem|TODO|placeholder|your text|create next app" app/ components/ --include="*.tsx"3. Every link goes somewhere real. No href="#", no dead footer links to pages that don't exist, no social icons pointing at twitter.com itself. Click every single one. AI-generated navs are the worst offenders here — they confidently link to pages nobody built.
The screen (4–7)
4. 375px, no horizontal scroll. Open devtools, set the viewport to 375 wide, scroll the entire page. Any sideways movement fails. The usual culprits: fixed-width elements, unwrapped tables, long unbroken strings, code blocks without internal scrolling.
5. Images are real images. Correctly sized (not a 4MB photo squeezed into a thumbnail), served through the framework's image component so they're optimized and don't shift the layout, and every one has honest alt text — empty alt="" only when genuinely decorative.
6. Forms have all three states. Success (clear confirmation), failure (a human message, not a hex code), and invalid input (inline, specific, polite). Then the test people skip: turn the network off and submit. If the button just spins forever, the form isn't finished.
7. The 404 page exists and belongs to the site. Type a garbage URL. If you get the framework's default page, the site has an unfurnished room. Thirty minutes of effort, and it's the page that makes people smile in an annoyed moment.
The metadata (8–11)
8. Every page has its own title and description. Not "Home | Site". In Next.js this is a metadata export per page — and the browser tab is the first thing a client actually looks at:
export const metadata = {
title: "Pricing — Marina Dental Clinic",
description:
"Transparent pricing for checkups, whitening and implants in Dubai Marina.",
};9. The share preview works. Paste the URL into a WhatsApp chat with yourself. Title, description, image — that card is the site's handshake, and by default it's blank. Open Graph tags plus one 1200×630 image fix it.
10. Favicon set. The default framework icon in the tab is the "hello world" of unfinished work. It takes ten minutes to never be that person.
11. Lighthouse: 90+ on performance and SEO.
npx lighthouse https://the-site.com --viewRun it against the deployed site, not localhost. Under 90 is almost always one of three cheap fixes: oversized images, a render-blocking font, or an unused script still loading.
The human (12–15)
12. Keyboard and focus. Tab through the whole page. Everything interactive must be reachable, in a sensible order, with a visible focus outline. If you removed outlines for being "ugly", you removed accessibility; style them instead.
13. Contrast passes AA. Grey-on-grey minimalism reads as elegant to designers and as invisible to a large chunk of actual customers. 4.5:1 for body text — check the real values, don't eyeball it.
14. The client can't break it. Put a 60-character name in the booking form. An empty state with zero testimonials. A menu item priced at 1,000,000. Real data is hostile, and layouts that only survive demo data are demos. This is, by a distance, where AI-built projects fail most — generated code is trained on happy paths.
15. It works on a phone that isn't yours. A real device, someone else's, ideally on mobile data — not the devtools emulator. Fonts render differently, tap targets shrink, that fixed header does something strange above the keyboard. Five minutes with a borrowed phone finds what an hour of emulation misses.
That's the list. Notice there's nothing exotic in it — no check requires skill, only discipline. Which is precisely why it separates anything at all: everyone can do these; professionals always do.
Making the AI run it
The checklist becomes properly powerful when it stops being your job. It's section six of my master prompt — the build isn't described as done until the checks pass — and the prompt ends with an instruction shaped like this:
## 6. QC CHECKLIST
Before reporting done: run tsc, lint and build until clean.
Then walk checks 2–14 and print a table:
check | pass/fail | evidence (file or command output).
Anything failed: fix it and re-run. Do not summarize —
show the evidence.Two details matter. Evidence, because an AI asked "does it pass?" says yes, while an AI asked to print the grep output has to actually run the grep. And re-run until clean, because a checklist consulted once is a suggestion; a checklist in the loop is a gate. Check 15 stays human — the borrowed phone doesn't fit in a prompt. The other fourteen the AI can execute, and making it do so is the single highest-leverage line in the entire master prompt.
Growing your own list
Mine wasn't designed; it accreted. Check 6 exists because a contact form once failed silently for eleven days — the client thought business was slow, and it was my code. Check 14 exists because a real menu had an item name twice as long as my layout imagined. Every scar became a line, and that's the actual rule I want you to leave with:
Every bug that reaches a client adds a check. Written the same day, in the same file, phrased so it can't be argued with. Your list will diverge from mine — different niches break differently — and after ten projects it will be the most valuable document you own: your taste plus your mistakes, compiled into a gate that your worst day can't get past.
Fifteen checks. About an hour, all told, on a project you spent days building. Most AI-built sites fail five of them, which means most of your competition ships at 70% and calls it done. The hour is the moat.