| id | spec-006-git-cms |
|---|---|
| title | Spec 006 — Git-based CMS |
| sidebar_label | 006 Git-based CMS |
Status: Shipped. Retroactive spec.
Source directory content (items, categories, tags, collections,
pages) from a separate Git repository that contains YAML / Markdown
files. The web app clones / pulls this repo at build time and at boot via
apps/web/scripts/clone.cjs, then exposes a typed content API in
apps/web/lib/content.ts consumed by
the rest of the app.
- Operating a directory is a content-heavy job; shipping content in Git gives non-developers a clean workflow (PR + review) and a free CDN for static assets.
- Git-as-CMS keeps content versioned, branchable, and easy to back up.
- Decouples deployment cadence (
apps/web) from content cadence (the data repo).
- A configurable
DATA_REPOSITORYenv var pointing to the content repo. - Bootstrapped via
scripts/clone.cjsinto.content/. - Hot reload during dev when content changes.
- Strongly typed content models in TypeScript.
- SEO-friendly slug generation and stable URL structure.
- A web-based content editor — out of scope (future plugin).
- Real-time collaboration on content — out of scope.
As a content editor, I want to manage items by editing Markdown / YAML
files and opening a PR, so my workflow is the same as the engineering
workflow.
As a developer, I want strongly typed access to content so my IDE
catches typos.
- AC-1:
DATA_REPOSITORYenv var clones into.content/. - AC-2: Content schema enforced via Zod.
- AC-3: Items, categories, tags, collections supported.
- AC-4: Build fails with a clear error when content is malformed.
- AC-5: Public listing and item detail pages render content.
- AC-6: Recent hardening landed in PR #690 (auth secret + content bootstrap).
- Multiple data repos at once (future spec).
- Per-user write access to data repo (future plugin).
No direct UX; content drives the public surface.
- Filesystem-based read API in
lib/content.ts. - DB tables that mirror content for fast queries (Drizzle).
- Cache invalidation through
lib/cache-invalidation.ts.
ContentSource will become a plugin interface (per
002) so adopters can swap Git for
a headless CMS (Contentful, Sanity, Hygraph) without touching core.
- Risk: large data repos slow first build. Mitigated by shallow
clone in
clone.cjs. - Open: add Hygraph adapter as a built-in plugin? Default: wait until plugin SDK is stable.
apps/web-e2e/tests/public/discover.spec.ts,apps/web-e2e/tests/public/item-detail.spec.ts,apps/web-e2e/tests/public/categories.spec.ts.
apps/web/scripts/clone.cjs(bootstrap)apps/web/lib/content.ts(read API)- Constitution: I (future plugin), II (TS), III (Spec), IV (Docs).