CASE STUDY — CMS · 2026
This Site
You're looking at the case study. This portfolio runs on a flat-file PHP CMS I built from scratch — a drag-and-drop block editor, sixteen block types from a single schema, no database, no framework. And I built it in partnership with Claude Code, which makes it a working demo of exactly how I ship AI-assisted software.
- 16
- block types, one schema single source of truth
- ~0KB
- framework JS on public pages server-rendered
- 0
- databases flat JSON files
The problem
My old portfolio was a WordPress site. It went down when the database connection died and the SSL cert expired — a stack too heavy for what a portfolio actually needs. I wanted the opposite: something I fully understand, that can't have a database outage because it has no database, and that would itself be the strongest thing in the portfolio. The portfolio should be the product.
And I wanted to build it the way I now build most things — with Claude Code as a pair — so the site could honestly stand as proof of that workflow.
The build
It's a flat-file PHP CMS. Content lives in JSON files, one per page and project; there's no database anywhere. A drag-and-drop block editor — vanilla JavaScript plus SortableJS, nothing else — lets me compose pages from sixteen block types, all defined in a single schema registry. That one registry is the source of truth for three things at once: the public renderer's whitelist, the admin form generator, and the save-time sanitizer. Add a field in one place, and the editor form, the render, and the validation all update together.
Every save takes a version snapshot first, so nothing is ever lost. Uploads go through a GD re-encoding pipeline that strips metadata and destroys anything hiding inside an image. Rich text is a Markdown subset with no raw HTML — which means there's no stored-XSS surface, by construction. The public pages ship essentially zero framework JavaScript; they're server-rendered PHP, and the whole thing runs happily on plain Namecheap shared cPanel hosting.
Stack decisions
Why flat files over a database. A portfolio's content changes rarely and is tiny. A database is operational risk with no payoff here — and its absence is exactly why the old site's failure mode can't recur.
Why one schema registry. Three consumers, one definition. It's the trick that keeps the editor, the renderer, and the sanitizer from ever drifting apart, and it's why adding a block type is a small, safe change.
Why Markdown-only, no raw HTML. You can't store an XSS payload in a format that doesn't allow markup. Security by construction beats security by filtering.
Why build it with Claude Code. Because it's how I work now, and a portfolio should be honest about that. The design tokens, the CSS, the OG images, and this style guide all render from the same tokens.json — a level of consistency that's far easier to hold when you've got an AI pair keeping every consumer in sync. This site is the demo of that workflow shipping real, production software.
Outcomes
The result is a site I can explain top to bottom, that loads fast, that can't lose its database because it hasn't got one, and that doubles as a live argument for AI-assisted development. The portfolio is the product — and the product is this.
// One registry, three consumers: renderer whitelist,
// admin form generator, and save-time sanitizer.
'hero' => ['label' => 'Hero', 'fields' => [
'eyebrow' => ['type' => 'text', 'label' => 'Eyebrow (mono)'],
'heading' => ['type' => 'text', 'label' => 'Heading'],
'lede_md' => ['type' => 'markdown', 'label' => 'Lede'],
'bg_motif' => ['type' => 'select', 'label' => 'Background motif',
'options' => ['none', 'topo']],
]],
// Add a field here and the editor form, the public
// render, and validation all update together.
Curious about the AI-assisted workflow?
This site is the proof of concept. If you want that approach applied to your product, let's talk.