Skip to content

feat: render architecture diagrams from Graphviz DOT instead of Mermaid - #240

Open
JohannesRudolph wants to merge 6 commits into
mainfrom
feat/graphviz-diagrams
Open

feat: render architecture diagrams from Graphviz DOT instead of Mermaid#240
JohannesRudolph wants to merge 6 commits into
mainfrom
feat/graphviz-diagrams

Conversation

@JohannesRudolph

Copy link
Copy Markdown
Member

Why

Mermaid gives no control over layout. There is no way to express "keep these three nodes on one row" and no way to express "this edge must not affect ranking", so any diagram with two related hierarchies comes out as diagonal spaghetti — and every attempt to fix it fights the engine rather than the diagram.

Graphviz DOT has both escape hatches, which is worth a render step.

What changed

Tooling

  • tools/diagrams/render-diagrams.mjs renders every *.dot in the repo to a sibling *.svg. Graphviz runs as a WASM npm package, so no system dot install is required.
  • task diagrams renders; task diagrams:check verifies. The new Diagrams Check workflow runs --check on PRs, so editing a .dot without committing the re-render fails CI instead of silently shipping a stale picture.
  • The generator strips Graphviz's version comment from the SVG so committed output doesn't churn on every version bump.
  • .gitattributes marks the diagram SVGs linguist-generated to keep PR diffs readable.

Converted diagrams

azure-kubernetes and stackit-kubernetes move from Mermaid to DOT — rank=same for rows, constraint=false for cross-cutting edges, splines=ortho for right-angle connectors, and xlabel for labels that survive ortho routing.

Why not inline HTML/SVG

The website renders these files through marked into Angular's [innerHTML], which strips <style> blocks, style attributes and inline <svg>; GitHub's markdown pipeline does the same. So the markdown references the SVG as a plain relative image — which renders on GitHub — and index.ts rewrites relative image links to absolute raw URLs pinned to the built commit so the same link resolves on the website.

Drive-by fix

getGitHubRemoteUrl() only normalized https remotes, so every generated link (sourceUrl, folderUrl, …) was malformed when index.ts ran in an SSH clone. It now handles scp-style git@github.com: remotes too.

Conventions

