Chapter 03 of 20 · 3 min · 15% through
The repository is the database
No database, on purpose
There is no database anywhere in this system. Every article, every book chapter, every deck caption and every site setting is a plain text file in a folder, kept in version control.
That is not minimalism for its own sake. A database would have bought me querying I do not need and cost me four things I do:
Diffs. I can see exactly what changed in a paragraph between two versions, in the same tool I use for code.
History. Every version of every article is kept, with a message explaining why it changed. Not “last modified 3 days ago” — the actual reason.
Rollback. Reverting a bad edit is reverting a commit.
Portability. The content is Markdown with a small block of metadata at the top. Any static site generator, any editor, any script can read it. There is no export step because there is nothing to export from.
How content is organised
Three kinds of content, three shapes on disk.
Articles are files. One Markdown file per article. The filename is the URL slug, which means renaming a file changes a published URL — a real hazard, and one the editing application is careful about.
Books are folders. A folder per book, with a metadata file carrying the
cover and blurb, and one file per chapter beside it. Chapter order is encoded
in the filenames themselves — 01-, 02-, and so on. That is a deliberate
choice: order becomes a fact about the files rather than a field someone can
forget to set, or set twice.
Decks are folders too, but with one file inside. A deck’s slides are images, not prose, and they get reordered constantly — so the slides live as an ordered list in the deck’s metadata rather than as files that would have to be renamed on every drag.
Each shape follows from what the content actually is. A chapter is a document. A slide is a picture with a caption. Treating them the same would have made one of them awkward.
The metadata block
Every content file opens with a small block of fields — title, publication date, category, tags, and a status. Everything below it is the writing.
The status field is the one that matters most, and it has a rule that runs through the whole system: anything that is not exactly “published” is a draft. A typo in that field, a half-migrated file, something restored from the trash — all of them fail closed. Nothing goes live by accident because a field was misspelled.
That rule is enforced in more than one place, which is the subject of the publishing chapter.
What the front end is allowed to see
Content is read through a single gate per collection. Page templates never reach into the content store directly; they ask the gate, and the gate applies the draft rule before handing anything back.
This sounds like ceremony until you imagine the alternative. If every page filtered drafts for itself, the next page anyone adds would be one forgotten line away from publishing unfinished work. Centralising it means there is nothing to forget — and a build-time check verifies the gates are still in place rather than trusting that they are.

The site’s own settings
One more file deserves a mention: the site configuration. Title, tagline, the author block, the navigation items, the category definitions, and the settings for content protection all live in a single structured file.
Which means the navigation menu is content, not code. Adding “Decks” to the main navigation — which happened partway through this system’s life — was a two-line change to a data file, not an edit to a template.