Files
Adnan Zahir 98dca237f4 Add infra-ops-toolkit plugin: topology diagram, html-to-pdf, teleport onboarding skills
Distills patterns from the Teleport access topology work: verified-data diagram
building, as-displayed HTML-to-PDF export via headless Chromium, and
container-scoped/host/database onboarding into an existing Teleport cluster.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R3ZTfgQrkR3q8DSEoZAmvs
2026-09-08 16:11:36 +07:00

6.5 KiB
Raw Permalink Blame History

name, description
name description
topology-diagram Build or update the MBU Group SSH/database access topology diagram (a light-theme HTML+SVG page mirrored into a .drawio.xml file). Use when asked to visualize, draw, update, or "perbarui" the infra access topology, network diagram, or Teleport topology — including adding a new provider/host/database, correcting IPs or specs, or fixing arrow/layout issues. Always re-verify every value against live infra before writing it; never hand-type an IP, spec, or resource name from memory.

Topology Diagram

Two files always ship together and must stay in sync:

  • topologi-ssh-teleport.html — the primary, richly-styled artifact (what people actually read)
  • topologi-ssh-teleport.drawio.xml — an editable mirror for the team, generated from the same coordinates/content, one visual generation behind on cosmetic-only details (see "drawio limitations" below)

Ask the user where these live in their vault/Downloads if unknown — don't assume a path.

Golden rule: verify before you draw

Never write an IP, spec, capacity number, or resource name from memory or from the diagram's own prior state. Before touching the file, pull fresh data from the actual source:

  • Droplets/VMs: doctl compute droplet list --format Name,PublicIPv4,PrivateIPv4,Memory,VCPUs,Disk,Region,Status
  • Managed databases: doctl databases list -o json (get storage_size_mib, size slug, num_nodes — the list view alone omits storage)
  • AWS compute: aws ec2 describe-instances (loop every region if the primary region search comes up empty — check with aws ec2 describe-regions)
  • AWS databases: aws rds describe-db-instances
  • Teleport's own view: tsh ls, tsh db ls -f json, tsh app ls — this is what's actually registered, which can differ from what a droplet list implies
  • Cluster roles/config: tctl get roles --format=json (see teleport-onboard skill for where tctl actually runs)

If a resource shows up in the diagram's current text but you can't re-confirm it from a live source, don't silently trust it — flag it as unverified in the diagram itself (dashed border + a short "perlu verifikasi manual" note) rather than deleting it or leaving it looking equally confident as verified data. This has caught real bugs: a database name that looked like a duplicate turned out to be a distinct self-hosted DB reachable only via tsh db ls, not doctl.

Design system (HTML)

Everything is driven by CSS custom properties on :root — change the palette in one place:

--bg, --surface, --line, --line-soft, --text, --text-dim, --text-faint   /* neutrals */
--accent   /* the single ingress chokepoint (e.g. the proxy/gateway) — spend this color deliberately, once */
--user, --core, --agent, --do, --db, --wire, --legacy, --aws  /* one hue per semantic category, reused everywhere: node icon, node border stripe, matching edges, zone eyebrow labels */

Pick a light or dark ground deliberately; light was chosen last for readability and print/PDF friendliness. Typography: a display sans (Archivo) for titles, a mono face (JetBrains Mono) for every IP/port/command/capacity number — the mono choice is not decorative, it's because the subject is literally terminal/IP data.

Node card pattern (repeated ~30×): a <path> (not <rect>) drawing a rectangle rounded only on the right (left corners stay square, matching the left accent stripe):

M{x},{y} L{x2-r},{y} A{r},{r} 0 0 1 {x2},{y+r} L{x2},{y2-r} A{r},{r} 0 0 1 {x2-r},{y2} L{x},{y2} Z

plus a thin <rect> (width:3-4, rx:0) at the same x/y as the left accent stripe in the category color, plus a <foreignObject> holding real HTML (icon svg + <b> title + .n-meta lines, one of which is usually .faint for the least-important line). foreignObject is what makes rich HTML-in-SVG possible at all — don't try to hand-roll the same layout with plain <text> elements.

Zone headers: a small mono eyebrow label + a thin <line> rule spanning the full content width — not a big tinted background band (tried first, looked muddy). Provider containers (DigitalOcean / Biznet / AWS): white fill, 2px border in that provider's category color, not a pastel fill.

Edges: orthogonal <path>s in the category color of what they represent (not what they connect), each with an arrow <marker> in <defs>. Labels are centered pills: wrap the label text in a flex-centered <div> inside a <foreignObject> sized/positioned at the edge's true midpoint, styled as border-radius:999px; background:var(--surface); border:1px solid var(--line); — this reads as a chip floating on the line, not text mashed into the background.

Layout discipline: when adding a new column (a new provider, a new agent lane), recenter it under its own container and re-run the numbers for every sibling that shares a header divider or trunk edge — don't leave one column narrower/off-center while others got the treatment. Widen the viewBox and extend header <line> rules to the new right margin; don't leave them stopping short.

Print/PDF: add an @media print block (@page{size:landscape}, .layout{display:block}, page-break-after on the diagram frame) so a browser's own print dialog doesn't crush a wide multi-column layout into an unreadable thumbnail. But if the user wants a PDF that matches the on-screen view exactly (not a print-reflowed one), that's a different tool — see the html-to-pdf skill instead of fighting the print dialog further.

drawio mirror

drawio's mxCell style language can't do per-corner rounding, arbitrary SVG icon paths, or CSS-variable-driven theming. Don't hand-edit 30+ mxCell blocks for a structural change — write a small Python generator with helper functions (node(), container(), edge(), eyebrow()) that takes the same coordinate/color/text data as the HTML and emits the XML. This is far less error-prone than manual edits and keeps the two files derivable from one source of truth even though they're not literally the same code.

Known, accepted gaps versus the HTML (state these to the user rather than silently mismatching): symmetric arcSize rounding on all four corners (not right-only), no custom icons (title + category color + left stripe carries the scanability instead), edge labels approximated via a child "edgeLabel" vertex with rounded=1;arcSize=100 for the pill look.

After any edit to either file: validate XML with python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.xml')", check <foreignObject>/<g> tag balance in the HTML, then open <path> to eyeball it in a browser before calling it done.