Dieser Post setzt den dreißigsten Teil fort.
Bis jetzt waren Bausteinsicht-Diagramme reine Visualisierung — man sieht ein System, aber es gibt keinen Weg hinein.
Mit dem link-Feld auf Elementen (docToolchain/Bausteinsicht#483) ändert sich das: jedes Element kann einen
Link bekommen, der beim draw.io-Export als klickbares link-Attribut auf dem Shape landet.
Das macht ein Diagramm zu einem echten Einstiegspunkt in die Doku-Landschaft — Sprung zu einer ADR, einem Jira-Ticket oder einer Confluence-Seite, direkt aus dem Shape heraus.
Nicht zu verwechseln mit der ADR-Registry aus Teil 11
( |
Das link-Feld im Modell
Jedes Element kann optional ein link-Feld bekommen:
"api": {
"kind": "container", "title": "REST API", "technology": "Go",
"link": "examples/teil_31_adr.html"
}Beim nächsten bausteinsicht sync landet dieser Wert als link-Attribut auf dem <object> im
draw.io-XML — im Diagramm ist das Shape dann direkt anklickbar, öffnet den Link im Browser.
Eine ADR als eigenständige Seite
Statt auf eine externe URL zu verlinken, zeigt dieses Beispiel etwas Griffigeres: eine selbst geschriebene Architecture Decision Record, die mit Asciidoctor zu HTML gebaut und direkt in diesem Tutorial-Post eingebettet wird.
Die ADR beschreibt genau die Regel, die weiter unten demonstriert wird — warum Drill-Down-Links Vorrang vor user-definierten Links haben:
asciidoctor examples/teil_31_adr.adoc -o examples/teil_31_adr.htmlDie Content-Pipeline (infra/builder/build-adr-html.sh) übernimmt das automatisch bei jedem Build —
analog zum bestehenden draw.io-Sync-Schritt. Jede examples/*_adr.adoc-Datei wird zu HTML gebaut und
als statisches Asset ausgeliefert.
Eingebettet sieht das so aus:
Kein Seitenwechsel nötig — die verlinkte ADR ist direkt hier lesbar, genau wie sie auch beim Klick
auf das api-Shape im Diagramm erscheinen würde.
Priority-Regel: Drill-Down schlägt User-Link (ADR-009)
Was passiert, wenn ein Element gleichzeitig Scope einer Detail-View ist (bekommt automatisch einen
Drill-Down-Link) und einen user-definierten link trägt? Beide könnten dasselbe Shape beanspruchen.
| Situation | Ergebnis |
|---|---|
Nur user-definierter | Link bleibt erhalten, zeigt auf die angegebene URL |
Nur Drill-Down (Element ist | Automatischer Link zur Detail-View ( |
Beide gleichzeitig | Drill-Down gewinnt — der user-definierte Link wird verworfen, |
Die Begründung steht in der eingebetteten ADR oben — kurz zusammengefasst: Drill-Down ist Navigation innerhalb der Diagramm-Serie und wird als grundlegender erwartet als ein Sprung nach außen.
Das Beispielmodell
teil_31.jsonc modelliert einen kleinen Online Shop mit vier Elementen, die vier unterschiedliche
Link-Use-Cases zeigen:
onlineshop.gateway—linkauf ein externes GitHub-Issue (docToolchain/Bausteinsicht#483, das Ticket, das dieses Feature eingeführt hat). Kein Konflikt, der Link bleibt im Export erhalten.onlineshop.api—linkauf eine ganze Seite,examples/teil_31_adr.html. Kein Konflikt, der Link bleibt im Export erhalten.onlineshop.payment— istscopederpayment-details-View und hat einenlink. Hier greift die Priority-Regel: der Drill-Down-Link gewinnt,syncgibt eine Warnung aus.onlineshop.db—linkmit Anchor auf eine absolute URL,https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_31_adr.html#_modellelement_database_postgresql, springt beim Klick direkt zum Abschnitt "Modellelement: Database (PostgreSQL)" statt an den Seitenanfang.
{
// Teil 31: Klickbare Links in exportierten Diagrammen — Online Shop Beispiel
"specification": {
"elements": {
"actor": { "notation": "Actor" },
"system": { "notation": "Software System", "container": true },
"container": { "notation": "Container", "container": true }
},
"relationships": {
"uses": { "notation": "uses" }
}
},
"model": {
"customer": { "kind": "actor", "title": "Customer" },
"onlineshop": {
"kind": "system", "title": "Online Shop",
"children": {
// Use Case: externer Ticket-Link — verweist auf das GitHub-Issue,
// das dieses Feature eingeführt hat. Kein Konflikt, der Link bleibt
// im Export erhalten.
"gateway": {
"kind": "container", "title": "API Gateway", "technology": "Go",
"link": "https://github.com/docToolchain/bausteinsicht/issues/483"
},
// Klarer Fall: user-definierter Link auf eine ganze Seite, kein
// Konflikt — dieses Element ist nirgends der `scope` einer View,
// der Link bleibt also im draw.io-Export erhalten wie modelliert.
"api": {
"kind": "container", "title": "REST API", "technology": "Go",
"link": "examples/teil_31_adr.html"
},
// Priority-Demo: dieses Element ist gleichzeitig `scope` der
// "payment-details"-View UND hat einen user-definierten Link.
// Der Drill-Down-Link gewinnt (ADR-009) — sync gibt eine Warnung aus.
"payment": {
"kind": "container", "title": "Payment Service", "technology": "Go",
"link": "examples/teil_31_adr.html#_entscheidung"
},
// Use Case: Deep-Link mit Anchor — verweist nicht nur auf die Seite,
// sondern direkt auf den Abschnitt, der diese Komponente beschreibt.
// Anders als beim `api`-Element ist der Link hier absolut (volle
// Produktions-URL): beim Inline-SVG-Export (siehe unten) überlebt
// nur eine absolute URL unverändert — ein relativer Link würde gegen
// den internen Pfad der draw.io-CLI aufgelöst und liefe ins Leere.
"db": {
"kind": "container", "title": "Database", "technology": "PostgreSQL",
"link": "https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_31_adr.html#_modellelement_database_postgresql"
}
}
}
},
"relationships": [
{ "from": "customer", "to": "onlineshop.gateway", "label": "kauft ein", "kind": "uses" },
{ "from": "onlineshop.gateway", "to": "onlineshop.api", "label": "routet zu", "kind": "uses" },
{ "from": "onlineshop.api", "to": "onlineshop.payment", "label": "delegiert Zahlung", "kind": "uses" },
{ "from": "onlineshop.payment", "to": "onlineshop.db", "label": "schreibt Transaktion", "kind": "uses" }
],
"views": {
"context": { "title": "System Context", "include": ["customer", "onlineshop"] },
"containers": { "title": "Container View", "scope": "onlineshop", "include": ["customer", "onlineshop.*"] },
"payment-details": {
"title": "Payment Service — Details",
"scope": "onlineshop.payment",
"include": ["onlineshop.api", "onlineshop.payment", "onlineshop.db"]
}
}
}bausteinsicht sync ausführen
bausteinsicht sync --model teil_31.jsoncDie Ausgabe zeigt die Priority-Warnung für onlineshop.payment:
WARNING: element onlineshop.payment: user-defined link overridden by drill-down link (ADR-009)
Forward (model → draw.io): 14 added, 0 updated, 0 deletedIm resultierenden draw.io-XML zeigt sich der Unterschied zwischen allen vier Fällen direkt:
<!-- onlineshop.gateway — externer Ticket-Link bleibt erhalten -->
<object label="API Gateway" link="https://github.com/docToolchain/bausteinsicht/issues/483" ...>
<!-- onlineshop.api — user-definierter Seiten-Link bleibt erhalten -->
<object label="REST API" link="examples/teil_31_adr.html" ...>
<!-- onlineshop.payment — Drill-Down gewinnt, user-Link wurde verworfen -->
<object label="Payment Service" link="data:page/id,view-payment-details" ...>
<!-- onlineshop.db — Deep-Link mit Anchor, absolute URL bleibt erhalten -->
<object label="Database" link="https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_31_adr.html#_modellelement_database_postgresql" ...>Ergebnis im Diagramm
Das draw.io-File dafür findest du hier: teil_31.drawio
Im draw.io-Viewer sind alle vier Shapes anklickbar, aber mit unterschiedlichem Ziel:
API Gatewayöffnet das GitHub-Issue in einem neuen Tab.REST APIöffnet die eingebettete ADR — genau die Seite, die weiter oben schon zu sehen war.Payment Servicespringt stattdessen zurpayment-details-View — die Drill-Down-Navigation bleibt intakt, obwohl auch dort einlink-Feld im Modell steht.Databaseöffnet dieselbe ADR wieREST API, aber direkt am Abschnitt, der die Database-Komponente beschreibt, statt oben auf der Seite.
Generierte PNG-Dateien:



Generierte PlantUML-Diagramme:
Direkt eingebettetes SVG mit echten Links
Der interaktive viewer.diagrams.net-iframe oben lädt die rohe .drawio-XML zur Laufzeit im Browser
nach — das funktioniert nur, wenn die Datei öffentlich unter der angegebenen URL erreichbar ist. Es gibt
eine Alternative, die ganz ohne externen Dienst und Netzwerk-Roundtrip auskommt:
bausteinsicht export --image-format svg nutzt die echte draw.io-CLI (nicht Kroki) und erhält dabei
link-Attribute als echte <a xlink:href>-Elemente im SVG. Direkt als Inline-Markup ins HTML
eingebettet — nicht als <img src="…svg">, das würde die Links verschlucken — sind einzelne Shapes
darin wirklich klickbar, ganz ohne JavaScript oder externen Dienst.
Die Content-Pipeline (infra/builder/generate-drawio-svg-inline.sh) erzeugt das bei jedem Build:
bausteinsicht export --image-format svg --output out/Für die Container View sieht das eingebettete Ergebnis so aus:
Zwei Einschränkungen gegenüber dem interaktiven Viewer:
Nur absolute URLs funktionieren — auch mit Anchor.
API Gateway(https://github.com/…;) ist korrekt klickbar, ebensoDatabase(https://paul-fleischmann.com/…teil_31_adr.html#_modellelement_database_postgresql) — der Klick landet direkt im Abschnitt, der die Database-Komponente beschreibt.REST APIhat dagegen einen relativen Link (examples/teil_31_adr.html, ohne Domain) — die draw.io-CLI löst den beim Export gegen ihr eigenes Installationsverzeichnis auf, nicht gegen die Seite, in die das SVG später eingebettet wird:<a xlink:href="file:///opt/drawio/resources/app.asar/drawio/src/main/webapp/examples/teil_31_adr.html">Im Browser läuft dieser Klick ins Leere. Damit relative Links hier funktionieren, müssten sie im Modell als absolute URL modelliert werden — mit oder ohne Anchor, das spielt keine Rolle, solange die Domain mit dabei ist.
Drill-Down-Links gehen komplett verloren.
Payment Servicehat im interaktiven Viewer einen klickbaren Sprung zurpayment-details-View (data:page/id,…). Dieses interne URL-Schema ist im Browser nicht navigierbar — die draw.io-CLI lässt das Shape beim SVG-Export deshalb ganz ohne<a>-Wrapper. Mehrseitige Navigation zwischen Views funktioniert nur im interaktiven iframe.
Der Ansatz lohnt sich also nur, wenn alle relevanten Links absolute URLs sind und keine Drill-Down-Navigation gebraucht wird — z. B. für ein einzelnes, in sich geschlossenes Diagramm mit externen Ticket- oder Doku-Links.
Wann lohnt sich das link-Feld?
| Situation | Empfehlung | Beispiel oben |
|---|---|---|
Element hat eine zugehörige ADR |
|
|
Element ist Gegenstand eines offenen Tickets |
|
|
Nur ein bestimmter Abschnitt einer Seite ist relevant |
|
|
Element hat ausführliche Doku in Confluence |
| — |
Element ist | Kein |
|
Was als nächstes kommt
Damit schließt die Bausteinsicht-Tutorial-Serie ein weiteres Kapitel ab: von reiner Visualisierung (Teil 1) bis zu Diagrammen, die direkt in die restliche Doku-Landschaft verlinken.
Die wichtigsten Einstiegspunkte zum Nachschlagen:
Neu starten? → Teil 2: Getting Started
ADRs als Registry im Modell? → Teil 11: ADR-Integration
Mehrere Views aus einem Modell? → Teil 30: Multi-View Design
Structurizr migrieren? → Teil 29: Big Bank Import
Offizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org