ADR 0026: Internal service documentation as source of truth

Ratification

This ADR sets rules for internal HTML under docs/internal/: what belongs there, how pages relate to code and OpenAPI, and how we keep history. It works with ADR 0025 (who reads what). Git history on main is the record for this file.

Context

Why this matters: External clients use OpenAPI (ADR 0007). Inside the team we still need one place we can review for rules across layers: business invariants, when an error is operational vs validation, how we expect to monitor a flow, and how HTTP handlers map to services and async work. Without that, people fall back to “read the code,” which is slow and unclear when code and branches differ.

This ADR makes docs/internal/ the main engineering narrative for those topics. It does not copy OpenAPI field lists; it explains them and ties them to behavior and operations.

Decision

  1. Location and format. Internal service documentation lives under docs/internal/ as static English HTML. All such pages use the shared site stylesheet docs/assets/docs.css and top navigation docs/assets/docs-nav.js. Multi-page internal docs (API hubs, resource hubs, per-method pages) additionally use docs/assets/internal-layout.css and docs/assets/internal-sidebar.js for the two-column shell and left navigation (see Navigation and chrome). In documentation indexes and guides (for example under docs/howto/ and docs/adr/), use semantic <section class="card"> blocks for major content groups, without nested <div class="card"> wrappers. New or changed pages are added or updated in the same pull request as the behavior change when the change is user-visible or alters invariants described here.
  2. Source of truth for engineering disputes. For topics explicitly covered in docs/internal/, the written page (on main after merge) is the normative reference for how the team intends the system to work. If code disagrees, either the code or the doc must be fixed in a follow-up; silent divergence is treated as a defect. Topics not yet documented remain governed by ADRs, runbooks, and code until a page exists.
  3. What to document (non-exhaustive). Pages should cover, as applicable:
    • Capability or domain slice — purpose, boundaries, key entities.
    • HTTP mapping — reference operationIds or paths that implement the slice; link to OpenAPI rather than copying schemas.
    • Business rules — invariants, ordering assumptions, idempotency and conflict behavior (see also ADR 0006).
    • Errors and observability — which codes or signals warrant alerts vs expected client mistakes; correlation with logs and metrics (see ADR 0003, ADR 0009, ADR 0023).
    • Async and integration — message topics, consumers, outbox patterns, or external systems, when present.
  4. History and traceability. Material pages include a short Page history subsection (table: date, author optional, summary of change). Git history remains the full audit trail; the table is for human scanning. Breaking behavioral changes also appear in root CHANGELOG.md per ADR 0013.
  5. Entry points. docs/internal/README.html is the top-level index (teams, practices, links into HTTP docs). The directory tree and contributor checklist live in docs/howto/internal-service-docs-layout.html; docs/internal/STRUCTURE.md is a short pointer to that page and should stay aligned when the tree changes.
  6. Relationship to ADRs. Cross-cutting policy (versioning, security, idempotency) stays in ADRs. docs/internal/ applies those policies to concrete flows and entities. If a new policy is needed, add or update an ADR; do not bury policy-only decisions in internal prose alone.

Repository layout under docs/internal/

Internal docs are organized so readers can move from product contextHTTP surfaceone resourceone endpoint, without a single monolithic HTML file for everything.

Path (under docs/internal/) Role
README.html Single entry: project context, service role and boundaries, contract and observability summary, links to ADRs and the HTTP API area. (Former service-overview.html content merged here.)
STRUCTURE.md + docs/howto/internal-service-docs-layout.html Full tree outline and contributor checklist in the how-to HTML page; STRUCTURE.md links there. Update both when adding resources or renaming paths.
api/README.html HTTP API hub: lists documented resources and points to each resource hub.
api/<resource>/index.html Single entry point per resource — business context, contract summary, governance, technical depth (layers, idempotency, errors, logging, metrics, dependencies), endpoint index, and stable fragment identifiers (e.g. #user-op-createUser) for deep links from per-method pages.
api/<resource>/operations/*.html One page per HTTP endpoint, named from method + path template (not from Python operationId), focused on call semantics; each page links back to anchors on the resource index.html.
api/<resource>/… redirect stubs (optional) Legacy filenames may remain as minimal HTML that redirect to index.html with hash preserved, so old bookmarks keep working.

Contributor workflow

When documenting or changing HTTP behavior:

  1. Keep OpenAPI (docs/openapi/) and contract tests aligned per ADR 0007.
  2. Update the resource api/<resource>/index.html if business narrative, invariants, or cross-cutting technical behavior (idempotency, logging, metrics) change.
  3. Update affected operations/*.html pages when endpoint-specific detail changes.
  4. Update INTERNAL_SIDEBAR_NAV when adding routes or pages; add a row to Page history on substantive hub updates.
  5. Reflect notable doc-tree changes in docs/CHANGELOG.md when the documentation set itself is part of the deliverable.

The checklist in docs/howto/internal-service-docs-layout.html mirrors this workflow for new resources (new folder under api/, naming convention for operation files, link from api/README.html).

Scope

Alternatives considered

  1. Wiki or external tool.
    • Pros: rich editors, permissions.
    • Cons: not versioned with the same PR as code; harder to enforce review alongside behavior changes.
  2. Markdown only under docs/internal/.
    • Pros: faster to write.
    • Cons: this site’s published docs are HTML-first; one stack keeps nav and styling consistent.
  3. One very long HTML file per resource.
    • Pros: single URL for everything.
    • Cons: poor scanability; heavy merge conflicts; we instead use a hub plus per-method pages with reciprocal anchor links.

Consequences

Positive

Trade-offs

Page history

Date Change Author
Added Page history section (repository baseline). Ivan Boyarkin