<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cms on Rindrics Mumbles</title>
    <link>https://rindrics.com/tags/cms/</link>
    <description>Cms</description>    
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Sat, 08 Aug 2026 00:00:00 +0900</lastBuildDate>
    <atom:link href="https://rindrics.com/tags/cms/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Model the Data, Not the Interface</title>
      <link>https://rindrics.com/posts/model-the-data-not-the-interface/</link>
      <pubDate>Sat, 08 Aug 2026 00:00:00 +0900</pubDate>
      
      <guid>https://rindrics.com/posts/model-the-data-not-the-interface/</guid>
      <description>&lt;figure&gt;&lt;img src=&#34;https://rindrics.com/images/2026-08-08-cms/shared-file.webp&#34;&gt;
&lt;/figure&gt;

&lt;p&gt;How a simple YAML data model let me add a client-facing CMS without touching the existing implementation.&lt;/p&gt;
&lt;h2 id=&#34;the-story&#34;&gt;The Story&lt;/h2&gt;
&lt;p&gt;A client asked for a profile page featuring his career timeline. Straightforward request. I built it, deployed it, and moved on.&lt;/p&gt;
&lt;p&gt;Months later, he came back with a new request: he wanted to update the timeline himself—to add new positions and modify past entries.&lt;/p&gt;
&lt;p&gt;Until then, I had been making those changes for him. Giving him direct access to the data wasn&amp;rsquo;t an option either: he was a non-technical user, and GitHub access was deliberately off the table.&lt;/p&gt;
&lt;p&gt;At first glance, adding a content management interface sounded like a change that might ripple through the existing implementation.&lt;/p&gt;
&lt;p&gt;It didn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;The reason went back to a small design decision I had made months earlier, before a CMS was even a consideration.&lt;/p&gt;
&lt;h2 id=&#34;the-initial-design-choice-yaml-over-markdown&#34;&gt;The Initial Design Choice: YAML Over Markdown&lt;/h2&gt;
&lt;p&gt;When I first built the profile page, I didn&amp;rsquo;t hard-code the timeline into HTML, but I didn&amp;rsquo;t put it in Markdown either. I started by asking what kind of content a career timeline actually is.&lt;/p&gt;
&lt;p&gt;A career history isn&amp;rsquo;t really a document. It&amp;rsquo;s structured data: a collection of dates, each associated with one or more events. So I represented it that way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#586e75&#34;&gt;# data/timeline.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;entries&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#268bd2&#34;&gt;date&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;2020&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#268bd2&#34;&gt;events&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - Joined the neighborhood cat council
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - Took responsibility for afternoon naps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#268bd2&#34;&gt;date&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;2021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#268bd2&#34;&gt;events&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - Became a boss cat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - Led a team of 5 cats
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then rendered the data with Hugo:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#586e75&#34;&gt;&amp;lt;!-- layouts/shortcodes/timeline.html --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#268bd2&#34;&gt;dl&lt;/span&gt; class&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;timeline&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ range .Site.Data.timeline.entries }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#268bd2&#34;&gt;div&lt;/span&gt; class&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;timeline-entry&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#268bd2&#34;&gt;dt&lt;/span&gt; class&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;timeline-date&amp;#34;&lt;/span&gt;&amp;gt;{{ .date }}&amp;lt;/&lt;span style=&#34;color:#268bd2&#34;&gt;dt&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#268bd2&#34;&gt;div&lt;/span&gt; class&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;timeline-events&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {{ range .events }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#268bd2&#34;&gt;dd&lt;/span&gt; class&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;timeline-event&amp;#34;&lt;/span&gt;&amp;gt;{{ . }}&amp;lt;/&lt;span style=&#34;color:#268bd2&#34;&gt;dd&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#268bd2&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#268bd2&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#268bd2&#34;&gt;dl&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This kept both the data structure and the implementation simple.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://rindrics.com/images/2026-08-08-cms/rendered.webp&#34;
    alt=&#34;The career timeline rendered from the YAML data&#34;&gt;&lt;figcaption&gt;
      &lt;p&gt;The career timeline rendered from the YAML data&lt;/p&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id=&#34;why-yaml-instead-of-markdown&#34;&gt;Why YAML Instead of Markdown?&lt;/h3&gt;
&lt;p&gt;Many static-site workflows are Markdown-first, and for good reason. Markdown is excellent for prose: articles, documentation, and other document-shaped content. But not all content is document-shaped.&lt;/p&gt;
&lt;p&gt;A career timeline is fundamentally a collection of structured records: dates with associated events. The same is often true of navigation menus, pricing tables, office locations, product specifications, and similar content.&lt;/p&gt;
&lt;p&gt;Representing those structures as Markdown would mean making the data fit the document format rather than choosing a format that fits the data. For the timeline, YAML was the more natural representation.&lt;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t thinking about CMS support at this point, nor was I trying to make the architecture extensible. I was simply representing the content in the form that best matched its nature.&lt;/p&gt;
&lt;p&gt;That distinction became useful later.&lt;/p&gt;
&lt;h2 id=&#34;the-requirement-change&#34;&gt;The Requirement Change&lt;/h2&gt;
&lt;p&gt;Months later, the client wanted to manage his own career history. The new editing workflow had a few constraints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It had to work for a non-technical user.&lt;/li&gt;
&lt;li&gt;GitHub access was off the table.&lt;/li&gt;
&lt;li&gt;Inputs needed validation: a year should be a number, and an entry should contain at least one event.&lt;/li&gt;
&lt;li&gt;Changes had to be committed and deployed automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The existing YAML files were already a perfectly good representation of the content. The problem wasn&amp;rsquo;t the data model; the problem was that the only interface for changing it was a text editor and Git.&lt;/p&gt;
&lt;p&gt;So instead of replacing the existing content model, I added another interface to it.&lt;/p&gt;
&lt;h2 id=&#34;the-solution-add-an-interface-not-a-new-data-model&#34;&gt;The Solution: Add an Interface, Not a New Data Model&lt;/h2&gt;
&lt;p&gt;I used Decap CMS, a Git-based CMS that can map an editing UI onto files stored in a repository.&lt;/p&gt;
&lt;p&gt;The configuration for the timeline looked roughly like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#586e75&#34;&gt;# static/admin/config.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#268bd2&#34;&gt;label&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;Profile&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;profile&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;files&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#268bd2&#34;&gt;label&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;Career History&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;timeline_data&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#268bd2&#34;&gt;file&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;data/timeline.yml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#268bd2&#34;&gt;fields&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#268bd2&#34;&gt;label&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;Career entries&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;entries&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#268bd2&#34;&gt;widget&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#268bd2&#34;&gt;fields&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#268bd2&#34;&gt;label&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;Year&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;widget&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;number&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;value_type&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;int&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;min&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;1980&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;max&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;2050&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            - &lt;span style=&#34;color:#268bd2&#34;&gt;label&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;Events&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;events&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;widget&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;field&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#268bd2&#34;&gt;widget&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#268bd2&#34;&gt;min&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Decap CMS could now present the existing data as a form suitable for the client.&lt;/p&gt;
&lt;div class=&#34;info&#34;&gt;&lt;strong&gt;Resources&lt;/strong&gt;
&lt;p&gt;A minimal working example is available on GitHub, with a live demo deployed on Netlify.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Live demo: &lt;a href=&#34;https://rindrics-model-data-not-interface.netlify.app/&#34;&gt;https://rindrics-model-data-not-interface.netlify.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Source: &lt;a href=&#34;https://github.com/rindrics/examples/tree/main/model-the-data-not-the-interface&#34;&gt;https://github.com/rindrics/examples/tree/main/model-the-data-not-the-interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;

&lt;p&gt;The important part was what I didn&amp;rsquo;t change.&lt;/p&gt;
&lt;p&gt;The YAML structure? ──Unchanged; The Hugo templates? ──Untouched; The site still rendered exactly the same way.&lt;/p&gt;
&lt;p&gt;I had simply added a new way to edit the existing data.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://rindrics.com/images/2026-08-08-cms/before-after.webp&#34;
    alt=&#34;Before (top) and after (bottom) adding a CMS: the existing data flow remains unchanged.s&#34;&gt;&lt;figcaption&gt;
      &lt;p&gt;Before (top) and after (bottom) adding a CMS: the existing data flow remains unchanged.s&lt;/p&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;No refactor, no breaking changes.&lt;/p&gt;
