A CMS where the schema is a TypeScript definition. @spfn/cms declares
labels in code — nested, multi-language, template-ready — syncs them to the database on server
startup, and serves reads from a published cache. Section names and properties are checked at
compile time; editors work in drafts and publish when ready.
Labels are declared in code with defineLabels — nested,
per-locale, with {placeholder} template variables. That definition is the source
of every default and of the types: section names and property paths autocomplete in the IDE,
and a typo is a compile error, not a blank string in production. On server startup
syncLabels writes the definition to the database — new labels created, changed
ones updated by deep-equality check, unchanged ones skipped. The database holds only what
editors change on top: a draft, then a published version, resolved as
Draft > Published > Default.
Label content lives in two tables — cms_labels for metadata,
cms_label_values for versioned per-locale values — but reads touch neither.
Publishing a section rebuilds cms_published_cache: one JSONB row of content per
section and locale, stamped with a version. getLabel hits that cache in a single
query — 5 ms where the JOIN path takes 87 ms — merges it over the code-defined
defaults bound to the current locale, and returns a typed nested object. Only the sections you
request are processed, so a 1,000-label app reading one 100-label section does 10% of the
work, and the version column drives client-side cache invalidation.
Section names and properties validated at compile time — typos are compile errors.
syncLabels on startup — creates, updates by deep equality, skips unchanged.
Single-query reads at 5ms vs 87ms with JOINs — 17x faster.
Admin routes per section — save drafts, publish, reset. Versioned.
Type-checked locales, resolved cookie → defaultLocale → 'en'.
Labels organized hierarchically, read with direct property access.
{placeholder} substitution via format() — strings and numbers.
One section direct, many by name — only requested sections processed.