ADR-0077 — MkDocs + Structurizr is the single source of truth for project documentation¶
Status: active
Date: 2026-04-28
Introduced by: Issue #747 ; operator scale-up directive
Supersedes: complements ADR-66 (UI Stack) by elevating MkDocs + Structurizr to SSoT status
Context¶
The project produces knowledge artefacts at multiple surfaces : ADRs, design docs, runbooks, architecture diagrams, committee dossiers, MLOps readiness templates, blueprints, README files, code comments, claude memory. These surfaces serve different audiences (operators, developers, AI assistants, future-self) but historically there has been no rule about which surface is authoritative when they disagree.
Observed failure modes :
- An architecture decision documented in a chat / claude memory but never landed in
documentation/architecture/→ next operator has no way to discover it - A Need designed in a
documentation/design/CVN-N<nnn>-*.mddoc but the doc is never published to docs.cvntrade.eu (mkdocs nav not updated) - A Structurizr
workspace.dslchange that adds a container but the corresponding mermaid diagram in the design doc is not updated → the two diverge - A new feature shipped without an architecture entry, requiring archaeology to understand later
- ADR-58 invariants (FTF guardrails) discoverable only by reading code comments
ADR-69 + ADR-76 codify SSoT for work tracking (OpenProject). This ADR codifies SSoT for documentation : if it's not in the docs site, it doesn't exist as project knowledge.
The mkdocs site at docs.cvntrade.eu (per ADR-66 stack choice) and the Structurizr workspace at documentation/architecture/workspace.dsl are the two artefacts that, together, form the canonical project knowledge base.
Decision¶
MkDocs (documentation/ rendered at docs.cvntrade.eu) + Structurizr (documentation/architecture/workspace.dsl) are the single source of truth for project documentation. Any project knowledge — Need, Epic, Design, Architecture decision, Operations procedure, MLOps template, runbook — MUST exist in documentation/ (and therefore on docs.cvntrade.eu) before the corresponding work is considered shipped.
Concrete rules :
- Need lifecycle : definition → committee
plan_review→ log indocumentation/needs/CVN-N<nnn>-<slug>.md(post-approval) → linked from OP Need wp - Design : every Need has a design doc at
documentation/design/CVN-N<nnn>-<slug>.md(templatedocumentation/templates/TEMPLATE_design.md) — committee-reviewed before implementation per ADR-68 - Architecture : load-bearing changes extend
documentation/architecture/workspace.dsl(Structurizr) AND have a correspondingdocumentation/architecture/<topic>.mdpage with a mermaid diagram (the mkdocs page is the readable extract ; the DSL is the canonical model) - Operations : new operator procedures land in
documentation/OPERATIONS.md(or a new section) — runbook discoverable from Grafana / OP wp comment - ADRs :
documentation/adr/<NNNN>-<kebab>.md(ADR template) + entry indocumentation/adr/index.md; new ADRs from ADR-56 onwards in English (ADR-57) - MLOps readiness : per-Story file
documentation/stories/<cvn_id>/mlops_readiness.md(templatedocumentation/templates/TEMPLATE_mlops_readiness.md) per ADR-70 - Discrepancy resolution : when a knowledge surface (chat, claude memory, code comment) disagrees with the docs site, mkdocs site wins. Reconcile other surfaces to the docs site, never the inverse.
- Strict-mode build :
mkdocs build --strictMUST pass on every PR (already enforced in CI per.github/workflows/docs-site.yml). A broken anchor / missing doc IS a CI failure that blocks merge. - Structurizr lockstep : when an ADR introduces a new container or relationship that is load-bearing for an active invariant (i.e., other ADRs / docs reference it as if it existed),
workspace.dslis updated in the same PR that ratifies the ADR — no exception, no "follow-up PR" loophole. Temporary waiver path : if the design genuinely needs further validation before the DSL change is meaningful (e.g., the container's responsibilities are still being negotiated), the operator MAY merge the ADR with statusproposed(per ADR-76 status-honesty pattern) ; the DSL update lands in the same PR that promotes the ADR toactive. This forbids the "active ADR + missing DSL" failure mode while preserving the ability to ship in-progress design work. The DSL is render-validated locally withstructurizr-clior the VS Code extension before commit.
Invariants¶
- I1 — Docs site is authoritative : every project knowledge artefact (Need, Design, ADR, Operations procedure, MLOps readiness, runbook) is what the docs site at docs.cvntrade.eu says it is. Other knowledge surfaces (chat, claude memory, code comment, README outside
documentation/) mirror the docs site, never the inverse. - I2 — Strict-mode CI is non-negotiable :
mkdocs build --strictis a hard gate on every PR. Pre-existing broken refs are technical debt to be fixed (cf. PR #728 — first cleanup of the strict-mode failure backlog), not a license to introduce more. - I3 — Structurizr coverage : every architectural container / relationship that load-bears for an ADR exists in
workspace.dsl. A mermaid-only diagram is acceptable for ad-hoc internal explanations, but the DSL model is the canonical view referenced from ADRs. - I4 — Migration on touch : pre-ADR-77 docs that don't follow the conventions are migrated when the work resumes on them — not retroactively in one batch. The CVN-N009 Epic (docs site health, #725) tracks the cleanup backlog.
- I5 — Need → Epic → Story chain documented : every Story has a discoverable path to its Epic and its Need via the docs site (cross-reference links + the OP wp tree). The
cvn_idnaming convention (per ADR-76 I2) makes this navigable. - I6 — No knowledge dark matter (scoped to implemented decisions) : if a finalized, implemented or about-to-be-implemented decision exists somewhere (chat, code comment, claude memory) but not in the docs site, the operator (or AI assistant) MUST land it in the docs site before considering the work done. "I'll document it later" is a violation. Out of scope : ephemeral ideation-phase discussions, abandoned alternatives, brainstorm threads — these are explicitly NOT subject to I6 (they don't represent project decisions, only exploration). The boundary : a decision is "finalized" once it has either (a) a committee
plan_reviewverdict, (b) an issue + branch, (c) a PR, or (d) a code change. Pre-(a) ideation stays in chat / claude memory without obligation. (Per committeeb7a2b7d4reco 2 — clarifies the rule's scope to avoid creating doc-write friction during early exploration.)
Alternatives rejected¶
- Wiki / Confluence / Notion : another vendor, no version control, not co-located with the code, hard to migrate. Rejected — mkdocs in-repo is co-located and version-controlled by definition.
- README files scattered across the repo : no central nav, no cross-doc anchors enforced, no rendered site. Rejected — README files are acceptable as
code-adjacentmicro-docs but the canonical knowledge MUST be indocumentation/. - Code comments + auto-generated API docs only : works for API surfaces, fails for architecture / process / decisions / runbooks. Rejected — code-only documentation is a known anti-pattern at scale.
- OpenProject as docs SSoT (collapse with ADR-76) : OP is good at work tracking but bad at long-form knowledge (no per-page anchors, no rendered diagrams, no cross-link validation, no version control). Rejected — keep ADR-76 (OP for work) and ADR-77 (mkdocs/Structurizr for docs) complementary.
- Mermaid diagrams in markdown sufficient (skip Structurizr) : mermaid handles per-doc diagrams well but doesn't model the cross-doc system architecture coherently. Structurizr's DSL is the canonical model that mermaid extracts can deviate from. Rejected — keep both, with Structurizr as the canonical model when load-bearing for an ADR.
Consequences¶
- Positive : single answer to "where is the knowledge ?" — docs.cvntrade.eu. Discoverability is uniform (search + nav). Diagrams stay coherent because the DSL is the source.
- Positive : strict-mode CI catches broken refs at PR time, preventing the slow rot we observed pre-PR #728.
- Positive : synergistic with ADR-66 (UI Stack chose mkdocs + Structurizr), ADR-68 (committee), ADR-69 + ADR-76 (OP). The 5 ADRs together form a coherent process + knowledge spine.
- Positive : the migrate-on-touch policy (I4) avoids a busywork rewrite of all pre-existing docs ; debt is paid down as work resumes on each surface.
- Negative : ~5-15 minutes overhead per substantive PR to land the doc update + mermaid / DSL diagram. Acceptable given the discoverability gain.
- Negative : Structurizr DSL learning curve for new contributors. Mitigated by the existing
documentation/architecture/workspace.dslas a worked example + the per-ADR extension pattern (cf. CVN-N010 design §4.5). - Neutral : claude memory continues to exist, but it is a cache (per ADR-76 §Alternatives), not a truth source. Memories that contradict the docs site are stale and should be deleted on discovery.
Rollback¶
This ADR is process. Rollback = remove this file + revert CLAUDE.md / OPERATIONS.md edits introduced by issue #747. The docs site at docs.cvntrade.eu and the Structurizr workspace stay (descriptive artefacts regardless of policy).
If the SSoT discipline proves systematically wasteful (e.g., > 30 % of operator time spent on docs updates with no measurable improvement in discoverability), revisit the migration-on-touch policy or the Structurizr lockstep requirement before retiring the ADR.
References¶
- ADR-26 — Grafana as single entry point (sister SSoT for observability surfaces)
- ADR-57 — ADRs in English (process discipline, applies to all docs from ADR-56)
- ADR-66 — UI Stack (chose mkdocs + Structurizr — this ADR elevates them to SSoT)
- ADR-68 — Expert Committee = default review channel (committee dossiers live in
documentation/reviews/) - ADR-69 — OpenProject orchestrator (Story dossiers in
documentation/stories/) - ADR-70 — MLOps readiness template (template + filled per-Story files in
documentation/) - ADR-76 — OpenProject SSoT for project memory (sister ADR, same scale-up directive — work tracking vs knowledge base)
documentation/architecture/workspace.dsl— Structurizr canonical modelmkdocs.yml— docs site nav config.github/workflows/docs-site.yml— strict-mode CI gate (I2 enforcement)- Issues : #593 (OP + docs Phase 1), #725 (CVN-N009 docs site health Epic — backlog cleanup), #747 (this ADR + ADR-76)
- Committee sessions :
b7a2b7d4(this ADR's plan_review, PASSED OK avg 8.4 strong, 0 blocker, 0 dissent, 8 forward-looking recos : reco 2 I6 scope clarified ✅ in this revision (ideation vs implementation boundary explicit) ; recos 1/3/4/5/6/7/8 captured as backlog : Structurizr training (1), CVN-N009 backlog reviews (3), doc-adherence metrics (4), PR-template semantic checklist (5), pilot adoption (6), recovery path doc in OPERATIONS.md (7),docsyncCLI abstraction (8))