templates.ContentSite/SPEC.md

12 KiB

Content Site (Blog / Docs) — product specification

This is the contract the project is built against. It is written for the agent that scaffolds the repository, but it doubles as the human-readable brief: every requirement below is meant to be implementable and verifiable.

Values in angle brackets (<Site name>, <content type>, <authoring>) come from the project-creation dialog and are recorded in the project record; replace them as you read. <content> is blog, documentation or marketing pages; <cms> is the authoring approach (Markdown/MDX, Contentful, Sanity or Notion).

1. Goal

A content site a real team could launch with: write structured entries in <cms>, have them rendered as <content> pages with navigation, tags, authors and search, and publish a fast, crawlable, shareable site. Content is stored against a typed content model and validated at build time, so a malformed entry fails the build instead of shipping a broken page. It must be runnable end-to-end on day one (even with seeded sample content), not a set of screens wired together later.

Non-goals (do not build unless the must-have list says otherwise): multi-tenant CMS, comments, subscriptions/paywalls, live collaborative editing, multi-language content.

2. Roles

Role Can do
Reader Anonymous. Browse the site, read entries, filter by tag/author, search, subscribe to the feed.
Author Everything a reader can, plus create and edit their own entries (draft → in review).
Editor Everything an author can, plus edit and review any entry, manage taxonomy and schedules, approve and publish.
Site admin Everything an editor can, plus site configuration, navigation, roles, feeds and redirects.

Reading is anonymous and never gated. Authoring happens in <cms> (for Markdown / MDX, in the repository itself; for hosted CMSs, in that CMS UI) and only the publishing side is guarded by roles. Provide a seeded author and editor for local development when the authoring approach has a local backend.

3. Information architecture (routes)

Public site:

  • / — home: hero/intro, latest or featured entries, section links.
  • /:section — section index for one collection (e.g. /blog, /docs), with pagination.
  • /:section/:slug — one entry: title, metadata (author, date, reading time), body, table of contents, related entries.
  • /tags and /tags/:tag — tag archive; /authors/:author — author archive; both paginated.
  • /search — search over titles, tags and body, with a no-results state.
  • /404 — not-found page (and a real 404 status for unknown routes).
  • Authoring preview where the chosen CMS provides one (draft preview URL for an unpublished entry); otherwise a local preview route.
  • Generated artifacts: /sitemap.xml, /rss.xml or /atom.xml, /robots.txt, and Open Graph images (/og/:section/:slug.png or static equivalents).

When <content> is Documentation, the section index is the docs sidebar: entries are ordered and grouped, and one document shows the same sidebar with the current page highlighted.

Admin (guarded by the editor/admin roles, only where the authoring approach has a local backend; hosted CMSs keep this in the CMS UI):

  • /admin — dashboard: draft/review queue and scheduled entries.
  • /admin/entries — list, create, edit, preview and publish/unpublish entries.
  • /admin/taxonomy — manage tags and authors.
  • /admin/site — site config, navigation and redirects.

4. Data model

Minimum viable entities (add fields the requirements imply; keep them typed and validated):

  • ContentEntry — slug, title, body (Markdown/MDX or a CMS reference), excerpt, type (reference to a ContentType), tags[], author (reference), status (draft | in_review | scheduled | published | archived), publishedAt, updatedAt, seo { title, description, canonicalUrl?, image?, noindex }.
  • ContentType — id/key, title, and fields[] (name, label, type, required, default) that define the front-matter a <content> entry must carry; the schema entries are validated against.
  • Author — id, slug, name, bio, avatar, links[].
  • Tag — id, slug, name, description, parentId? (categories are tags with children).
  • SiteConfig — site name, base URL, locale, defaultSeo, and navigation[] (label, href, order, children?) used for the header and the docs sidebar.
  • Relationship — a typed edge between entries: parent/child for the docs sidebar tree, series for an ordered series, related for hand-picked links.

The content model is the source of truth: front-matter missing a required field, an unknown field, or a wrong type is a build error, with the offending file and field named. Document the model so an author can add an entry without reading the renderer.

5. Key flows

  1. Author → publish. An author adds a Markdown/MDX file (or creates an entry in <cms>) with the required front-matter. A malformed entry fails validation with a clear message and the build stops; a valid draft entry renders in preview only. The author marks it ready, an editor reviews and publishes it, and it appears on the section index, the tag archive and the feed with publishedAt set.
  2. Read. A reader lands on the home page, opens a section, reads an entry; the table of contents tracks the scroll position, related entries are listed below, and the document's canonical URL and Open Graph metadata are present in the HTML head.
  3. Documentation navigation. A reader in the docs section sees the ordered sidebar, moves between sibling and child documents, and breadcrumbs show the path from the section root.
  4. Search. A reader types a query on /search and gets ranked matches over current published entries (client-side over an index for small sites, or a hosted search service); an empty query shows recent entries and a no-results query shows a clear empty state.
  5. Schedule. An editor sets a future publishedAt on an entry; it is scheduled, excluded from production builds and the feed, and a rebuild at/after that time publishes it.
  6. Taxonomy and feeds. The editor renames a tag; the tag archive, the entry pages and the sitemap all reflect the change, and sitemap.xml and the feed stay valid.