AGENTS.md gains a Diagrams section documenting the layout, the commands, the DOT attributes that matter, and the traps — including bgcolor="white" (a transparent background renders dark-on-dark in GitHub's dark theme) and avoiding ordering=out (it silently mirrors rows).

Verification

  • task diagrams:check passes; verified it fails on a deliberately stale SVG.
  • node index.ts regenerates the catalog with correctly absolutized image URLs.
  • Both rendered SVGs reviewed visually.

Follow-up

The STACKIT Landing Zone diagram in #236 is the diagram this approach was designed against — it adopts this once #236 lands.

Note on dark mode

The SVGs commit to a white background on purpose. In GitHub's dark theme they will read as a light panel; the alternative (transparent) makes dark text invisible. Shipping light/dark pairs behind <picture> is possible later if wanted.

🤖 Generated with Claude Code

Mermaid gives no control over layout. There is no way to say "keep these three
nodes on one row" and no way to say "this edge must not affect ranking", so any
diagram with two related hierarchies comes out as diagonal spaghetti and every
attempt to fix it fights the engine.

Switch reference architecture diagrams to Graphviz DOT committed next to the
markdown, with the rendered SVG committed alongside:

- tools/diagrams/render-diagrams.mjs renders every *.dot to a sibling *.svg.
  Graphviz runs as a WASM npm package, so no system `dot` install is needed.
  --check re-renders in memory and diffs against what is committed.
- task diagrams / task diagrams:check wrap it; a Diagrams Check workflow runs
  --check on PRs so a .dot edit without a re-render fails instead of shipping a
  stale picture.
- Convert azure-kubernetes and stackit-kubernetes from Mermaid to DOT, using
  rank=same for rows, constraint=false for cross-cutting edges, splines=ortho
  for right-angle connectors and xlabel for labels that survive ortho routing.

Inline HTML/SVG is not an option for these diagrams: the website renders the
markdown through marked into Angular's [innerHTML], which strips <style>,
style attributes and inline SVG, and GitHub's pipeline does the same. So the
markdown references the SVG as a plain relative image, which renders on GitHub,
and index.ts rewrites relative image links to absolute raw URLs pinned to the
built commit so the same link works on the website.

While here, teach getGitHubRemoteUrl to normalize scp-style SSH remotes. It only
handled https, so every generated link was malformed when the script ran in an
SSH clone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Scorecard Check

Scorecard run on commit c7e1a156c3592f77d602f2503bb9c9e5a14034ff relative to origin/main

modules/aks/logo.svg

Module directory not found (deleted?).

modules/aws/logo.svg

Module directory not found (deleted?).

modules/azure/logo.svg

Module directory not found (deleted?).

modules/azuredevops/logo.svg

Module directory not found (deleted?).

modules/cloudfoundry/logo.png

Module directory not found (deleted?).

modules/gcp/logo.png

Module directory not found (deleted?).

modules/github/logo.png

Module directory not found (deleted?).

modules/ionos/logo.png

Module directory not found (deleted?).

modules/oci/logo.png

Module directory not found (deleted?).

modules/openshift/logo.png

Module directory not found (deleted?).

modules/openstack/logo.png

Module directory not found (deleted?).

modules/sapbtp/logo.png

Module directory not found (deleted?).

modules/ske/logo.svg

Module directory not found (deleted?).

modules/stackit/logo.png

Module directory not found (deleted?).

@aws-amplify-eu-central-1

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-240.d1o16zfeoh2slu.amplifyapp.com

JohannesRudolph and others added 5 commits July 31, 2026 10:20
The DOT diagrams were correct but plain. What made the earlier HTML mockup
read better was not the tool: it was a consistent emoji vocabulary and a
palette where colour meant something. Those are conventions, so write them
down and apply them.

Add .agents/references/diagrams.md, following the existing reference-file
pattern, and reduce the AGENTS.md section to a pointer. It captures:

- Composition. One top-level cluster per system, with the relationships as
  dotted constraint=false edges across the boundary; a lifecycle split only
  when the story is who-does-what rather than how two systems map onto each
  other. Single-node clusters read as noise.
- A five-role palette (definition / instance / provider / structure / muted)
  where colour encodes what kind of thing a box is, never decoration.
- A shared emoji vocabulary, so the same concept gets the same icon across
  diagrams and a reader can match boxes between them.
- A canonical preamble, so spacing, type and stroke weight match everywhere.
- Layout control and its traps, including two found the hard way here.

Restyle both diagrams accordingly: emoji on every node, palette applied by
role (the starterkit BBD reads as a meshStack definition, per-team objects as
instances, cloud services as provider-managed), and the single-node catalog
cluster dropped in favour of a free-standing node.

Two corrections to what the previous commit assumed:

- Emoji need the U+FE0F variation selector to render in colour. ☸ ⚙ 🗄 🗂 🛰
  default to text presentation and came out as small monochrome symbols. The
  earlier note said to omit the selector, which was backwards.
- style=invis edges in a rank=same block only hint at left-to-right order. A
  constraint=false edge between two same-rank nodes is itself a flat edge and
  outranks them, which is what pulled SKE out of its declared position.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both diagrams mixed a lifecycle split ("Per Application Team") with a
system split ("Azure — managed by the platform team"), which the diagram
conventions forbid, and left the starterkit BBD floating outside every
cluster with no meshStack layering around it.

- one cluster per system: Azure/GitHub/meshStack and STACKIT/meshStack
- give the meshStack side its own depth: platform -> landing zone ->
  project, alongside the BBD composition
- cross-boundary edges are dotted + constraint=false so they no longer
  distort the ranking they describe
- collapse the dev/prod twins to x2 cardinality labels, which removes
  most of the old edge spaghetti
- meshStack constructs always point at the cloud resources they manage

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant