MakerFLOSS/notes/dev/specs/2026-06-24-rack-documentation-design.md
sjat c362c93f65 docs(spec): rack documentation design (md → CI → SVG/mermaid)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 13:25:28 +02:00

7 KiB
Raw Permalink Blame History

Rack Documentation Design

Date: 2026-06-24 Status: Approved

Goal

Document the 48U server rack as hand-edited Markdown that a CI pass turns into a clear visual presentation, mirroring the existing docs/hardware/*.mdgen_overview.py → generated-index pattern. The rendered output covers three views: a physical rack elevation (SVG), a power distribution graph (mermaid), and a network cabling graph (mermaid).

Authors (operator or AI) edit frontmatter; a push regenerates the artifacts and CI fails on drift, so the published page at docs.makerfloss.eu is always in sync with the source.

Context

  • Per-item frontmatter is already the norm: docs/hardware/*.md and docs/services/*.md carry YAML frontmatter validated by scripts/gen_overview.py against schemas in scripts/overview_config.yml.
  • The generator writes a grouped/sorted index.md; CI (.forgejo/workflows/docs.yml) regenerates it and runs git diff --exit-code to fail on drift.
  • Mermaid already renders in the Marp slide pipeline; it is not yet enabled in MkDocs. Enabling it is a small mkdocs.yml change (superfences custom fence; Material ships mermaid.js).
  • The rack contains devices that already have host pages (mf01..mf04).
  • The physical rack is labeled U1 at the top, descending to U48 at the bottom (non-standard; standard racks number U1 at the bottom). The elevation must match the physical labels.

Data model

Rack data is added to host frontmatter (decision: extend existing files rather than introduce a separate layout file). Rack-mounted items that are not hosts (PDUs, patch panels, shelves, blank panels, UPS, KVM) each get their own lightweight file in docs/hardware/ using new kind values.

Frontmatter fields

# placement (Phase 1)
rack: rack01          # rack identifier; one rack today, field enables future racks
rack_u: 12            # lowest U occupied (148)
u_height: 2           # number of U occupied
rack_face: front      # front | rear | both | left | right  (0U PDUs use left/right rails)

# power (Phase 2) — on each powered device
power:
  - { pdu: pdu01, outlet: 3 }
  - { pdu: pdu02, outlet: 3 }   # a second entry expresses a redundant PSU feed

# network (Phase 3) — on each device, one entry per cable end originating here
links:
  - { local: eth0, peer: sw01, peer_port: 12, speed_gbps: 1 }

New kind enum values

Extend the hardware enum in overview_config.yml with: pdu, patch-panel, shelf, blank, ups, kvm (joining the existing server, laptop, sbc, switch, ap, desktop).

Non-host item files declare their own capacity where relevant:

# docs/hardware/pdu01.md
hostname: pdu01
kind: pdu
status: in-use
rack: rack01
rack_face: left
outlets: 8
# docs/hardware/pp01.md
hostname: pp01
kind: patch-panel
status: in-use
rack: rack01
rack_u: 24
u_height: 1
rack_face: front
ports: 24

Generator: scripts/gen_rack.py

A sibling to gen_overview.py, sharing its style (stdlib + PyYAML, deterministic, offline, SchemaError → non-zero exit). It reads every docs/hardware/*.md with a rack: field, validates the rack schema, groups by rack, and writes generated artifacts per rack.

Outputs (do-not-edit, generated)

  • docs/infrastructure/racks/rack01-elevation.svg — the elevation picture.
  • docs/infrastructure/racks/rack01.md — generated page embedding, in order:
    1. the elevation SVG (![Rack rack01 elevation](rack01-elevation.svg)),
    2. a mermaid power graph (Phase 2),
    3. a mermaid network graph (Phase 3),
    4. an occupancy table (U-range, hostname/link, kind, face, status).

Each generated file carries the same "Auto-generated … do not edit by hand" banner the existing indices use.

Rendering

  • Elevation (SVG): two side-by-side columns, front and rear. 48 U rows numbered U1 at the top → U48 at the bottom to match the physical rack. Each device is a rectangle spanning its true u_height, filled by a per-kind color, labeled with hostname and U-range. Empty U slots drawn faintly. 0U side-rail items (rack_face: left|right) drawn as thin vertical bars beside the columns. Plain hand-written SVG strings — no external drawing library.
  • Power (mermaid): flowchart of pdu → (outlet) → device; redundant feeds appear as multiple edges into one device.
  • Network (mermaid): flowchart of device[:local] -- speed --> peer[:port] edges built from links.

Validation rules (CI-enforced, fail with a clear message)

  1. rack_u in 148; rack_u + u_height 1 ≤ 48.
  2. No two items overlap the same U range on the same rack_face within a rack.
  3. Every power[].pdu resolves to a file whose kind: pdu; outlet within that PDU's outlets.
  4. Every links[].peer resolves to a real file; peer_port within the peer's declared ports/port count where the peer declares one.
  5. Items with rack_face: left|right (0U) must omit rack_u/u_height; all other rack items must include them.

Integration

File Change
scripts/gen_rack.py New generator (SVG + mermaid + table + validation)
scripts/overview_config.yml Extend hardware kind enum with new values; optional rack config block if reusing config-driven validation
docs/hardware/*.md Add placement (then power, then links) fields to rack occupants; add new non-host item files
docs/infrastructure/racks/ New dir holding generated rack01.md + rack01-elevation.svg
Makefile docs-index/docs-check gain a gen_rack.py step
.forgejo/workflows/docs.yml Run gen_rack.py; extend the drift git diff guard to the generated rack artifacts
mkdocs.yml Enable mermaid (superfences custom fence) [Phase 3]; add the rack page to nav

Phasing

Each phase is independently shippable as its own PR.

  1. Phase 1 — Elevation. Placement schema + new kinds + gen_rack.py producing the SVG elevation and occupancy table + CI drift check + nav entry. Populate rack01 with the current devices.
  2. Phase 2 — Power. power fields + PDU files + generated mermaid power graph + validation rules 3.
  3. Phase 3 — Network. links fields + patch-panel files + generated mermaid network graph + validation rule 4 + enable mermaid in mkdocs.yml.

Test plan

  • Unit (per phase): run python3 scripts/gen_rack.py; assert it writes the expected artifacts and exits 0 on a valid fixture set.
  • Validation: craft fixtures that violate each rule (U overflow, overlap, dangling pdu/peer, bad outlet/port, 0U with U fields) and assert non-zero exit with the right message.
  • Drift: run the generator, confirm git diff --exit-code is clean; mutate a source file without regenerating and confirm CI's guard fails.
  • Visual: make docs-build (or docs-serve), open the rack page, confirm the SVG shows U1 at the top, devices at correct positions/faces, and (Phase 2/3) the mermaid graphs render rather than appearing as code blocks.