Why This Portfolio’s Content Lives With the Code
Moving the portfolio’s editorial content out of a hosted CMS made publishing less magical, but it also made every public claim reviewable, versioned, and easier to keep in sync with the product.
In April I removed the portfolio’s BaseHub dependency and moved its long-lived content into the repository.
That was not a verdict on hosted content systems. A CMS is the right tool when editors need to publish independently, when content changes much more often than code, or when a structured editorial workflow matters more than a Git history. This site had a different shape: one author, a small number of carefully edited pages, and public claims that often change alongside the implementation.
For that shape, a second source of truth was creating more work than it removed.
The important split is not CMS versus Markdown
The useful question was: which data should travel with a deployment, and which data needs to change while the application is running?
The portfolio now keeps the first category in the repository:
- biography and site copy in typed TypeScript data;
- long-form Work entries in Markdown;
- blog posts in MDX with validated frontmatter;
- registered-IP material in its own content collection;
- public route descriptions and machine-readable documentation beside the code that renders them.
The second category still belongs in services designed for live state. Comments and reactions can change without a deployment. Reading and activity snapshots come from integrations. The contact form sends a message rather than editing a file.
That boundary is more useful than insisting that every byte live in one place. Editorial truth is versioned with the site; visitor and integration state stays dynamic.
A file can still have a contract
“It is just Markdown” becomes a liability when any filename or frontmatter shape is accepted and failures only appear during a production build.
The blog loader therefore validates fields such as title, slug, description,
issue date, publication date, tags, and visibility. Work entries have a separate
shape. A file under content/work becomes a Work route; a published file under
content/blog enters the blog archive, sitemap, command menu, and the portfolio
assistant’s directory.
The important part is not the parser. It is that one content decision propagates through the public surfaces instead of being copied into five registries by hand.
This also makes omission deliberate. A draft can stay on disk with
published: false while the public loader excludes it everywhere. That is much
safer than relying on a hidden link or remembering not to add it to the sitemap.
Git is a useful editorial record
Portfolio copy contains claims about projects, roles, releases, and technology. Those claims deserve the same review discipline as code.
Keeping the source in Git gives every change a diff. A rewritten description can be compared with the previous wording. A removed project leaves a history. A date correction is visible. The build can reject malformed frontmatter before a deploy reaches production.
It also makes broad corrections practical. If a legal term, product name, or
domain changes, the repository can be searched as a whole. The result can be
checked across visible pages, structured data, the sitemap, and llms.txt
instead of trusting a collection of unrelated editor screens.
None of that makes the content automatically true. Git preserves mistakes just as faithfully as good edits. It does, however, make the evidence trail and the review surface much clearer.
The admin can still be the writing interface
Repository-backed content does not require writing raw frontmatter forever. The x70 Admin can research a topic, prepare an MDX draft, show the sources and preview, and then publish the resulting file through the repository workflow.
That is the architecture I prefer here: the Admin is an authoring and review tool, while the repository remains the canonical publication record. If the Admin disappears, the articles are ordinary files. If the site is rebuilt, the same commit produces the same editorial archive.
The move made publishing a little less abstract. A post is a file, a review, a commit, a build, and a deployed route. For a personal portfolio, that explicit chain is a feature.
You can see the result in the current Work archive, blog, and Stack: different content types, one inspectable publication model.