Documenting a feature or System
Audience: developers & AI agents documenting a capability · Scope: how to structure docs for a feature, a System (multi-doc), or an integration layer · Last reviewed: 2026-07-20
Part of the documentation standards; builds on writing.md (the base every doc follows).
TL;DR — A feature doc explains a cohesive capability that spans many files — its purpose, its moving parts, and how they connect — so a reader can build a mental model and jump to any piece. On top of the base standard it adds a feature-specific spine: what & why → map the parts → admin settings → flow → integrations → data model → deployment → testing → gotchas. A feature big enough to need several docs becomes a System — one folder, a hub, and spoke docs.
Living standard — amend it.
Where a doc belongs — the top-level kinds
Most docs describe a capability you built — classify those by how much they span (it decides the doc
form). A few top-level areas are fixed scaffolding: they already exist and you write into them rather
than adding new ones. Everything at the top level of docs/ — folder or single file — is one of these kinds.
Capability tiers — pick one for a new capability:
| Tier | What it is | Example | Doc form |
|---|---|---|---|
| Feature | one focused capability someone uses | tracking (analytics) | one focused doc under docs/features/ |
| System | a group of features sharing one data model, vocabulary, and purpose | Quote Follow-Up | a folder: a hub (README.md) + spoke docs |
| Integration layer | shared infrastructure that many systems build on | Pipedrive, Google Sheets | its own top-level doc or folder, referenced by systems |
Fixed areas — the scaffolding around the capabilities; you write into these and rarely add new ones:
| Area | What it is | Where |
|---|---|---|
| Foundation / platform | the substrate the whole site runs on — not something you added, the ground it stands on | docs/configbox/ (ConfigBox / Kenedo) |
| Cross-cutting | a practice or toolchain that applies across every capability | docs/testing/, plus the single-file scheduled-jobs.md and monitoring.md |
| Meta | docs about the docs — these standards | docs/standards/ |
| Planning | not reference material — a register of work, prefixed _ so Docusaurus ignores it | docs/_known-issues.md, admin-guide/_backlog.md |
A cross-cutting area only needs a folder once it has spokes. A single focused doc at the top level (
scheduled-jobs.md,monitoring.md) is fine and preferable to a folder with one file in it — the same rule that applies to features.
The operator-facing Admin Guide (admin-guide/) is a separate audience area, not a kind of reference
doc — see admin-guide.md.
It's a System, not a Feature, when ≥ 2 hold: it's made of multiple stand-alone features; they share a data model and vocabulary (the quote, the agent, the magic-link token, the imported stages); it spans multiple entry points / runtimes (a page and cron and a webhook and an API); no single doc can explain it without sprawling or duplicating.
System vs Integration layer: a System owns business capability; an Integration layer is shared plumbing.
Test — if an unrelated system would also use it, it's a layer, not part of this system. So Pipedrive and
Google Sheets are dependencies the Quote Follow-Up System links to, not spokes of it. (Our pipedrive/README.md
already calls itself a "foundational layer" — same idea.)
How to document a System
One folder per System — which is also exactly what a Docusaurus sidebar category is, so this choice serves both the repo and the docs site:
docs/quote-follow-up/
_category_.json ← Docusaurus: the sidebar category's label + order
README.md ← the hub, and the category's index page: what the System is + the map
landing-page.md ← spoke (the page: states, save, data model)
authentication.md ← spoke (the no-login magic link + the machine Link API)
pipeline-stages.md ← spoke (imported Pipedrive pipelines & stages)
nudge-cadence.md ← spoke
stage-sync.md ← spoke
link-api-n8n.md ← spoke
README.mdis the hub and the category index. GitHub shows it when you open the folder; Docusaurus auto-uses a folder'sREADME.md/index.mdas the category's index page; an AI/raw reader treats it as the entry point. One file, three readers._category_.jsonsets the sidebar label and order without ugly numeric filename prefixes (see the snippet below). With aREADME.mdpresent you don't need alink— Docusaurus links the category to it.- Spokes are normal feature docs (the spine below); order them with a
sidebar_positionfront-matter field, not a filename prefix (prefixes leak into the URL slug). - Integration layers stay top-level (
docs/pipedrive/README.md) and are linked from the hub — never nested inside a System folder, because other systems use them too. - Never document the same behaviour twice. One doc owns each fact; the hub and the other spokes link to it.
- Small features live in
docs/features/— one focused doc each. Don't make a per-feature folder for a single doc; promote a feature to its own top-level System folder only when it grows into a System (the test above).
Worked example: the Quote Follow-Up System lives in quote-follow-up/ — the hub (
README.md) maps its spokes landing-page.md, authentication.md, pipeline-stages.md, nudge-cadence.md, stage-sync.md, and link-api-n8n.md, with Pipedrive/Sheets linked as Integration layers.
The spine of a feature doc
Start with the base skeleton (title · Audience/Scope/Last reviewed blockquote · TL;DR), then these
sections in this order. Include the ones that apply and omit the rest — don't ship empty headings —
except Admin settings and the Deployment runbook, which are mandatory: if none apply, say so
explicitly (e.g. "No admin settings." / "No manual steps — ships with the code.") rather than dropping the
section, so an operator always knows where to look. This holds for a standalone feature doc and for every
spoke of a System.
- What it is & why it exists. The problem, the user, and the 30-second mental model, in one or two paragraphs. Link the live URL / entry point. (No changelog — see the base standard.)
- How it fits together. The centrepiece of a feature doc: a small diagram of the flow plus a
moving-parts table — one row per component (
file→ role). A parts list and a picture of how they connect, so a reader jumps straight to the right file. - Admin settings. (Mandatory.) Every admin-facing setting the feature exposes, in a table: name · where it's set (admin group / screen) · default · effect of blank/off. Be complete — this is the technical reference, not a sample. A System spoke lists the settings it owns and links the System's admin manual for the full picture. (The plain-language operator how-to for these settings lives in the separate Admin Guide — parallel, not duplicate.)
- Control / data flow. The request lifecycle (a page) or the pipeline (a job): inbound and outbound, what fires what, idempotency, and any ordering that matters.
- Integrations & contracts. External systems (Pipedrive, Google Sheets), auth, and the wire contract (endpoints, status codes, payload shape) — the part another team or automation codes against.
- Data model. The tables/columns the feature owns (name the migration that adds each — as a reference, not a history), plus any denormalisation / carry-forward rules. (Below settings & integrations — read what it does and how it's configured before its storage.)
- Deployment runbook (manual steps). (Mandatory.) The ordered, numbered manual steps to deploy / roll this out end to end — run migrations, set the settings, run any imports / setup CLI, add the cron entries, register the webhook, then a smoke test — so an operator can follow it top to bottom. Include how to turn it on/off. A System spoke covers its own steps and links the System's deployment playbook for the cross-cutting order.
- Testing. What's covered, how to run it, and the capture/guard rules. Link the testing doc.
- Gotchas & caveats. Prerequisites and footguns — the "why did this bite me" section.
- Extension points / possible follow-ups. Where to plug in next; genuinely open items only (no ✅-done).
- Related docs. Cross-links to sibling features and the hub.
Copy-paste: feature-doc skeleton
# <Feature> — <plain-words what it is>
> **Audience:** … · **Scope:** … · **Last reviewed:** YYYY-MM-DD
**TL;DR** — <the capability + the single most important rule, in 2–4 lines.>
## What it is & why it exists
## How it fits together ← diagram + moving-parts table (file → role)
## Admin settings ← MANDATORY: table of EVERY setting — name · where set · default · blank/off
## Control / data flow ← inbound + outbound
## Integrations & contracts
## Data model ← tables/columns (+ owning migration)
## Deployment runbook ← MANDATORY: ordered manual steps (migrate → settings → import → cron → smoke) + on/off
## Testing
## Gotchas & caveats
## Possible follow-ups
## Related docs
Copy-paste: System hub (docs/<system>/README.md)
# <System> — overview
> **Audience:** … · **Scope:** the <System> as a whole; a map to its spoke docs · **Last reviewed:** YYYY-MM-DD
**TL;DR** — what the System does, end to end, in a few lines; then the map below.
## The parts (map) ← a diagram of the spokes + a table: spoke → doc → one-line role
## End-to-end flow ← how one unit of work moves across the spokes
## Shared concepts ← the SINGLE source of truth for things that span spokes
(the magic-link token, the imported stages, the quote↔deal model)
## Dependencies ← the Integration layers it builds on (links to pipedrive/README.md, the Sheets layer)
## Cross-cutting ops ← links to the deploy playbook / admin manual / testing doc
Alongside it, docs/<system>/_category_.json (Docusaurus reads the README as the category index automatically):
{ "label": "<System>", "position": 6, "collapsed": true }
Feature-doc anti-patterns
- Kitchen-sink file — one doc covering five sub-systems; nobody finds their piece. Split, add a hub.
- A parts list with no map — a
Filestable is necessary but not sufficient; show how they connect. - Duplicated behaviour across the hub and a spoke (or two spokes). One owner; the rest link.
- Config buried in prose — put settings in a table (name · default · effect), not scattered sentences.
- Changelog masquerading as status — commit hashes, dated "Status", ✅-done lists. See the base standard.
- An Integration layer nested inside a System folder — shared plumbing (Pipedrive, Sheets) lives top-level and is linked, not owned by one System.
- A folder for a one-doc feature — folders are for Systems; a lone feature lives in
docs/features/as a single doc.
Checklist — a feature doc is done when…
- The base checklist (writing.md) passes.
- A newcomer can state what the feature does and why from the first screen.
- "How it fits together" has both a diagram and a moving-parts table (file → role).
- Admin settings and a Deployment runbook (manual steps) are both present (mandatory) — if none apply, the section says so explicitly rather than being dropped.
- Admin settings is a complete table (every setting · where set · default · blank/off), not a sample.
- The Deployment runbook is ordered / numbered and followable top to bottom (migrate → settings → import → cron → smoke), and says how to turn the feature on/off.
- Data model, control/data flow, integrations, and testing are covered — or deliberately N/A.
- It links the admin/deploy/testing docs instead of duplicating them; the hub (if any) links here and back.
- Only genuinely-open follow-ups remain; nothing resolved.
- If it's a System: a folder with a
README.mdhub +_category_.json; spokes ordered viasidebar_position; the shared concepts live once in the hub; Integration-layer dependencies are linked, not nested.