6. Functional requirements

  • Authoring: Markdown/MDX with front-matter, or entries authored in <cms>; code blocks render with syntax highlighting; images and links resolve; the chosen CMS's preview is wired in where it exists.
  • Typed validation: entry front-matter is validated against its ContentType at build time; a required field missing, an unknown field or a wrong type fails the build with the file, field and expectation in the message.
  • Rendering: table of contents generated from headings; reading time computed; breadcrumbs in the docs layout; related content from series/related edges (fallback: shared tags).
  • Indexes: section, tag and author archives are paginated with a stable page size and their own metadata; pagination links are crawlable.
  • Search: over titles, tags and body; client-side or hosted; no query sent to a third party without the configuration saying so.
  • Feeds & discovery: rss.xml (or atom.xml) built from published entries newest-first; sitemap.xml covering every published route; robots.txt with the sitemap reference and non-production hosts disallowed.
  • Metadata: every route has a unique title and description and an absolute canonical URL; Open Graph and Twitter card tags are emitted; JSON-LD (Article/BlogPosting, BreadcrumbList, WebSite) is present where it applies.
  • Draft/scheduled exclusion: draft, in_review and scheduled entries are excluded from production builds, the sitemap and the feed; they are visible only in preview/local mode.
  • Seed data: sample content (≥ 8 entries across ≥ 2 sections, ≥ 4 tags, ≥ 2 authors, one draft and one scheduled entry) so the site is presentable on first run.

7. Non-functional requirements

This is the SEO and performance template, so these are hard requirements, not polish.

  • SEO: semantic HTML (one h1 per page, ordered headings), unique title/description per route, absolute canonical URLs, a valid sitemap and feed, correct hreflang/locale if used, and no indexable duplicate routes.
  • Performance: static output where possible (pre-render every published route at build time); a Lighthouse budget of LCP < 2.5 s and CLS < 0.1 on an article page; images optimised with explicit width/height and lazy loading below the fold; no client JavaScript on non-interactive pages (article, archives, 404); route-level code splitting only where interactivity needs it.
  • Accessibility (AA): correct landmarks (header/nav/main/footer), heading order, alt text on every meaningful image, labelled links and controls, visible focus, contrast at least AA, keyboard-operable search and navigation.
  • Resilience: explicit loading, empty and error states; a missing entry renders the 404 page with a real 404 status, not an empty shell.
  • Observability: build-time report of validation errors and skipped drafts; structured logs for publish/build events; a health or build-status check for the deployed site.
  • Security: no secrets in the repository; CMS tokens stay server-side and are documented in .env.example; validate and cap CMS and search inputs.

8. Acceptance criteria (definition of done)

  • Install, dev server, lint, typecheck, tests and production build all pass.
  • A malformed front-matter entry (missing required field, unknown field or wrong type) fails the build with a message naming the file and field.
  • sitemap.xml and rss.xml/atom.xml are generated, cover the published routes and validate against their schemas.
  • Every route has a unique title, description and absolute canonical URL; Open Graph and JSON-LD are present.
  • A static article page ships no client JavaScript and meets the LCP/CLS budget.
  • Draft, in-review and scheduled entries never appear in the production build, sitemap or feed; preview still shows them.
  • Search returns ranked results for published entries and has an explicit no-results state.
  • Code highlighting, table of contents, reading time, related content and pagination work on seeded entries.
  • Docs navigation (sidebar order, breadcrumbs, active highlight) works when <content> is documentation.
  • Seeded sample content makes the site presentable immediately; .env.example documents every secret.
  • README quickstart (install, run, build, env) is accurate; loading/empty/error states exist.
  • Accessibility pass: landmarks, heading order, alt text, contrast AA, keyboard-operable search.
  • CI runs install + lint + typecheck + tests + build.

9. Suggested build order

Follow this order and finish (and verify) a layer before starting the next:

  1. Scaffold the chosen stack, install dependencies, get the dev server and the empty shell running, and commit the skeleton.
  2. Content model + typed validation: the ContentType/field schema, front-matter parsing and the build-time validation that fails on a bad entry.
  3. Layouts + navigation: base layout, section index, entry page, breadcrumbs, the docs sidebar and taxonomy pages, rendered from seeded entries.
  4. SEO / feed / sitemap: metadata per route, canonical URLs, JSON-LD, sitemap.xml, rss.xml/atom.xml, robots.txt, Open Graph images, and draft/scheduled exclusion.
  5. Search & related content: the search index or hosted search plus related/series links.
  6. Authoring workflow: <cms> wiring and preview, roles, draft → review → publish, scheduling.
  7. Quality / performance: tests for validation and rendering, static-output check, Lighthouse budget, accessibility pass, CI, README and .env.example.