Blog / changelog index

mandatory

HTML index page at `kds.koder.dev/blog/` that lists Koder Design releases as blog-style cards, ordered newest-first. Material parity (`/blog`). Backed by the same source data that powers the existing `feed.xml` RSS feed.

Spec — Blog / changelog index

Facet *ool*of Koder Design. Material parity: https://m3.material.io/blog.

URL: https://kds.koder.dev/{locale}/blog/ (canonical; /changelog/ 301 → /blog/).

Two views

View URL Use
*ndex* /blog/ List of all releases (paginated)
*ntry* /blog/{version-slug}/ Single release detail

Both views render via design-gen kind blog (new kind).

R1 — Index layout

┌─────────────────────────────────────────────┐
│  Koder Design · Blog                         │
│ ─────────────────────────────────────────── │
│                                              │
│  [Latest] [v1.x] [v0.x] [All]                │  ← version filter chips
│                                              │
│  v1.4.0 · 2026-05-11                         │  ← entry card
│  Cluster 4 wave 2 — 16 components            │
│  3,686 lines added · 16 new specs            │
│  [Read more →]  [Migrate from v1.3.0 →]      │
│ ─────────────────────────────────────────── │
│  v1.3.0 · 2026-05-09                         │
│  Cluster 4 wave 1 — 8 component specs        │
│  ...                                          │
│ ─────────────────────────────────────────── │
│  v1.2.0 · ...                                 │
│                                              │
│  [← Previous] · 1 of 3 · [Next →]            │
└─────────────────────────────────────────────┘
  • Entry cards stacked vertically
  • Each card: version + date + 1-line summary + 2 metric facts +

    buttons (Read more, Migrate from prev)

  • Filter chips at top: All (default) / Latest minor major / by major

    version

  • Pagination: 10 entries per page

R2 — Entry detail layout

/blog/v1.4.0/ (single release page):

┌─────────────────────────────────────────────┐
│  v1.4.0 · 2026-05-11                         │  ← header
│  Cluster 4 wave 2 — 16 components            │
│ ─────────────────────────────────────────── │
│  Summary  (1-2 paragraph hand-written)       │
│ ─────────────────────────────────────────── │
│  ## Added                                     │
│  - 16 component specs in `specs/components/`  │
│  - Consolidation policy: Material agrupa     │
│  ...                                          │
│                                              │
│  ## Changed                                   │
│  - Umbrella #049: 31/62 → 47/62 (50% → 76%)  │
│                                              │
│  ## Deprecated / Removed                      │
│  - (none)                                     │
│                                              │
│  ## Stats                                     │
│  - 3,686 lines added / 20 removed             │
│  - 16 files created                           │
│  - 1 commit                                   │
│ ─────────────────────────────────────────── │
│  [← All releases] · [Migrate from v1.3.0 →]  │
│  [GitHub diff →]                              │
└─────────────────────────────────────────────┘

R3 — Source of truth

A single meta/docs/stack/releases/releases.toml file holds all release metadata. Each release stanza:

[[releases]]
version = "v1.4.0"
date    = "2026-05-11"
title   = "Cluster 4 wave 2 — 16 components"
summary = "Wave 2 of the Material.io parity programme ..."
tags    = ["components", "wave-2", "#049"]
commits = ["1956224163"]
stats   = { added = 3686, removed = 20, files = 16 }
migrate-from = "v1.3.0"

The design-gen blog kind reads this file (TOML), sorts by date desc, paginates, and renders both views.

R4 — Adding a new release entry

Per releases.kmd policy, each tag of meta/docs/stack/v* automation:

  1. Auto-extracts version + date + commit refs from tag
  2. Owner writes the summary (1-2 paragraphs) at tag time
  3. Generator writes the stanza to releases.toml
  4. design-gen rebuilds /blog/ index + new entry page
  5. RSS feed (feed.xml) regenerates from same source

Migration guide crosslink autocomputed (migrate-from field).

R5 — RSS feed (existing)

feed.xml already exists per Makefile (make rss VERSION=vX.Y.Z).

This spec adds the HTML index that mirrors the RSS:

  • RSS = machine-readable
  • Blog = human-readable
  • Both consume the same releases.toml

R6 — Filter chips

Per components/chips.kmd filter variant:

  • [Latest] (single-select, shows only the latest entry)
  • [v1.x] (multi-select with other major filters; shows all v1.* releases)
  • [v0.x]
  • [All] (default, no filter)

URL state: /blog/?version=v1.x (shareable).

Single search box at top of index — full-text over title + summary + tags fields. Live-filters cards as user types. No server roundtrip (client-side index, < 50 KB).

R8 — Pagination

10 entries per page default; URL params: ?page=2. "Previous" / "Next" buttons + numbered page links (e.g., "1 of 3").

If filtered to < 10 entries, no pagination shown.

R9 — Per-locale content

Index UI strings localized (filter chip labels, "Read more", pagination labels). Entry detail content (summary, sections) is en-US source; ptBR localization optional per release (ownercurated when material is significant).

R10 — Accessibility

  • Entry cards: <article> semantic, <h2> for version title
  • Pagination: aria-label="Pagination" + aria-current="page" on

    active page

  • Filter chips: role="checkbox" per chip (multi-select group)
  • Search box: role="searchbox"
  • Skiptocontent link
  • Headings hierarchical: h1 (page) → h2 (entry) → h3 (Added / Changed

    sections inside entry detail)

R11 — Performance

  • Index page: < 50 KB HTML (only first 10 entries + filter chips)
  • Search index: < 50 KB JSON (titles + summaries + tags)
  • Lighthouse score ≥ 95 (matches rest of KDS site)

R12 — Forbidden patterns

  • ❌ Hardcoded HTML release list (always generate from

    releases.toml)

  • ❌ Separate index page per locale duplicating releases.toml

    content

  • ❌ Releases without migrate-from (every release ≥ second has a

    predecessor — link out to migration guide)

  • ❌ Pagination with > 20 entries per page (perf + scan ergonomics)
  • ❌ "Subscribe" form that's not RSS / Atom (no email gating)
  • tools/migration-guides.kmd — entry detail links to migration

    guide (migrate-from field)

  • releases/packaging.kmd — release artifact names + tag policy
  • landing-pages/products.kmd — overall site structure
  • Generator code: tools/design-gen/internal/kinds/blog.{go,templ}
  • Source file: meta/docs/stack/releases/releases.toml

Source: ../home/koder/dev/koder/meta/docs/stack/specs/tools/blog-changelog-index.kmd