From 6c7e5776332614467b8bf55ed27dec6cb245312f Mon Sep 17 00:00:00 2001 From: Jonathon Wright Date: Mon, 3 Aug 2026 16:47:07 +1000 Subject: [PATCH] blog: three curated series across the whole catalogue + badge on post pages Extends the lone security thread into three arcs that read as skill pillars - SECURITY (6), NETWORKING (5), PLATFORM (7) - so every post carries a numbered badge and the catalogue advertises three areas of depth rather than a loose list. Adds the badge to the post detail header too, styled to match the cards. --- src/data/series.ts | 35 +++++++++++++++++++++++++++++++---- src/pages/blog/[slug].astro | 17 +++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/data/series.ts b/src/data/series.ts index 3c5982b..8e1987f 100644 --- a/src/data/series.ts +++ b/src/data/series.ts @@ -1,7 +1,34 @@ -// Post series — numbered badges on blog cards. Keyed by post slug. -// The security series threads the zero-trust arc across posts as they publish. +// Post series - numbered badges on blog cards, keyed by post slug. +// +// Three arcs, each a skill pillar the site advertises. A post carries exactly +// ONE badge; the number is its reading order within the arc (curated, not by +// date). New posts pick their series at draft time - see the blog-writing skill. +// +// SECURITY - identity, secrets, least-privilege, blast-radius (zero-trust) +// NETWORKING - Cilium/eBPF, edge exposure, TLS, load-balancing +// PLATFORM - GitOps delivery, immutable infra, operations, DR export const series: Record = { + // SECURITY SERIES - the zero-trust spine "secret-zero": { name: "SECURITY SERIES", number: 1 }, - "broker-pattern": { name: "SECURITY SERIES", number: 2 }, - "workload-least-privilege": { name: "SECURITY SERIES", number: 3 }, + "workload-least-privilege": { name: "SECURITY SERIES", number: 2 }, + "broker-pattern": { name: "SECURITY SERIES", number: 3 }, + "authentik-sso-2fa": { name: "SECURITY SERIES", number: 4 }, + "one-doorman-many-doors": { name: "SECURITY SERIES", number: 5 }, + "clone-not-keys": { name: "SECURITY SERIES", number: 6 }, + + // NETWORKING SERIES - the eBPF datapath and the edge + "landing-on-cilium": { name: "NETWORKING SERIES", number: 1 }, + "observe-first-deny-second": { name: "NETWORKING SERIES", number: 2 }, + "snat-ate-my-source": { name: "NETWORKING SERIES", number: 3 }, + "outbound-only-exposure": { name: "NETWORKING SERIES", number: 4 }, + "cert-couldnt-see-its-proof": { name: "NETWORKING SERIES", number: 5 }, + + // PLATFORM SERIES - how the fleet is delivered and kept alive + "shipping-this-site": { name: "PLATFORM SERIES", number: 1 }, + "no-ssh": { name: "PLATFORM SERIES", number: 2 }, + "bastion-is-a-pattern": { name: "PLATFORM SERIES", number: 3 }, + "init-gating-gpu-readiness": { name: "PLATFORM SERIES", number: 4 }, + "sleep-half-the-fleet": { name: "PLATFORM SERIES", number: 5 }, + "restore-or-rumour": { name: "PLATFORM SERIES", number: 6 }, + "stage-the-locks": { name: "PLATFORM SERIES", number: 7 }, }; diff --git a/src/pages/blog/[slug].astro b/src/pages/blog/[slug].astro index 8811595..7627b76 100644 --- a/src/pages/blog/[slug].astro +++ b/src/pages/blog/[slug].astro @@ -2,6 +2,7 @@ import Layout from "../../layouts/Layout.astro"; import { getPosts, formatDate } from "../../lib/blog"; import { readingTime } from "../../lib/reading"; +import { series } from "../../data/series"; import { render } from "astro:content"; import type { GetStaticPaths } from "astro"; @@ -21,6 +22,12 @@ const { Content } = await render(entry);