
- Skill Set
- learning-log
- project-management
- solution-design
How I built this portfolio spec-first with Claude Code
This site went from an empty repo to production in two weeks, on a $0 free tier. The method: write the spec first, give every requirement an ID, record decisions as ADRs, and let Claude Code implement test-first while I own every product decision and approve each gate.
The short answer
This portfolio (resume, case studies, a writing CMS and a private skill tracker) went from an empty repository on 5 October 2026 to production in about two weeks, on a $0/month free tier (Next.js on Vercel, Supabase for Postgres, auth and storage). I built it with spec-driven development: the written spec is the source of truth, every requirement has an ID, every architecture decision is an ADR, and Claude Code implements each task test-first. I make every product decision and approve each gate.
The point of the method is not speed. It is that the code, the tests and the documentation never quietly disagree.
Why spec-first, and why with an AI coding agent
An AI coding agent is fast, and that is exactly the risk: it can produce a lot of plausible code that nobody asked for. A spec turns "build me a portfolio" into decisions that can be checked:
- What is being built and for whom (a PRD with requirement IDs such as
FR-RES-04). - How it should look (a design document with tokens and components).
- How it fits together (an architecture document with numbered decisions).
- How we know it works (a test strategy tied to each requirement).
When the agent proposes something, I compare it with the spec, not with my memory. I'm currently learning the same discipline more formally in Dicoding's Spec-Driven Development course; this site is where I practise it end to end.
The documents that run the project
The repository has a docs/ folder with 12 documents: the PRD, design, architecture, technical spec, the skill-tracker spec, content inventory, security and privacy, testing and QA, deployment and operations, roadmap with a traceability matrix, a project guide and a release log.
Three rules keep them honest:
- Behaviour change ⇒ spec change in the same pull request, with a version bump and a changelog row.
- Architecture decisions are ADRs, and an accepted ADR is never edited; a new one supersedes it. There are 18 ADRs so far.
- Requirement IDs travel: they appear in commit messages, pull requests and the traceability matrix, so any line of code can be traced back to the reason it exists.
How one feature moves from idea to production
Open full sizeLook at the gates under the boxes. Each step produces something I can read and approve before the next one starts:
- Brainstorm. The agent proposes two or three approaches with a recommendation; I pick one.
- Spec. The decision is written down: what changes, what stays private, how it will be tested.
- Plan. The spec becomes small tasks, each with its files, interfaces and tests.
- Build. Every task is test-first: a failing test, the minimal code, green, commit.
- Review. Each task is reviewed, then the whole branch. Findings are fixed before merge.
- Release. A full quality gate runs, then a pull request and a written runbook for production.
The dashed line matters most. When a demo shows that something should change, the change goes back into the spec in the same pull request.
A real example: the Skill Atlas honeycomb
The home page shows a public summary of my private skill tracker as a hexagon honeycomb. That feature shows the method in practice:
- A product decision, written down. Showing mastery per skill tree publicly was my explicit choice, recorded as ADR-018. Node-level progress stays private.
- Privacy enforced in the database, not the UI. Row-level security in Postgres decides what an anonymous visitor can read; the public page only ever sees the summary table.
- Changes after the demo went into the spec. After seeing the local demo, I asked for hover details (codes like SOL and ARCH were unclear) and for the grid to grow a ring when a 13th tree is added. Both were built test-first and written into the spec as amendments in the same pull request, so the spec still describes what shipped.
- A safe rollout by design. The database change was additive and backward-compatible, so when the pull request was merged before the migration ran, production kept working and showed a placeholder ring until the summary was republished.
What the agent did, and what I did
| Claude Code | Me |
|---|---|
| Proposed options with trade-offs | Chose between them |
| Wrote specs, plans, code and tests | Approved specs and plans; reviewed demos |
| Ran the quality gate and reported failures | Decided what ships and when |
| Ran review passes on every task | Merged pull requests and approved every production step |
| Kept docs, ADRs and changelogs in sync | Owned content, data and account access |
The agent never handles production secrets or creates accounts; those steps stay with me.
The numbers, two weeks in
| Item | Count |
|---|---|
| Commits | 267 |
| Architecture decision records | 18 |
| Database migrations (append-only) | 11 |
| Unit and integration tests | about 2,400 |
| End-to-end tests (Chromium + mobile WebKit) | 324 |
| Database tests (pgTAP) | 206 |
| Hosting cost | $0/month |
What went wrong, and what I learned
- Test on the browsers your visitors use. A 3D CSS orbit looked right in Chromium but was flattened in mobile WebKit. It became a 2D effect that works everywhere.
- Measure before you assert. I assumed the profile photo was the page's largest contentful paint; it was the headline. The test was corrected to match reality.
- Release order matters, so design for the wrong order. A pull request was merged before its migration. Nothing broke, because the change was additive, but the lesson went into the runbook.
- Parallel changelogs conflict. Two branches bumping the same document version blocked a merge. Merging
maininto a branch before opening the pull request avoids it. - Flaky tests are debt. A few timing-sensitive tests still fail when the machine is busy; they are tracked, not ignored.
FAQ
What is spec-driven development? Spec-driven development means writing the requirements, design and test plan before the code, and treating that written spec as the source of truth. Every change to behaviour updates the spec in the same change, so the documentation stays accurate.
Does the AI write all the code? Claude Code writes most of the code and tests, but only against an approved spec and plan, and every task is reviewed. Product decisions, approvals, merges, content and production access stay with me.
Can a portfolio like this really run for free? Yes, within free-tier limits: Vercel hosts the Next.js app and Supabase provides Postgres, authentication and storage. Weekly encrypted backups run on GitHub Actions, and a restore drill confirms they can be recovered.
Where can I see it? You're on it. The portfolio has the case studies, and this writing section is the CMS in use.
Stack: Next.js 16, React 19, Supabase (Postgres, Auth, Storage, RLS), Vercel, Playwright, Vitest, pgTAP. Last updated: 20 October 2026.