How it was built
Building Career Command Center
A full product in one continuous run: a brainstormed spec, a 14-task plan executed by fresh AI subagents with an independent reviewer gating every task, live Claude API extraction, and a hosted read-only demo — 20+ commits, 28 unit tests, ~21,000 lines.
The idea
Job tracking tools are spreadsheets with better fonts. The brief was different: a career operating system that feels like Notion's organization, Apple's polish, and an F1 race engineer's telemetry wall — where every screen answers one question: what should I do next to get hired? AI is the engine, not a gimmick: paste a job URL and Claude reads the posting, extracts ~23 structured fields, writes a summary, and files it into the pipeline. One more constraint: local-first. Your applications live in a private database on your own machine.
Under the hood
Structured extraction, not string parsing
Job postings are messy HTML. A small fetcher strips them to readable text, then the Claude API returns a schema-validated object — the extraction is defined as a zod schema (23 fields, every one deliberately nullable so the model says "not stated" instead of inventing salaries), and the SDK's structured-output mode guarantees the response parses. Sites that block scraping degrade gracefully: the intake dialog flips to a paste tab with the same extraction, and a manual form needs no AI at all.
An AI layer nothing else imports around
All AI calls go through one AIProvider interface — extraction,
per-application summaries, and the dashboard's coaching insight. The vendor SDK is
imported in exactly one file. No API key? The provider is null and every
feature shows a designed "not configured" state instead of an error. That same
discipline is what made the public demo trivial to secure later.
Server components, server actions, and one seam for auth
Pages are React Server Components reading straight from Prisma; every write is a
server action that stamps activity timestamps and appends to an automatic
per-application timeline. Every row carries a userId and every query
filters by one getCurrentUserId() helper — today it returns a constant,
and swapping in real authentication means changing one function.
One schema, two databases
Local runs on SQLite — zero setup, one file. The hosted demo runs on Supabase Postgres. Rather than maintaining two schemas, a build script derives the Postgres schema from the SQLite one by swapping the datasource block, so the models can never drift. Vercel's build regenerates the Prisma client against Postgres; the laptop keeps SQLite.
Analytics as pure, tested math
Funnel counts, response/interview/offer rates, weekly velocity, and stale detection are pure functions with an explicit metric contract written in comments (a rejection counts as a response; fourteen idle days means stale) — built test-first, so the dashboard numbers are provably right before any pixel renders them.
A demo that can't be vandalized
The public demo sets one environment variable, and all eighteen mutating server actions check it before touching the database — dragging a kanban card in the demo gets a polite toast, not a write. Because it's enforced server-side, no amount of browser fiddling gets around it, and the demo carries no API key for strangers to spend.
Key design decisions
Nullable-by-design extraction
Every extracted field allows null, and the prompt forbids invented values. A posting without a salary produces an honest blank — hallucinated compensation would be worse than none.
Degrade features, never the app
Missing API key, blocked URL, failed AI call — each has a designed fallback state. An AI summary failure never loses the save; the application lands and offers a retry.
Optimistic UI with a race guard
Kanban drags update instantly and reconcile with the server after. A per-card request token discards stale responses, so even a rapid double-drag can't desync the board — a bug the review process caught before it shipped.
Color means something
The design system is white, gray, and frosted glass; color appears only as meaning — blue for info, green for offers, amber for stale, red for rejections, purple for AI. If it's colorful, it's telling you something.
The Claude Code process
This build used the most rigorous process on the site. It started as a written product spec, was brainstormed into an approved design document, then decomposed into a 14-task implementation plan. Each task was executed by a fresh Claude subagent with exactly the context it needed — and then a separate reviewer subagent audited the diff against the task's requirements before the next task could start.
The reviewers earned their keep: they caught a database driver version mismatch that would have crashed the first real query, an entity-decoding bug in the HTML parser, a race condition in the kanban's optimistic updates, and a command palette that couldn't actually open — each fixed and re-reviewed before moving on. A final whole-branch review across all 20+ commits found five integration gaps the per-task reviews couldn't see (including a framework upload limit silently contradicting the app's own), all fixed before merge. The read-only demo — Supabase database, Vercel deployment, browser-verified write blocking — shipped the same day as a follow-up feature through the same spec-first flow.