&lt;h2 id=&#34;why-so-little-had-to-change&#34;&gt;Why So Little Had to Change&lt;/h2&gt;
&lt;p&gt;What made this work was surprisingly simple: the editing side and the rendering side could depend on the same file-based data model.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://rindrics.com/images/2026-08-08-cms/shared-file.webp&#34;
    alt=&#34;File-based integration via a shared data contract&#34;&gt;&lt;figcaption&gt;
      &lt;p&gt;File-based integration via a shared data contract&lt;/p&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The Hugo templates depend on the structure of the YAML to render the timeline, while the Decap CMS configuration depends on the same structure to provide an editing interface. But the two sides don&amp;rsquo;t need to know about each other: Decap CMS doesn&amp;rsquo;t know how Hugo renders the timeline, and Hugo doesn&amp;rsquo;t know that Decap CMS exists.&lt;/p&gt;
&lt;p&gt;They only agree on the shape of the data.&lt;/p&gt;
&lt;p&gt;The YAML structure acts as a shared data contract between authoring and publishing. Adding another way to display the same data means writing another consumer of the model; adding another way to edit it means adding another authoring interface. Neither necessarily requires changing the underlying content model.&lt;/p&gt;
&lt;p&gt;Of course, if the content itself changes—if a career entry suddenly needs locations, employers, categories, or relationships—the data model should change too. The point isn&amp;rsquo;t that the model never changes; it&amp;rsquo;s that adding an interface doesn&amp;rsquo;t inherently require it to change.&lt;/p&gt;
&lt;h2 id=&#34;model-the-content-for-what-it-is&#34;&gt;Model the Content for What It Is&lt;/h2&gt;
&lt;p&gt;What&amp;rsquo;s interesting to me is that none of this was planned. When I chose YAML, I wasn&amp;rsquo;t anticipating a CMS. There was no abstraction layer waiting for future requirements, no repository interface, and no elaborate content architecture.&lt;/p&gt;
&lt;p&gt;I simply looked at the content and asked:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is this thing?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The answer was structured data, so I represented it as structured data. That gave the later CMS integration a clean boundary almost for free.&lt;/p&gt;
&lt;p&gt;This is different from trying to future-proof a system through speculative abstraction. I didn&amp;rsquo;t predict the future requirement; I represented the requirement I already had accurately enough that the future requirement fit naturally around it.&lt;/p&gt;
&lt;p&gt;This applies beyond career timelines. A blog post or an article is usually document-shaped, making Markdown a natural fit. But a timeline is a collection of records, a navigation menu is a tree, and a pricing table is a collection of products, attributes, and prices. Different kinds of content have different natural structures.&lt;/p&gt;
&lt;p&gt;So rather than starting with the tool—&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How should I write this in Markdown?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;—I find it more useful to start with the content:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is this content, really?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The representation follows from there. Markdown is often ideal for document-shaped content. YAML, JSON, or another structured store may better represent structured content. Relational or highly dynamic data may belong in a database.&lt;/p&gt;
&lt;p&gt;The specific format is secondary. What matters is whether the model reflects the structure of the thing being represented.&lt;/p&gt;
&lt;h2 id=&#34;takeaway&#34;&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;Adding CMS support to this site turned out to be surprisingly small—not because I had designed the system for a CMS or anticipated the requirement, and not because I had introduced abstractions to protect against future changes. I had simply modeled a career timeline as what it was: structured data.&lt;/p&gt;
&lt;p&gt;When the client later needed an editing interface, Decap CMS could depend on that same model while Hugo continued rendering it exactly as before. The CMS became another interface to the data, rather than a replacement for the architecture.&lt;/p&gt;
&lt;p&gt;That experience left me with a simple design heuristic:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t model content around the tool that happens to consume it today. Model it around what the content actually is.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this case, the flexibility followed naturally.&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
