7 KiB
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/*.md →
gen_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/*.mdanddocs/services/*.mdcarry YAML frontmatter validated byscripts/gen_overview.pyagainst schemas inscripts/overview_config.yml. - The generator writes a grouped/sorted
index.md; CI (.forgejo/workflows/docs.yml) regenerates it and runsgit diff --exit-codeto fail on drift. - Mermaid already renders in the Marp slide pipeline; it is not yet enabled in
MkDocs. Enabling it is a small
mkdocs.ymlchange (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 (1–48)
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:- the elevation SVG (
), - a mermaid power graph (Phase 2),
- a mermaid network graph (Phase 3),
- an occupancy table (U-range, hostname/link, kind, face, status).
- the elevation SVG (
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-kindcolor, 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):
flowchartofpdu → (outlet) → device; redundant feeds appear as multiple edges into one device. - Network (mermaid):
flowchartofdevice[:local] -- speed --> peer[:port]edges built fromlinks.
Validation rules (CI-enforced, fail with a clear message)
rack_uin 1–48;rack_u + u_height − 1 ≤ 48.- No two items overlap the same U range on the same
rack_facewithin a rack. - Every
power[].pduresolves to a file whosekind: pdu;outletwithin that PDU'soutlets. - Every
links[].peerresolves to a real file;peer_portwithin the peer's declaredports/port count where the peer declares one. - Items with
rack_face: left|right(0U) must omitrack_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.
- Phase 1 — Elevation. Placement schema + new kinds +
gen_rack.pyproducing the SVG elevation and occupancy table + CI drift check + nav entry. Populaterack01with the current devices. - Phase 2 — Power.
powerfields + PDU files + generated mermaid power graph + validation rules 3. - Phase 3 — Network.
linksfields + patch-panel files + generated mermaid network graph + validation rule 4 + enable mermaid inmkdocs.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-codeis clean; mutate a source file without regenerating and confirm CI's guard fails. - Visual:
make docs-build(ordocs-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.