How publishing and the site fleet work
The problem: one platform publishes to many sites, each with its own brand, domain and theme. Coupling the content engine to site rendering makes every theme change a platform deploy and every platform bug a fleet outage. The design answer is three layers that deploy independently.
Layer 1 — the three-layer topology
Section titled “Layer 1 — the three-layer topology”The hub is a vendored microservice with its own instance registry: per-site records carrying template, status, deploy target and public URL. The registry — not the platform database — is the hub’s source of truth for where each brand lives. The platform hands the hub a finished article; everything from “markdown file in the right folder” to “site rebuilt and rsynced” is the hub’s business.
Layer 2 — the publish flow, end to end
Section titled “Layer 2 — the publish flow, end to end”Two details carry the reliability:
- Upsert by source URL. The hub keeps its own article registry keyed by the source URL, so republishing an improved version replaces the page instead of minting a duplicate.
- Slug identity lives on the platform side. The published-URL registry keys identity as (instance, normalized source URL) — deliberately not the article’s internal id, which changes on regeneration. A regenerated article reuses its frozen slug; a brand-new source mints one. This is what protects accumulated SEO equity from being reshuffled by routine regeneration.
Layer 3 — brand configuration is code, not server state
Section titled “Layer 3 — brand configuration is code, not server state”Branding (title, logo, colors, taxonomies, the author roster) lives in git templates per brand over a shared theme. A hand-edit on the web host survives only until the next build — by design: the template is the single source of truth, and every deploy reasserts it. New sites start as staged port-instances (reachable, no domain) and convert to production domains in a short, reversible procedure (DNS → vhost → registry URL → platform record).
Layer 4 — deploying the layers themselves
Section titled “Layer 4 — deploying the layers themselves”Each layer ships on its own cadence, with its own invariants:
- Platform — a four-phase deploy script: preflight (refuses while runs are active; snapshots the secret surface), code swap with a timestamped backup, container rebuild, postflight (health-wait + re-hash of the secret surface — an unexpected diff aborts). Database migrations apply automatically at container boot.
- Hub — rebuilt from its repo; a template change redeploys per instance without touching the platform.
- This documentation — built statically, shipped as an immutable release directory with a symlink flip; rollback is flipping the symlink back.
The trade-offs, honestly
Section titled “The trade-offs, honestly”Three layers mean three registries of truth (platform DB, hub instance registry, git templates) — and the operational cost is keeping their pointers aligned; misaligned registry state has produced “instance not found” incidents. The verified-live-URL rule also means publishing is only as done as the slowest site build — a queue at the hub delays proof, not just delivery. Both costs are accepted in exchange for fleet-wide brand changes that never require touching the content engine.
See it in two minutes
Section titled “See it in two minutes”Any published article row carries its live URL; fetch it — that URL
responding is the platform’s own definition of “published”. The
instances API domain lists the fleet the hub serves.
Specs: SPEC-073 (published-URL identity), SPEC-096 (publish-path hardening), SPEC-097 (publish stack), plus the vendored hub service.