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./tagsand/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.xmlor/atom.xml,/robots.txt, and Open Graph images (/og/:section/:slug.pngor 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/childfor the docs sidebar tree,seriesfor an ordered series,relatedfor 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
- 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 validdraftentry 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 withpublishedAtset. - 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.
- 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.
- Search. A reader types a query on
/searchand 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. - Schedule. An editor sets a future
publishedAton an entry; it isscheduled, excluded from production builds and the feed, and a rebuild at/after that time publishes it. - Taxonomy and feeds. The editor renames a tag; the tag archive, the entry pages and the
sitemap all reflect the change, and
sitemap.xmland 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
ContentTypeat 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(oratom.xml) built from published entries newest-first;sitemap.xmlcovering every published route;robots.txtwith 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_reviewandscheduledentries 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
h1per page, ordered headings), unique title/description per route, absolute canonical URLs, a valid sitemap and feed, correcthreflang/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.xmlandrss.xml/atom.xmlare 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.exampledocuments 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:
- Scaffold the chosen stack, install dependencies, get the dev server and the empty shell running, and commit the skeleton.
- Content model + typed validation: the
ContentType/field schema, front-matter parsing and the build-time validation that fails on a bad entry. - Layouts + navigation: base layout, section index, entry page, breadcrumbs, the docs sidebar and taxonomy pages, rendered from seeded entries.
- 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. - Search & related content: the search index or hosted search plus related/series links.
- Authoring workflow:
<cms>wiring and preview, roles, draft → review → publish, scheduling. - Quality / performance: tests for validation and rendering, static-output check, Lighthouse
budget, accessibility pass, CI, README and
.env.example.