[{"content":" Das Grundproblem: Dokumentation veraltet Software-Architektur wird meistens einmal dokumentiert — beim Start des Projekts, wenn der Architekt noch motiviert ist und das System noch überschaubar. Drei Monate später sieht die Realität anders aus. Ein neuer Service ist dazugekommen. Eine Abhängigkeit wurde umgezogen. Das alte Diagramm zeigt noch die ursprüngliche Idee, nicht das aktuelle System.\nDas Problem ist strukturell: Diagramme leben in Präsentationen, Wikis oder Draw.io-Dateien. Code lebt im Repository. Die beiden Welten synchronisieren sich nicht automatisch — also driften sie auseinander.\nArchitecture-as-Code: Text als Quelle der Wahrheit Die Antwort der Architecture-as-Code-Bewegung: Architektur gehört ins Repository, neben dem Code. Textbasierte Beschreibung, versionierbar, reviewbar, diffbar. Wenn ein Service hinzukommt, ändert sich auch das Architekturmodell — im selben Commit, im selben Pull Request.\nDas Prinzip funktioniert. Was es schwieriger macht: Textmodelle sind keine Diagramme. Architekten und Teams denken visuell. Ein YAML-File, das einen Graphen beschreibt, ist korrekt — aber nicht intuitiv navigierbar.\nDie zwei Lager: Text-first vs. Visual-first Bestehende Tools lösen das Problem jeweils von einer Seite:\nTool Stärke Schwäche Structurizr\nEigene DSL, strukturiertes C4-Modell, viele Exportformate\nKein visuelles Editieren — Text ist die einzige Quelle\nLikeC4\nModerne DSL, VS Code Extension, Live-Vorschau\nDiagramm ist Output, kein editierbares Frontend\nC4 model\nKlare Methodologie (Context, Container, Component, Code)\nKein Tool, nur ein Rahmenwerk\nC4InterFlow\nErweitert C4 um Interface- und Flow-Konzepte\nSehr spezifisch auf Interaktionsmodellierung ausgerichtet\nDer gemeinsame Nenner: Text ist die Quelle, Diagramm ist der Output. Das Diagramm selbst kann nicht editiert werden, zumindest nicht auf eine Weise die zurück ins Modell fließt.\nWas Bausteinsicht anders macht: Bidirektionale Synchronisation Bausteinsicht dreht die Frage um: Warum muss man sich entscheiden?\nDas Modell liegt als JSONC-Datei im Repository — textbasiert, versionierbar, LLM-lesbar. draw.io ist das visuelle Frontend — ein weit verbreitetes, ausgereifte Diagrammwerkzeug. Beide Seiten sind gleichwertig. Änderungen im Text fließen ins Diagramm. Änderungen im Diagramm fließen zurück in den Text.\n# Modell ändern → Diagramm aktualisieren bausteinsicht sync # Diagramm in draw.io editieren → Modell aktualisieren bausteinsicht sync # Kontinuierlich bei jeder Dateiänderung bausteinsicht watch Das ist kein Export. Das ist ein Merge: Positionen, Labels, neue Elemente — der sync-Befehl erkennt was sich geändert hat und führt beide Seiten zusammen, ohne die jeweils andere Seite zu überschreiben.\nDas Modell: JSONC mit drei Sektionen Das Herzstück ist eine architecture.jsonc — JSON mit Kommentaren. Drei Sektionen definieren alles:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; } } }, \u0026#34;model\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Frontend\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;React\u0026#34; } } } }, \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Context View\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop\u0026#34;] }, \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container View\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop.*\u0026#34;] } } } specification definiert die Sprache: welche Arten von Elementen und Beziehungen im Modell existieren können. model enthält die konkreten Systemelemente mit beliebig tiefer Hierarchie. views steuert, welche Elemente in welchem Diagramm auftauchen — ein Element kann in mehreren Views erscheinen.\nWarum draw.io als Frontend? Draw.io ist kein zufälliger Kandidat:\nWeit verbreitet — viele Teams haben es bereits im Einsatz\nOffline-fähig, keine Cloud-Abhängigkeit\nXML-basiertes Format, das programmatisch gelesen und geschrieben werden kann\nFreie Positionierung und visuelle Anpassung möglich\nDer entscheidende Punkt ist das Format: draw.io-Dateien sind unkomprimiertes XML. Bausteinsicht kann das XML gezielt lesen, Elemente zuordnen, Positionen mergen und das Ergebnis zurückschreiben — ohne die Draw.io-Applikation zu öffnen.\nDas macht bidirektionale Synchronisation technisch möglich. Mit einem proprietären Binary-Format wäre es das nicht.\nBeispiel-Modell Das Beispiel für diesen Teil ist als ausführbare JSONC-Datei unter teil_1.jsonc abgelegt.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_1.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Dieser Post gibt einen Überblick — die folgenden Posts gehen in die Tiefe:\nGetting Started — vom leeren Ordner zum ersten Diagramm\nDas Datenmodell — specification, model, views im Detail\nBidirektionale Synchronisation — wie der Merge-Algorithmus funktioniert\nWer direkt loslegen will:\n# Installation (Linux amd64) curl -Lo bausteinsicht.tar.gz \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ # Erstes Projekt mkdir meine-architektur \u0026amp;\u0026amp; cd meine-architektur bausteinsicht init bausteinsicht sync Offizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-projektvorstellung/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_grundproblem_dokumentation_veraltet\"\u003eDas Grundproblem: Dokumentation veraltet\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eSoftware-Architektur wird meistens einmal dokumentiert — beim Start des Projekts, wenn der Architekt noch motiviert ist und das System noch überschaubar.\nDrei Monate später sieht die Realität anders aus.\nEin neuer Service ist dazugekommen.\nEine Abhängigkeit wurde umgezogen.\nDas alte Diagramm zeigt noch die ursprüngliche Idee, nicht das aktuelle System.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas Problem ist strukturell: Diagramme leben in Präsentationen, Wikis oder Draw.io-Dateien.\nCode lebt im Repository.\nDie beiden Welten synchronisieren sich nicht automatisch — also driften sie auseinander.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 1: Was ist Architecture-as-Code — und warum macht Bausteinsicht es anders?"},{"content":" Dieser Post ist Teil der EthTrcv-Serie und baut auf dem AUTOSAR Grundlagen-Post auf. Er richtet sich an Software-Entwickler die täglich EthTrcv konfigurieren, aber noch nie genau wissen wollten was dabei auf PCB-Ebene passiert.\nWer einen ARXML-Parameter wie EthTrcvBusIdx auf ETHTRCV_BUS_TYPE_RGMII setzt, trifft eine Hardware-Entscheidung — auch wenn er das vielleicht nicht so empfindet. Dieser Post macht sichtbar was hinter diesen Parametern steckt.\nDer PHY-Chip als Mittler Ein Ethernet PHY-Chip sitzt exakt in der Mitte zwischen zwei Welten:\nSoC / Microcontroller Kabel ┌─────────────────┐ ┌────────┐ │ Ethernet MAC │◄── MII/RMII/RGMII ─►│ PHY │◄── MDI ──► Twisted Pair │ │◄── MDIO ────────── ─►│ Chip │ └─────────────────┘ └────────┘ Auf der linken Seite: digitale Interfaces zum MAC im SoC. Auf der rechten Seite: analoge Schnittstelle zum Kabel. In der Mitte: alles was die Konvertierung ausmacht — Encoding, Scrambling, Signal-Shaping.\nEthTrcv_Init initialisiert diesen Chip. Was genau dabei passiert, erklärt dieser Post von links nach rechts.\nDie MAC-seitigen Interfaces (MII-Familie) Die MAC-seitige Schnittstelle zwischen SoC und PHY ist standardisiert. IEEE 802.3 definiert mehrere Varianten — alle unter dem Oberbegriff MII-Familie.\nMII — Media Independent Interface Das Original aus IEEE 802.3u (1995). Heute in neuen Designs kaum noch anzutreffen, aber zum Verständnis der Nachfolger unverzichtbar.\nSignale: TX_CLK, TXD[3:0], TX_EN, TX_ER RX_CLK, RXD[3:0], RX_DV, RX_ER, CRS, COL Takt: 25 MHz (100 Mbit/s) / 2,5 MHz (10 Mbit/s) Datenbreite: 4 Bit parallel (Nibble) Leitungen: ~16 Datenleitungen + Steuer-/Taktleitungen Warum es kaum noch gebaut wird: 16+ Leitungen auf dem PCB, hoher Routing-Aufwand, und bei modernen SoCs sind die GPIO-Pins zu wertvoll.\nRMII — Reduced MII Reduzierte Variante mit nur 9 Leitungen statt 16+. Typisch bei kleineren Mikrocontrollern wo GPIO-Pins knapp sind.\nSignale: REF_CLK (50 MHz, vom PHY oder extern), TXD[1:0], TX_EN RXD[1:0], CRS_DV, RX_ER Takt: 50 MHz fix (ein Takt für beide Richtungen) Datenbreite: 2 Bit parallel Besonderheit: MAC und PHY teilen sich einen gemeinsamen 50 MHz Referenztakt Der 50 MHz REF_CLK muss entweder vom PHY geliefert oder extern eingespeist werden. Wer den Takt vergisst oder falsch verdrahtet, hat kein Link und fragt sich warum.\nRGMII — Reduced Gigabit MII Der heute dominierende Standard für Automotive Ethernet mit 1 Gbit/s und für viele moderne 100 Mbit/s Designs.\nSignale: TXC, TXD[3:0], TX_CTL RXC, RXD[3:0], RX_CTL Takt: 125 MHz (1 Gbit/s) / 25 MHz (100 Mbit/s) / 2,5 MHz (10 Mbit/s) Datenbreite: 4 Bit, DDR (Double Data Rate — Daten auf steigender UND fallender Flanke) Leitungen: 12 Signale statt MII\u0026#39;s 16+ DDR bei 125 MHz liefert effektiv 8 Bit pro Taktzyklus → 1 Gbit/s. Das klingt elegant, hat aber einen Haken: RGMII Timing Delays.\nDie Spezifikation schreibt vor dass Daten um 1,5–2 ns gegenüber dem Takt verzögert sein müssen. Diese Verzögerung kann im PHY, im MAC oder über PCB-Trace-Längen realisiert werden — und ist ein häufiger Grund für sporadische Übertragungsfehler wenn das PCB-Layout nicht stimmt.\nIn AUTOSAR sieht man das nicht direkt, aber der EthTrcvBusIdx-Parameter wählt unter anderem ob interne PHY-Delays aktiviert werden oder ob der MAC-Treiber sie übernimmt.\nSGMII / SerDes Für Szenarien wo PHY und MAC weiter auseinanderliegen — typisch bei Switch-Chips die mehrere PHYs aggregieren.\nSignale: TX+ / TX- (differenziell), RX+ / RX- (differenziell) Takt: 1,25 GBaud seriell (8b/10b kodiert → 1 Gbit/s Nutzlast) Leitungen: 4 (zwei differentielle Paare) Vorteil: Längere PCB-Strecken möglich, weniger Leitungen Bei EthSwt-Konfigurationen begegnet man SGMII häufiger als bei einfachen EthTrcv-Setups.\nEntscheidungshilfe: Welches Interface wofür? Interface Max. Geschwindigkeit Leitungen Typischer Einsatz Automotive-Relevanz MII\n100 Mbit/s\n16+\nLegacy\nKaum noch neu\nRMII\n100 Mbit/s\n9\nKleine MCUs\nMittel (Steuergeräte)\nRGMII\n1 Gbit/s\n12\nApplication-SoCs, 1000BASE-T1\nHoch (ADAS, Gateway)\nSGMII\n1 Gbit/s\n4\nSwitch-Aggregation\nHoch bei Zonal Architecture\nDer MDIO-Bus MDIO (Management Data Input/Output) ist der Steuerbus zum PHY. Über ihn läuft EthTrcv_Init — nicht über MII/RGMII.\nSoC │ ├── MDC (Management Data Clock) ────────────► PHY 1 └── MDIO (Management Data I/O, bidirektional) ─► PHY 1 ► PHY 2 (gleiche Leitung) ► PHY 3 (gleiche Leitung) Elektrische Spezifikation Spannung: typisch 3,3 V LVCMOS (oder 1,8 V bei modernen SoCs) MDC-Frequenz: max. 2,5 MHz laut IEEE, viele PHYs tolerieren bis 25 MHz Pull-up: MDIO benötigt einen Pull-up-Widerstand (typisch 1,5 kΩ – 4,7 kΩ) Bus-Last: bis zu 32 PHY-Adressen pro MDIO-Bus möglich Der Pull-up ist kritisch: fehlt er, bleibt MDIO dauerhaft low und alle Register-Lesevorgänge liefern 0xFF oder 0x00 — was genauso aussieht wie ein falsch konfigurierter PHY.\nClause 22 vs. Clause 45 IEEE 802.3 definiert zwei Frame-Formate für MDIO:\nClause 22 (klassisch):\nST | OP | PHYAD[4:0] | REGAD[4:0] | TA | DATA[15:0] 2 2 5 5 2 16 Bit 32 PHY-Adressen, 32 Register pro PHY. Reicht für einfache PHYs.\nClause 45 (erweitert):\nST | OP | PRTAD[4:0] | DEVAD[5:0] | TA | ADDR/DATA[15:0] 2 2 5 5 2 16 Bit Clause 45 führt einen DEVAD (Device Address) ein — dadurch werden 32 Adressräume à 65536 Register möglich. Pflicht für 1000BASE-T1-PHYs und alle PHYs mit Safety- oder MACsec-Features.\nManche SoC-MAC-Treiber unterstützen nur Clause 22 nativ. Clause 45 auf solchen Systemen erfordert einen Workaround via „Clause 22 Preamble Suppression\u0026#34; — ein häufiger Fallstrick bei neueren PHY-Chips.\nTiming und MDC-Frequenz MDC ───┐ ┌──┐ ┌──┐ ┌──┐ ┌── └──┘ └──┘ └──┘ └──┘ MDIO ════╪═════╪═════╪════ Setup↑ ↑Hold Setup-Zeit (MDIO vor steigender MDC-Flanke stabil): min. 10 ns\nHold-Zeit (MDIO nach steigender MDC-Flanke stabil): min. 10 ns\nBei zu hoher MDC-Frequenz oder langen PCB-Traces werden diese Zeiten verletzt. Symptom: Register-Reads liefern korrumpierte Werte, PHY reagiert nicht auf Init.\nMehrere PHYs an einem MDIO-Bus Jeder PHY hat eine 5-Bit-PHY-Adresse (0–31), häufig per Hardware-Pins konfiguriert. Im ARXML entspricht das dem Parameter EthTrcvPhyAddress.\nSoC-MDIO-Bus ├── PHY @ Adresse 1 (PHYAD-Pins: 00001) ├── PHY @ Adresse 2 (PHYAD-Pins: 00010) └── PHY @ Adresse 3 (PHYAD-Pins: 00011) Adresskonflikte (zwei PHYs mit gleicher Adresse) sind ein klassischer Hardware-Bug: beide PHYs antworten gleichzeitig, der Bus wird korrumpiert, alle MDIO-Reads liefern Unsinn.\nDie leitungsseitigen Interfaces Auf der anderen Seite des PHY-Chips: der Anschluss ans Kabel.\nMDI — Medium Dependent Interface MDI ist der physikalische Anschluss des PHY ans Übertragungsmedium. Der Name sagt: ab hier ist alles mediumabhängig — der PHY-Standard definiert die elektrischen Eigenschaften des Signals auf der Leitung.\n100BASE-T1 — Das automotive Single-Pair Interface Klassisches 100BASE-TX verwendet zwei verdrillte Aderpaare (TX und RX getrennt). 100BASE-T1 kommt mit einem einzigen verdrillten Aderpaar aus.\n100BASE-TX: ──[TX+/TX-]── ──[RX+/RX-]── (2 Paare, ≈ RJ45 Stecker) 100BASE-T1: ──[T1+/T1-]── (1 Paar, differenziell, bidirektional) Bidirektionaler Betrieb auf einem Paar ist möglich weil das Signal Echo-Cancellation im PHY verwendet — der Chip subtrahiert das eigene Sendesignal um das Empfangssignal zu isolieren.\nKabelspezifikation:\nImpedanz: 100 Ω (±15 %) Maximale Länge: 15 m (Standard), bis 40 m mit geringerer Datenrate Kabeltyp: Unshielded Twisted Pair (UTP), automotive-zugelassen AWG: typisch AWG 22–24 1000BASE-T1 Gleiche Philosophie wie 100BASE-T1, aber mit 1 Gbit/s über ein Single-Pair-Kabel. Verwendet PAM3 mit höherer Symbolrate, kürzere maximale Kabellänge (ca. 15 m). In Fahrzeugen zunehmend für Backbone-Verbindungen (Zonal Controller → Domain Controller).\nSteckverbinder im Fahrzeug Das Kabel muss irgendwo angeschlossen werden. In der Automotive-Welt gibt es dafür etablierte Steckverbinder-Standards:\nSteckverbinder Einsatz Relevanz für Ethernet FAKRA\nHochfrequenz-Koaxial, klassisch für Antennen und Kameras\nNicht für Twisted-Pair Ethernet — häufige Verwechslung\nHSD (High Speed Data)\n4-poliger Steckverbinder, für Datenübertragung im Fahrzeug\nWird für 100BASE-T1 und USB verwendet, verbreitet\nMATEnet\nTE Connectivity Standard speziell für Automotive Ethernet\nOptimiert für 100BASE-T1 / 1000BASE-T1, niedrige Einfügedämpfung\nH-MTD\nKleiner, für enge Einbausituationen\nZunehmend für 1000BASE-T1 in kompakten Steuergeräten\nDer Steckverbinder beeinflusst die Signal-Integrität. Ein HSD-Stecker mit falscher Impedanzanpassung kann bei 1000BASE-T1 genauso gut Link-Probleme verursachen wie ein defektes Kabel.\nEMV-Aspekte Software-Entwickler denken selten an EMV — Hardware-Entwickler immer. Die Schnittstelle liegt im Fahrzeug nahe an anderen Störquellen (Zündanlage, DC/DC-Wandler).\nCommon-Mode-Filter (CMF): Direkt am MDI-Anschluss verbaut. Unterdrückt Gleichtaktstörungen auf der Leitung. Falscher oder fehlender CMF → PHY hat erhöhtes Rauschen → sporadische Bitfehler.\nESD-Schutz: Transient Voltage Suppressor (TVS) oder ähnliche Bauelemente am Stecker. Schützt den PHY vor elektrostatischen Entladungen beim Stecken/Ziehen. In der Serienapplikation Pflicht — in Entwicklungsboards oft weggelassen.\nPCB-Layout: Die differentielle Leitungsführung (T1+ / T1-) muss mit exakt gleicher Länge geroutet werden (Differential-Pair Matching). Längenunterschied \u0026gt; 150 mil → messbare Signal-Qualitätsverluste.\nEnergieversorgung und Spannungsebenen Ein moderner Automotive PHY-Chip hat typischerweise mehrere Versorgungsdomänen:\nVDD_IO 3,3 V — I/O-Pegel für MII/MDIO-Signale zur MAC/SoC VDD_Core 1,8 V — Interne Core-Logik VDD_PLL 1,8 V — PLL für Takterzeugung (oft separates Rail) VDD_MDI 3,3 V — Analoge Seite, Leitungsankopplung Power Sequencing Die Reihenfolge beim Einschalten ist im PHY-Datenblatt spezifiziert und muss eingehalten werden. Typische Sequenz:\n1. VDD_Core einschalten 2. VDD_IO einschalten (≥ 100 µs nach Core) 3. VDD_MDI einschalten 4. Hardware-Reset (RST_N) deasserten 5. Warten auf PHY-Bootzeit (typisch 1–5 ms) 6. MDIO-Zugriff möglich → EthTrcv_Init kann starten Verletzung der Sequenz → PHY bootet in undefiniertem Zustand. Symptom: EthTrcv_Init kehrt zurück, aber der Link kommt nie hoch.\nWakeUp-Pin und INH-Pin Zwei Pins die Software-Entwickler kennen sollten, auch wenn sie sie nie direkt ansteuern:\nWakeUp-Pin (WU): Eingang am PHY für einen externen WakeUp-Impuls. Wenn das Steuergerät im Sleep ist und Ethernet-WakeUp unterstützt, kann ein spezifischer Impuls auf diesem Pin das Steuergerät aufwecken. AUTOSAR-seitig wird das in EthTrcv_CheckWakeup ausgewertet.\nINH-Pin (Inhibit): Ausgang des PHY, der den Spannungsregler des Steuergeräts steuert. Wenn der PHY in Sleep geht, zieht er INH low → Spannungsregler schaltet ab → Steuergerät schläft. Wenn WakeUp erkannt wird, setzt der PHY INH aktiv → Spannungsregler startet → System wacht auf.\nWakeUp-Impuls auf Leitung → PHY erkennt Impuls → PHY setzt INH aktiv → Spannungsregler startet → SoC bootet → EcuM ruft EthTrcv_CheckWakeup auf → AUTOSAR WakeUp-Validierung läuft durch Vom Bit zum Signal — ein Frame durch den PHY Zum Abschluss der vollständige Weg eines Ethernet-Frames durch den PHY-Chip, von der MAC-Übergabe bis zum differenziellen Signal auf der Leitung.\nSchritt 1: MAC übergibt Frame via RGMII SoC-MAC übergibt: TXD[3:0] = Nibble, TX_CTL = 1 (valid), TXC = 125 MHz PHY empfängt 4 Bit pro Taktflanke (DDR) → 8 Bit pro Taktzyklus Bei 125 MHz: 8 Bit × 125.000.000 = 1.000.000.000 Bit/s = 1 Gbit/s Schritt 2: PCS — Physical Coding Sublayer Der PCS bereitet die Bits für die Übertragung vor:\nScrambling — Bitfolge pseudozufällig verwürfeln, verhindert Dauerpegel (DC-Balance)\nEncoding — Bei 100BASE-T1: keine 8b/10b, stattdessen direkte PAM3-Abbildung mit Trellis-Code\nSchritt 3: PMA — Physical Medium Attachment Der PMA konvertiert die codierten Bits in physikalische Symbole:\nPAM3 bei 100BASE-T1:\nDrei Spannungspegel: +1 (positiv), 0 (null), -1 (negativ) Symbolrate: 66,67 MBaud (66,67 Millionen Symbole/Sekunde) Jedes Symbol: trägt ~1,58 Bit Information (log₂(3)) Nutzlast: 100 Mbit/s nach Overhead Drei Pegel statt zwei — das ist der Grund warum 100 Mbit/s über ein Single-Pair-Kabel mit nur 66 MBaud Symbolrate möglich ist.\nSchritt 4: Echo-Cancellation Da Senden und Empfangen auf demselben Leitungspaar stattfinden, muss der PHY das eigene Sendesignal vom Empfangssignal subtrahieren. Das passiert digital im PHY mit einem adaptiven Filter — und ist der Grund warum 100BASE-T1 PHYs deutlich komplexer sind als klassische PHYs.\nSchritt 5: Signal auf der Leitung Differenzielles Signal: T1+ und T1- mit 100 Ω Impedanz Amplitude: typisch ±1 V (differenziell) Frequenzbereich: DC bis ~66 MHz (Hauptenergie) Latenz durch den PHY RGMII → PCS → PMA → Kabel: typisch 150–500 ns (abhängig von PHY-Chip und Implementierung) Kabel (15 m @ ~0,6c): ca. 80 ns Empfangsseite (Kabel → MAC): nochmal 150–500 ns Gesamtlatenz für einen Frame: ca. 500 ns – 1,5 µs. Relevant für gPTP (Issue #14) wo Sub-Mikrosekunden-Genauigkeit gefordert ist.\nZusammenfassung Interface Kernaussage für Software-Entwickler MII/RMII/RGMII\nWahl beeinflusst EthTrcvBusIdx-Parameter; RGMII-Timing-Delays sind ein häufiger PCB-Bug\nMDIO\nPull-up vergessen → alle Reads liefern Unsinn; Clause 45 für moderne PHYs prüfen\nMDI / 100BASE-T1\nSingle-Pair, bidirektional durch Echo-Cancellation; Kabelimpedanz und Stecker sind Signal-Qualitätsfaktoren\nEMV\nCommon-Mode-Filter am Stecker ist Pflicht — fehlt er, zeigen sich Probleme erst im Fahrzeug-EMV-Test\nPower Sequencing\nFalsche Reihenfolge → PHY antwortet nicht auf Init, kein offensichtlicher Fehlercode\nWakeUp/INH-Pin\nDiese Pins steuern den Spannungsregler des Steuergeräts — AUTOSAR EcuM muss korrekt konfiguriert sein\nWeiter in der EthTrcv-Serie: EthTrcv Teil 1 — Grundlagen \u0026amp; Einordnung\n","permalink":"https://paul-fleischmann.com/autosar/ethtrcv/ethtrcv-hardware-deep-dive/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post ist Teil der EthTrcv-Serie und baut auf dem \u003ca href=\"/autosar/\"\u003eAUTOSAR Grundlagen-Post\u003c/a\u003e auf.\nEr richtet sich an Software-Entwickler die täglich EthTrcv konfigurieren,\naber noch nie genau wissen wollten was dabei auf PCB-Ebene passiert.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eWer einen ARXML-Parameter wie \u003ccode\u003eEthTrcvBusIdx\u003c/code\u003e auf \u003ccode\u003eETHTRCV_BUS_TYPE_RGMII\u003c/code\u003e setzt,\ntrifft eine Hardware-Entscheidung — auch wenn er das vielleicht nicht so empfindet.\nDieser Post macht sichtbar was hinter diesen Parametern steckt.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_der_phy_chip_als_mittler\"\u003eDer PHY-Chip als Mittler\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eEin Ethernet PHY-Chip sitzt exakt in der Mitte zwischen zwei Welten:\u003c/p\u003e\n\u003c/div\u003e","title":"EthTrcv Hardware Deep Dive — Die physikalischen Interfaces des PHY-Chips"},{"content":" Warum überhaupt? Wer täglich AUTOSAR-Stacks entwickelt, kennt das Problem: die eigentliche Hardware ist weit weg. Zwischen dem Code den ich schreibe und dem Chip auf dem er läuft stecken Konfigurationswerkzeuge, Build-Systeme, Integrationsprozesse und meistens noch ein Evaluierungsboard das ich mir mit dem Rest des Teams teile.\nPrivat wollte ich das anders haben. Ein Board, das mir gehört. Ein Projekt, das ich von Anfang bis Ende selbst verantworte — Anforderungen, Architektur, Implementierung, CI/CD. Kein Auftraggeber, kein Prozess-Overhead, kein Kompromiss.\nDer BeagleBone Black war die naheliegende Wahl: ARM Cortex-A8, AM335x, Linux-fähig, gut dokumentiert, und seit Jahren in der Embedded-Community etabliert. Kein Raspberry Pi — der BeagleBone ist näher an der Hardware, und genau das war der Punkt.\nWas das Projekt ist Es ist kein Produkt und kein Tutorial-Projekt. Es ist eine Plattform auf der ich Dinge ausprobiere, die mich beruflich interessieren — aber unter Bedingungen, die ich vollständig kontrolliere.\nKonkret: ein Embedded-System mit einer strikten 5-Schicht-Architektur, mehrsprachigem Stack und einer vollständigen CI/CD-Pipeline — so wie ich es auch in einem professionellen Projekt aufbauen würde, nur ohne die Constraints eines Kundenprojekts.\nDie Hardware Board: BeagleBone Black\nProzessor: Texas Instruments AM335x, ARM Cortex-A8, 1 GHz\nRAM: 512 MB DDR3\nStorage: 4 GB eMMC + microSD\nSchnittstellen: GPIO, I2C, UART, SPI, USB, Ethernet\nDer AM335x ist interessant weil er neben dem Cortex-A8 auch zwei PRU-Cores (Programmable Real-Time Units) mitbringt — für deterministisches Echtzeit-Verhalten direkt auf dem SoC, ohne separaten Mikrocontroller.\nDie Softwarearchitektur Das Projekt folgt einer strikten 5-Schicht-Architektur:\n┌─────────────────────────────┐ │ Applikation │ ← Python / Go ├─────────────────────────────┤ │ Services │ ← Go ├─────────────────────────────┤ │ Hardware Abstraction │ ← C / Rust ├─────────────────────────────┤ │ Treiber │ ← C ├─────────────────────────────┤ │ Hardware │ ← AM335x / Linux └─────────────────────────────┘ Jede Schicht kennt nur die Schicht direkt darunter — kein Durchgriff, keine Abkürzungen. Das ist kein akademisches Prinzip, sondern eine pragmatische Entscheidung: wenn ich in sechs Monaten den Treiber für ein Peripheriegerät austausche, soll der Rest des Systems das nicht merken.\nDer Sprachenmix C — Treiber und HAL, dort wo es auf Kontrolle ankommt\nRust — Hardware Abstraction Layer, dort wo Speichersicherheit ohne Performance-Overhead gefragt ist\nGo — Services und REST API\nPython — Applikationsschicht, Scripting, Testautomatisierung\nDas ist kein Sprachenmix um des Sprachenmixes willen. Jede Sprache ist dort eingesetzt wo ihre Stärken liegen.\nDie Infrastruktur Ein privates Projekt ohne vernünftige Infrastruktur degeneriert schnell zum Chaos. Deshalb hat das Projekt von Anfang an eine vollständige CI/CD-Pipeline:\nGitHub — Git Repository und Issue-Tracking\nDrone CI — Build-Pipeline, läuft als Podman-Container\nCross-Kompilierung — CMake mit ARMv7-Toolchain, Build läuft auf x86\nDeployment — automatisch auf das BeagleBone Black nach erfolgreichem Build\nJeder Commit triggert die Pipeline. Build, Tests, Deployment — automatisch, reproduzierbar, ohne manuelle Schritte.\nDrone CI mit Podman statt Docker hat seine Tücken — dazu gibt es einen eigenen Post.\nAnforderungsmanagement Was mich an professionellen Projekten manchmal frustriert: Anforderungen die irgendwo in einem Word-Dokument leben und mit dem Code nichts zu tun haben.\nIn diesem Projekt verwende ich StrictDoc — ein dokumentenbasiertes Anforderungsmanagement-Tool das Anforderungen direkt mit dem Code verknüpft. Jede Anforderung hat eine ID, jede Implementierung referenziert sie. Traceability von der Anforderung bis zum Test.\nDas ist Overkill für ein privates Projekt — und genau deshalb mache ich es. Wenn es hier funktioniert, funktioniert es überall.\nWas als nächstes kommt Das ist der erste Post einer Serie über dieses Projekt. Alle Posts in der richtigen Reihenfolge:\nRust in der HAL — warum und wie\nDie REST API in Go — GPIO, I2C und UART über HTTP\nCross-Kompilierung für ARMv7 mit CMake\nDrone CI mit Podman — Fallstricke und Lösungen\nStrictDoc in der Praxis — Anforderungen die mit dem Code leben\nZur Übersicht aller BeagleBone-Posts →\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_warum_überhaupt\"\u003eWarum überhaupt?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eWer täglich AUTOSAR-Stacks entwickelt, kennt das Problem:\ndie eigentliche Hardware ist weit weg. Zwischen dem Code den ich schreibe\nund dem Chip auf dem er läuft stecken Konfigurationswerkzeuge,\nBuild-Systeme, Integrationsprozesse und meistens noch ein Evaluierungsboard\ndas ich mir mit dem Rest des Teams teile.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003ePrivat wollte ich das anders haben.\nEin Board, das mir gehört. Ein Projekt, das ich von Anfang bis Ende\nselbst verantworte — Anforderungen, Architektur, Implementierung, CI/CD.\nKein Auftraggeber, kein Prozess-Overhead, kein Kompromiss.\u003c/p\u003e\n\u003c/div\u003e","title":"BeagleBone Black: Mein privates Embedded-Projekt"},{"content":" Dieser Post setzt den ersten Teil fort. Dort ging es darum, was Architecture-as-Code ist und was Bausteinsicht von anderen Tools unterscheidet. Hier wird es praktisch: Installation, erstes Projekt, erstes Diagramm.\nVoraussetzungen Bausteinsicht Binary (Linux, macOS oder Windows)\ndraw.io Desktop oder die draw.io VS Code Extension\nEin Editor mit JSON-Support (VS Code empfohlen)\nInstallation # Aktuelle Version automatisch ermitteln (Linux amd64) VER=$(curl -s https://api.github.com/repos/docToolchain/Bausteinsicht/releases/latest \\ | grep \u0026#39;\u0026#34;tag_name\u0026#34;\u0026#39; | cut -d\u0026#39;\u0026#34;\u0026#39; -f4 | sed \u0026#39;s/^v//\u0026#39;) curl -Lo bausteinsicht.tar.gz \\ \u0026#34;https://github.com/docToolchain/Bausteinsicht/releases/download/v${VER}/Bausteinsicht_${VER}_linux_amd64.tar.gz\u0026#34; tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ # macOS (Apple Silicon) curl -Lo bausteinsicht.tar.gz \\ \u0026#34;https://github.com/docToolchain/Bausteinsicht/releases/download/v${VER}/Bausteinsicht_${VER}_darwin_arm64.tar.gz\u0026#34; tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ # Go Install (alle Plattformen — immer neueste Version) go install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@latest Prüfen ob die Installation funktioniert:\nbausteinsicht --version Schritt 1: Projekt initialisieren Neuen Ordner anlegen und Bausteinsicht initialisieren:\nmkdir meine-architektur \u0026amp;\u0026amp; cd meine-architektur bausteinsicht init init erzeugt vier Dateien:\nDatei Zweck architecture.jsonc\nDas Architekturmodell — die einzige Quelle der Wahrheit\narchitecture.drawio\nDas generierte draw.io-Diagramm\ntemplate.drawio\nVisuelle Stile für Element-Typen (Farben, Formen)\n.bausteinsicht-sync\nSync-State-Datei — gehört ins Git neben dem Modell\nSchritt 2: Das generierte Modell verstehen Bausteinsicht legt ein Beispiel-Modell eines Online-Shops an. Öffne architecture.jsonc im Editor — du siehst die drei Hauptbereiche:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;actor\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Actor\u0026#34; }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;component\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Component\u0026#34;, \u0026#34;container\u0026#34;: true } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; }, \u0026#34;reads\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;reads\u0026#34;, \u0026#34;dashed\u0026#34;: true } } }, \u0026#34;model\u0026#34;: { \u0026#34;customer\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Customer\u0026#34; }, \u0026#34;onlineshop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Frontend\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;React\u0026#34; }, \u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } } } }, \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;System Context\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;onlineshop\u0026#34;] }, \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container View\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;onlineshop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;onlineshop.*\u0026#34;] } } } specification definiert die Sprache des Modells. model beschreibt das konkrete System. views steuert welche Elemente in welchem Diagramm auftauchen.\nDas Modell validieren:\nbausteinsicht validate Ausgabe: Model is valid.\nSchritt 3: Das Diagramm öffnen architecture.drawio in draw.io öffnen. Du siehst zwei Tabs:\nSystem Context — Customer und Online Shop auf der obersten Ebene\nContainer View — die internen Container des Online Shops\nNeue Elemente erscheinen mit rotem gestricheltem Rahmen als visueller Marker. Positionen lassen sich per Drag \u0026amp; Drop anpassen — Bausteinsicht merkt sich die gesetzten Positionen bei der nächsten Synchronisation.\nDas Layout ist bewusst manuell — und das ist ein Feature, keine Einschränkung. Bausteinsicht übernimmt die Positionen nicht automatisch, weil kein Algorithmus weiß, welche räumliche Nähe in deinem Diagramm Bedeutung trägt. Du entscheidest, welche Elemente zusammengehören und wie die Lesrichtung fließt. Einmal gesetzt bleiben die Positionen bei jedem sync erhalten — du musst nie neu layouten, solange du keine neuen Elemente hinzufügst. Wer dennoch automatisch anordnen möchte, kann bausteinsicht sync --relayout nutzen — das setzt alle Positionen zurück und wendet das hierarchische Auto-Layout an. Details dazu in Teil 14: Auto-Layout. Schritt 4: Element per CLI hinzufügen Einen neuen Email-Service zum Modell hinzufügen:\nbausteinsicht add element \\ --id emailservice \\ --kind container \\ --title \u0026#34;Email Service\u0026#34; \\ --technology \u0026#34;Go\u0026#34; \\ --parent onlineshop \\ --description \u0026#34;Sendet transaktionale E-Mails\u0026#34; Ausgabe: Added element \u0026#39;onlineshop.emailservice\u0026#39; (kind: container) to model.\nJetzt eine Beziehung vom REST API zum Email Service anlegen:\nbausteinsicht add relationship \\ --from onlineshop.api \\ --to onlineshop.emailservice \\ --label \u0026#34;sendet E-Mails\u0026#34; \\ --kind uses Schritt 5: Modell → Diagramm synchronisieren bausteinsicht sync Ausgabe:\nForward (model → draw.io): 2 added, 0 updated, 0 deleted architecture.drawio in draw.io neu laden — der Email Service erscheint mit rotem Rahmen in der Container View.\nSchritt 6: Diagramm → Modell synchronisieren Jetzt die andere Richtung: eine Änderung im Diagramm zurück ins Modell schreiben.\nIn draw.io architecture.drawio öffnen\nDoppelklick auf „Web Frontend\u0026#34;\nTitel ändern auf „Web App\u0026#34;\nDatei speichern\nbausteinsicht sync Ausgabe:\nReverse (draw.io → model): 0 added, 1 updated, 0 deleted architecture.jsonc öffnen — der Titel ist auf \u0026#34;Web App\u0026#34; aktualisiert. Das ist bidirektionale Synchronisation in der Praxis.\nSchritt 7: Watch-Modus Für kontinuierliche Synchronisation während der Arbeit:\nbausteinsicht watch Bausteinsicht überwacht beide Dateien und synct automatisch bei jeder Änderung. Damit kann man im Editor und in draw.io gleichzeitig arbeiten — ohne manuelles sync. Ctrl+C beendet den Watch-Modus.\nwatch eignet sich gut für Workshops und Review-Sessions: mehrere Personen können gleichzeitig Modell und Diagramm bearbeiten, der Watch-Prozess hält alles in Sync. Beispiel-Modell Das Beispiel für diesen Teil ist als ausführbare JSONC-Datei unter teil_2.jsonc abgelegt.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_2.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 3: Das Datenmodell im Detail — specification, model, views und alle verfügbaren Felder\nTeil 4: Bidirektionale Synchronisation — wie der Merge-Algorithmus funktioniert und was passiert wenn beide Seiten gleichzeitig geändert wurden\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-getting-started/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-projektvorstellung/\"\u003eersten Teil\u003c/a\u003e fort.\nDort ging es darum, was Architecture-as-Code ist und was Bausteinsicht von anderen Tools unterscheidet.\nHier wird es praktisch: Installation, erstes Projekt, erstes Diagramm.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_voraussetzungen\"\u003eVoraussetzungen\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/docToolchain/Bausteinsicht/releases\"\u003eBausteinsicht Binary\u003c/a\u003e (Linux, macOS oder Windows)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://www.drawio.com/\"\u003edraw.io Desktop\u003c/a\u003e oder die draw.io VS Code Extension\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eEin Editor mit JSON-Support (VS Code empfohlen)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect2\"\u003e\n\u003ch3 id=\"_installation\"\u003eInstallation\u003c/h3\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e# Aktuelle Version automatisch ermitteln (Linux amd64)\nVER=$(curl -s https://api.github.com/repos/docToolchain/Bausteinsicht/releases/latest \\\n      | grep \u0026#39;\u0026#34;tag_name\u0026#34;\u0026#39; | cut -d\u0026#39;\u0026#34;\u0026#39; -f4 | sed \u0026#39;s/^v//\u0026#39;)\ncurl -Lo bausteinsicht.tar.gz \\\n  \u0026#34;https://github.com/docToolchain/Bausteinsicht/releases/download/v${VER}/Bausteinsicht_${VER}_linux_amd64.tar.gz\u0026#34;\ntar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/\n\n# macOS (Apple Silicon)\ncurl -Lo bausteinsicht.tar.gz \\\n  \u0026#34;https://github.com/docToolchain/Bausteinsicht/releases/download/v${VER}/Bausteinsicht_${VER}_darwin_arm64.tar.gz\u0026#34;\ntar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/\n\n# Go Install (alle Plattformen — immer neueste Version)\ngo install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@latest\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 2: Von 0 zum ersten Architekturdiagramm mit Bausteinsicht"},{"content":" Dieser Post ist Teil der Serie über mein privates BeagleBone-Black-Projekt. Dort habe ich die 5-Schicht-Architektur und den Sprachenmix vorgestellt — hier gehe ich auf einen konkreten Aspekt ein, der oft Fragen aufwirft: Warum überhaupt Rust im HAL, wenn C dort schon seit Jahrzehnten funktioniert?\nWarum Rust in der HAL? Die ehrliche Antwort: weil ich es ausprobieren wollte. Privat betriebene Projekte sind genau dafür da. Im Berufsalltag treffe ich Technologieentscheidungen unter Zeitdruck, mit Rücksicht auf das Team und die bestehende Codebasis. Rust hatte dort bisher keinen Platz.\nHier schon. Dieser Drang, etwas Neues wirklich zu verstehen, nicht nur darüber gelesen zu haben, sondern es eingebaut, debuggt und zum Laufen gebracht zu haben, ist einer der Hauptgründe warum dieses Projekt existiert. Rust in der HAL ist mein Lernlabor für eine Sprache, die mich seit Jahren interessiert aber beruflich noch nicht gefordert hat.\nUnd dann gibt es noch die technischen Gründe, die das Experiment rechtfertigen.\nDas Problem mit C im HAL C gibt dir volle Kontrolle — und volle Verantwortung. Ein falsch gesetzter Pointer, ein vergessenes free, ein Off-by-one beim Auslesen eines I2C-Puffers: der Compiler sagt nichts, das System schweigt bis es zur Laufzeit abstürzt. In einem privaten Projekt ist das verkraftbar. In einem sicherheitskritischen System wäre es ein Incident-Bericht.\nWas Rust anders macht Rust erzwingt Korrektheit zur Compile-Zeit statt zur Laufzeit:\nOwnership — jede Ressource hat genau einen Besitzer, kein Double-Free möglich\nlet buf = vec![0u8; 64]; // buf ist Eigentümer des Speichers let buf2 = buf; // Ownership wird übertragen // buf hier zu verwenden ist ein Compile-Fehler — kein Double-Free möglich Borrow-Checker — gleichzeitiger lesender und schreibender Zugriff wird verhindert\nlet mut reg = 0u8; let r = \u0026amp;reg; // lesende Referenz // reg = 1; // Compile-Fehler: schreibender Zugriff während Borrow aktiv println!(\u0026#34;{}\u0026#34;, r); Kein Garbage Collector — deterministische Ressourcenfreigabe, kein Pausieren\n{ let fd = open_i2c_bus(1); // Ressource wird geöffnet // ... I2C-Operationen ... } // Drop wird hier exakt aufgerufen — kein GC, kein unbestimmtes Warten zero-cost abstractions — Iteratoren, Traits, Generics — ohne Runtime-Overhead\n// Dieser Iterator-Chain kompiliert zu derselben Maschinenkode wie eine handgeschriebene Schleife let sum: u32 = readings.iter() .filter(|\u0026amp;\u0026amp;v| v \u0026gt; 0) .map(|\u0026amp;v| v as u32) .sum(); Für Hardware-Code bedeutet das konkret: ein Registerwert der nur einmal geschrieben werden darf, ein I2C-Bus der nicht gleichzeitig von zwei Threads genutzt werden soll — Rust macht solche Invarianten zur Typebene, nicht zur Konvention.\nRust ist kein Allheilmittel. Der Borrow-Checker schützt vor Speicherfehlern, nicht vor Logikfehlern. Falscher I2C-Befehl, falsche Register-Adresse — das findet er nicht.\nAbgrenzung zu C Das Projekt hat zwei Schichten unterhalb der Services:\n┌─────────────────────────────┐ │ Hardware Abstraction │ ← Rust (diese Schicht) ├─────────────────────────────┤ │ Treiber │ ← C (Linux sysfs / ioctl) ├─────────────────────────────┤ │ Hardware │ ← AM335x / Linux └─────────────────────────────┘ C bleibt in der Treiberschicht:\nDirekter Zugriff auf Linux-Kernel-APIs (ioctl, open, read, write)\n/dev/i2c-, /sys/class/gpio/, /dev/ttyO*\nMinimale, gut verstandene Strukturen\nRust übernimmt die HAL-Logik:\nTypgesichertes API über die rohen Treiberfunktionen\nFehlerbehandlung mit Result\u0026lt;T, E\u0026gt; statt roher Fehlercodes\nZustandsmaschinen für Peripherieprotokolle\nDie Grenze ist pragmatisch: wo der Linux-Kernel-Aufruf aufhört, fängt Rust an.\nRust-FFI zu C Rust kann C-Funktionen direkt aufrufen — aber nicht ohne Aufwand. Das Schlüsselwort ist unsafe und das Attribut extern \u0026#34;C\u0026#34;.\nC-Treiber einbinden Der C-Treiber für I2C stellt diese Funktion bereit:\n// i2c_driver.h int i2c_read(int bus_fd, uint8_t addr, uint8_t reg, uint8_t *buf, size_t len); In Rust wird die Signatur deklariert:\nuse std::os::raw::{c_int, c_uchar, c_size_t}; extern \u0026#34;C\u0026#34; { fn i2c_read( bus_fd: c_int, addr: c_uchar, reg: c_uchar, buf: *mut c_uchar, len: c_size_t, ) -\u0026gt; c_int; } Der Aufruf selbst ist unsafe — Rust kann die Korrektheit der C-Funktion nicht prüfen:\npub fn read_register(bus_fd: i32, addr: u8, reg: u8) -\u0026gt; Result\u0026lt;u8, HalError\u0026gt; { let mut buf: u8 = 0; let ret = unsafe { i2c_read(bus_fd, addr, reg, \u0026amp;mut buf as *mut u8, 1) }; if ret \u0026lt; 0 { Err(HalError::I2cReadFailed(ret)) } else { Ok(buf) } } Das unsafe-Block ist bewusst minimal gehalten. Die öffentliche API nach außen ist vollständig safe.\nLinker-Konfiguration Die C-Bibliothek muss beim Build eingebunden werden. In build.rs:\nfn main() { println!(\u0026#34;cargo:rustc-link-search=native=../c/lib\u0026#34;); println!(\u0026#34;cargo:rustc-link-lib=static=bbb_drivers\u0026#34;); } Rust als Bibliothek für Go Die Services-Schicht ist in Go geschrieben. Go kann C-kompatible Bibliotheken einbinden (cgo) — aber kein Rust direkt. Der Trick: Rust kompiliert als C-kompatible Shared Library.\ncbindgen — Header automatisch generieren cbindgen liest den Rust-Code und erzeugt daraus einen C-Header:\n# cbindgen.toml language = \u0026#34;C\u0026#34; include_guard = \u0026#34;BBB_HAL_H\u0026#34; Für jede pub extern \u0026#34;C\u0026#34;-Funktion in Rust:\n#[no_mangle] pub extern \u0026#34;C\u0026#34; fn hal_i2c_read( bus_fd: i32, addr: u8, reg: u8, out: *mut u8, ) -\u0026gt; i32 { match read_register(bus_fd, addr, reg) { Ok(val) =\u0026gt; { unsafe { *out = val }; 0 } Err(_) =\u0026gt; -1, } } erzeugt cbindgen automatisch:\n// bbb_hal.h (auto-generated) int32_t hal_i2c_read(int32_t bus_fd, uint8_t addr, uint8_t reg, uint8_t *out); cgo-Integration in Go package hal // #cgo LDFLAGS: -L../../rust/target/armv7-unknown-linux-gnueabihf/release -lbbb_hal // #include \u0026#34;bbb_hal.h\u0026#34; import \u0026#34;C\u0026#34; import \u0026#34;fmt\u0026#34; func I2CRead(busFd int, addr, reg uint8) (uint8, error) { var out C.uint8_t ret := C.hal_i2c_read(C.int32_t(busFd), C.uint8_t(addr), C.uint8_t(reg), \u0026amp;out) if ret \u0026lt; 0 { return 0, fmt.Errorf(\u0026#34;i2c read failed: %d\u0026#34;, ret) } return uint8(out), nil } Konkretes Beispiel: I2C-Read End-to-End Der vollständige Pfad eines I2C-Lesevorgangs durch alle Schichten:\nGo (API-Handler) → hal.I2CRead(bus, addr, reg) [Go, cgo-Call] → hal_i2c_read(bus_fd, addr, reg) [Rust, pub extern \u0026#34;C\u0026#34;] → read_register(...) [Rust, safe wrapper] → i2c_read(...) [C, unsafe-Block] → ioctl(I2C_RDWR) [Linux Kernel] → AM335x I2C-Bus Jede Schicht fügt genau eine Abstraktion hinzu: * C: roher Kernel-Aufruf * Rust: Result-basierte Fehlerbehandlung * Go: idomatisches Go-Interface\nCross-Compilation für ARMv7 Der Build läuft auf x86, das Binary muss auf dem ARM Cortex-A8 laufen.\nRust-Target installieren rustup target add armv7-unknown-linux-gnueabihf .cargo/config.toml [target.armv7-unknown-linux-gnueabihf] linker = \u0026#34;arm-linux-gnueabihf-gcc\u0026#34; Build-Befehl cargo build \\ --release \\ --target armv7-unknown-linux-gnueabihf Das Binary liegt danach unter: target/armv7-unknown-linux-gnueabihf/release/libbbb_hal.so\nDas cross-Tool kapselt Cross-Compilation in einem Docker-Container — weniger Setup, dafür Container-Dependency. Ich verwende die manuelle Toolchain weil sie besser in die Drone-CI-Pipeline passt.\nOwnership und Lifetimes im Hardware-Kontext Hardware-Ressourcen sind von Natur aus exklusiv. Ein I2C-Bus kann nicht gleichzeitig von zwei Threads beschrieben werden. Ein GPIO-Pin hat genau einen Treiber.\nRust’s Ownership-System modelliert das direkt:\npub struct I2cBus { fd: i32, } impl I2cBus { pub fn open(bus: u8) -\u0026gt; Result\u0026lt;Self, HalError\u0026gt; { // ... Ok(I2cBus { fd }) } pub fn read(\u0026amp;mut self, addr: u8, reg: u8) -\u0026gt; Result\u0026lt;u8, HalError\u0026gt; { read_register(self.fd, addr, reg) } } impl Drop for I2cBus { fn drop(\u0026amp;mut self) { unsafe { libc::close(self.fd) }; } } I2cBus ist nicht Clone und nicht Copy. Es kann genau eine Instanz geben, die den Bus besitzt. Wenn die Instanz aus dem Scope fällt, wird der File-Descriptor automatisch geschlossen.\nDas ist kein Pattern das ich mir ausgedacht habe — es ist wie Rust Hardware-Zugriff idiomatisch modelliert.\nFazit Rust im HAL ist mehr Aufwand als C — das ist ehrlich. FFI-Bindings, cbindgen, Cross-Compilation-Setup, Borrow-Checker der manchmal mit dem ARM-Linker aneinandergerät.\nAber der Gewinn ist real:\nCompile-Zeit-Garantien statt Laufzeit-Crashes\nExplizite Fehlerbehandlung mit Result\u0026lt;T, E\u0026gt; statt roher Fehlercodes\nRessourcenverwaltung über Ownership statt manuelles close()\nFür ein professionelles System wo Speicherfehler im HAL einen Rückruf bedeuten würden, ist das kein Overkill sondern Minimum. Für ein privates Projekt ist es die beste Gelegenheit, das Handwerkszeug zu üben bevor man es braucht.\nNächster Post in der Serie: Die REST API in Go — GPIO, I2C und UART über HTTP\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/rust-in-der-hal/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post ist Teil der Serie über mein \u003ca href=\"/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/\"\u003eprivates BeagleBone-Black-Projekt\u003c/a\u003e.\nDort habe ich die 5-Schicht-Architektur und den Sprachenmix vorgestellt —\nhier gehe ich auf einen konkreten Aspekt ein, der oft Fragen aufwirft:\nWarum überhaupt Rust im HAL, wenn C dort schon seit Jahrzehnten funktioniert?\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_warum_rust_in_der_hal\"\u003eWarum Rust in der HAL?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDie ehrliche Antwort: weil ich es ausprobieren wollte.\nPrivat betriebene Projekte sind genau dafür da.\nIm Berufsalltag treffe ich Technologieentscheidungen unter Zeitdruck,\nmit Rücksicht auf das Team und die bestehende Codebasis.\nRust hatte dort bisher keinen Platz.\u003c/p\u003e\n\u003c/div\u003e","title":"Rust in der HAL — warum und wie"},{"content":" Dieser Post setzt den zweiten Teil fort. Dort wurde bausteinsicht init, sync und watch vorgestellt. Hier geht es um das Herzstück: das JSONC-Datenmodell mit allen Feldern und Erweiterungspunkten.\nDie Grundstruktur Eine architecture.jsonc-Datei hat vier Pflichtfelder und mehrere optionale Abschnitte:\n{ \u0026#34;$schema\u0026#34;: \u0026#34;./node_modules/.bausteinsicht/bausteinsicht.schema.json\u0026#34;, \u0026#34;config\u0026#34;: { ... }, \u0026#34;specification\u0026#34;: { ... }, \u0026#34;model\u0026#34;: { ... }, \u0026#34;relationships\u0026#34;: [ ... ], \u0026#34;views\u0026#34;: { ... }, \u0026#34;asIs\u0026#34;: { ... }, \u0026#34;toBe\u0026#34;: { ... }, \u0026#34;dynamicViews\u0026#34;: [ ... ], \u0026#34;constraints\u0026#34;: [ ... ] } config Globale Einstellungen für die Diagrammgenerierung:\n\u0026#34;config\u0026#34;: { \u0026#34;author\u0026#34;: \u0026#34;Paul Fleischmann\u0026#34;, \u0026#34;repo\u0026#34;: \u0026#34;https://github.com/mein-org/mein-repo\u0026#34;, \u0026#34;metadata\u0026#34;: true, \u0026#34;legend\u0026#34;: true } specification Die specification definiert die Sprache des Modells — welche Element-Typen und Beziehungsarten existieren. Sie ist die einzige Stelle, die man einmal aufsetzen und dann selten ändern muss.\nspecification.elements \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;actor\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Actor\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Ein Benutzer oder externes System\u0026#34;, \u0026#34;container\u0026#34;: false }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;component\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Component\u0026#34;, \u0026#34;container\u0026#34;: true } } } Das container-Flag steuert, ob ein Element in der Hierarchie children haben darf. Fehlt das Flag (oder ist false), lehnt bausteinsicht validate jedes Modell-Element dieses Typs mit children ab.\nspecification.relationships \u0026#34;specification\u0026#34;: { \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;dashed\u0026#34;: false }, \u0026#34;reads\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;reads\u0026#34;, \u0026#34;dashed\u0026#34;: true } } } specification.tags Tags werden unter specification.tags definiert und können optionales draw.io-Styling mitbringen:\n\u0026#34;specification\u0026#34;: { \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Externes System außerhalb unserer Kontrolle\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#f5f5f5\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#666666\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;legacy\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Altsystem — keine aktive Weiterentwicklung\u0026#34; } ] } specification.patterns Patterns sind wiederverwendbare Topologie-Vorlagen — z.B. ein Standard-Microservice-Muster mit Frontend, API und Datenbank:\n\u0026#34;specification\u0026#34;: { \u0026#34;patterns\u0026#34;: { \u0026#34;microservice\u0026#34;: { \u0026#34;description\u0026#34;: \u0026#34;Standardmuster: API + Datenbank\u0026#34;, \u0026#34;elements\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;api\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;{{name}} API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;db\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;{{name}} Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } ], \u0026#34;relationships\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;r1\u0026#34;, \u0026#34;from\u0026#34;: \u0026#34;api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads/writes\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; } ] } } } specification.decisions ADR-Referenzen (Architecture Decision Records) können direkt in der Specification verwaltet werden:\n\u0026#34;specification\u0026#34;: { \u0026#34;decisions\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;ADR-001\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;PostgreSQL als primäre Datenbank\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;active\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-01-15\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/adr/001-postgresql.md\u0026#34; } ] } model Das model beschreibt die konkreten Elemente des Systems. Jeder Schlüssel ist die Element-ID — sie muss innerhalb der Hierarchieebene eindeutig sein.\nElement-Felder \u0026#34;model\u0026#34;: { \u0026#34;onlineshop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Der Kern des Systems\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go, PostgreSQL\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;, \u0026#34;legacy\u0026#34;], \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-001\u0026#34;], \u0026#34;metadata\u0026#34;: { \u0026#34;owner\u0026#34;: \u0026#34;Team Backend\u0026#34;, \u0026#34;cost\u0026#34;: \u0026#34;€500/month\u0026#34; }, \u0026#34;children\u0026#34;: { \u0026#34;frontend\u0026#34;: { ... }, \u0026#34;api\u0026#34;: { ... } } } } Verschachtelte Hierarchie Elemente lassen sich beliebig tief verschachteln, solange der jeweilige kind container: true hat:\n\u0026#34;model\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;backend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Backend\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;orderservice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Order Service\u0026#34; }, \u0026#34;paymentservice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Service\u0026#34; } } } } } } Die Element-ID in Beziehungen und Views verwendet Punkt-Notation für den Pfad: shop.backend.orderservice.\nstatus-Werte Status Bedeutung draw.io Farbe proposed\nGeplant, noch nicht begonnen\nGelb\ndesign\nIm Entwurf\nBlau\nimplementation\nIn Entwicklung\nOrange\ndeployed\nProduktiv\nGrün\ndeprecated\nVeraltet, wird abgelöst\nRot\narchived\nEingestellt\nGrau\nrelationships Beziehungen werden als flaches Array auf Top-Level definiert, nicht innerhalb der Elemente. Das ermöglicht Beziehungen zwischen Elementen verschiedener Hierarchieebenen:\n\u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;shop.backend.orderservice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.backend.paymentservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;bestätigt Zahlung\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Synchroner REST-Call\u0026#34;, \u0026#34;cardinality\u0026#34;: \u0026#34;1:N\u0026#34;, \u0026#34;dataFlow\u0026#34;: \u0026#34;sync\u0026#34;, \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-002\u0026#34;] } ] views Views definieren, welche Elemente in welchem Diagramm-Tab erscheinen. Jeder Schlüssel wird ein Tab in architecture.drawio.\nView-Felder \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;System Context\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Übersicht aller Systeme\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;shop\u0026#34;], \u0026#34;exclude\u0026#34;: [\u0026#34;shop.backend.legacy\u0026#34;], \u0026#34;filter-tags\u0026#34;: [\u0026#34;external\u0026#34;], \u0026#34;exclude-tags\u0026#34;: [\u0026#34;archived\u0026#34;], \u0026#34;layout\u0026#34;: \u0026#34;auto\u0026#34; } } include mit Wildcards:\n\u0026#34;include\u0026#34;: [ \u0026#34;customer\u0026#34;, \u0026#34;shop.*\u0026#34;, \u0026#34;shop.**\u0026#34; ] Optionale Erweiterungen asIs / toBe Für As-Is/To-Be-Vergleiche kann die aktuelle und die Zielarchitektur direkt im Modell hinterlegt werden:\n\u0026#34;asIs\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;legacy-monolith\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Legacy Monolith\u0026#34; } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;legacy-monolith\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34; } ] }, \u0026#34;toBe\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop (Microservices)\u0026#34; } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34; } ] } bausteinsicht diff visualisiert den Unterschied zwischen asIs und toBe als annotiertes Diagramm.\ndynamicViews Sequenzdiagramme beschreiben den zeitlichen Ablauf von Interaktionen:\n\u0026#34;dynamicViews\u0026#34;: [ { \u0026#34;key\u0026#34;: \u0026#34;checkout\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Checkout-Flow\u0026#34;, \u0026#34;steps\u0026#34;: [ { \u0026#34;index\u0026#34;: 1, \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;frontend\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;klickt Kaufen\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 2, \u0026#34;from\u0026#34;: \u0026#34;frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;orderservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;POST /orders\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 3, \u0026#34;from\u0026#34;: \u0026#34;orderservice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge()\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 4, \u0026#34;from\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;orderservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;OK\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; } ] } ] type-Werte: sync (durchgezogener Pfeil) | async (offener Pfeil) | return (gestrichelt zurück). bausteinsicht export sequence generiert daraus PlantUML oder Mermaid.\nconstraints Architekturregeln werden als maschinenprüfbare Constraints definiert und mit bausteinsicht lint ausgewertet:\n\u0026#34;constraints\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;NO-DIRECT-DB-ACCESS\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur Services dürfen direkt auf die Datenbank zugreifen\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;no-relationship\u0026#34;, \u0026#34;from-kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;to-kind\u0026#34;: \u0026#34;database\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;REQUIRE-DESCRIPTION\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Systeme brauchen eine Beschreibung\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;required-field\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;field\u0026#34;: \u0026#34;description\u0026#34; } ] Verfügbare rule-Werte: no-relationship, allowed-relationship, required-field, max-depth, technology-allowed.\nJSON Schema für IDE-Autovervollständigung Ohne Plugin funktioniert die Autovervollständigung über das mitgelieferte JSON Schema. Den $schema-Eintrag in architecture.jsonc setzen:\n{ \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34; } In VS Code (und jedem Editor mit JSON Schema Support) erscheint dann direkt Autovervollständigung für alle Felder — ohne Extension installieren zu müssen.\nBeispiel-Modell Das Beispiel für diesen Teil ist als ausführbare JSONC-Datei unter teil_3.jsonc abgelegt und zeigt specification, model, views und relationships mit allen optionalen Feldern.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_3.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 4: Bidirektionale Synchronisation — wie der Merge-Algorithmus funktioniert und was passiert wenn beide Seiten gleichzeitig geändert wurden\nTeil 5: Multi-View — mehrere Diagrammperspektiven aus einem Modell\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-datenmodell/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-getting-started/\"\u003ezweiten Teil\u003c/a\u003e fort.\nDort wurde \u003ccode\u003ebausteinsicht init\u003c/code\u003e, sync und watch vorgestellt.\nHier geht es um das Herzstück: das JSONC-Datenmodell mit allen Feldern und Erweiterungspunkten.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_die_grundstruktur\"\u003eDie Grundstruktur\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eEine \u003ccode\u003earchitecture.jsonc\u003c/code\u003e-Datei hat vier Pflichtfelder und mehrere optionale Abschnitte:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e{\n  \u0026#34;$schema\u0026#34;: \u0026#34;./node_modules/.bausteinsicht/bausteinsicht.schema.json\u0026#34;,\n  \u0026#34;config\u0026#34;: { ... },\n  \u0026#34;specification\u0026#34;: { ... },\n  \u0026#34;model\u0026#34;: { ... },\n  \u0026#34;relationships\u0026#34;: [ ... ],\n  \u0026#34;views\u0026#34;: { ... },\n\n  \u0026#34;asIs\u0026#34;:         { ... },\n  \u0026#34;toBe\u0026#34;:         { ... },\n  \u0026#34;dynamicViews\u0026#34;: [ ... ],\n  \u0026#34;constraints\u0026#34;:  [ ... ]\n}\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 3: Das JSONC-Datenmodell von Bausteinsicht im Detail"},{"content":" Dieser Post ist Teil der Serie über mein privates BeagleBone-Black-Projekt. Die Services-Schicht des Projekts ist in Go geschrieben und stellt Hardware-Peripherie über eine REST API bereit. Damit lassen sich GPIO, I2C und UART von außen steuern — ohne direkt mit dem Board verbunden zu sein.\nAPI-Design Die API folgt REST-Prinzipien: Ressourcen statt Aktionen, HTTP-Verben mit Bedeutung, JSON als Datenformat.\nBasis-URL: http://beaglebone:8080/api/v1\nEndpunkt-Übersicht:\nGET /gpio/{pin} → Pin-Zustand lesen PUT /gpio/{pin} → Pin-Zustand setzen GET /i2c/{bus}/{addr}/{reg} → I2C-Register lesen POST /i2c/{bus}/{addr} → I2C-Bytes schreiben GET /uart/{port} → UART-Daten lesen (polling) POST /uart/{port} → UART-Daten senden Keine HATEOAS, kein GraphQL — das ist ein privates Projekt, nicht eine Enterprise-API. Einfach und funktional.\nAnbindung an die HAL-Schicht Go kann keine Rust-Bibliotheken direkt laden — aber C-kompatible Shared Libraries. Rust kompiliert als C-kompatible Library, Go bindet sie via cgo ein.\npackage hal // #cgo LDFLAGS: -L${SRCDIR}/../../rust/target/armv7-unknown-linux-gnueabihf/release -lbbb_hal // #cgo LDFLAGS: -L${SRCDIR}/../../c/build-arm -lbbb_drivers // #include \u0026#34;bbb_hal.h\u0026#34; import \u0026#34;C\u0026#34; import \u0026#34;unsafe\u0026#34; Der cgo-Kommentarblock wird vom Go-Compiler direkt ausgewertet. LDFLAGS zeigt auf die cross-kompilierten ARM-Libraries.\nGPIO über HTTP Handler type GPIOHandler struct { hal *hal.HAL } func (h *GPIOHandler) Get(w http.ResponseWriter, r *http.Request) { pin, err := strconv.Atoi(chi.URLParam(r, \u0026#34;pin\u0026#34;)) if err != nil { http.Error(w, \u0026#34;invalid pin\u0026#34;, http.StatusBadRequest) return } value, err := h.hal.GPIORead(pin) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } json.NewEncoder(w).Encode(map[string]any{ \u0026#34;pin\u0026#34;: pin, \u0026#34;value\u0026#34;: value, }) } func (h *GPIOHandler) Put(w http.ResponseWriter, r *http.Request) { pin, _ := strconv.Atoi(chi.URLParam(r, \u0026#34;pin\u0026#34;)) var body struct { Value int `json:\u0026#34;value\u0026#34;` } if err := json.NewDecoder(r.Body).Decode(\u0026amp;body); err != nil { http.Error(w, \u0026#34;invalid body\u0026#34;, http.StatusBadRequest) return } if body.Value != 0 \u0026amp;\u0026amp; body.Value != 1 { http.Error(w, \u0026#34;value must be 0 or 1\u0026#34;, http.StatusBadRequest) return } if err := h.hal.GPIOWrite(pin, body.Value); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) } Beispiel-Requests # Pin 48 lesen (LED auf BeagleBone Black) curl http://beaglebone:8080/api/v1/gpio/48 # {\u0026#34;pin\u0026#34;:48,\u0026#34;value\u0026#34;:0} # Pin 48 auf HIGH setzen curl -X PUT http://beaglebone:8080/api/v1/gpio/48 \\ -H \u0026#34;Content-Type: application/json\u0026#34; \\ -d \u0026#39;{\u0026#34;value\u0026#34;: 1}\u0026#39; # 204 No Content I2C über HTTP I2C ist etwas komplexer: Bus-Nummer, Device-Adresse und Register-Adresse sind alle Teil des Pfads.\nHandler func (h *I2CHandler) Get(w http.ResponseWriter, r *http.Request) { bus, _ := strconv.Atoi(chi.URLParam(r, \u0026#34;bus\u0026#34;)) addr, _ := strconv.ParseUint(chi.URLParam(r, \u0026#34;addr\u0026#34;), 0, 8) // hex: 0x48 reg, _ := strconv.ParseUint(chi.URLParam(r, \u0026#34;reg\u0026#34;), 0, 8) value, err := h.hal.I2CRead(bus, uint8(addr), uint8(reg)) if err != nil { // I2C-Fehler → 502 Bad Gateway (Hardware-Downstream-Fehler) http.Error(w, err.Error(), http.StatusBadGateway) return } json.NewEncoder(w).Encode(map[string]any{ \u0026#34;bus\u0026#34;: bus, \u0026#34;addr\u0026#34;: fmt.Sprintf(\u0026#34;0x%02x\u0026#34;, addr), \u0026#34;reg\u0026#34;: fmt.Sprintf(\u0026#34;0x%02x\u0026#34;, reg), \u0026#34;value\u0026#34;: value, }) } Fehlerbehandlung bei Bus-Fehlern Hardware-Fehler sind keine Client-Fehler (4xx) sondern Upstream-Fehler (5xx). Ein nicht reagierendes I2C-Device ist 502 Bad Gateway, eine falsche Adresse im Request ist 400 Bad Request.\nvar ( ErrI2CDeviceNotFound = errors.New(\u0026#34;i2c device not found\u0026#34;) ErrI2CBusError = errors.New(\u0026#34;i2c bus error\u0026#34;) ) func httpStatusForHALError(err error) int { switch { case errors.Is(err, ErrI2CDeviceNotFound): return http.StatusNotFound // 404: Device nicht vorhanden case errors.Is(err, ErrI2CBusError): return http.StatusBadGateway // 502: Bus-Fehler default: return http.StatusInternalServerError } } Beispiel-Request # Temperatur-Sensor LM75 auf Bus 1, Adresse 0x48, Register 0x00 curl http://beaglebone:8080/api/v1/i2c/1/0x48/0x00 # {\u0026#34;bus\u0026#34;:1,\u0026#34;addr\u0026#34;:\u0026#34;0x48\u0026#34;,\u0026#34;reg\u0026#34;:\u0026#34;0x00\u0026#34;,\u0026#34;value\u0026#34;:42} UART über HTTP UART über HTTP ist die ungewöhnlichste Kombination. Zwei Varianten: Polling (Request/Response) und Streaming. Für dieses Projekt reicht Polling.\nHandler func (h *UARTHandler) Get(w http.ResponseWriter, r *http.Request) { port := chi.URLParam(r, \u0026#34;port\u0026#34;) // \u0026#34;ttyO1\u0026#34;, \u0026#34;ttyO2\u0026#34;, etc. // Timeout aus Query-Parameter, default 100ms timeout := 100 * time.Millisecond if t := r.URL.Query().Get(\u0026#34;timeout\u0026#34;); t != \u0026#34;\u0026#34; { if d, err := time.ParseDuration(t); err == nil { timeout = d } } data, err := h.hal.UARTRead(port, timeout) if err != nil { http.Error(w, err.Error(), http.StatusBadGateway) return } json.NewEncoder(w).Encode(map[string]any{ \u0026#34;port\u0026#34;: port, \u0026#34;data\u0026#34;: base64.StdEncoding.EncodeToString(data), \u0026#34;len\u0026#34;: len(data), }) } func (h *UARTHandler) Post(w http.ResponseWriter, r *http.Request) { port := chi.URLParam(r, \u0026#34;port\u0026#34;) var body struct { Data string `json:\u0026#34;data\u0026#34;` // base64-kodiert } if err := json.NewDecoder(r.Body).Decode(\u0026amp;body); err != nil { http.Error(w, \u0026#34;invalid body\u0026#34;, http.StatusBadRequest) return } raw, err := base64.StdEncoding.DecodeString(body.Data) if err != nil { http.Error(w, \u0026#34;data must be base64\u0026#34;, http.StatusBadRequest) return } if err := h.hal.UARTWrite(port, raw); err != nil { http.Error(w, err.Error(), http.StatusBadGateway) return } w.WriteHeader(http.StatusNoContent) } UART-Daten sind Binärdaten — base64 ist die sicherste Kodierung für JSON. Wer nur ASCII sendet, kann auch direkt einen String nutzen, muss aber mit Encoding-Problemen rechnen.\nBeispiel: vollständiger Request-Flow Wie sieht der Weg eines HTTP-Requests bis zum GPIO-Register aus?\nHTTP Client GET /api/v1/gpio/48 │ ▼ Go Router (chi) GPIOHandler.Get(w, r) │ ▼ hal.GPIORead(48) ← Go-Funktion │ ▼ hal_gpio_read(48, \u0026amp;value) ← cgo-Aufruf → Rust pub extern \u0026#34;C\u0026#34; │ ▼ gpio_read_sysfs(48, \u0026amp;value) ← Rust ruft C-Treiber auf (unsafe) │ ▼ open(\u0026#34;/sys/class/gpio/gpio48/value\u0026#34;) ← C, Linux sysfs │ ▼ AM335x GPIO-Register Jede Schicht hat eine klar definierte Aufgabe. Go kennt keine Dateinamen, C kennt keine HTTP-Handler.\nDeployment als systemd-Service # /etc/systemd/system/bbb-hal.service [Unit] Description=BeagleBone Black HAL REST API After=network.target [Service] Type=simple User=pi WorkingDirectory=/opt/bbb-hal ExecStart=/opt/bbb-hal/bbb-api --port 8080 Restart=always RestartSec=5 # Hardware-Zugriff erlauben SupplementaryGroups=gpio i2c dialout [Install] WantedBy=multi-user.target sudo systemctl enable --now bbb-hal sudo systemctl status bbb-hal Nächster Post in der Serie: Rust in der HAL — warum und wie\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/rest-api-go-gpio-i2c-uart/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post ist Teil der Serie über mein \u003ca href=\"/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/\"\u003eprivates BeagleBone-Black-Projekt\u003c/a\u003e.\nDie Services-Schicht des Projekts ist in Go geschrieben und stellt Hardware-Peripherie\nüber eine REST API bereit. Damit lassen sich GPIO, I2C und UART von außen steuern —\nohne direkt mit dem Board verbunden zu sein.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_api_design\"\u003eAPI-Design\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDie API folgt REST-Prinzipien: Ressourcen statt Aktionen, HTTP-Verben mit Bedeutung,\nJSON als Datenformat.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cstrong\u003eBasis-URL:\u003c/strong\u003e \u003ccode\u003e\u003ca href=\"http://beaglebone:8080/api/v1\" class=\"bare\"\u003ehttp://beaglebone:8080/api/v1\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cstrong\u003eEndpunkt-Übersicht:\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode\u003eGET    /gpio/{pin}              → Pin-Zustand lesen\nPUT    /gpio/{pin}              → Pin-Zustand setzen\nGET    /i2c/{bus}/{addr}/{reg}  → I2C-Register lesen\nPOST   /i2c/{bus}/{addr}        → I2C-Bytes schreiben\nGET    /uart/{port}             → UART-Daten lesen (polling)\nPOST   /uart/{port}             → UART-Daten senden\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Die REST API in Go — GPIO, I2C und UART über HTTP"},{"content":" Dieser Post setzt den dritten Teil fort. Das Alleinstellungsmerkmal von Bausteinsicht ist die bidirektionale Synchronisation: Änderungen im JSONC-Modell landen im draw.io-Diagramm — und Änderungen im Diagramm landen im Modell. Wie das funktioniert, erklärt dieser Post.\nDas Problem: Zwei Repräsentationen, eine Wahrheit Architekturdiagramme haben ein fundamentales Problem: entweder ist der Code die Quelle der Wahrheit und das Diagramm wird automatisch generiert (gut für Konsistenz, schlecht für visuelle Kontrolle), oder das Diagramm ist die Quelle und wird manuell gepflegt (gut für Aussehen, schlecht für Konsistenz).\nBausteinsicht löst das durch echte Bidirektionalität: Modell und Diagramm sind gleichwertig. Der Sync-Algorithmus erkennt, welche Seite sich geändert hat, und überträgt die Änderung zur anderen Seite.\nDie .bausteinsicht-sync State-Datei Die Grundlage des Sync-Algorithmus ist die .bausteinsicht-sync-Datei. Sie enthält einen Snapshot des Zustands nach dem letzten erfolgreichen Sync:\n{ \u0026#34;timestamp\u0026#34;: \u0026#34;2025-06-11T09:00:00Z\u0026#34;, \u0026#34;model_hash\u0026#34;: \u0026#34;sha256:a1b2c3...\u0026#34;, \u0026#34;drawio_hash\u0026#34;: \u0026#34;sha256:d4e5f6...\u0026#34;, \u0026#34;elements\u0026#34;: { \u0026#34;onlineshop.frontend\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Web Frontend\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;React\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34; } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;onlineshop\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; } ], \u0026#34;rendered_elements\u0026#34;: { \u0026#34;onlineshop.frontend\u0026#34;: true, \u0026#34;onlineshop.api\u0026#34;: true } } Diese State-Datei ist der Dreiwegs-Vergleich: sync vergleicht den aktuellen Zustand von Modell und Diagramm jeweils mit dem letzten bekannten Zustand — und erkennt dadurch auf welcher Seite sich etwas verändert hat.\nDie .bausteinsicht-sync-Datei gehört ins Git-Repository neben architecture.jsonc. Sie ist der einzige Weg, wie Bausteinsicht Konflikte von legitimen Änderungen unterscheidet. Der Sync-Zyklus bausteinsicht sync führt jeden Lauf als atomaren Fünf-Schritte-Zyklus aus:\n1. DetectChanges → ChangeSet (was hat sich auf welcher Seite geändert?) 2. ResolveConflicts → conflicting fields aufgelöst (Modell gewinnt) 3. ApplyForward → Modell-Änderungen → draw.io übertragen 4. ApplyReverse → draw.io-Änderungen → Modell übertragen 5. SaveState → .bausteinsicht-sync aktualisieren Der gesamte Zyklus ist eine pure Funktion ohne Seiteneffekte — alle I/O findet davor und danach statt. Das macht den Algorithmus testbar und deterministisch.\nForward-Sync: Modell → draw.io Der Forward-Sync übernimmt alle Modelländerungen ins Diagramm.\nNeue Elemente Neue Elemente erscheinen mit einem roten gestrichelten Rahmen als visueller Marker:\nstrokeColor=#FF0000;dashed=1; Der rote Rahmen signalisiert: „Dieses Element wurde gerade hinzugefügt — positioniere es.\u0026#34; Sobald das Element manuell verschoben wurde und sync erneut läuft, verschwindet der rote Rahmen.\nPositionen werden beibehalten Bausteinsicht merkt sich die gesetzten Positionen im Diagramm. Bei jedem Forward-Sync werden nur Titel, Beschreibung, Technologie und Stile aktualisiert — nicht die Position. Manuell arrangierte Layouts bleiben erhalten.\nTag-Stile werden angewendet Wenn ein Element Tags hat, die in specification.tags mit style-Attributen definiert sind, werden diese Stile auf das draw.io-Element angewendet:\n\u0026#34;specification\u0026#34;: { \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#f5f5f5\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#666666\u0026#34; } } ] }, \u0026#34;model\u0026#34;: { \u0026#34;paymentprovider\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Provider\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] } } Status-Badges Elements mit status-Feld erhalten automatisch einen farbigen Badge im Diagramm:\nStatus Farbe Bedeutung proposed\nGelb\nGeplant\ndesign\nBlau\nIm Entwurf\nimplementation\nOrange\nIn Entwicklung\ndeployed\nGrün\nProduktiv\ndeprecated\nRot\nVeraltet\narchived\nGrau\nEingestellt\nReverse-Sync: draw.io → Modell Der Reverse-Sync überträgt Änderungen aus dem Diagramm zurück ins JSONC-Modell.\nWas wird zurückgeschrieben? Folgende Änderungen im Diagramm landen im Modell:\ndraw.io Aktion Effekt im Modell Element umbenennen (Doppelklick → neuer Titel)\ntitle des Elements wird aktualisiert\nTechnologie-Label ändern\ntechnology wird aktualisiert\nNeues Element in eine Container-Box ziehen\nNeues Element wird als children hinzugefügt\nElement aus dem Diagramm löschen\nElement wird aus dem Modell entfernt\nVerbindung zwischen zwei Elementen ziehen\nNeue Relationship wird im relationships-Array angelegt\nVerbindungspfeil umdrehen\nfrom und to der Relationship werden getauscht, Metadaten bleiben erhalten\nVerbindung löschen\nRelationship wird aus dem Modell entfernt\nRelationship Lifting Ein wichtiges Konzept: Relationship Lifting. Wenn in draw.io eine Verbindung zwischen zwei Elementen gezogen wird, die in der Modell-Hierarchie auf verschiedenen Ebenen liegen, „hebt\u0026#34; Bausteinsicht die Verbindung automatisch auf die passende Hierarchieebene an.\nBeispiel: Das Diagramm zeigt shop.frontend und shop.api (beide Container-Kinder von shop). Man zieht eine Verbindung von frontend zu api — genau diese Beziehung landet im Modell:\n\u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;API calls\u0026#34; } ] Zieht man dagegen eine Verbindung von customer (Top-Level-Actor) zu shop.api (verschachtelter Container), wird sie korrekt als customer → shop.api angelegt — ohne manuelle Korrektur der IDs.\nKonflikterkennung und -auflösung Ein Konflikt entsteht wenn dasselbe Feld auf beiden Seiten gleichzeitig geändert wurde — also seit dem letzten sync.\nWann passiert das? Typisches Szenario: Du änderst title im JSONC-Modell und jemand anderes ändert gleichzeitig denselben Titel direkt im draw.io-Diagramm — ohne vorher zu synchronisieren.\nAuflösung: Modell gewinnt Bausteinsicht verwendet eine einfache und vorhersehbare Strategie: das Modell gewinnt immer.\nConflict detected for element \u0026#34;shop.frontend\u0026#34;: Field: title Model value: \u0026#34;Web App\u0026#34; draw.io value: \u0026#34;Frontend Application\u0026#34; Last sync: \u0026#34;Web Frontend\u0026#34; → Keeping model value. Edit draw.io manually if needed. Der Konflikt wird als Warning ausgegeben — die Änderung im Modell wird übernommen, die draw.io-Änderung wird verworfen.\nDiese Strategie ist bewusst einfach gehalten. Das JSONC-Modell ist die primäre Quelle der Wahrheit — draw.io ist ein View darauf.\nPraktisches Beispiel: Vollständiger Sync-Zyklus Ausgangssituation architecture.jsonc und architecture.drawio sind synchron (letzter Sync vor 10 Minuten).\nSchritt 1: Modell ändern Im JSONC einen neuen Container hinzufügen:\n\u0026#34;model\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Frontend\u0026#34; }, \u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34; }, \u0026#34;cache\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Redis Cache\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Redis\u0026#34; } } } } Schritt 2: Im Diagramm den API-Titel ändern architecture.drawio öffnen, Doppelklick auf „REST API\u0026#34;, umbenennen zu „REST API v2\u0026#34;, speichern.\nSchritt 3: Sync ausführen bausteinsicht sync Ausgabe:\nForward (model → draw.io): 1 added, 0 updated, 0 deleted Reverse (draw.io → model): 0 added, 1 updated, 0 deleted Ergebnis:\ndraw.io: Redis Cache erscheint mit rotem gestricheltem Rahmen in der Container View\narchitecture.jsonc: \u0026#34;title\u0026#34;: \u0026#34;REST API v2\u0026#34; für den API-Container\nBeide Seiten wurden in einem einzigen sync-Durchlauf aktualisiert.\nWatch-Modus: Kontinuierliche Synchronisation bausteinsicht watch überwacht beide Dateien mit einem Filesystem-Watcher und triggert den Sync-Zyklus automatisch bei jeder Änderung.\nDas Resultat: Man kann gleichzeitig im Editor das Modell bearbeiten und in draw.io das Diagramm anpassen — der Watch-Prozess hält alles in Echtzeit synchron.\nIm Watch-Modus empfiehlt sich git commit nach jedem abgeschlossenen Änderungsschritt. Der .bausteinsicht-sync State zeigt im git diff genau welche Elemente geändert wurden — ein nützliches Protokoll. Beispiel-Modell Das Beispiel für diesen Teil ist als ausführbare JSONC-Datei unter teil_4.jsonc abgelegt und zeigt den Zustand nach einem vollständigen Sync-Zyklus (inkl. Reverse-Sync: \u0026#34;REST API v2\u0026#34;).\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_4.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 5: Multi-View — mehrere Diagrammperspektiven aus einem Modell\nTeil 8: Validation \u0026amp; Linting — Architekturregeln mit bausteinsicht lint durchsetzen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-bidirektionale-synchronisation/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-datenmodell/\"\u003edritten Teil\u003c/a\u003e fort.\nDas Alleinstellungsmerkmal von Bausteinsicht ist die bidirektionale Synchronisation:\nÄnderungen im JSONC-Modell landen im draw.io-Diagramm — und Änderungen im Diagramm landen im Modell.\nWie das funktioniert, erklärt dieser Post.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_zwei_repräsentationen_eine_wahrheit\"\u003eDas Problem: Zwei Repräsentationen, eine Wahrheit\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eArchitekturdiagramme haben ein fundamentales Problem: entweder ist der Code die Quelle der Wahrheit und das Diagramm wird automatisch generiert (gut für Konsistenz, schlecht für visuelle Kontrolle), oder das Diagramm ist die Quelle und wird manuell gepflegt (gut für Aussehen, schlecht für Konsistenz).\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 4: Bidirektionale Synchronisation — Wie draw.io und JSONC in sync bleiben"},{"content":" Dieser Post ist Teil der Serie über mein privates BeagleBone-Black-Projekt. Der C-Teil des HAL wird auf einem x86-Entwicklungsrechner kompiliert — das Binary muss aber auf dem ARM Cortex-A8 des BeagleBone Black laufen. Das ist Cross-Kompilierung, und CMake macht das handhabbar.\nVoraussetzungen Toolchain installieren Auf Ubuntu/Debian:\nsudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf Das installiert die wichtigsten Tools:\narm-linux-gnueabihf-gcc — C-Compiler für ARMv7 mit Hard-Float ABI\n`arm-linux-gnueabihf-g` — C-Compiler\narm-linux-gnueabihf-ld — Linker\narm-linux-gnueabihf-strip — Symbol-Stripper\nVersion prüfen:\narm-linux-gnueabihf-gcc --version # arm-linux-gnueabihf-gcc (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0 Sysroot (optional aber empfohlen) Ein Sysroot ist eine Kopie des Ziel-Dateisystems — mit den korrekten Libraries und Headern für die Zielplattform. Ohne Sysroot linkt der Compiler gegen die Host-Libraries, was zu ABI-Mismatches führt.\nSysroot vom BeagleBone Black kopieren:\nrsync -avz \\ --exclude=\u0026#34;/proc\u0026#34; --exclude=\u0026#34;/sys\u0026#34; --exclude=\u0026#34;/dev\u0026#34; \\ pi@beaglebone:/ \\ ~/bbb-sysroot/ Für einfache Projekte ohne systemspezifische Libraries reicht die Toolchain alleine. Sobald man gegen libgpiod, libi2c oder andere Board-spezifische Libraries linkt, ist das Sysroot nötig.\nCMake Toolchain-File Das Herzstück ist das Toolchain-File — eine CMake-Datei die dem Build-System mitteilt, welchen Compiler, welchen Linker und welches Zielsystem es nutzen soll.\nDatei cmake/armv7-toolchain.cmake:\n# Zielsystem set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR armv7) # Toolchain-Prefix set(TOOLCHAIN_PREFIX arm-linux-gnueabihf) # Compiler set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) # Sysroot (auskommentieren wenn kein Sysroot vorhanden) # set(CMAKE_SYSROOT /home/user/bbb-sysroot) # Nur im Sysroot nach Libraries suchen, nicht auf dem Host set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # ARMv7 Cortex-A8 spezifische Flags set(CMAKE_C_FLAGS \u0026#34;-march=armv7-a -mfpu=neon -mfloat-abi=hard\u0026#34; CACHE STRING \u0026#34;\u0026#34;) set(CMAKE_CXX_FLAGS \u0026#34;-march=armv7-a -mfpu=neon -mfloat-abi=hard\u0026#34; CACHE STRING \u0026#34;\u0026#34;) Die wichtigsten Variablen erklärt:\nCMAKE_SYSTEM_NAME Teilt CMake mit, dass für ein anderes Betriebssystem gebaut wird. Deaktiviert viele Host-Checks.\nCMAKE_SYSTEM_PROCESSOR Prozessor-Architektur des Zielsystems — beeinflusst Compiler-Defaults.\nCMAKE_C_COMPILER Absoluter Pfad oder Name des Cross-Compilers.\nCMAKE_SYSROOT Wo CMake nach Headers und Libraries sucht.\nCMAKE_FIND_ROOT_PATH_MODE_* Verhindert dass CMake versehentlich Host-Libraries findet.\nCMakeLists.txt-Besonderheiten Die CMakeLists.txt selbst unterscheidet sich kaum von einer normalen Konfiguration. Ein paar Punkte sind beim Cross-Compile zu beachten:\ncmake_minimum_required(VERSION 3.20) project(bbb_hal C) # Compiler-Test deaktivieren wenn kein Emulator vorhanden # (CMake versucht sonst das kompilierte Binary auszuführen) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # Ziel-Bibliothek add_library(bbb_drivers STATIC src/gpio_driver.c src/i2c_driver.c src/uart_driver.c ) target_include_directories(bbb_drivers PUBLIC include) # Installationspfad für Deploy-Script install(TARGETS bbb_drivers DESTINATION lib) install(DIRECTORY include/ DESTINATION include) CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY ist entscheidend. Ohne diese Einstellung versucht CMake ein Test-Binary zu linken und auszuführen — was auf dem x86-Host nicht funktioniert.\nBuild ausführen # Build-Verzeichnis erstellen und konfigurieren cmake \\ -DCMAKE_TOOLCHAIN_FILE=cmake/armv7-toolchain.cmake \\ -DCMAKE_BUILD_TYPE=Release \\ -B build-arm # Kompilieren cmake --build build-arm # Prüfen: ist es wirklich ein ARM-Binary? file build-arm/libbbb_drivers.a # build-arm/libbbb_drivers.a: current ar archive arm-linux-gnueabihf-readelf -h build-arm/libbbb_drivers.a | grep Machine # Machine: ARM Integration in Drone CI Im CI-Container muss die Toolchain installiert sein. Ich verwende in der Pipeline direktes apt-get um keine eigenen Images pflegen zu müssen:\nsteps: - name: build-c image: ubuntu:22.04 commands: - apt-get update -q - apt-get install -y cmake gcc-arm-linux-gnueabihf - cmake -DCMAKE_TOOLCHAIN_FILE=cmake/armv7-toolchain.cmake -DCMAKE_BUILD_TYPE=Release -B build-arm - cmake --build build-arm --parallel $(nproc) Deployment auf das Board Nach dem Build muss das Binary auf den BeagleBone Black:\n# Library und Header übertragen rsync -avz build-arm/libbbb_drivers.a pi@beaglebone:/opt/bbb-hal/lib/ rsync -avz include/ pi@beaglebone:/opt/bbb-hal/include/ # Shared Library (wenn gebaut) rsync -avz build-arm/libbbb_drivers.so pi@beaglebone:/usr/local/lib/ ssh pi@beaglebone \u0026#34;ldconfig\u0026#34; Im CI-Deploy-Step:\n- name: deploy image: alpine environment: SSH_KEY: from_secret: bbb_ssh_key commands: - apk add --no-cache openssh-client rsync - eval $(ssh-agent -s) - echo \u0026#34;$SSH_KEY\u0026#34; | ssh-add - - rsync -avz build-arm/ pi@beaglebone:/opt/bbb-hal/ - ssh pi@beaglebone \u0026#34;systemctl restart bbb-hal\u0026#34; when: branch: [main] Häufige Fehler Falscher ABI: hard vs softfp /usr/bin/ld: skipping incompatible /usr/lib/libm.so when searching for -lm Der Linker findet eine Library mit falschem Float-ABI. Lösung: Sysroot korrekt setzen oder Libraries explizit mit -mfloat-abi=hard kompilieren.\nFehlende Sysroot-Header fatal error: linux/i2c-dev.h: No such file or directory Der Header existiert nicht in der Toolchain selbst, nur im Board-Sysroot. Lösung: Sysroot korrekt konfigurieren oder Header manuell einbinden.\nCMake findet Host-Libraries -- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libssl.so (found version \u0026#34;3.0.2\u0026#34;) CMake hat die Host-Library gefunden statt der ARM-Version. Lösung: CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY im Toolchain-File prüfen.\nBinary läuft nicht auf dem Board pi@beaglebone:~$ ./myapp bash: ./myapp: cannot execute binary file: Exec format error Das Binary wurde für x86 kompiliert, nicht für ARM. Ursache: Toolchain-File wurde nicht übergeben. Prüfen mit file myapp — sollte ARM zeigen.\nRust Cross-Compilation Als Bonus: so sieht Cross-Compilation für den Rust-Teil des Projekts aus.\n# Target installieren rustup target add armv7-unknown-linux-gnueabihf Datei .cargo/config.toml:\n[target.armv7-unknown-linux-gnueabihf] linker = \u0026#34;arm-linux-gnueabihf-gcc\u0026#34; Build:\ncargo build \\ --release \\ --target armv7-unknown-linux-gnueabihf Rust und CMake nutzen dieselbe Toolchain (arm-linux-gnueabihf-gcc). Wer das Toolchain-File für CMake richtig konfiguriert hat, hat den schwersten Teil der Rust-Konfiguration schon hinter sich.\nNächster Post in der Serie: Rust in der HAL — warum und wie\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/cross-kompilierung-armv7-cmake/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post ist Teil der Serie über mein \u003ca href=\"/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/\"\u003eprivates BeagleBone-Black-Projekt\u003c/a\u003e.\nDer C-Teil des HAL wird auf einem x86-Entwicklungsrechner kompiliert —\ndas Binary muss aber auf dem ARM Cortex-A8 des BeagleBone Black laufen.\nDas ist Cross-Kompilierung, und CMake macht das handhabbar.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_voraussetzungen\"\u003eVoraussetzungen\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"sect2\"\u003e\n\u003ch3 id=\"_toolchain_installieren\"\u003eToolchain installieren\u003c/h3\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAuf Ubuntu/Debian:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003esudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas installiert die wichtigsten Tools:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003earm-linux-gnueabihf-gcc\u003c/code\u003e — C-Compiler für ARMv7 mit Hard-Float ABI\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e`arm-linux-gnueabihf-g` — C-Compiler\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003earm-linux-gnueabihf-ld\u003c/code\u003e — Linker\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003earm-linux-gnueabihf-strip\u003c/code\u003e — Symbol-Stripper\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Cross-Kompilierung für ARMv7 mit CMake"},{"content":" Dieser Post setzt den vierten Teil fort. In den vorigen Teilen hatte jedes Beispiel-Modell ein oder zwei Views. Hier geht es darum, wie Bausteinsicht C4-ähnliche Multi-Level-Views aus einem einzigen Modell erzeugt.\nViews als Linsen auf das Modell Das Modell in Bausteinsicht beschreibt das vollständige System — alle Elemente, alle Beziehungen, alle Hierarchieebenen. Eine View ist eine Linse, die ausschneidet was in einem bestimmten Kontext relevant ist.\nDas bedeutet: dieselben Elemente können in mehreren Views erscheinen. Der model-Abschnitt in architecture.jsonc bleibt eine Quelle der Wahrheit — die Views bestimmen nur die Darstellung.\nDas C4-Muster mit Bausteinsicht Das C4-Modell (Context → Container → Component → Code) lässt sich direkt auf Bausteinsicht-Views abbilden:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;actor\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Actor\u0026#34; }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;component\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Component\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;database\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Database\u0026#34; } } }, \u0026#34;model\u0026#34;: { \u0026#34;customer\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Customer\u0026#34; }, \u0026#34;admin\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Admin\u0026#34; }, \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Frontend\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;React\u0026#34; }, \u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;orderhandler\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Order Handler\u0026#34; }, \u0026#34;producthandler\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Product Handler\u0026#34; }, \u0026#34;authhandler\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Handler\u0026#34; } } }, \u0026#34;db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;PostgreSQL\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; }, \u0026#34;cache\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Redis Cache\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Redis\u0026#34; } } }, \u0026#34;payment\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Provider (extern)\u0026#34; } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;kauft ein\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;admin\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;verwaltet\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;REST calls\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads/writes\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.cache\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;cache lookup\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;reads\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;payment\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge()\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.api.orderhandler\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;persist orders\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.api.producthandler\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;read products\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;reads\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.api.authhandler\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.cache\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;validate token\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;reads\u0026#34; } ], \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;System Context\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;admin\u0026#34;, \u0026#34;shop\u0026#34;, \u0026#34;payment\u0026#34;] }, \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container View\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;admin\u0026#34;, \u0026#34;shop.*\u0026#34;, \u0026#34;payment\u0026#34;] }, \u0026#34;api-components\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;API Components\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop.api.*\u0026#34;, \u0026#34;shop.db\u0026#34;, \u0026#34;shop.cache\u0026#34;] } } } Das ergibt drei Tabs in architecture.drawio: System Context, Container View, API Components.\nscope: Die Bounding Box Das scope-Feld in einer View ist der Schlüssel zu strukturierten Diagrammen.\nWenn eine View einen scope definiert, wird das Scope-Element als Bounding Box (Swimlane / Container-Rahmen) gerendert. Alle anderen Elemente der View erscheinen entweder innerhalb dieser Box (wenn sie Kinder des Scope-Elements sind) oder außerhalb (externe Akteure und Systeme).\nBeispiel: Container View mit scope = \u0026#34;shop\u0026#34; ┌─────────────────────────────────────────────────────┐ │ Online Shop │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ Web Frontend │→ │ REST API │→ │PostgreSQL│ │ │ │ React │ │ Go │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────┘ │ │ ↓ │ │ ┌──────────────┐ │ │ │ Redis Cache │ │ │ └──────────────┘ │ └─────────────────────────────────────────────────────┘ ↑ customer, admin (außerhalb der Box) ↗ payment (außerhalb) Die Bounding Box visualisiert die Systemgrenze auf einen Blick.\ninclude: Welche Elemente erscheinen? include akzeptiert exakte IDs und Wildcards:\nPattern Bedeutung \u0026#34;shop\u0026#34;\nExakt das Element shop\n\u0026#34;shop.*\u0026#34;\nAlle direkten Kinder von shop (frontend, api, db, cache) — aber nicht deren Kinder\n\u0026#34;shop.**\u0026#34;\nAlle Kinder und Kindeskinder von shop (rekursiv)\n\u0026#34;shop.api.*\u0026#34;\nAlle Komponenten innerhalb von shop.api\nfilter-tags und exclude-tags Views lassen sich auch nach Tags filtern:\n\u0026#34;views\u0026#34;: { \u0026#34;external-systems\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Externe Systeme\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;external\u0026#34;], \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;shop\u0026#34;, \u0026#34;payment\u0026#34;] }, \u0026#34;active-only\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Aktive Komponenten\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop.**\u0026#34;], \u0026#34;exclude-tags\u0026#34;: [\u0026#34;deprecated\u0026#34;, \u0026#34;archived\u0026#34;] } } Drill-Down-Links: Navigation zwischen Views Wenn ein Element als scope einer View verwendet wird, setzt Bausteinsicht automatisch einen Drill-Down-Link auf dieses Element in allen anderen Views.\nIn der Context View ist shop ein normales Rechteck. Da shop aber der Scope der Container View ist, bekommt das Rechteck in der Context View einen klickbaren Link — ein Klick öffnet direkt die Container View.\nDasselbe gilt für shop.api als Scope der API-Components-View: ein Klick auf die API-Box in der Container View öffnet die Components-View.\nDas ergibt eine navigierbare Zoom-Hierarchie:\nSystem Context → [click \u0026#34;Online Shop\u0026#34;] → Container View → [click \u0026#34;REST API\u0026#34;] → API Components Kein manuelles Setzen von Links — Bausteinsicht leitet das vollständig aus der scope-Konfiguration ab.\nRücknavigation: Zurück zur übergeordneten View Views mit scope bekommen automatisch einen Back-Button in der oberen linken Ecke des Diagramms. Der Button navigiert zur übergeordneten View — der View, aus der man per Drill-Down hierher navigiert ist.\nDas macht die Navigation bidirektional: rein- und rauszoomen ohne manuelles Tab-Wechseln.\nPraktisches Beispiel: Drei Views generieren Mit dem Modell aus dem Abschnitt oben:\nbausteinsicht sync Ausgabe:\nForward (model → draw.io): 12 added, 0 updated, 0 deleted architecture.drawio öffnen — drei Tabs:\nSystem Context: Customer, Admin, Online Shop (ein Rechteck mit Drill-Down-Link), Payment Provider\nContainer View: Scope-Box \u0026#34;Online Shop\u0026#34; mit Frontend, REST API, PostgreSQL, Redis Cache darin; Customer, Admin und Payment außerhalb\nAPI Components: Scope-Box \u0026#34;REST API\u0026#34; mit den drei Handlern darin; PostgreSQL und Redis Cache außerhalb\nDie drei Views teilen sich dasselbe Modell. Eine Beziehung im Modell ändert sich — ein sync aktualisiert alle drei Tabs gleichzeitig.\nUnsichtbare Elemente: Eine nützliche Warnung Wenn ein Element im Modell existiert, aber in keiner View auftaucht, gibt bausteinsicht sync eine Warnung aus:\nWARNING: Element \u0026#34;shop.api.orderhandler\u0026#34; exists in the model but is not visible in any view — add it to a view\u0026#39;s include list Das ist kein Fehler — das Element bleibt im Modell und kann jederzeit einer View hinzugefügt werden. Die Warnung verhindert, dass Elemente im Modell „verschwinden\u0026#34; ohne es zu bemerken.\nMit bausteinsicht status bekommt man eine Übersicht aller Elemente und ob sie in einer View sichtbar sind. Beispiel-Modell Das Beispiel für diesen Teil ist als ausführbare JSONC-Datei unter teil_5.jsonc abgelegt mit allen drei Views (context, containers, api-components).\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_5.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram — hier die Container View:\nWas als nächstes kommt Teil 6: Export-Features — Mermaid, Structurizr DSL, PNG und mehr\nTeil 7: Snapshots \u0026amp; Changelog — Architektur über Zeit versionieren\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-multi-view/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-bidirektionale-synchronisation/\"\u003evierten Teil\u003c/a\u003e fort.\nIn den vorigen Teilen hatte jedes Beispiel-Modell ein oder zwei Views.\nHier geht es darum, wie Bausteinsicht C4-ähnliche Multi-Level-Views aus einem einzigen Modell erzeugt.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_views_als_linsen_auf_das_modell\"\u003eViews als Linsen auf das Modell\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas Modell in Bausteinsicht beschreibt das vollständige System — alle Elemente, alle Beziehungen, alle Hierarchieebenen.\nEine \u003cstrong\u003eView\u003c/strong\u003e ist eine Linse, die ausschneidet was in einem bestimmten Kontext relevant ist.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas bedeutet: dieselben Elemente können in mehreren Views erscheinen.\nDer \u003ccode\u003emodel\u003c/code\u003e-Abschnitt in \u003ccode\u003earchitecture.jsonc\u003c/code\u003e bleibt eine Quelle der Wahrheit — die Views bestimmen nur die Darstellung.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 5: Multi-View — Mehrere Diagrammperspektiven aus einem Modell"},{"content":" Dieser Post ist Teil der Serie über mein privates BeagleBone-Black-Projekt. Die CI/CD-Infrastruktur des Projekts läuft auf Drone CI — aber nicht mit Docker, sondern mit Podman als Container-Backend. Was auf dem Papier einfach klingt, hat in der Praxis ein paar Ecken.\nWarum Podman statt Docker? Die kurze Antwort: rootless-Betrieb und kein Daemon.\nDocker erfordert einen privilegierten Daemon der permanent läuft — dockerd — und der Zugriff auf den Docker-Socket bedeutet de facto Root-Rechte auf dem Host. Das ist für viele Umgebungen ein akzeptables Tradeoff, für meinen privaten Server nicht.\nPodman läuft ohne Daemon:\n# Docker: Client spricht mit Daemon der als root läuft docker run ubuntu echo hello # Podman: kein Daemon, direkter fork/exec als normaler User podman run ubuntu echo hello Konkrete Vorteile im Betrieb:\nKein dauerhaft laufender privilegierter Prozess\nContainer laufen unter dem eigenen UID des aufrufenden Users\npodman-auto-update statt Docker Watchers\nDrop-in-kompatibel zu Docker für die meisten Fälle\nPodman ist kein perfekter Docker-Ersatz. Wo es Unterschiede gibt, beschreibe ich sie weiter unten bei den Fallstricken.\nDrone CI Serverinstallation mit Podman Drone Server und Runner laufen selbst als Container — gestartet mit Podman.\nDrone Server podman run \\ --detach \\ --name=drone \\ --restart=always \\ --env=DRONE_GITEA_SERVER=https://gitea.example.com \\ --env=DRONE_GITEA_CLIENT_ID=\u0026lt;client-id\u0026gt; \\ --env=DRONE_GITEA_CLIENT_SECRET=\u0026lt;secret\u0026gt; \\ --env=DRONE_RPC_SECRET=\u0026lt;shared-secret\u0026gt; \\ --env=DRONE_SERVER_HOST=drone.example.com \\ --env=DRONE_SERVER_PROTO=https \\ --publish=80:80 \\ --publish=443:443 \\ --volume=/var/lib/drone:/data \\ docker.io/drone/drone:2 Drone Runner (Podman-Backend) Der Standard-Drone-Docker-Runner spricht gegen den Docker-Socket. Für Podman gibt es zwei Wege:\nOption A — Docker-kompatiblen Socket exponieren:\nPodman kann einen Docker-kompatiblen Socket bereitstellen:\nsystemctl --user enable --now podman.socket # Socket liegt unter: /run/user/\u0026lt;UID\u0026gt;/podman/podman.sock Den Runner dann mit dem Podman-Socket starten:\npodman run \\ --detach \\ --name=drone-runner \\ --restart=always \\ --env=DRONE_RPC_PROTO=https \\ --env=DRONE_RPC_HOST=drone.example.com \\ --env=DRONE_RPC_SECRET=\u0026lt;shared-secret\u0026gt; \\ --env=DRONE_RUNNER_CAPACITY=2 \\ --volume=/run/user/1000/podman/podman.sock:/var/run/docker.sock \\ docker.io/drone/drone-runner-docker:1 Option B — Exec Runner (kein Container-Socket nötig):\nDer Exec Runner führt Steps direkt auf dem Host aus — einfacher, weniger isoliert:\npodman run \\ --detach \\ --name=drone-runner-exec \\ --restart=always \\ --env=DRONE_RPC_PROTO=https \\ --env=DRONE_RPC_HOST=drone.example.com \\ --env=DRONE_RPC_SECRET=\u0026lt;shared-secret\u0026gt; \\ --volume=/var/run/drone-runner:/data \\ docker.io/drone/drone-runner-exec:latest Ich verwende Option A weil der Docker-Runner die bessere Step-Isolation bietet und .drone.yml-Dateien ohne Anpassung funktionieren.\nFallstricke Volume-Mounts und Dateiberechtigungen Das größte Problem beim rootless Betrieb: Dateiberechtigungen.\nRootless Podman mappt UIDs im Container auf Subuid-Ranges des Host-Users. Ein Prozess der im Container als root (UID 0) läuft, läuft auf dem Host als UID des Users plus Offset.\nProblem: Ein Build-Step schreibt Dateien unter root im Container — nach dem Build gehören diese Dateien auf dem Host einem UID der nicht existiert.\nLösung: Explizites UID-Mapping oder --userns=keep-id:\n# .drone.yml steps: - name: build image: ubuntu:22.04 volumes: - name: workspace path: /workspace environment: DRONE_WORKSPACE_BASE: /workspace volumes: - name: workspace host: path: /tmp/drone-workspace Oder den Drone-Runner mit --userns=keep-id starten, damit der Container-User mit dem Host-User übereinstimmt.\nNetzwerk-Isolation zwischen Steps Docker-Runner-Steps im selben Pipeline-Run teilen ein Netzwerk. Bei Podman mit rootless-Setup kann das Netzwerk-Backend (slirp4netns vs pasta) zu unterschiedlichen Ergebnissen führen.\nProblem: Ein Datenbankcontainer in Step A ist aus Step B unter localhost nicht erreichbar.\nLösung: Service-Container explizit benennen und per Hostname ansprechen:\nservices: - name: postgres image: postgres:15 environment: POSTGRES_DB: testdb POSTGRES_PASSWORD: test steps: - name: test image: golang:1.21 commands: # Hostname ist der Service-Name, nicht localhost - go test -db-host=postgres ./... Secrets und Environment-Variablen Drone-Secrets funktionieren unverändert — das ist kein Podman-spezifisches Problem. Aber: bei rootless Podman dürfen Secrets nicht in gemountete Host-Verzeichnisse geschrieben werden die anderen Users zugänglich sind.\nBest Practice: Secrets nur als Umgebungsvariablen, nie als Dateien in /tmp.\nsteps: - name: deploy image: alpine environment: SSH_KEY: from_secret: ssh_private_key commands: # Key in memory halten, nie auf Disk - eval $(ssh-agent -s) - echo \u0026#34;$SSH_KEY\u0026#34; | ssh-add - - ssh user@host \u0026#34;systemctl restart myservice\u0026#34; Cross-Compilation und privilegierte Operationen Mein Build-Setup cross-kompiliert für ARMv7. Der Cross-Kompilierungs-Container braucht keine besonderen Rechte — aber ich bin anfangs in die Falle getappt, --privileged zu setzen weil ein anderer Schritt es brauchte.\nRegel: Jeden Step auf minimale Rechte reduzieren. --privileged nur wenn wirklich nötig (z. B. Kernel-Module laden). Cross-Kompilierung braucht es nie.\nFunktionierende .drone.yml-Konfiguration Das ist meine tatsächliche Pipeline — vereinfacht aber funktionierend:\nkind: pipeline type: docker name: beaglebone-build steps: - name: build-c image: ubuntu:22.04 commands: - apt-get update -q \u0026amp;\u0026amp; apt-get install -y cmake gcc-arm-linux-gnueabihf - cmake -DCMAKE_TOOLCHAIN_FILE=cmake/armv7-toolchain.cmake -B build-arm - cmake --build build-arm - name: build-rust image: rust:1.75 commands: - rustup target add armv7-unknown-linux-gnueabihf - cd rust - cargo build --release --target armv7-unknown-linux-gnueabihf - name: build-go image: golang:1.21 commands: - cd go-api - go build ./... - go test ./... - name: deploy image: alpine environment: SSH_KEY: from_secret: bbb_ssh_key commands: - apk add --no-cache openssh-client rsync - eval $(ssh-agent -s) - echo \u0026#34;$SSH_KEY\u0026#34; | ssh-add - - rsync -avz build-arm/ pi@beaglebone:/opt/bbb-hal/ - ssh pi@beaglebone \u0026#34;systemctl restart bbb-hal\u0026#34; when: branch: - main Fazit Podman als Drone-CI-Backend funktioniert gut — mit ein paar Anpassungen.\nWann Podman sich lohnt:\nKein Docker-Daemon soll dauerhaft laufen\nRootless-Betrieb ist eine Anforderung\nPrivater Server ohne komplexe Container-Orchestrierung\nWann Docker einfacher ist:\nGroße Teams mit bestehenden Docker-Workflows\nViele Images die Docker-Socket direkt nutzen\nWenn Kompatibilitätsprobleme mehr Zeit kosten als der Daemon-Betrieb\nFür mein privates Projekt ist Podman die richtige Wahl. Die Fallstricke waren lösbar, und das Ergebnis ist eine CI-Infrastruktur die ohne privilegierte Hintergrunddienste auskommt.\nNächster Post in der Serie: Cross-Kompilierung für ARMv7 mit CMake\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/drone-ci-podman/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post ist Teil der Serie über mein \u003ca href=\"/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/\"\u003eprivates BeagleBone-Black-Projekt\u003c/a\u003e.\nDie CI/CD-Infrastruktur des Projekts läuft auf Drone CI — aber nicht mit Docker,\nsondern mit Podman als Container-Backend.\nWas auf dem Papier einfach klingt, hat in der Praxis ein paar Ecken.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_warum_podman_statt_docker\"\u003eWarum Podman statt Docker?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDie kurze Antwort: rootless-Betrieb und kein Daemon.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDocker erfordert einen privilegierten Daemon der permanent läuft — \u003ccode\u003edockerd\u003c/code\u003e —\nund der Zugriff auf den Docker-Socket bedeutet de facto Root-Rechte auf dem Host.\nDas ist für viele Umgebungen ein akzeptables Tradeoff, für meinen privaten Server nicht.\u003c/p\u003e\n\u003c/div\u003e","title":"Drone CI mit Podman — Fallstricke und Lösungen"},{"content":" Dieser Post setzt den fünften Teil fort. Das Bausteinsicht-Modell ist die Quelle der Wahrheit — und aus ihr lassen sich viele verschiedene Ausgabeformate generieren. Dieser Post zeigt alle verfügbaren Export-Befehle.\nÜberblick: Die vier Export-Befehle Befehl Zweck bausteinsicht export\nPNG oder SVG via draw.io CLI (visuelles Ergebnis)\nbausteinsicht export-diagram\nText-Diagramme: PlantUML, Mermaid, DOT, D2, HTML5, Structurizr DSL\nbausteinsicht export-sequence\nSequenzdiagramme aus dynamicViews\nbausteinsicht export-table\nElement-Tabellen als AsciiDoc oder Markdown\nexport: PNG und SVG bausteinsicht export ruft die draw.io CLI headless auf und rendert jede View als Bilddatei.\n# Alle Views als PNG exportieren (Standardformat) bausteinsicht export --output docs/images/ # Nur eine bestimmte View exportieren bausteinsicht export --view containers --output docs/images/ # SVG statt PNG (besser für Print und Web) bausteinsicht export --image-format svg --output docs/images/ # Retina-Auflösung für Print (2x) bausteinsicht export --image-format png --scale 2.0 --output docs/images/ # Mit eingebettetem draw.io XML (zum Weiterbearbeiten) bausteinsicht export --embed-diagram --output docs/images/ Ausgabe:\nExported: docs/images/context.png Exported: docs/images/containers.png Exported: docs/images/api-components.png export erfordert die draw.io Desktop-Anwendung auf dem System. Bausteinsicht erkennt den Pfad automatisch. Auf CI-Systemen kann draw.io headless als Docker-Container betrieben werden. export-diagram: Text-basierte Diagramme bausteinsicht export-diagram generiert text-basierte Diagrammformate direkt aus dem JSONC-Modell — ohne draw.io.\nPlantUML bausteinsicht export-diagram --diagram-format plantuml --output docs/diagrams/ # → docs/diagrams/context.puml, containers.puml, ... # Einzelne View auf stdout bausteinsicht export-diagram --diagram-format plantuml --view context Beispielausgabe (C4-Context-Diagramm):\nMermaid bausteinsicht export-diagram --diagram-format mermaid --output docs/diagrams/ # → docs/diagrams/context.mmd, containers.mmd, ... Mermaid-Diagramme lassen sich direkt in GitHub-Markdown einbetten:\n```mermaid C4Context Person(customer, \u0026#34;Customer\u0026#34;) System(shop, \u0026#34;Online Shop\u0026#34;) Rel(customer, shop, \u0026#34;kauft ein\u0026#34;) ``` DOT (Graphviz) bausteinsicht export-diagram --diagram-format dot --output docs/diagrams/ # → docs/diagrams/architecture-context.dot # Direkt zu PNG via Graphviz bausteinsicht export-diagram --diagram-format dot --view context | dot -Tpng -o context.png D2 bausteinsicht export-diagram --diagram-format d2 --output docs/diagrams/ # → docs/diagrams/architecture-context.d2 HTML5-Viewer Der HTML-Export erzeugt eine interaktive Standalone-HTML-Seite:\nbausteinsicht export-diagram --diagram-format html --output docs/ # → docs/context.html, docs/containers.html, ... Die HTML-Seiten lassen sich ohne Server öffnen — ideal für Dokumentations-Reviews ohne Build-Pipeline.\nStructurizr DSL Der Structurizr-Export erzeugt eine vollständige workspace.dsl-Datei:\nbausteinsicht export-diagram --diagram-format structurizr --output docs/ # → docs/workspace.dsl --view ist beim Structurizr-Format nicht unterstützt — es exportiert immer den gesamten Workspace. JSON-Ausgabe für CI-Pipelines Alle export-diagram-Formate unterstützen --format json für strukturierte Ausgabe in CI-Pipelines:\nbausteinsicht export-diagram --diagram-format mermaid --format json Ausgabe:\n[ { \u0026#34;view\u0026#34;: \u0026#34;context\u0026#34;, \u0026#34;format\u0026#34;: \u0026#34;mermaid\u0026#34;, \u0026#34;source\u0026#34;: \u0026#34;C4Context\\n...\u0026#34; }, { \u0026#34;view\u0026#34;: \u0026#34;containers\u0026#34;, \u0026#34;format\u0026#34;: \u0026#34;mermaid\u0026#34;, \u0026#34;source\u0026#34;: \u0026#34;C4Container\\n...\u0026#34; } ] export-sequence: Sequenzdiagramme bausteinsicht export-sequence exportiert dynamicViews aus dem Modell als Sequenzdiagramme.\n# PlantUML (Standard) bausteinsicht export-sequence --output docs/diagrams/ # → docs/diagrams/sequence-checkout.puml # Mermaid bausteinsicht export-sequence --diagram-format mermaid --output docs/diagrams/ # → docs/diagrams/sequence-checkout.md # Einzelne Dynamic View bausteinsicht export-sequence --view checkout --diagram-format plantuml Für das Checkout-Beispiel aus Teil 3:\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_6.drawio\nexport-table: Element-Tabellen bausteinsicht export-table exportiert die Elemente einer View als strukturierte Tabelle — nützlich für Dokumentation und Compliance-Reviews.\n# AsciiDoc-Tabelle (Standard) für alle Views bausteinsicht export-table --output docs/ # Nur eine View bausteinsicht export-table --view containers --table-format adoc --output docs/ # Markdown-Tabelle bausteinsicht export-table --table-format md --output docs/ # Alle Elemente dedupliziert über alle Views bausteinsicht export-table --combined --output docs/ # → docs/elements.adoc Beispielausgabe (AsciiDoc):\n[cols=\u0026#34;1,1,1,2\u0026#34;, options=\u0026#34;header\u0026#34;] |=== | Element | Kind | Technology | Description | Web Frontend | container | React | | REST API | container | Go | | PostgreSQL | database | PostgreSQL | | Redis Cache | database | Redis | |=== Für --format json:\nbausteinsicht export-table --view containers --format json Ausgabe:\n[ { \u0026#34;element\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Frontend\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;React\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;\u0026#34; }, { \u0026#34;element\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;\u0026#34; } ] Import: Von Structurizr und LikeC4 Neben dem Export unterstützt Bausteinsicht auch den Import aus anderen Formaten:\n# Structurizr DSL importieren bausteinsicht import --from structurizr workspace.dsl --output architecture.jsonc # LikeC4 DSL importieren bausteinsicht import --from likec4 architecture.c4 --output architecture.jsonc # Vorschau ohne zu schreiben bausteinsicht import --from structurizr workspace.dsl --dry-run # Existierende Datei überschreiben bausteinsicht import --from likec4 architecture.c4 --force Das ist der Migrationspfad für bestehende Projekte: einmalig importieren, dann mit Bausteinsicht weiterarbeiten.\nWann welcher Export? Szenario Empfehlung Befehl Dokumentation in Confluence oder AsciiDoc\nPNG/SVG einbetten\nexport --image-format png\nGitHub-README oder PR-Beschreibung\nMermaid direkt einbetten\nexport-diagram --diagram-format mermaid\nTeam ohne draw.io möchte Diagramme reviewen\nHTML5-Viewer verteilen\nexport-diagram --diagram-format html\nMigration zu Structurizr oder LikeC4\nDSL exportieren\nexport-diagram --diagram-format structurizr\nArchitektur-Review mit Stakeholdern\nPDF via PlantUML oder PNG\nexport --scale 2.0\nCI-Pipeline, automatische Dokumentation\nJSON-Ausgabe verarbeiten\nexport-diagram --format json\nCompliance-Dokumentation\nAsciiDoc-Tabelle\nexport-table --combined\nBeispiel-Modell Das Basis-Modell für alle Export-Befehle in diesem Teil liegt unter teil_6.jsonc.\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 7: Snapshots \u0026amp; Changelog — Architektur über Zeit versionieren\nTeil 8: Validation \u0026amp; Linting — Architekturregeln mit bausteinsicht lint durchsetzen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-export-features/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-multi-view/\"\u003efünften Teil\u003c/a\u003e fort.\nDas Bausteinsicht-Modell ist die Quelle der Wahrheit — und aus ihr lassen sich viele verschiedene Ausgabeformate generieren.\nDieser Post zeigt alle verfügbaren Export-Befehle.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_überblick_die_vier_export_befehle\"\u003eÜberblick: Die vier Export-Befehle\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003ctable class=\"tableblock frame-all grid-all stretch\"\u003e\n\u003ccolgroup\u003e\n\u003ccol style=\"width: 40%;\"/\u003e\n\u003ccol style=\"width: 60%;\"/\u003e\n\u003c/colgroup\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eBefehl\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eZweck\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003ebausteinsicht export\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003ePNG oder SVG via draw.io CLI (visuelles Ergebnis)\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003ebausteinsicht export-diagram\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eText-Diagramme: PlantUML, Mermaid, DOT, D2, HTML5, Structurizr DSL\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003ebausteinsicht export-sequence\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eSequenzdiagramme aus \u003ccode\u003edynamicViews\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003ebausteinsicht export-table\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eElement-Tabellen als AsciiDoc oder Markdown\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Teil 6: Export-Features — Mermaid, Structurizr DSL, PNG und mehr"},{"content":" Dieser Post ist Teil der Serie über mein privates BeagleBone-Black-Projekt. Das Projekt nutzt StrictDoc für Anforderungsmanagement — kein Word-Dokument, kein Jira-Ticket, sondern Textdateien direkt im Repository. Was merkwürdig klingt, ist in der Praxis überraschend sinnvoll.\nWas ist StrictDoc? StrictDoc ist ein Open-Source-Tool für dokumentenbasiertes Anforderungsmanagement. Anforderungen werden in .sdoc-Textdateien geschrieben, die im selben Repository wie der Code leben — und damit auch im selben Git-Verlauf.\nWarum kein klassisches ALM-Tool?\nJira, Azure DevOps, Polarion — all diese Tools haben denselben Nachteil: die Anforderungen leben getrennt vom Code. Eine Anforderung wird geändert, der Code angepasst, aber niemand verknüpft beides explizit. Nach einem Jahr weiß niemand mehr ob die Implementierung noch zur Anforderung passt.\nStrictDoc zwingt zur Verknüpfung. Ein Code-Kommentar referenziert eine Anforderungs-ID, und StrictDoc kann prüfen ob jede Anforderung mindestens eine Implementierungs-Referenz hat.\nStrictDoc ist kein DOORS-Ersatz für sicherheitskritische Systeme mit regulativen Anforderungen. Für ein privates Projekt ist es genau richtig.\nDokumentenstruktur StrictDoc-Dokumente sind .sdoc-Textdateien mit einer einfachen Syntax.\nBasis-Struktur [DOCUMENT] TITLE: BeagleBone Black — GPIO Anforderungen [SECTION] TITLE: Funktionale Anforderungen [REQUIREMENT] UID: BBB-GPIO-001 STATUS: Active TITLE: GPIO Pin lesen STATEMENT: Das System MUSS den digitalen Zustand eines konfigurierten GPIO-Pins lesen können. [REQUIREMENT] UID: BBB-GPIO-002 STATUS: Active TITLE: GPIO Pin setzen STATEMENT: Das System MUSS einen konfigurierten GPIO-Pin auf HIGH oder LOW setzen können. RELATIONS: - TYPE: Refines VALUE: BBB-GPIO-001 Wichtige Felder:\nUID Eindeutige ID — wird im Code referenziert. Nie ändern nach dem ersten Commit.\nSTATUS Active, Draft, Obsolete\nSTATEMENT Die eigentliche Anforderung — mit SHALL/MUST/SHOULD wenn man EARS-Notation nutzt\nRELATIONS Verknüpfung zu anderen Anforderungen (Refines, Implements, Verifies)\nHierarchie: System bis Software Ich trenne Anforderungen in drei Ebenen:\ndocs/requirements/ system/ gpio.sdoc ← Systemanforderungen (was das System können muss) software/ hal-gpio.sdoc ← Software-Anforderungen (wie der HAL es umsetzt) api-gpio.sdoc ← API-Anforderungen (wie die REST API es exponiert) tests/ gpio-tests.sdoc ← Testfälle (wie verifiziert wird) Anforderungen schreiben — GPIO-Beispiel Systemebene (system/gpio.sdoc) [DOCUMENT] TITLE: System — GPIO [REQUIREMENT] UID: SYS-GPIO-001 TITLE: Digitaler Ausgang STATEMENT: Das System MUSS mindestens 4 unabhängige digitale Ausgänge bereitstellen. [REQUIREMENT] UID: SYS-GPIO-002 TITLE: Digitaler Eingang STATEMENT: Das System MUSS mindestens 4 unabhängige digitale Eingänge bereitstellen. Softwareebene (software/hal-gpio.sdoc) [DOCUMENT] TITLE: HAL — GPIO [REQUIREMENT] UID: SW-GPIO-001 TITLE: GPIO lesen über sysfs STATEMENT: Der HAL MUSS GPIO-Zustände über das Linux sysfs-Interface lesen. RELATIONS: - TYPE: Implements VALUE: SYS-GPIO-002 [REQUIREMENT] UID: SW-GPIO-002 TITLE: GPIO schreiben über sysfs STATEMENT: Der HAL MUSS GPIO-Zustände über das Linux sysfs-Interface schreiben. RELATIONS: - TYPE: Implements VALUE: SYS-GPIO-001 Traceability im Code Die Implementierungs-Referenz sitzt direkt im Quellcode als Kommentar.\nC-Treiber /** * gpio_read - Liest den Zustand eines GPIO-Pins via sysfs. * * @req SW-GPIO-001 */ int gpio_read(int pin, int *value) { char path[64]; snprintf(path, sizeof(path), \u0026#34;/sys/class/gpio/gpio%d/value\u0026#34;, pin); FILE *f = fopen(path, \u0026#34;r\u0026#34;); if (!f) return -ENODEV; fscanf(f, \u0026#34;%d\u0026#34;, value); fclose(f); return 0; } Rust HAL /// GPIO-Read via C-Treiber. /// @req SW-GPIO-001 pub fn gpio_read(pin: u32) -\u0026gt; Result\u0026lt;u8, HalError\u0026gt; { let mut value: i32 = 0; let ret = unsafe { c_gpio_read(pin as i32, \u0026amp;mut value) }; if ret \u0026lt; 0 { return Err(HalError::GPIOReadFailed(ret)); } Ok(value as u8) } Test // TestGPIORead verifiziert SW-GPIO-001 und SYS-GPIO-002. // @req SW-GPIO-001 // @req SYS-GPIO-002 func TestGPIORead(t *testing.T) { h := hal.NewMockHAL() h.SetGPIOValue(48, 1) val, err := h.GPIORead(48) assert.NoError(t, err) assert.Equal(t, 1, val) } Das @req-Tag ist eine Konvention, kein StrictDoc-Feature. StrictDoc selbst bietet Source-File-Tracing mit konfigurierbarem Pattern.\nStrictDoc HTML-Export # Installation pip install strictdoc # HTML-Export aller Anforderungsdokumente strictdoc export docs/requirements/ --output-dir out/requirements Der HTML-Export zeigt:\nAlle Anforderungen mit Status und Text\nTraceability-Matrix: welche Anforderung hat welche Implementierung\nLücken: Anforderungen ohne Code-Referenz (rot markiert)\nAbdeckungsgrad pro Dokument\nLückenanalyse StrictDoc hebt Anforderungen ohne Implementierungs-Referenz hervor. Das ist der eigentliche Mehrwert: nicht nur dokumentieren was implementiert ist, sondern sehen was noch fehlt.\nstrictdoc check docs/requirements/ # [ERROR] SW-GPIO-003: no implementation reference found CI-Integration In der Drone-Pipeline:\nsteps: - name: requirements-check image: python:3.11-slim commands: - pip install strictdoc --quiet - strictdoc export docs/requirements/ --output-dir out/requirements --formats=html - strictdoc check docs/requirements/ Ein fehlgeschlagener StrictDoc-Check blockiert den Merge — genau wie ein fehlgeschlagener Unit-Test.\nFazit Lohnt sich StrictDoc für ein privates Projekt?\nJa, wenn:\nman lernen will wie Anforderungsmanagement in der Praxis aussieht\nman sehen will wie Code und Anforderungen auseinanderlaufen (sie tun es immer)\nman ein Portfolio-Projekt zeigen will das über \u0026#34;ich habe Code geschrieben\u0026#34; hinausgeht\nNein, wenn:\nman schnell Ergebnisse will und Dokumentation als Overhead sieht\ndas Projekt nur wenige Wochen läuft\nFür mich ist es die richtige Wahl. Ich arbeite beruflich in einem Umfeld wo Traceability eine regulatorische Anforderung ist — das hier ist mein Übungsfeld um zu verstehen was das wirklich bedeutet, jenseits der Prozessdokumente.\nNächster Post in der Serie: Drone CI mit Podman\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/strictdoc-in-der-praxis/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post ist Teil der Serie über mein \u003ca href=\"/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/\"\u003eprivates BeagleBone-Black-Projekt\u003c/a\u003e.\nDas Projekt nutzt StrictDoc für Anforderungsmanagement — kein Word-Dokument,\nkein Jira-Ticket, sondern Textdateien direkt im Repository.\nWas merkwürdig klingt, ist in der Praxis überraschend sinnvoll.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_ist_strictdoc\"\u003eWas ist StrictDoc?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eStrictDoc ist ein Open-Source-Tool für dokumentenbasiertes Anforderungsmanagement.\nAnforderungen werden in \u003ccode\u003e.sdoc\u003c/code\u003e-Textdateien geschrieben,\ndie im selben Repository wie der Code leben — und damit auch im selben Git-Verlauf.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cstrong\u003eWarum kein klassisches ALM-Tool?\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eJira, Azure DevOps, Polarion — all diese Tools haben denselben Nachteil:\ndie Anforderungen leben getrennt vom Code.\nEine Anforderung wird geändert, der Code angepasst, aber niemand verknüpft beides explizit.\nNach einem Jahr weiß niemand mehr ob die Implementierung noch zur Anforderung passt.\u003c/p\u003e\n\u003c/div\u003e","title":"StrictDoc in der Praxis — Anforderungen die mit dem Code leben"},{"content":" Dieser Artikel ist in Vorbereitung. Kommt bald.\nTeil der Serie über mein privates BeagleBone-Black-Projekt.\n1. Ziel Dieses Tutorial beschreibt den Aufbau einer Yocto-Entwicklungsumgebung für den BeagleBone Black. Die komplette Build-Umgebung wird reproduzierbar in einem Ubuntu Docker Container erstellt.\nZiel:\nUbuntu Docker Build-Umgebung\nYocto Project Setup\nBeagleBone Black BSP Integration\nErstes Yocto Image bauen\nSD-Karte vorbereiten und booten\n2. Voraussetzungen Benötigt:\nLinux Host (empfohlen Ubuntu 22.04/24.04)\nDocker installiert\nmindestens 50 GB freier Speicher\nmindestens 8 GB RAM empfohlen\nBeagleBone Black\nSD-Karte\n3. Step 1: Ubuntu Docker Build Environment erstellen 3.1. Verzeichnis anlegen mkdir yocto-bbb cd yocto-bbb 3.2. Dockerfile erstellen Datei Dockerfile:\nFROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt update \u0026amp;\u0026amp; apt install -y \\ git \\ wget \\ curl \\ vim \\ nano \\ sudo \\ locales \\ build-essential \\ gcc \\ g++ \\ make \\ chrpath \\ cpio \\ diffstat \\ gawk \\ texinfo \\ unzip \\ socat \\ python3 \\ python3-pip \\ python3-pexpect \\ xz-utils \\ file \\ iputils-ping \\ rsync \\ zstd \\ lz4 \\ bzip2 \\ \u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/* RUN locale-gen en_US.UTF-8 ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en ENV LC_ALL=en_US.UTF-8 RUN useradd -ms /bin/bash yocto \u0026amp;\u0026amp; \\ echo \u0026#34;yocto ALL=(ALL) NOPASSWD:ALL\u0026#34; \u0026gt;\u0026gt; /etc/sudoers USER yocto WORKDIR /home/yocto CMD [\u0026#34;/bin/bash\u0026#34;] 3.3. Docker Image bauen docker build -t yocto-bbb . 3.4. Container starten Den aktuellen Ordner als Workspace mounten:\ndocker run -it \\ --name yocto-bbb-build \\ -v $(pwd):/home/yocto/workspace \\ yocto-bbb 4. Step 2: Yocto Quellen holen Im Container:\ncd ~/workspace git clone https://git.yoctoproject.org/poky cd poky git checkout kirkstone cd .. 5. Step 3: Zusätzliche Layers installieren git clone https://git.openembedded.org/meta-openembedded cd meta-openembedded git fetch --all git checkout kirkstone cd .. git clone https://github.com/beagleboard/meta-beagleboard.git 6. Step 4: Build Environment initialisieren cd ~/workspace/poky source oe-init-build-env build-bbb 7. Step 5: BeagleBone Black konfigurieren Datei conf/local.conf bearbeiten und folgenden Eintrag setzen:\nMACHINE = \u0026#34;beaglebone-yocto\u0026#34; 8. Step 6: Layers aktivieren bitbake-layers add-layer \\ ../meta-openembedded/meta-oe bitbake-layers add-layer \\ ../meta-openembedded/meta-python bitbake-layers add-layer \\ ../meta-openembedded/meta-networking bitbake-layers add-layer \\ ../meta-beagleboard 9. Step 7: Erstes Image bauen bitbake core-image-minimal 10. Step 8: Build Ergebnis Nach erfolgreichem Build befinden sich die Artefakte in:\ntmp/deploy/images/beaglebone-yocto/ Enthält:\nKernel (zImage)\nDevice Tree (*.dtb)\nU-Boot (u-boot.img, MLO)\nRoot Filesystem (core-image-minimal-beaglebone-yocto.tar.xz)\n11. Step 9: SD-Karte vorbereiten Partitionen:\nboot FAT32 rootfs ext4 Boot-Dateien kopieren:\ncp MLO /boot/ cp u-boot.img /boot/ cp *.dtb /boot/ cp zImage /boot/ RootFS installieren:\ntar xf core-image-minimal*.tar.xz -C /mnt/rootfs 12. Step 10: BeagleBone Black starten UART-Verbindung herstellen:\n115200 baud 8N1 Bootmeldungen beobachten und System testen.\n13. GitHub Actions Workflow Der Yocto-Build lässt sich auch automatisiert in GitHub Actions ausführen — der folgende Workflow startet einen ubuntu:22.04-Container direkt auf dem GHA-Runner, installiert alle Abhängigkeiten und baut core-image-minimal.\nEin sstate-cache- und downloads-Cache reduziert Folgebuilds von mehreren Stunden auf ca. 20–40 Minuten.\nStandard-GHA-Runner haben nur ~14 GB Disk — für einen vollständigen Yocto-Build wird ein self-hosted Runner mit ≥ 50 GB Disk und ≥ 8 GB RAM empfohlen.\nname: Yocto Build – BeagleBone Black on: workflow_dispatch: push: paths: - \u0026#39;.github/workflows/yocto-build.yml\u0026#39; jobs: build: runs-on: ubuntu-latest container: image: ubuntu:22.04 options: --user root env: DEBIAN_FRONTEND: noninteractive LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 steps: - name: Install Yocto dependencies run: | apt-get update \u0026amp;\u0026amp; apt-get install -y \\ git wget curl sudo locales \\ build-essential gcc g++ make \\ chrpath cpio diffstat gawk texinfo \\ unzip socat python3 python3-pip python3-pexpect \\ xz-utils file rsync zstd lz4 bzip2 \\ \u0026amp;\u0026amp; locale-gen en_US.UTF-8 \\ \u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/* - name: Create yocto user run: | useradd -ms /bin/bash yocto echo \u0026#34;yocto ALL=(ALL) NOPASSWD:ALL\u0026#34; \u0026gt;\u0026gt; /etc/sudoers - name: Restore sstate-cache and downloads uses: actions/cache@v4 with: path: | /home/yocto/downloads /home/yocto/sstate-cache key: yocto-kirkstone-bbb-${{ hashFiles(\u0026#39;.github/workflows/yocto-build.yml\u0026#39;) }} restore-keys: | yocto-kirkstone-bbb- - name: Clone poky (kirkstone) run: | su - yocto -c \u0026#34;git clone --depth=1 -b kirkstone https://git.yoctoproject.org/poky /home/yocto/poky\u0026#34; - name: Clone meta-openembedded (kirkstone) run: | su - yocto -c \u0026#34;git clone --depth=1 -b kirkstone https://git.openembedded.org/meta-openembedded /home/yocto/meta-openembedded\u0026#34; - name: Clone meta-beagleboard run: | su - yocto -c \u0026#34;git clone --depth=1 https://github.com/beagleboard/meta-beagleboard.git /home/yocto/meta-beagleboard\u0026#34; - name: Initialize build environment and configure run: | su - yocto -c \u0026#34; cd /home/yocto/poky source oe-init-build-env /home/yocto/build-bbb echo \u0026#39;MACHINE = \\\u0026#34;beaglebone-yocto\\\u0026#34;\u0026#39; \u0026gt;\u0026gt; conf/local.conf echo \u0026#39;DL_DIR = \\\u0026#34;/home/yocto/downloads\\\u0026#34;\u0026#39; \u0026gt;\u0026gt; conf/local.conf echo \u0026#39;SSTATE_DIR = \\\u0026#34;/home/yocto/sstate-cache\\\u0026#34;\u0026#39; \u0026gt;\u0026gt; conf/local.conf bitbake-layers add-layer /home/yocto/meta-openembedded/meta-oe bitbake-layers add-layer /home/yocto/meta-openembedded/meta-python bitbake-layers add-layer /home/yocto/meta-openembedded/meta-networking bitbake-layers add-layer /home/yocto/meta-beagleboard \u0026#34; - name: Build core-image-minimal run: | su - yocto -c \u0026#34; cd /home/yocto/poky source oe-init-build-env /home/yocto/build-bbb bitbake core-image-minimal \u0026#34; - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: beaglebone-yocto-image path: /home/yocto/build-bbb/tmp/deploy/images/beaglebone-yocto/ retention-days: 7 14. Weiterführende Themen Eigenes Yocto Layer erstellen\nEigene Recipes schreiben\nKernel-Änderungen und Device Tree Anpassungen\nsystemd Services integrieren\nEthernet konfigurieren\nPRU-Entwicklung\n","permalink":"https://paul-fleischmann.com/projekte/beaglebone/yocto-tutorial-fur-beaglebone-black/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"admonitionblock note\"\u003e\n\u003ctable\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd class=\"icon\"\u003e\n\u003ci class=\"fa icon-note\" title=\"📝 Hinweis\"\u003e\u003c/i\u003e\n\u003c/td\u003e\n\u003ctd class=\"content\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Artikel ist in Vorbereitung. Kommt bald.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cem\u003eTeil der Serie über mein \u003ca href=\"/projekte/beaglebone/beaglebone-black-projekt-einfuehrung/\"\u003eprivates BeagleBone-Black-Projekt\u003c/a\u003e.\u003c/em\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_ziel\"\u003e1. Ziel\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieses Tutorial beschreibt den Aufbau einer Yocto-Entwicklungsumgebung für den BeagleBone Black.\nDie komplette Build-Umgebung wird reproduzierbar in einem Ubuntu Docker Container erstellt.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eZiel:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eUbuntu Docker Build-Umgebung\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eYocto Project Setup\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eBeagleBone Black BSP Integration\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eErstes Yocto Image bauen\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSD-Karte vorbereiten und booten\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_voraussetzungen\"\u003e2. Voraussetzungen\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBenötigt:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eLinux Host (empfohlen Ubuntu 22.04/24.04)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDocker installiert\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003emindestens 50 GB freier Speicher\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003emindestens 8 GB RAM empfohlen\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eBeagleBone Black\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSD-Karte\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Yocto Tutorial für BeagleBone Black"},{"content":" Dieser Post setzt den sechsten Teil fort. Architecture-as-Code hat gegenüber manuellen Diagrammen einen entscheidenden Vorteil: die Architektur lebt im Git-Repository. Bausteinsicht nutzt das mit zwei Werkzeugen — snapshot und changelog.\nDas Problem: Architekturdrift ohne Nachvollziehbarkeit In agilen Projekten ändert sich die Architektur kontinuierlich. Nach sechs Monaten Entwicklung weiß oft niemand mehr: was wurde wann entschieden? Warum haben wir damals den Monolithen in Microservices aufgeteilt? Was ist zwischen Sprint 5 und Sprint 10 passiert?\nGit löst das für Code. bausteinsicht snapshot und changelog lösen es für Architektur.\nbausteinsicht snapshot Snapshots sind benannte Momentaufnahmen des Architekturmodells, gespeichert in .bausteinsicht-snapshots/. Sie sind unabhängig von Git-Commits — ein Snapshot kann zu jedem Zeitpunkt gespeichert werden.\nSnapshot speichern # Einfacher Snapshot ohne Nachricht bausteinsicht snapshot save # Snapshot mit beschreibender Nachricht bausteinsicht snapshot save --message \u0026#34;Sprint 5 Ende: Payment-Service extrahiert\u0026#34; Ausgabe:\nSnapshot saved: 20250611-143022 Timestamp: 2025-06-11T14:30:22Z Elements: 12 Relationships: 8 Message: Sprint 5 Ende: Payment-Service extrahiert Die ID ist ein Timestamp (YYYYMMDD-HHMMSS) — das erleichtert die zeitliche Zuordnung.\nSnapshots auflisten bausteinsicht snapshot list Ausgabe:\nID TIMESTAMP ELEMENTS RELATIONSHIPS MESSAGE 20250301-090000 2025-03-01 09:00:00 5 3 Projekt-Start: Monolith 20250415-140000 2025-04-15 14:00:00 8 6 Sprint 3: Auth-Service 20250611-143022 2025-06-11 14:30:22 12 8 Sprint 5: Payment-Service Als JSON für Scripting:\nbausteinsicht snapshot list --format json Snapshots vergleichen Das eigentliche Feature: zwei Snapshots (oder einen Snapshot mit dem aktuellen Modell) vergleichen.\n# Snapshot vs. aktuellen Zustand bausteinsicht snapshot diff 20250301-090000 # Zwei Snapshots vergleichen bausteinsicht snapshot diff 20250301-090000 20250611-143022 Ausgabe:\nArchitecture Differences (Total Changes: 9) ================================================== Added Elements (4): + authservice + authservice.tokenstore + paymentservice + paymentservice.ledger Removed Elements (1): - monolith Changed Elements (2): ~ shop.api technology: \u0026#34;Go (monolith)\u0026#34; → \u0026#34;Go\u0026#34; ~ shop.db description: \u0026#34;\u0026#34; → \u0026#34;Primäre Datenbank für Orders und Products\u0026#34; Added Relationships (3): + shop.frontend → authservice (authenticate) + shop.api → paymentservice (charge) + paymentservice → shop.db (audit log) Removed Relationships (1): - shop.frontend → monolith (uses) Als JSON für CI-Pipelines oder Weiterverarbeitung:\nbausteinsicht snapshot diff 20250301-090000 --format json Snapshot wiederherstellen Ein Snapshot kann als JSONC-Datei exportiert werden — zum Inspizieren oder als Ausgangspunkt für einen neuen Branch:\n# In eine neue Datei exportieren bausteinsicht snapshot restore 20250301-090000 architecture-v1.jsonc # Bestehende Datei überschreiben bausteinsicht snapshot restore 20250301-090000 architecture.jsonc --force restore überschreibt das aktuelle Modell. Vorher sicherstellen, dass der aktuelle Stand in Git committed ist oder als Snapshot gespeichert ist. Snapshot löschen bausteinsicht snapshot delete 20250301-090000 bausteinsicht changelog changelog erzeugt einen lesbaren Architektur-Changelog aus der Git-History — ohne dass vorab Snapshots angelegt wurden.\nDer Befehl liest das Modell an zwei verschiedenen Git-Refs (--since und --until) und berechnet den Unterschied.\nChangelog seit dem letzten Tag # Seit dem letzten Git-Tag bis HEAD bausteinsicht changelog # Explizite Referenzen bausteinsicht changelog --since v1.0.0 --until HEAD # Seit einem bestimmten Commit bausteinsicht changelog --since abc1234 --until HEAD # Nur den letzten Sprint (Branch-basiert) bausteinsicht changelog --since origin/main --until feature/sprint-6 Ausgabeformate # Markdown (Standard) — für GitHub PRs, README bausteinsicht changelog --format markdown # AsciiDoc — für technische Dokumentation bausteinsicht changelog --format asciidoc --output docs/architecture-changelog.adoc # JSON — für CI-Auswertung bausteinsicht changelog --format json Beispiel-Ausgabe (Markdown):\n## Architecture Changelog **From:** v1.0.0 (2025-03-01) **To:** HEAD (2025-06-11) ### Added Elements (4) - `authservice` — Auth Service - `authservice.tokenstore` — Token Store - `paymentservice` — Payment Service - `paymentservice.ledger` — Ledger ### Removed Elements (1) - `monolith` — Legacy Monolith ### Changed Elements (2) - `shop.api`: technology changed from \u0026#34;Go (monolith)\u0026#34; to \u0026#34;Go\u0026#34; - `shop.db`: description added ### Added Relationships (3) - `shop.frontend` → `authservice` (authenticate) - `shop.api` → `paymentservice` (charge) - `paymentservice` → `shop.db` (audit log) ### Removed Relationships (1) - `shop.frontend` → `monolith` (uses) As-Is / To-Be Vergleich Für geplante Migrationen bietet das Modell selbst einen Vergleichsmechanismus: die asIs- und toBe-Sektionen (→ Teil 3).\nbausteinsicht diff visualisiert den Unterschied zwischen aktuellem Zustand (asIs) und Zielarchitektur (toBe) als annotiertes Diagramm:\nbausteinsicht diff Im draw.io-Diagramm erscheinen:\nNeue Elemente (nur in toBe): grün markiert\nZu entfernende Elemente (nur in asIs): rot markiert\nUnveränderte Elemente: normal\nDas ist der Unterschied zu snapshot diff: snapshot diff vergleicht vergangene Zustände, diff visualisiert den geplanten Migrationspfad.\nPraktischer Workflow in agilen Projekten Zeitpunkt Aktion Sprint-Start\nbausteinsicht snapshot save --message \u0026#34;Sprint N Start\u0026#34;\nGrößere Architekturentscheidung\nModell ändern → commit → snapshot save --message \u0026#34;ADR-007: …​\u0026#34;\nSprint-Review\nbausteinsicht snapshot diff \u0026lt;sprint-start-id\u0026gt; als Review-Input\nRelease\nbausteinsicht changelog --since \u0026lt;letztes-release-tag\u0026gt; --format markdown → in Release Notes\nArchitektur-Review alle 3 Monate\nbausteinsicht changelog --since \u0026lt;quartal-start\u0026gt; → für Review-Meeting\nPR-Beschreibung\nbausteinsicht changelog --since origin/main --until HEAD --format markdown\nSnapshots und .bausteinsicht-sync gehören beide ins Git-Repository. So ist der vollständige Architekturverlauf in der Versionskontrolle — kein externes Werkzeug nötig. Beispiel-Modell Das Beispiel für diesen Teil (Sprint 5: Payment-Service extrahiert) liegt unter teil_7.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_7.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 8: Validation \u0026amp; Linting — Architekturregeln mit bausteinsicht lint automatisch durchsetzen\nTeil 9: Graph-Analyse — Zyklen und Abhängigkeiten aufdecken\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-snapshots-changelog/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-export-features/\"\u003esechsten Teil\u003c/a\u003e fort.\nArchitecture-as-Code hat gegenüber manuellen Diagrammen einen entscheidenden Vorteil: die Architektur lebt im Git-Repository.\nBausteinsicht nutzt das mit zwei Werkzeugen — \u003ccode\u003esnapshot\u003c/code\u003e und \u003ccode\u003echangelog\u003c/code\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_architekturdrift_ohne_nachvollziehbarkeit\"\u003eDas Problem: Architekturdrift ohne Nachvollziehbarkeit\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eIn agilen Projekten ändert sich die Architektur kontinuierlich.\nNach sechs Monaten Entwicklung weiß oft niemand mehr: was wurde wann entschieden?\nWarum haben wir damals den Monolithen in Microservices aufgeteilt?\nWas ist zwischen Sprint 5 und Sprint 10 passiert?\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 7: Snapshots \u0026 Changelog — Architektur über Zeit versionieren"},{"content":" Dieser Post setzt den siebten Teil fort. Architekturprinzipien schreiben sich leicht in ADRs. Schwieriger ist es, sicherzustellen dass der Code — und die Architektur — diese Prinzipien über Monate und Teams hinweg tatsächlich einhält. Bausteinsicht löst das mit maschinenprüfbaren Constraints.\nWas ist Architektur-Linting? Linting kennt man aus der Entwicklung: ESLint prüft JavaScript-Code auf Stilregeln und Fehler, go vet prüft Go-Code auf Antipatterns. Architektur-Linting macht dasselbe für das Architekturmodell:\nKeine direkte Datenbankverbindung aus der UI-Schicht\nAlle Systeme brauchen eine Beschreibung\nMaximale Verschachtelungstiefe von 3 Ebenen\nKeine zirkulären Abhängigkeiten\nNur freigegebene Technologien\nDiese Regeln sind im Modell als constraints definiert und werden mit bausteinsicht lint geprüft.\nConstraints im Modell definieren Constraints gehören in den constraints-Array in architecture.jsonc (→ Teil 3).\nJeder Constraint braucht id, description und rule — plus regelspezifische Felder.\nno-relationship Verhindert direkte Verbindungen zwischen bestimmten Element-Typen:\n\u0026#34;constraints\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;NO-UI-DB\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;UI-Komponenten dürfen nicht direkt auf die Datenbank zugreifen\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;no-relationship\u0026#34;, \u0026#34;from-kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;to-kind\u0026#34;: \u0026#34;database\u0026#34; } ] allowed-relationship Definiert positiv, welche Element-Typen sich mit einem bestimmten Typ verbinden dürfen:\n{ \u0026#34;id\u0026#34;: \u0026#34;DB-ACCESS-ONLY-SERVICES\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur Services und Repositories dürfen auf Datenbanken zugreifen\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;allowed-relationship\u0026#34;, \u0026#34;to-kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;from-kinds\u0026#34;: [\u0026#34;service\u0026#34;, \u0026#34;repository\u0026#34;] } required-field Erzwingt dass ein Feld bei allen Elementen eines bestimmten Typs gesetzt ist:\n{ \u0026#34;id\u0026#34;: \u0026#34;SYSTEM-NEEDS-DESCRIPTION\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Systeme müssen eine Beschreibung haben\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;required-field\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;field\u0026#34;: \u0026#34;description\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;CONTAINER-NEEDS-TECHNOLOGY\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Container müssen eine Technologie angeben\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;required-field\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;field\u0026#34;: \u0026#34;technology\u0026#34; } Unterstützte Felder: description, technology, title.\nmax-depth Begrenzt die Verschachtelungstiefe des Modells:\n{ \u0026#34;id\u0026#34;: \u0026#34;MAX-NESTING-3\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Maximale Verschachtelungstiefe ist 3 (System → Container → Component)\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;max-depth\u0026#34;, \u0026#34;max\u0026#34;: 3 } no-circular-dependency Erkennt Zyklen im Abhängigkeitsgraphen mittels Tiefensuche:\n{ \u0026#34;id\u0026#34;: \u0026#34;NO-CYCLES\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Keine zirkulären Abhängigkeiten zwischen Elementen\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;no-circular-dependency\u0026#34; } technology-allowed Erzwingt einen genehmigten Technologie-Stack:\n{ \u0026#34;id\u0026#34;: \u0026#34;APPROVED-BACKEND-STACK\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Backend-Container dürfen nur genehmigte Technologien verwenden\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;technology-allowed\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;technologies\u0026#34;: [\u0026#34;Go\u0026#34;, \u0026#34;Rust\u0026#34;, \u0026#34;Python\u0026#34;, \u0026#34;PostgreSQL\u0026#34;, \u0026#34;Redis\u0026#34;] } bausteinsicht lint bausteinsicht lint Ausgabe bei Verstößen:\nVIOLATION [NO-UI-DB]: UI-Komponenten dürfen nicht direkt auf die Datenbank zugreifen: component kind must not relate to database kind - shop.frontend → shop.db VIOLATION [CONTAINER-NEEDS-TECHNOLOGY]: Alle Container müssen eine Technologie angeben: all container elements must have \u0026#34;technology\u0026#34; set - shop.legacy: missing technology lint: 2 violation(s) found Ausgabe wenn alle Regeln bestanden:\nAll constraints passed. Exit-Code: 0 bei Erfolg, 1 bei Verstößen — damit direkt in CI verwendbar.\nJSON-Ausgabe für CI-Auswertung bausteinsicht lint --format json { \u0026#34;passed\u0026#34;: false, \u0026#34;total\u0026#34;: 2, \u0026#34;violations\u0026#34;: [ { \u0026#34;constraintId\u0026#34;: \u0026#34;NO-UI-DB\u0026#34;, \u0026#34;message\u0026#34;: \u0026#34;...\u0026#34;, \u0026#34;elements\u0026#34;: [\u0026#34;shop.frontend → shop.db\u0026#34;] } ] } bausteinsicht validate validate ist leichtgewichtiger als lint — es prüft nur die strukturelle Korrektheit des Modells (Schema, Referenzen):\nbausteinsicht validate Prüft:\nAlle kind-Werte in model sind in specification.elements definiert\nAlle kind-Werte in relationships sind in specification.relationships definiert\nAlle decisions-Referenzen in Elementen existieren in specification.decisions\nAlle tags in Elementen sind in specification.tags definiert\ncontainer: true für Elemente mit children\nvalidate läuft implizit vor jedem sync — ein invalid Model wird nicht synchronisiert.\nbausteinsicht health health bewertet die Architekturqualität über mehrere Dimensionen hinweg und gibt einen Score von 0–100 (Note A–F):\nbausteinsicht health Ausgabe:\nArchitecture Health Report ========================== Overall Score: 74.5/100 [B] Summary: Good architecture documentation with some gaps Timestamp: 2025-06-11T14:30:22Z Model Statistics ---------------- Elements: 15 Relationships: 11 Views: 3 Category Scores --------------- Completeness: 85.0/100 (weight: 40%) Details: 13/15 elements have descriptions Conformance: 90.0/100 (weight: 30%) Details: All constraints passed Complexity: 60.0/100 (weight: 30%) Details: High relationship density detected Findings -------- Completeness (2 findings): [WARN] Missing descriptions shop.legacy, shop.legacy.api: description is empty Complexity (1 finding): [INFO] High coupling shop.api has 7 outgoing relationships — consider splitting Kurzansicht für CI-Dashboards:\nbausteinsicht health --summary # → Overall Score: 74.5/100 [B] # Als JSON bausteinsicht health --format json --summary # Report in Datei schreiben bausteinsicht health --output docs/health-report.txt CI/CD Integration lint und validate sind direkt für CI gemacht. Beispiel GitHub Actions:\n- name: Validate architecture model run: bausteinsicht validate - name: Lint architecture constraints run: bausteinsicht lint - name: Architecture health check (informational) run: bausteinsicht health --summary continue-on-error: true # health bricht nicht den Build, informiert nur lint gibt Exit-Code 1 bei Verstößen zurück — der CI-Build schlägt fehl. Das ist bewusst so: Architekturregeln sollen genauso verbindlich sein wie Coding-Guidelines. Vollständiges Constraint-Set für eine Schichtenarchitektur \u0026#34;constraints\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;NO-CYCLES\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Keine zirkulären Abhängigkeiten\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;no-circular-dependency\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;NO-UI-TO-DB\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;UI greift nicht direkt auf DB zu\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;no-relationship\u0026#34;, \u0026#34;from-kind\u0026#34;: \u0026#34;frontend\u0026#34;, \u0026#34;to-kind\u0026#34;: \u0026#34;database\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;DB-ONLY-FROM-BACKEND\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur Backend-Services greifen auf DB zu\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;allowed-relationship\u0026#34;, \u0026#34;to-kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;from-kinds\u0026#34;: [\u0026#34;service\u0026#34;, \u0026#34;repository\u0026#34;] }, { \u0026#34;id\u0026#34;: \u0026#34;MAX-DEPTH\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Maximale Tiefe: System → Container → Component\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;max-depth\u0026#34;, \u0026#34;max\u0026#34;: 3 }, { \u0026#34;id\u0026#34;: \u0026#34;SYSTEM-DOCUMENTED\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Systeme brauchen eine Beschreibung\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;required-field\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;field\u0026#34;: \u0026#34;description\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;CONTAINER-TECH\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Container deklarieren ihre Technologie\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;required-field\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;field\u0026#34;: \u0026#34;technology\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;APPROVED-STACK\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur freigegebene Technologien\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;technology-allowed\u0026#34;, \u0026#34;element-kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;technologies\u0026#34;: [\u0026#34;Go\u0026#34;, \u0026#34;TypeScript\u0026#34;, \u0026#34;React\u0026#34;, \u0026#34;PostgreSQL\u0026#34;, \u0026#34;Redis\u0026#34;, \u0026#34;Kafka\u0026#34;] } ] Beispiel-Modell Das Beispiel für diesen Teil mit Schichtenarchitektur und Constraints liegt unter teil_8.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_8.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 9: Graph-Analyse — Zyklen und Abhängigkeiten mit bausteinsicht graph aufdecken\nTeil 10: Overlay \u0026amp; Heatmap — Metriken auf Architekturdiagramme legen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-validation-linting/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-snapshots-changelog/\"\u003esiebten Teil\u003c/a\u003e fort.\nArchitekturprinzipien schreiben sich leicht in ADRs.\nSchwieriger ist es, sicherzustellen dass der Code — und die Architektur — diese Prinzipien über Monate und Teams hinweg tatsächlich einhält.\nBausteinsicht löst das mit maschinenprüfbaren Constraints.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_ist_architektur_linting\"\u003eWas ist Architektur-Linting?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eLinting kennt man aus der Entwicklung: ESLint prüft JavaScript-Code auf Stilregeln und Fehler, \u003ccode\u003ego vet\u003c/code\u003e prüft Go-Code auf Antipatterns.\nArchitektur-Linting macht dasselbe für das Architekturmodell:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eKeine direkte Datenbankverbindung aus der UI-Schicht\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAlle Systeme brauchen eine Beschreibung\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMaximale Verschachtelungstiefe von 3 Ebenen\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eKeine zirkulären Abhängigkeiten\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eNur freigegebene Technologien\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Teil 8: Validation \u0026 Linting — Architekturregeln automatisch durchsetzen"},{"content":" Dieser Post setzt den achten Teil fort. bausteinsicht validate und bausteinsicht lint prüfen das Modell auf der Kommandozeile. Noch besser: Fehler direkt im Editor sehen — beim Tippen, ohne den Terminal zu verlassen. Das ermöglicht das Language Server Protocol.\nWas ist LSP? Das Language Server Protocol (LSP) ist ein offener Standard von Microsoft. Ein Language Server läuft im Hintergrund und analysiert Quellcode (oder Konfigurationsdateien) — der Editor fragt ihn ab und zeigt die Ergebnisse an:\nRote Unterstreichungen bei Fehlern\nAutovervollständigung für bekannte Werte\nHover-Informationen\nCodeLens (kleine Infos über Zeilen)\nWeil LSP ein Standard ist, funktioniert bausteinsicht-lsp mit jedem LSP-fähigen Editor: VS Code, Neovim, Emacs, Zed, IntelliJ.\nbausteinsicht-lsp installieren bausteinsicht-lsp ist ein separates Binary — es läuft als Hintergrundprozess, den der Editor startet:\n# Via Go Install go install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht-lsp@latest # Via Release-Binary (Linux amd64) curl -Lo bausteinsicht-lsp \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht-lsp_linux_amd64 chmod +x bausteinsicht-lsp \u0026amp;\u0026amp; sudo mv bausteinsicht-lsp /usr/local/bin/ VS Code Einrichtung Option A: VS Code Extension (empfohlen) Die offizielle Bausteinsicht VS Code Extension installiert und konfiguriert den LSP automatisch:\nExtensions-Panel öffnen (Ctrl+Shift+X)\nNach „Bausteinsicht\u0026#34; suchen\nExtension installieren\nDie Extension aktiviert sich automatisch sobald eine *.jsonc-Datei geöffnet wird, die architecture im Dateinamen enthält.\nOption B: Manuelle Konfiguration Für andere Editoren oder manuelle Kontrolle: bausteinsicht-lsp über die LSP-Konfiguration des Editors registrieren.\nVS Code settings.json:\n{ \u0026#34;languageServerExample.maxNumberOfProblems\u0026#34;: 100, \u0026#34;[jsonc]\u0026#34;: { \u0026#34;editor.defaultFormatter\u0026#34;: \u0026#34;esbenp.prettier-vscode\u0026#34; } } Oder via vscode-languageclient in einer Extension:\n{ \u0026#34;command\u0026#34;: \u0026#34;bausteinsicht-lsp\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;--stdio\u0026#34;], \u0026#34;filenamePattern\u0026#34;: \u0026#34;*architecture*.jsonc\u0026#34; } Was der LSP bietet Inline-Validierung Der LSP ruft bausteinsicht validate --format json im Hintergrund auf und zeigt Fehler direkt als rote Unterstreichung im Editor:\n\u0026#34;frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;children\u0026#34;: { ... } ← ⚠ Error: kind \u0026#39;container\u0026#39; has container:false in specification } Fehlermeldungen erscheinen beim Hover über der markierten Stelle — ohne Terminal öffnen.\nSeverity-Stufen: * Error (rot): Strukturfehler, die validate blockieren * Warning (gelb): Warnungen aus lint (Constraint-Verstöße) * Info (blau): Hinweise (z.B. Element nicht in einer View sichtbar) * Hint (grau): Stil-Empfehlungen\nCodeLens: Inline-Metadaten Über jeder Element-Definition zeigt der LSP eine CodeLens-Zeile mit Metadaten:\n\u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34; } Die CodeLens zeigt: * Element-Typ (kind) * Lifecycle-Status (status, wenn gesetzt) * Anzahl der Views, in denen das Element erscheint\nEin Klick auf die CodeLens öffnet das draw.io-Diagramm an der entsprechenden Stelle.\nValidierung beim Speichern Jedes Mal wenn architecture.jsonc gespeichert wird, laufen validate und lint automatisch im Hintergrund. Verstöße erscheinen sofort im Problems-Panel von VS Code — kein manuelles bausteinsicht lint nötig.\nJSON Schema: Die schlanke Alternative Ohne LSP-Setup funktioniert Autovervollständigung auch über JSON Schema. VS Code unterstützt das nativ.\nDen $schema-Eintrag in architecture.jsonc setzen (→ Teil 3):\n{ \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34;, ... } Das gibt sofort:\nAutovervollständigung für alle bekannten Felder (kind, title, technology, etc.)\nTyp-Validierung (z.B. container muss ein Boolean sein)\nHover-Dokumentation für alle Felder\nJSON Schema prüft nur die Struktur, nicht die inhaltliche Konsistenz (z.B. ob ein kind-Wert in specification.elements definiert ist). Dafür ist der LSP zuständig. Lokales Schema (ohne Internetverbindung) # Schema herunterladen curl -Lo schemas/bausteinsicht.schema.json \\ https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json # In architecture.jsonc referenzieren # \u0026#34;$schema\u0026#34;: \u0026#34;./schemas/bausteinsicht.schema.json\u0026#34; LSP vs. JSON Schema: Wann was? Feature JSON Schema bausteinsicht-lsp Felddokumentation beim Hover\n✅\n✅\nAutovervollständigung (bekannte Felder)\n✅\n✅\nTyp-Validierung\n✅\n✅\nConstraint-Prüfung (lint)\n✗\n✅\nModell-Konsistenz (validate)\n✗\n✅\nCodeLens (kind/status/views)\n✗\n✅\nSetup-Aufwand\nMinimal (1 Zeile)\nGering (Binary installieren)\nFunktioniert offline\n✗ (Remote-URL) / ✅ (lokal)\n✅\nFür die meisten Projekte reicht JSON Schema. bausteinsicht-lsp lohnt sich wenn man regelmäßig mit dem Modell arbeitet und Constraint-Feedback sofort im Editor haben möchte.\nBeispiel-Modell Das Beispiel für diesen Teil (Elemente mit status-Feld für LSP-CodeLens) liegt unter teil_9.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_9.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 10: Graph-Analyse — Zyklen und Abhängigkeiten aufdecken\nTeil 11: ADR-Integration — Architecture Decision Records mit dem Modell verknüpfen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-lsp-integration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-validation-linting/\"\u003eachten Teil\u003c/a\u003e fort.\n\u003ccode\u003ebausteinsicht validate\u003c/code\u003e und \u003ccode\u003ebausteinsicht lint\u003c/code\u003e prüfen das Modell auf der Kommandozeile.\nNoch besser: Fehler direkt im Editor sehen — beim Tippen, ohne den Terminal zu verlassen.\nDas ermöglicht das Language Server Protocol.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_ist_lsp\"\u003eWas ist LSP?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas Language Server Protocol (LSP) ist ein offener Standard von Microsoft.\nEin \u003cstrong\u003eLanguage Server\u003c/strong\u003e läuft im Hintergrund und analysiert Quellcode (oder Konfigurationsdateien) — der Editor fragt ihn ab und zeigt die Ergebnisse an:\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 9: LSP-Integration — Autovervollständigung im Editor"},{"content":" Dieser Post setzt den neunten Teil fort. Die bisherigen Teile haben gezeigt wie Bausteinsicht das Architekturmodell für Menschen lesbar macht — im Editor, in Diagrammen, in Reports. Dieser Teil dreht das um: wie macht man das Modell für Maschinen lesbar, damit LLM-Assistenten wie Claude Code damit arbeiten können?\nDas Problem: LLMs kennen deine Architektur nicht Claude Code, GitHub Copilot und andere KI-Assistenten wissen nichts über das konkrete System, an dem du arbeitest. Sie müssen erraten: welche Services existieren, wie sie miteinander kommunizieren, welche Technologien erlaubt sind.\nBausteinsicht löst das: das Architekturmodell ist eine maschinenlesbare Quelle der Wahrheit. Mit --format json liefern alle Befehle strukturierte Ausgabe — genau das, was ein LLM als Kontext braucht.\n--format json: Maschinenlesbare Ausgabe Fast alle Bausteinsicht-Befehle unterstützen --format json:\nbausteinsicht export --format json # vollständiges Modell als JSON bausteinsicht lint --format json # Constraint-Verstöße strukturiert bausteinsicht validate --format json # Validierungsfehler strukturiert bausteinsicht health --format json # Health-Score mit Details bausteinsicht find auth --format json # Suchergebnisse strukturiert bausteinsicht status --format json # Lifecycle-Status aller Elemente bausteinsicht snapshot list --format json # Snapshot-Liste strukturiert bausteinsicht snapshot diff \u0026lt;id\u0026gt; --format json # Diff strukturiert bausteinsicht changelog --format json # Changelog strukturiert Der Unterschied zur Textausgabe: JSON ist deterministisch, enthält keine Leerzeichen-Formatierung und lässt sich zuverlässig parsen — von Skripten und von LLMs.\nbausteinsicht find: Das Modell abfragen find durchsucht alle Elemente, Beziehungen und Views nach einem Begriff. Die Suche ist case-insensitiv, partiell (pay\u0026#39;\u0026#39; trifft payment-service\u0026#39;\u0026#39;) und verwendet AND-Semantik bei mehreren Wörtern.\n# Alle Elemente zum Thema \u0026#34;auth\u0026#34; bausteinsicht find auth # Nur Elemente (keine Relationships oder Views) bausteinsicht find auth --type element # Mehrere Suchbegriffe (AND) bausteinsicht find payment service # JSON-Ausgabe für LLM-Kontext bausteinsicht find auth --format json JSON-Ausgabe:\n{ \u0026#34;query\u0026#34;: \u0026#34;auth\u0026#34;, \u0026#34;total\u0026#34;: 3, \u0026#34;results\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;element\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;, \u0026#34;score\u0026#34;: 95 }, { \u0026#34;type\u0026#34;: \u0026#34;element\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;authservice.tokenstore\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Token Store\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Redis\u0026#34;, \u0026#34;score\u0026#34;: 72 }, { \u0026#34;type\u0026#34;: \u0026#34;relationship\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;shop.frontend→authservice\u0026#34;, \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;authenticate\u0026#34;, \u0026#34;score\u0026#34;: 60 } ] } Ergebnisse sind nach Relevanz-Score sortiert — der LLM erhält automatisch die relevantesten Treffer zuerst.\nbausteinsicht status: Lifecycle-Übersicht status listet alle Elemente mit ihrem Lifecycle-Status (→ Teil 3).\n# Alle Elemente mit Status bausteinsicht status # Nur Elemente in einem bestimmten Status bausteinsicht status --filter proposed # Als JSON bausteinsicht status --format json JSON-Ausgabe:\n{ \u0026#34;summary\u0026#34;: { \u0026#34;proposed\u0026#34;: 2, \u0026#34;design\u0026#34;: 1, \u0026#34;implementation\u0026#34;: 3, \u0026#34;deployed\u0026#34;: 8, \u0026#34;deprecated\u0026#34;: 1, \u0026#34;archived\u0026#34;: 0, \u0026#34;unset\u0026#34;: 2 }, \u0026#34;elements\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;paymentservice.v2\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Service v2\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;proposed\u0026#34; } ] } Das Summary gibt einem LLM sofort einen Überblick: 2 Elemente sind proposed, 8 sind deployed — ohne das gesamte Modell zu laden.\nClaude Code als Architektur-Assistent Mit diesen Werkzeugen lässt sich Claude Code direkt in den Architektur-Workflow einbinden.\nModell als Kontext bereitstellen Die einfachste Integration: relevanten Modell-Ausschnitt vor einer Frage in den Kontext geben.\n# Im Terminal — dann Claude Code starten bausteinsicht export --format json \u0026gt; /tmp/architecture.json # In Claude Code: Datei lesen und Frage stellen # \u0026#34;Lies /tmp/architecture.json und erkläre mir die Abhängigkeiten des payment-service\u0026#34; Oder direkter mit find:\nbausteinsicht find payment --format json | \\ claude -p \u0026#34;Welche Elemente sind mit dem Payment-Service verknüpft und \\ gibt es offensichtliche Probleme in dieser Abhängigkeitsstruktur?\u0026#34; Architekturmodell via CLAUDE.md einbinden In CLAUDE.md (oder .claude/CLAUDE.md) lässt sich ein permanenter Architekturkontext definieren:\n## Architekturmodell Das aktuelle Architekturmodell abfragen: - `bausteinsicht export --format json` — vollständiges Modell - `bausteinsicht find \u0026lt;begriff\u0026gt; --format json` — gezielter Kontext - `bausteinsicht status --format json` — welche Elemente gerade in Entwicklung sind Vor Entscheidungen mit Architektur-Einfluss: erst `bausteinsicht find` nutzen, um bestehende Elemente und deren Beziehungen zu prüfen. Claude Code liest diese Instruktionen automatisch — ab jetzt kennt der Assistent die Befehle und kann sie selbst ausführen.\nWorkflow: Neues Element hinzufügen mit KI-Unterstützung Ein realistisches Beispiel: ein neues Element soll ins Modell aufgenommen werden.\n# 1. Bestehende ähnliche Elemente finden bausteinsicht find notification --format json # 2. Aktuell in Entwicklung? bausteinsicht status --filter implementation --format json # 3. Constraints prüfen bevor man hinzufügt bausteinsicht lint --format json Claude Code kann diese Befehle in Folge ausführen und dann einen konsistenten JSONC-Eintrag vorschlagen — mit dem richtigen kind, passender technology, und ohne Constraint-Verstöße einzuführen.\nWorkflow: Architecture Review vor dem PR In .github/PULL_REQUEST_TEMPLATE.md oder als CLAUDE.md-Anweisung:\n# Diff zur Zielbranch bausteinsicht changelog --since origin/main --until HEAD --format json # Neue Constraint-Verstöße? bausteinsicht lint --format json # Health-Änderung? bausteinsicht health --format json Claude Code kann diesen Review automatisch in die PR-Beschreibung einbauen.\nGrenzen und Risiken LLMs halluzinieren Elemente Ein LLM kann plausibel klingende Element-IDs, Technologie-Werte oder Beziehungen erfinden, die nicht im Modell existieren.\nImmer bausteinsicht validate nach KI-generierten Änderungen am Modell laufen lassen. Validate prüft Referenzen — halluzinierte IDs werden erkannt. JSON-Kontext hat Grenzen Große Modelle (export --format json) können den Kontext-Window eines LLMs übersteigen. find und status sind genau dafür da: zielgerichtete Teilausschnitte statt dem Gesamtmodell.\nFaustregel: LLMs als präzise Suchanfragen formulieren → find → Ergebnis als Kontext, nicht das komplette Modell dumpen.\nModell als Single Source of Truth — nicht der LLM Der LLM kann Vorschläge machen, aber das Modell in architecture.jsonc ist die Wahrheit. bausteinsicht sync ist der Kanal zwischen Modell und draw.io — nicht der LLM.\nDer LLM unterstützt den Architekten, er ersetzt ihn nicht.\nVeralteter Kontext Ein LLM-Assistent, dem die JSON-Ausgabe von vor drei Sprints als Kontext übergeben wurde, arbeitet mit einer veralteten Architektur. Immer bausteinsicht export oder find im selben Terminal-Session ausführen, nicht gecachte Snapshots verwenden.\nPraktische Abkürzungen Für häufige Abfragen lohnen sich Shell-Aliase:\n# ~/.bashrc oder ~/.zshrc # Schneller Architektur-Kontext für Claude alias arch-ctx=\u0026#39;bausteinsicht export --format json\u0026#39; alias arch-find=\u0026#39;bausteinsicht find --format json\u0026#39; alias arch-status=\u0026#39;bausteinsicht status --format json\u0026#39; # Review-Paket für PR alias arch-review=\u0026#39;bausteinsicht changelog --since origin/main --format json \u0026amp;\u0026amp; bausteinsicht lint --format json\u0026#39; Beispiel-Modell Das Beispiel für diesen Teil (Modell mit mehreren abfragbaren Elementen für bausteinsicht find) liegt unter teil_10.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_10.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 11: ADR-Integration — Architecture Decision Records direkt im Modell verknüpfen\nTeil 12: Overlay \u0026amp; Heatmap — Metriken auf Architekturdiagramme projizieren\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-llm-ai-workflows/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-lsp-integration/\"\u003eneunten Teil\u003c/a\u003e fort.\nDie bisherigen Teile haben gezeigt wie Bausteinsicht das Architekturmodell für Menschen lesbar macht — im Editor, in Diagrammen, in Reports.\nDieser Teil dreht das um: wie macht man das Modell für Maschinen lesbar, damit LLM-Assistenten wie Claude Code damit arbeiten können?\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_llms_kennen_deine_architektur_nicht\"\u003eDas Problem: LLMs kennen deine Architektur nicht\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eClaude Code, GitHub Copilot und andere KI-Assistenten wissen nichts über das konkrete System, an dem du arbeitest.\nSie müssen erraten: welche Services existieren, wie sie miteinander kommunizieren, welche Technologien erlaubt sind.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 10: LLM/AI Workflows — KI-gestützte Architekturmodellierung"},{"content":" Dieser Post setzt den zehnten Teil fort. Architekturentscheidungen landen oft in Markdown-Dateien irgendwo im Repository — und niemand weiß mehr, warum das Modell so aussieht wie es aussieht. Bausteinsicht löst das: ADRs lassen sich direkt mit Elementen und Beziehungen im Modell verknüpfen.\nWas sind ADRs? Architecture Decision Records (ADRs) dokumentieren eine Architekturentscheidung mit Kontext, Optionen und Begründung. Das Format ist bewusst leichtgewichtig — typischerweise eine kurze Markdown-Datei pro Entscheidung.\nDas Problem: ohne direkte Verlinkung sind ADRs vom Modell isoliert. Man sieht im Diagramm dass ein Element existiert, aber nicht warum es so gestaltet wurde.\nADRs in der Specification definieren ADRs gehören in specification.decisions in architecture.jsonc:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;decisions\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;ADR-001\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Monolith → Microservices Migration\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;active\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-03-15\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-001-microservices.md\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;ADR-002\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;PostgreSQL als primäre Datenbank\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;active\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-03-20\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-002-postgresql.md\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;ADR-003\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth via JWT statt Sessions\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;active\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-04-01\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-003-jwt-auth.md\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;ADR-004\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API Gateway Pattern\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;superseded\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-02-10\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-004-api-gateway.md\u0026#34; } ] } } Mögliche Status-Werte:\nStatus Bedeutung proposed\nEntscheidung vorgeschlagen, noch nicht final\nactive\nAktuelle, gültige Entscheidung\ndeprecated\nVeraltet, aber noch nicht abgelöst\nsuperseded\nDurch eine neuere ADR ersetzt\nDas file-Feld zeigt auf die eigentliche ADR-Datei im Repository. Bausteinsicht öffnet sie nicht automatisch — es ist ein Zeiger für Entwickler und Werkzeuge.\nADRs an Elemente verknüpfen Jedes Element kann ein decisions-Array mit ADR-IDs enthalten:\n{ \u0026#34;model\u0026#34;: { \u0026#34;authservice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;, \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-003\u0026#34;] }, \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop System\u0026#34;, \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-001\u0026#34;], \u0026#34;children\u0026#34;: { \u0026#34;db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop DB\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34;, \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-002\u0026#34;] } } } } } ADRs an Beziehungen verknüpfen Auch Beziehungen können ADRs referenzieren — etwa wenn eine Entscheidung die Kommunikationsarchitektur betrifft:\n{ \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;authenticate\u0026#34;, \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-003\u0026#34;] } ] } bausteinsicht adr list Alle ADRs im Modell anzeigen:\nbausteinsicht adr list Ausgabe:\nDecisions (4): ────────────────────────────────────────── ADR-001 ✓ Monolith → Microservices Migration Date: 2025-03-15 File: docs/decisions/ADR-001-microservices.md ADR-002 ✓ PostgreSQL als primäre Datenbank Date: 2025-03-20 File: docs/decisions/ADR-002-postgresql.md ADR-003 ✓ Auth via JWT statt Sessions Date: 2025-04-01 File: docs/decisions/ADR-003-jwt-auth.md ADR-004 ✗ REST API Gateway Pattern Date: 2025-02-10 File: docs/decisions/ADR-004-api-gateway.md Status-Icons: ✓ aktiv, ◯ proposed, ⚠ deprecated, ✗ superseded.\nADRs für ein bestimmtes Element bausteinsicht adr list --element shop.db Zeigt nur ADRs die direkt mit shop.db verknüpft sind.\nJSON-Ausgabe bausteinsicht adr list --format json [ { \u0026#34;id\u0026#34;: \u0026#34;ADR-001\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Monolith → Microservices Migration\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;active\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-03-15\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-001-microservices.md\u0026#34; } ] bausteinsicht adr show Details zu einer einzelnen ADR — inklusive welche Elemente und Beziehungen sie referenzieren:\nbausteinsicht adr show ADR-003 Ausgabe:\nADR: ADR-003 ✓ ────────────────────────────────────────── Title: Auth via JWT statt Sessions Status: active Date: 2025-04-01 File: docs/decisions/ADR-003-jwt-auth.md Referenced by: - element: authservice - relationship: shop.frontend → authservice Das zeigt auf einen Blick: diese Entscheidung betrifft den Auth Service und die Verbindung vom Frontend zum Auth Service.\nTypischer ADR-Workflow Neue Entscheidung dokumentieren ADR-Datei schreiben (z.B. docs/decisions/ADR-005-event-sourcing.md)\nEintrag in specification.decisions hinzufügen\nBetroffene Elemente/Beziehungen mit \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-005\u0026#34;] verknüpfen\nbausteinsicht validate — stellt sicher dass alle referenzierten ADR-IDs existieren\nbausteinsicht validate # ✓ All ADR references are valid Validate prüft dass alle ADR-IDs in decisions-Arrays auch in specification.decisions definiert sind.\nEntscheidung ablösen Wenn ADR-004 durch ADR-007 abgelöst wird:\n{ \u0026#34;id\u0026#34;: \u0026#34;ADR-004\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API Gateway Pattern\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;superseded\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-02-10\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-004-api-gateway.md\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;ADR-007\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;GraphQL Federation statt REST Gateway\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;active\u0026#34;, \u0026#34;date\u0026#34;: \u0026#34;2025-07-01\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;docs/decisions/ADR-007-graphql-federation.md\u0026#34; } ADR-004 bleibt im Modell — der Status superseded zeigt dass sie nicht mehr gilt. So bleibt der Entscheidungsverlauf nachvollziehbar.\nWarum direkt im Modell statt in separaten Werkzeugen? ADR-Werkzeuge wie adr-tools oder Log4brains verwalten ADRs gut — aber sie wissen nichts über das Architekturmodell. Die Verknüpfung in Bausteinsicht bringt beides zusammen:\nIm draw.io-Diagramm sieht man welche Elemente ADRs haben (→ CodeLens via LSP, Teil 9)\nbausteinsicht adr show zeigt den Impact einer Entscheidung auf das Modell\nLLMs erhalten mit bausteinsicht adr list --format json den vollständigen Entscheidungskontext (→ Teil 10)\nBausteinsicht speichert nur Metadaten (ID, Titel, Status, Datum, Pfad) — nicht den ADR-Inhalt selbst. Die eigentlichen Dateien liegen weiterhin im Repository, Bausteinsicht verweist nur darauf. Beispiel-Modell Das Beispiel für diesen Teil (Elemente und Beziehungen mit decisions-Referenzen) liegt unter teil_11.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_11.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 12: Overlay \u0026amp; Heatmap — Metriken wie Error-Rate oder Coverage auf Architekturdiagramme legen\nTeil 13: Graph-Analyse — Zyklen und Abhängigkeitsmuster im Modellgraphen aufdecken\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-adr-integration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-llm-ai-workflows/\"\u003ezehnten Teil\u003c/a\u003e fort.\nArchitekturentscheidungen landen oft in Markdown-Dateien irgendwo im Repository — und niemand weiß mehr, warum das Modell so aussieht wie es aussieht.\nBausteinsicht löst das: ADRs lassen sich direkt mit Elementen und Beziehungen im Modell verknüpfen.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_sind_adrs\"\u003eWas sind ADRs?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eArchitecture Decision Records (ADRs) dokumentieren eine Architekturentscheidung mit Kontext, Optionen und Begründung.\nDas Format ist bewusst leichtgewichtig — typischerweise eine kurze Markdown-Datei pro Entscheidung.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas Problem: ohne direkte Verlinkung sind ADRs vom Modell isoliert.\nMan sieht im Diagramm dass ein Element existiert, aber nicht \u003cstrong\u003ewarum\u003c/strong\u003e es so gestaltet wurde.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 11: ADR-Integration — Architecture Decision Records mit dem Modell verknüpfen"},{"content":" Dieser Post setzt den elften Teil fort. Architekturdiagramme zeigen Struktur — aber nicht wie es dem System gerade geht. Mit dem Overlay-Feature lassen sich externe Metriken als Heatmap direkt auf die draw.io-Elemente legen.\nDas Konzept bausteinsicht overlay apply lädt eine JSON-Datei mit Metriken und färbt die draw.io-Elemente entsprechend ein. Die Originalfarben werden in Metadaten des Diagramms gesichert — overlay remove stellt sie exakt wieder her.\nTypische Anwendungsfälle:\nError-Rate pro Service nach einem Incident\nTest-Coverage pro Modul vor einem Release\nLatenz-P99 aus Prometheus/Datadog\nDeployment-Frequenz aus dem CI-System\nMetriken-Datei vorbereiten Die Metriken liegen in einer JSON-Datei mit festem Schema:\n{ \u0026#34;meta\u0026#34;: { \u0026#34;source\u0026#34;: \u0026#34;Datadog\u0026#34;, \u0026#34;generated\u0026#34;: \u0026#34;2025-06-11T06:00:00Z\u0026#34;, \u0026#34;metric_descriptions\u0026#34;: { \u0026#34;error_rate\u0026#34;: \u0026#34;HTTP 5xx Rate (letzte 1h)\u0026#34;, \u0026#34;p99_latency_ms\u0026#34;: \u0026#34;P99 Latenz in Millisekunden\u0026#34; } }, \u0026#34;metrics\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;values\u0026#34;: { \u0026#34;error_rate\u0026#34;: 0.02, \u0026#34;p99_latency_ms\u0026#34;: 145 } }, { \u0026#34;id\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;values\u0026#34;: { \u0026#34;error_rate\u0026#34;: 0.08, \u0026#34;p99_latency_ms\u0026#34;: 312 } }, { \u0026#34;id\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;values\u0026#34;: { \u0026#34;error_rate\u0026#34;: 0.41, \u0026#34;p99_latency_ms\u0026#34;: 890 } }, { \u0026#34;id\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;values\u0026#34;: { \u0026#34;error_rate\u0026#34;: 0.01, \u0026#34;p99_latency_ms\u0026#34;: 22 } } ] } Die id-Felder müssen den Element-IDs im Modell entsprechen. Elemente ohne Eintrag in der Metriken-Datei bleiben unverändert.\nbausteinsicht overlay list Welche Metriken sind in der Datei verfügbar?\nbausteinsicht overlay list metrics.json Ausgabe:\n📊 Metrics from: Datadog (2025-06-11T06:00:00Z) Available metrics (4 elements): • error_rate: HTTP 5xx Rate (letzte 1h) • p99_latency_ms: P99 Latenz in Millisekunden bausteinsicht overlay apply # Error-Rate als Heatmap anzeigen bausteinsicht overlay apply metrics.json --metric error_rate # Latenz als Heatmap anzeigen bausteinsicht overlay apply metrics.json --metric p99_latency_ms # Andere draw.io-Datei als Ziel bausteinsicht overlay apply metrics.json --metric error_rate \\ --output architecture-incident.drawio Bausteinsicht berechnet automatisch die Farbskala: niedrige Werte werden grün, hohe Werte rot eingefärbt (Standard-Farbschema).\nNach dem Apply sieht das Diagramm so aus (farblich):\nshop.frontend → hellgrün (error_rate: 0.02 — niedrig) authservice → gelb (error_rate: 0.08 — mittel) paymentservice → rot (error_rate: 0.41 — kritisch) shop.db → grün (error_rate: 0.01 — sehr niedrig) Das Diagramm öffnet sich in draw.io mit den Heatmap-Farben. Elemente ohne Metrik-Eintrag bleiben in ihrer Originalfarbe.\nJSON-Ausgabe bausteinsicht overlay apply metrics.json --metric error_rate --format json { \u0026#34;status\u0026#34;: \u0026#34;applied\u0026#34;, \u0026#34;metric\u0026#34;: \u0026#34;error_rate\u0026#34;, \u0026#34;file\u0026#34;: \u0026#34;architecture.drawio\u0026#34; } bausteinsicht overlay remove Heatmap entfernen und Originalfarben wiederherstellen:\nbausteinsicht overlay remove Bausteinsicht liest die gesicherten Originalstile aus den draw.io-Metadaten und stellt jeden Element-Style exakt wieder her. Keine manuelle Farbanpassung nötig.\nOriginalfarben werden beim ersten overlay apply in draw.io-Elementmetadaten gespeichert. Solange kein overlay remove ausgeführt wird, bleiben sie dort — auch wenn die draw.io-Datei in Git committed wird. Metriken aus externen Quellen erzeugen Die Metriken-JSON kann aus jedem System kommen. Beispiele:\nPrometheus / Grafana # HTTP Error-Rate der letzten Stunde als JSON exportieren promtool query instant \\ \u0026#39;rate(http_requests_total{status=~\u0026#34;5..\u0026#34;}[1h]) / rate(http_requests_total[1h])\u0026#39; \\ | jq \u0026#39;...\u0026#39; \u0026gt; metrics.json CI-System (Test Coverage) # Coverage-Report aus Go Test in das Overlay-Format konvertieren go test ./... -coverprofile=coverage.out # Dann Coverage per Service aggregieren und in metrics.json schreiben GitHub Actions: Automatisches Overlay vor Review - name: Fetch metrics and apply overlay run: | curl -s \u0026#34;$METRICS_API_URL\u0026#34; \u0026gt; /tmp/metrics.json bausteinsicht overlay apply /tmp/metrics.json --metric error_rate - name: Upload diagram with overlay uses: actions/upload-artifact@v4 with: name: architecture-with-metrics path: architecture.drawio Grenzen Bausteinsicht erzeugt keine Metriken — es visualisiert nur externe Daten\nDie Farbskala ist linear (Min → Grün, Max → Rot); keine logarithmische Skalierung\nNur numerische Metriken werden unterstützt — keine kategorischen Werte\nDas --metric-Flag wählt genau eine Metrik pro Apply; für mehrere Metriken mehrfach aufrufen\nBeispiel-Modell Das Basis-Modell für die Overlay-Beispiele in diesem Teil liegt unter teil_12.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_12.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 13: Graph-Analyse — Zyklen, Zentralität und Abhängigkeitsmuster mit bausteinsicht graph aufdecken\nTeil 14: Auto-Layout — Diagramme automatisch hierarchisch anordnen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-overlay-heatmap/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-adr-integration/\"\u003eelften Teil\u003c/a\u003e fort.\nArchitekturdiagramme zeigen Struktur — aber nicht wie es dem System gerade geht.\nMit dem Overlay-Feature lassen sich externe Metriken als Heatmap direkt auf die draw.io-Elemente legen.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_konzept\"\u003eDas Konzept\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003ebausteinsicht overlay apply\u003c/code\u003e lädt eine JSON-Datei mit Metriken und färbt die draw.io-Elemente entsprechend ein.\nDie Originalfarben werden in Metadaten des Diagramms gesichert — \u003ccode\u003eoverlay remove\u003c/code\u003e stellt sie exakt wieder her.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eTypische Anwendungsfälle:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eError-Rate pro Service nach einem Incident\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTest-Coverage pro Modul vor einem Release\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eLatenz-P99 aus Prometheus/Datadog\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDeployment-Frequenz aus dem CI-System\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Teil 12: Overlay \u0026 Heatmap — Metriken auf Architekturdiagramme legen"},{"content":" Dieser Post setzt den zwölften Teil fort. Architekturmodelle wachsen — und mit ihnen die Komplexität der Abhängigkeiten. bausteinsicht graph analysiert den Beziehungsgraphen und macht Probleme sichtbar, die im Diagramm schwer zu erkennen sind.\nWas ist eine Graph-Analyse? Das Architekturmodell ist mathematisch gesehen ein gerichteter Graph: Elemente sind Knoten, Beziehungen sind Kanten. Graph-Analyse-Algorithmen beantworten Fragen wie:\nGibt es Zyklen? (A → B → C → A)\nWelche Elemente sind am stärksten vernetzt?\nIst der Graph ein DAG (Directed Acyclic Graph)?\nWelche Komponenten bilden stark gekoppelte Cluster?\nbausteinsicht graph bausteinsicht graph --model architecture.jsonc Ausgabe:\nRelationship Graph Analysis =========================== Summary ------- Elements: 12 Relationships: 14 Max Dependency Depth: 4 Graph Type: DAG (acyclic) No cycles detected (valid DAG) Strongly Connected Components: 3 -------- Component 1 (CYCLE): [shop.api, authservice, shop.frontend] Centrality Metrics (top 5 by out-degree): Element | In-Degree | Out-Degree | Betweenness | Closeness ---------------------- | --------- | ---------- | ----------- | --------- shop.api | 2 | 5 | 8.40 | 0.67 authservice | 3 | 2 | 4.20 | 0.58 shop.frontend | 1 | 3 | 3.10 | 0.52 Nur Zyklen anzeigen bausteinsicht graph --model architecture.jsonc --cycles-only Schneller Check für CI: gibt es überhaupt Zyklen?\nZentralitätsmetriken anzeigen bausteinsicht graph --model architecture.jsonc --centrality Zeigt für jedes Element:\nMetrik Bedeutung In-Degree\nAnzahl eingehender Verbindungen — hohe Werte: viele Abhängige\nOut-Degree\nAnzahl ausgehender Verbindungen — hohe Werte: viele Abhängigkeiten\nBetweenness\nWie oft liegt das Element auf dem kürzesten Pfad zwischen zwei anderen — hohe Werte: kritischer Engpass\nCloseness\nWie nahe ist das Element an allen anderen — hohe Werte: zentrale Position im Graph\nReport in Datei schreiben bausteinsicht graph --model architecture.jsonc --centrality \\ --output docs/graph-report.txt JSON-Ausgabe bausteinsicht graph --model architecture.jsonc --format json { \u0026#34;element_count\u0026#34;: 12, \u0026#34;relationship_count\u0026#34;: 14, \u0026#34;max_depth\u0026#34;: 4, \u0026#34;is_dag_valid\u0026#34;: false, \u0026#34;cycles\u0026#34;: [ { \u0026#34;length\u0026#34;: 3, \u0026#34;elements\u0026#34;: [\u0026#34;shop.api\u0026#34;, \u0026#34;authservice\u0026#34;, \u0026#34;shop.frontend\u0026#34;] } ], \u0026#34;components\u0026#34;: [ { \u0026#34;id\u0026#34;: 0, \u0026#34;elements\u0026#34;: [\u0026#34;shop.api\u0026#34;, \u0026#34;authservice\u0026#34;, \u0026#34;shop.frontend\u0026#34;], \u0026#34;is_cycle\u0026#34;: true } ], \u0026#34;centrality\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;in_degree\u0026#34;: 2, \u0026#34;out_degree\u0026#34;: 5, \u0026#34;betweenness\u0026#34;: 8.4, \u0026#34;closeness\u0026#34;: 0.67 } ] } Zyklen in der Architektur Ein Zyklus (A → B → C → A) in der Architektur bedeutet:\nDeployment-Abhängigkeiten sind zirkulär — keines der beteiligten Systeme lässt sich unabhängig deployen\nTestbarkeit leidet — Komponenten können nicht isoliert getestet werden\nVersteckte Kopplung — die Systeme können nicht unabhängig weiterentwickelt werden\nZirkuläre Abhängigkeiten lassen sich auch als no-circular-dependency-Constraint definieren (→ Teil 8) und automatisch in der CI prüfen. bausteinsicht graph gibt zusätzlich die konkreten Zyklen aus — nützlich zur Analyse welche Elemente betroffen sind. Zyklus auflösen Typische Strategien:\nDependency Inversion: gemeinsames Interface/Abstraktion einführen\nEvent-basierte Entkopplung: direkte Aufrufe durch Events ersetzen\nNeue Schicht einziehen: gemeinsam genutzte Logik in ein separates Element auslagern\nZentralität als Architektur-Signal Hohes Out-Degree + hohe Betweenness = potentieller Monolith oder God Object. Ein Element das viele andere kennt und auf vielen Pfaden liegt, ist ein Architekturrisiko:\nÄnderungen dort brechen viele andere Komponenten\nTesten wird komplex\nDeployment blockiert andere\nDie Zentralitätswerte lassen sich gut mit dem Overlay-Feature kombinieren (→ Teil 12): Betweenness-Werte als Metriken-JSON exportieren und als Heatmap visualisieren. CI-Integration - name: Check for architectural cycles run: | bausteinsicht graph --model architecture.jsonc --cycles-only --format json \\ | jq \u0026#39;if .cycles | length \u0026gt; 0 then error(\u0026#34;cycles detected\u0026#34;) else . end\u0026#39; Alternativ über den no-circular-dependency-Constraint (einfacher, kein jq nötig):\n- name: Lint architecture run: bausteinsicht lint # schlägt fehl wenn NO-CYCLES-Constraint verletzt Beispiel-Modell Das Beispiel für diesen Teil (REST API als zentraler Hub mit hohem Out-Degree) liegt unter teil_13.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_13.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 14: Auto-Layout — Diagramme automatisch hierarchisch anordnen\nTeil 15: Templates — Eigene visuelle Stile für Element-Typen definieren\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-graph-analyse/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-overlay-heatmap/\"\u003ezwölften Teil\u003c/a\u003e fort.\nArchitekturmodelle wachsen — und mit ihnen die Komplexität der Abhängigkeiten.\n\u003ccode\u003ebausteinsicht graph\u003c/code\u003e analysiert den Beziehungsgraphen und macht Probleme sichtbar, die im Diagramm schwer zu erkennen sind.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_ist_eine_graph_analyse\"\u003eWas ist eine Graph-Analyse?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas Architekturmodell ist mathematisch gesehen ein gerichteter Graph: Elemente sind Knoten, Beziehungen sind Kanten.\nGraph-Analyse-Algorithmen beantworten Fragen wie:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eGibt es Zyklen? (A → B → C → A)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWelche Elemente sind am stärksten vernetzt?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eIst der Graph ein DAG (Directed Acyclic Graph)?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWelche Komponenten bilden stark gekoppelte Cluster?\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Teil 13: Graph-Analyse — Zyklen und Abhängigkeiten aufdecken"},{"content":" Dieser Post setzt den dreizehnten Teil fort. Wenn neue Elemente ins Modell kommen landen sie in draw.io oft übereinander oder an ungünstigen Positionen. bausteinsicht layout berechnet ein hierarchisches Layout und schreibt die Positionen direkt ins Diagramm.\nbausteinsicht layout bausteinsicht layout Bausteinsicht erkennt das Modell automatisch (AutoDetect) und die zugehörige architecture.drawio im gleichen Verzeichnis.\nAusgabe:\nLayout applied (hierarchical): architecture.drawio Das Diagramm ist jetzt hierarchisch angeordnet — Elemente mit vielen ausgehenden Verbindungen stehen oben, Blätter stehen unten.\nRichtung wählen # Top-to-Bottom (Standard) bausteinsicht layout --rank-dir TB # Left-to-Right (für breite Diagramme) bausteinsicht layout --rank-dir LR LR eignet sich besonders für Systeme mit vielen parallelen Diensten auf gleicher Ebene.\nPinning: Bestimmte Elemente fixieren Nicht alle Elemente sollen automatisch verschoben werden. Externe Systeme, wichtige Kerndienste oder manuell positionierte Übersichtselemente können mit einem Metadaten-Flag fixiert werden:\nIn architecture.jsonc:\n{ \u0026#34;model\u0026#34;: { \u0026#34;external-payment-provider\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Provider\u0026#34;, \u0026#34;metadata\u0026#34;: { \u0026#34;bausteinsicht-pinned\u0026#34;: \u0026#34;true\u0026#34; } } } } Beim Layout-Befehl bleibt dieses Element an seiner Position — alle anderen werden neu angeordnet:\n# Standard: gepinnte Elemente werden nicht verschoben bausteinsicht layout --preserve-pinned true # Alle Elemente neu anordnen (Pinning ignorieren) bausteinsicht layout --preserve-pinned false Typischer Workflow Nach dem Hinzufügen neuer Elemente (z.B. via bausteinsicht add element oder manuellem Editieren):\n# 1. Neues Element hinzufügen bausteinsicht add element --id newservice --kind service --title \u0026#34;New Service\u0026#34; # 2. Sync: draw.io kennt das neue Element bausteinsicht sync # 3. Layout neu berechnen bausteinsicht layout # 4. draw.io öffnen — sauber angeordnet layout verändert nur die Positionen in architecture.drawio, nicht das Modell in architecture.jsonc. Die Positions-Änderungen werden von sync nicht überschrieben — sync aktualisiert Elemente und Stile, aber nicht Positionen. Grenzen Aktuell wird nur der hierarchical-Algorithmus unterstützt (Sugiyama-basiert)\nÜberlappungen bei sehr dichten Diagrammen möglich — manuelles Nacharbeiten kann nötig sein\nScope-Boxen (→ Teil 5) werden als Container behandelt und beeinflussen das Layout\nBeispiel-Modell Das Beispiel für diesen Teil (Modell mit gepinntem externen System) liegt unter teil_14.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_14.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 15: Templates — Eigene visuelle Stile für alle Element-Typen als draw.io-Template generieren\nTeil 16: Workspace — Mehrere Architekturmodelle in einem Workspace kombinieren\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-auto-layout/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-graph-analyse/\"\u003edreizehnten Teil\u003c/a\u003e fort.\nWenn neue Elemente ins Modell kommen landen sie in draw.io oft übereinander oder an ungünstigen Positionen.\n\u003ccode\u003ebausteinsicht layout\u003c/code\u003e berechnet ein hierarchisches Layout und schreibt die Positionen direkt ins Diagramm.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_bausteinsicht_layout\"\u003ebausteinsicht layout\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003ebausteinsicht layout\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBausteinsicht erkennt das Modell automatisch (\u003ccode\u003eAutoDetect\u003c/code\u003e) und die zugehörige \u003ccode\u003earchitecture.drawio\u003c/code\u003e im gleichen Verzeichnis.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAusgabe:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre\u003eLayout applied (hierarchical): architecture.drawio\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDas Diagramm ist jetzt hierarchisch angeordnet — Elemente mit vielen ausgehenden Verbindungen stehen oben, Blätter stehen unten.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 14: Auto-Layout — Diagramme automatisch anordnen"},{"content":" Dieser Post setzt den vierzehnten Teil fort. Jedes Team hat eigene visuelle Konventionen — Farben, Formen, Notationen. bausteinsicht generate-template generiert eine draw.io-Template-Datei die alle Element-Typen aus der Spezifikation mit konsistenten Stilen enthält.\nWas ist ein draw.io-Template? Eine Template-Datei ist eine draw.io-Datei mit vordefinierten Shapes für jeden Element-Typ. Statt im Diagramm Elemente manuell zu stylen, zieht man einfach den passenden Shape aus dem Template-Panel.\ngenerate-template leitet die Shapes automatisch aus specification.elements in architecture.jsonc ab — für jeden kind wird ein gestylter Shape generiert.\nbausteinsicht generate-template bausteinsicht generate-template Erstellt architecture-template.drawio mit Shapes für jeden Element-Typ.\nStyle-Presets # Standard-Preset (blaue Shapes, weiße Beschriftung) bausteinsicht generate-template --style default # C4-Notation (farblich nach C4-Standard: blau/grau/grün) bausteinsicht generate-template --style c4 # Minimalist (nur Umrisse, keine Füllfarbe) bausteinsicht generate-template --style minimal # Dark Mode (dunkle Hintergründe, helle Schrift) bausteinsicht generate-template --style dark Ausgabedatei wählen bausteinsicht generate-template --output docs/diagrams/team-template.drawio Template in draw.io verwenden generate-template ausführen → architecture-template.drawio entsteht\nIn draw.io: Extras → Vorlagen bearbeiten → Template-Datei importieren\nIm linken Panel erscheinen die eigenen Element-Shapes\nJeder Shape hat bereits den korrekten Namen und Style — beim Ziehen ins Diagramm wird das Element direkt mit dem richtigen kind-Wert annotiert, den bausteinsicht sync erkennt.\nTemplate aus eigener Spezifikation Das Template spiegelt immer die aktuelle specification.elements:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;frontend\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Browser\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Web-Frontend\u0026#34; }, \u0026#34;service\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Hexagon\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Backend-Service\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;database\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Cylinder\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Persistenz\u0026#34; }, \u0026#34;queue\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Parallelogram\u0026#34;,\u0026#34;description\u0026#34;: \u0026#34;Message Queue\u0026#34; }, \u0026#34;external\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Cloud\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Externes System\u0026#34; } } } } generate-template erstellt für jeden dieser Typen einen Shape im gewählten Style. Neue Element-Typen → Template neu generieren → sofort im Panel verfügbar.\nTemplate ins Repository committen git add architecture-template.drawio git commit -m \u0026#34;update draw.io template for current element types\u0026#34; So hat das gesamte Team immer das aktuelle Template — kein manuelles Verteilen von Stildateien.\nDas Template neu generieren wenn neue kind-Werte zur Spezifikation hinzukommen. Ein kurzer generate-template \u0026amp;\u0026amp; git add \u0026amp;\u0026amp; git commit reicht. Beispiel-Modell Das Beispiel für diesen Teil (benutzerdefinierte Elementtypen: Browser, Hexagon, Cylinder, Parallelogram, Cloud) liegt unter teil_15.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_15.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 16: Workspace — Mehrere Architekturmodelle in einem Workspace kombinieren\nTeil 17: Sequenzdiagramme — Dynamische Views als PlantUML und Mermaid exportieren\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-templates/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-auto-layout/\"\u003evierzehnten Teil\u003c/a\u003e fort.\nJedes Team hat eigene visuelle Konventionen — Farben, Formen, Notationen.\n\u003ccode\u003ebausteinsicht generate-template\u003c/code\u003e generiert eine draw.io-Template-Datei die alle Element-Typen aus der Spezifikation mit konsistenten Stilen enthält.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_ist_ein_draw_io_template\"\u003eWas ist ein draw.io-Template?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eEine Template-Datei ist eine draw.io-Datei mit vordefinierten Shapes für jeden Element-Typ.\nStatt im Diagramm Elemente manuell zu stylen, zieht man einfach den passenden Shape aus dem Template-Panel.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003egenerate-template\u003c/code\u003e leitet die Shapes automatisch aus \u003ccode\u003especification.elements\u003c/code\u003e in \u003ccode\u003earchitecture.jsonc\u003c/code\u003e ab — für jeden \u003ccode\u003ekind\u003c/code\u003e wird ein gestylter Shape generiert.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 15: Templates — Eigene visuelle Stile definieren"},{"content":" Dieser Post setzt den fünfzehnten Teil fort. In größeren Organisationen pflegt jedes Team sein eigenes Architekturmodell. Der Workspace kombiniert mehrere Modelle zu einer übergreifenden Sicht — ohne die Team-Autonomie aufzugeben.\nDas Problem: Teamgrenzen im Architekturmodell Team A besitzt shop-model/architecture.jsonc, Team B auth-model/architecture.jsonc. Beide wollen ihre Modelle unabhängig pflegen — aber die Plattformarchitektur braucht eine Gesamtsicht.\nDer Workspace ist die Antwort: eine workspace.jsonc referenziert beide Modelle und definiert die Verbindungen zwischen ihnen.\nworkspace.jsonc { \u0026#34;workspace\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;E-Commerce Platform\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Gesamtarchitektur aller Teams\u0026#34; }, \u0026#34;models\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;path\u0026#34;: \u0026#34;teams/shop/architecture.jsonc\u0026#34;, \u0026#34;prefix\u0026#34;: \u0026#34;shop\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;auth\u0026#34;, \u0026#34;path\u0026#34;: \u0026#34;teams/auth/architecture.jsonc\u0026#34;, \u0026#34;prefix\u0026#34;: \u0026#34;auth\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;payment\u0026#34;, \u0026#34;path\u0026#34;: \u0026#34;teams/payment/architecture.jsonc\u0026#34;, \u0026#34;prefix\u0026#34;: \u0026#34;payment\u0026#34; } ], \u0026#34;crossModelRelationships\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;shop-uses-auth\u0026#34;, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;auth.service\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;authenticate\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;rest\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;shop-uses-payment\u0026#34;, \u0026#34;from\u0026#34;: \u0026#34;shop.checkout\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;payment.gateway\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;rest\u0026#34; } ], \u0026#34;views\u0026#34;: { \u0026#34;platform-overview\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Platform-Übersicht\u0026#34;, \u0026#34;include-from\u0026#34;: [\u0026#34;shop\u0026#34;, \u0026#34;auth\u0026#34;, \u0026#34;payment\u0026#34;], \u0026#34;description\u0026#34;: \u0026#34;Alle Teams, nur Top-Level-Elemente\u0026#34; }, \u0026#34;checkout-flow\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Checkout-Flow\u0026#34;, \u0026#34;include-from\u0026#34;: [\u0026#34;shop\u0026#34;, \u0026#34;payment\u0026#34;], \u0026#34;include-kinds\u0026#34;: [\u0026#34;service\u0026#34;, \u0026#34;database\u0026#34;] } } } Element-Präfix Das prefix-Feld verhindert ID-Kollisionen beim Merge: api aus dem Shop-Modell wird zu shop.api, service aus dem Auth-Modell zu auth.service.\nOhne expliziten prefix wird die id des Modells als Präfix verwendet.\nbausteinsicht workspace list Modelle im Workspace anzeigen:\nbausteinsicht workspace list workspace.jsonc Ausgabe:\nWorkspace: E-Commerce Platform Description: Gesamtarchitektur aller Teams Models: 1. ID: shop, Path: teams/shop/architecture.jsonc, Prefix: shop 2. ID: auth, Path: teams/auth/architecture.jsonc, Prefix: auth 3. ID: payment, Path: teams/payment/architecture.jsonc, Prefix: payment Cross-Model Relationships: 2 Workspace Views: 2 bausteinsicht workspace validate Alle referenzierten Modelle laden und validieren:\nbausteinsicht workspace validate workspace.jsonc Prüft: * Alle Modell-Pfade existieren und sind valide JSONC * Jedes einzelne Modell besteht bausteinsicht validate * Cross-Model-Referenzen zeigen auf existierende (präfixierte) Elemente\nBei Erfolg:\n✓ Workspace configuration is valid (3 models) JSON-Ausgabe für CI:\nbausteinsicht workspace validate workspace.jsonc --format json # → {\u0026#34;valid\u0026#34;: true, \u0026#34;models\u0026#34;: 3} bausteinsicht workspace merge Alle Modelle zu einem einzigen zusammengeführten Modell vereinen:\nbausteinsicht workspace merge workspace.jsonc merged-architecture.jsonc Das resultierende merged-architecture.jsonc:\nEnthält alle Elemente aller Teams mit Präfix-IDs\nEnthält alle Cross-Model-Relationships\nBesteht bausteinsicht validate\nDas Merged-Modell kann dann für Exports, Graph-Analyse oder Overlay-Visualisierung verwendet werden:\nbausteinsicht workspace merge workspace.jsonc /tmp/merged.jsonc # Graph-Analyse auf Gesamtarchitektur bausteinsicht graph --model /tmp/merged.jsonc # Overlay auf Gesamtdiagramm bausteinsicht overlay apply metrics.json --model /tmp/merged.jsonc --metric error_rate Typische Workspace-Struktur im Repository architecture/ ├── workspace.jsonc ← Workspace-Konfiguration ├── teams/ │ ├── shop/ │ │ ├── architecture.jsonc │ │ └── architecture.drawio │ ├── auth/ │ │ ├── architecture.jsonc │ │ └── architecture.drawio │ └── payment/ │ ├── architecture.jsonc │ └── architecture.drawio └── merged/ └── architecture.jsonc ← Generiert, nicht manuell editieren Das merged/-Verzeichnis in .gitignore aufnehmen oder als Build-Artefakt behandeln — es wird aus den Team-Modellen regeneriert und soll nicht direkt bearbeitet werden. CI: Workspace-Validierung - name: Validate workspace run: bausteinsicht workspace validate architecture/workspace.jsonc - name: Merge and analyze run: | bausteinsicht workspace merge architecture/workspace.jsonc /tmp/merged.jsonc bausteinsicht graph --model /tmp/merged.jsonc --cycles-only Beispiel-Modell Das Beispiel für diesen Teil (Team-Modell \u0026#34;shop\u0026#34; — eines von mehreren Modellen im Workspace) liegt unter teil_16.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_16.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 17: Sequenzdiagramme — Dynamische Views als PlantUML und Mermaid exportieren\nTeil 18: CLI-Modellierung — Architektur direkt per Kommandozeile aufbauen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-workspace/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-templates/\"\u003efünfzehnten Teil\u003c/a\u003e fort.\nIn größeren Organisationen pflegt jedes Team sein eigenes Architekturmodell.\nDer Workspace kombiniert mehrere Modelle zu einer übergreifenden Sicht — ohne die Team-Autonomie aufzugeben.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_teamgrenzen_im_architekturmodell\"\u003eDas Problem: Teamgrenzen im Architekturmodell\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eTeam A besitzt \u003ccode\u003eshop-model/architecture.jsonc\u003c/code\u003e, Team B \u003ccode\u003eauth-model/architecture.jsonc\u003c/code\u003e.\nBeide wollen ihre Modelle unabhängig pflegen — aber die Plattformarchitektur braucht eine Gesamtsicht.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDer Workspace ist die Antwort: eine \u003ccode\u003eworkspace.jsonc\u003c/code\u003e referenziert beide Modelle und definiert die Verbindungen zwischen ihnen.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 16: Workspace — Mehrere Architekturmodelle kombinieren"},{"content":" Dieser Post setzt den sechzehnten Teil fort. Statische Architekturdiagramme zeigen Struktur. Sequenzdiagramme zeigen Verhalten — wer spricht wen in welcher Reihenfolge an. Bausteinsicht nennt das Dynamic Views.\nDynamic Views im Modell Dynamic Views werden als Array dynamicViews in architecture.jsonc definiert:\n{ \u0026#34;dynamicViews\u0026#34;: [ { \u0026#34;key\u0026#34;: \u0026#34;checkout-flow\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Checkout-Flow\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Ablauf eines erfolgreichen Bestellvorgangs\u0026#34;, \u0026#34;steps\u0026#34;: [ { \u0026#34;index\u0026#34;: 1, \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;POST /orders\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 2, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;validate token\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 3, \u0026#34;from\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;200 OK\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; }, { \u0026#34;index\u0026#34;: 4, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge(amount)\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 5, \u0026#34;from\u0026#34;: \u0026#34;paymentservice\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;INSERT payment\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 6, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;INSERT order\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 7, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;eventbus\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;order.created\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;async\u0026#34; }, { \u0026#34;index\u0026#34;: 8, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;201 Created\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; } ] }, { \u0026#34;key\u0026#34;: \u0026#34;auth-refresh\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Token-Refresh-Flow\u0026#34;, \u0026#34;steps\u0026#34;: [ { \u0026#34;index\u0026#34;: 1, \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;POST /refresh\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; }, { \u0026#34;index\u0026#34;: 2, \u0026#34;from\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.frontend\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;new JWT\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; } ] } ] } Schritt-Typen Typ Darstellung sync\nDurchgehender Pfeil (synchroner Aufruf)\nasync\nGestrichelter Pfeil (Nachricht / Event)\nreturn\nGepunkteter Rückgabepfeil\nbausteinsicht export-sequence # Alle Dynamic Views als PlantUML exportieren (Standard) bausteinsicht export-sequence # Als Mermaid bausteinsicht export-sequence --diagram-format mermaid # Nur eine bestimmte View bausteinsicht export-sequence --view checkout-flow # In Verzeichnis schreiben bausteinsicht export-sequence --output docs/sequences/ Ausgabe (PlantUML, checkout-flow.puml):\n@startuml checkout-flow title Checkout-Flow participant \u0026#34;shop.frontend\u0026#34; as shop_frontend participant \u0026#34;shop.api\u0026#34; as shop_api participant \u0026#34;authservice\u0026#34; as authservice participant \u0026#34;paymentservice\u0026#34; as paymentservice participant \u0026#34;shop.db\u0026#34; as shop_db participant \u0026#34;eventbus\u0026#34; as eventbus shop_frontend -\u0026gt; shop_api : POST /orders shop_api -\u0026gt; authservice : validate token authservice --\u0026gt; shop_api : 200 OK shop_api -\u0026gt; paymentservice : charge(amount) paymentservice -\u0026gt; shop_db : INSERT payment shop_api -\u0026gt; shop_db : INSERT order shop_api -\u0026gt;\u0026gt; eventbus : order.created shop_api --\u0026gt; shop_frontend : 201 Created @enduml Ausgabe (Mermaid, checkout-flow.md):\nsequenceDiagram title Checkout-Flow shop.frontend-\u0026gt;\u0026gt;shop.api: POST /orders shop.api-\u0026gt;\u0026gt;authservice: validate token authservice--\u0026gt;\u0026gt;shop.api: 200 OK shop.api-\u0026gt;\u0026gt;paymentservice: charge(amount) paymentservice-\u0026gt;\u0026gt;shop.db: INSERT payment shop.api-\u0026gt;\u0026gt;shop.db: INSERT order shop.api-)eventbus: order.created shop.api--\u0026gt;\u0026gt;shop.frontend: 201 Created In Dokumentation einbetten PlantUML lässt sich direkt in AsciiDoc referenzieren:\n\\[plantuml, checkout-flow, svg] Unresolved directive in \u0026lt;stdin\u0026gt; - include::sequences/checkout-flow.puml[]\nMermaid funktioniert direkt in GitHub-Markdown und in Wikis.\nUnterschied zu statischen Views Aspekt Statische View (Teil 5) Dynamic View Zeigt\nWelche Elemente existieren\nWer kommuniziert in welcher Reihenfolge\nFormat\ndraw.io-Diagramm\nPlantUML / Mermaid\nGut für\nStrukturübersicht\nAblaufdokumentation, API-Beschreibung\nDie Elemente in steps müssen nicht in einer statischen View sichtbar sein — sie müssen nur im model existieren. bausteinsicht validate prüft alle from/to-Referenzen in Dynamic Views. Beispiel-Modell Das Beispiel für diesen Teil (Modell mit dynamicViews für den Checkout-Flow) liegt unter teil_17.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_17.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGeneriertes PlantUML-Diagramm (statische Sicht) via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 18: CLI-Modellierung — Elemente, Beziehungen und Views direkt per Kommandozeile hinzufügen\nTeil 19: Health Score — Architekturqualität mit A–F bewerten\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-sequenzdiagramme/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-workspace/\"\u003esechzehnten Teil\u003c/a\u003e fort.\nStatische Architekturdiagramme zeigen Struktur.\nSequenzdiagramme zeigen Verhalten — wer spricht wen in welcher Reihenfolge an.\nBausteinsicht nennt das \u003cstrong\u003eDynamic Views\u003c/strong\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_dynamic_views_im_modell\"\u003eDynamic Views im Modell\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDynamic Views werden als Array \u003ccode\u003edynamicViews\u003c/code\u003e in \u003ccode\u003earchitecture.jsonc\u003c/code\u003e definiert:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e{\n  \u0026#34;dynamicViews\u0026#34;: [\n    {\n      \u0026#34;key\u0026#34;:         \u0026#34;checkout-flow\u0026#34;,\n      \u0026#34;title\u0026#34;:       \u0026#34;Checkout-Flow\u0026#34;,\n      \u0026#34;description\u0026#34;: \u0026#34;Ablauf eines erfolgreichen Bestellvorgangs\u0026#34;,\n      \u0026#34;steps\u0026#34;: [\n        { \u0026#34;index\u0026#34;: 1, \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop.api\u0026#34;,       \u0026#34;label\u0026#34;: \u0026#34;POST /orders\u0026#34;,      \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; },\n        { \u0026#34;index\u0026#34;: 2, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;authservice\u0026#34;,    \u0026#34;label\u0026#34;: \u0026#34;validate token\u0026#34;,    \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; },\n        { \u0026#34;index\u0026#34;: 3, \u0026#34;from\u0026#34;: \u0026#34;authservice\u0026#34;,   \u0026#34;to\u0026#34;: \u0026#34;shop.api\u0026#34;,       \u0026#34;label\u0026#34;: \u0026#34;200 OK\u0026#34;,            \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; },\n        { \u0026#34;index\u0026#34;: 4, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge(amount)\u0026#34;,    \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; },\n        { \u0026#34;index\u0026#34;: 5, \u0026#34;from\u0026#34;: \u0026#34;paymentservice\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;,        \u0026#34;label\u0026#34;: \u0026#34;INSERT payment\u0026#34;,    \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; },\n        { \u0026#34;index\u0026#34;: 6, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;shop.db\u0026#34;,        \u0026#34;label\u0026#34;: \u0026#34;INSERT order\u0026#34;,      \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; },\n        { \u0026#34;index\u0026#34;: 7, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;eventbus\u0026#34;,       \u0026#34;label\u0026#34;: \u0026#34;order.created\u0026#34;,     \u0026#34;type\u0026#34;: \u0026#34;async\u0026#34; },\n        { \u0026#34;index\u0026#34;: 8, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;shop.frontend\u0026#34;,  \u0026#34;label\u0026#34;: \u0026#34;201 Created\u0026#34;,       \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; }\n      ]\n    },\n    {\n      \u0026#34;key\u0026#34;:   \u0026#34;auth-refresh\u0026#34;,\n      \u0026#34;title\u0026#34;: \u0026#34;Token-Refresh-Flow\u0026#34;,\n      \u0026#34;steps\u0026#34;: [\n        { \u0026#34;index\u0026#34;: 1, \u0026#34;from\u0026#34;: \u0026#34;shop.frontend\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;POST /refresh\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;sync\u0026#34; },\n        { \u0026#34;index\u0026#34;: 2, \u0026#34;from\u0026#34;: \u0026#34;authservice\u0026#34;,   \u0026#34;to\u0026#34;: \u0026#34;shop.frontend\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;new JWT\u0026#34;,       \u0026#34;type\u0026#34;: \u0026#34;return\u0026#34; }\n      ]\n    }\n  ]\n}\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 17: Sequenzdiagramme — Dynamische Views als PlantUML und Mermaid exportieren"},{"content":" Dieser Post setzt den siebzehnten Teil fort. Das Modell lässt sich nicht nur manuell in architecture.jsonc bearbeiten — alle strukturellen Änderungen gehen auch über die CLI. Das ist besonders nützlich für Skripte, LLM-Workflows (→ Teil 10) und CI-Pipelines.\nbausteinsicht add element Neues Element zum Modell hinzufügen:\n# Top-Level-Element bausteinsicht add element \\ --id paymentservice \\ --kind service \\ --title \u0026#34;Payment Service\u0026#34; \\ --technology \u0026#34;Go\u0026#34; \\ --description \u0026#34;Verarbeitet Zahlungen\u0026#34; # Verschachteltes Element (child von paymentservice) bausteinsicht add element \\ --id ledger \\ --kind database \\ --title \u0026#34;Payment Ledger\u0026#34; \\ --technology \u0026#34;PostgreSQL\u0026#34; \\ --parent paymentservice Validierungen: * --id darf nur Buchstaben, Ziffern, Bindestriche, Unterstriche enthalten (keine Punkte — Punkte sind Hierarchietrennzeichen) * --kind muss in specification.elements definiert sein * Parent muss existieren und container: true in seiner Spezifikation haben * Duplikate werden abgelehnt\nJSON-Ausgabe:\nbausteinsicht add element --id newservice --kind service --title \u0026#34;New Service\u0026#34; --format json # → {\u0026#34;id\u0026#34;: \u0026#34;newservice\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;New Service\u0026#34;} bausteinsicht add relationship Beziehung zwischen zwei bestehenden Elementen hinzufügen:\nbausteinsicht add relationship \\ --from shop.api \\ --to paymentservice \\ --label \u0026#34;charge(amount)\u0026#34; \\ --kind rest \\ --description \u0026#34;Initiiert Zahlung\u0026#34; Validierungen: * --from und --to müssen im Modell existieren * --kind muss in specification.relationships definiert sein (falls angegeben) * Duplikate (gleiche from/to/kind-Kombination) werden abgelehnt\nbausteinsicht add view Neue View erstellen oder bestehende View um Elemente erweitern:\n# Neue View mit Scope bausteinsicht add view payment-view \\ --title \u0026#34;Payment System\u0026#34; \\ --scope paymentservice \\ --include \u0026#34;paymentservice.*\u0026#34; # Bestehende View um Element erweitern bausteinsicht add view payment-view \\ --include shop.api --include akzeptiert Element-IDs und Wildcards wie paymentservice.* (alle direkten Children).\nbausteinsicht add-from-pattern Patterns sind wiederverwendbare Element-Topologien in specification.patterns. Sie werden mit add-from-pattern instanziiert:\n# Pattern \u0026#34;microservice\u0026#34; mit ID \u0026#34;notificationservice\u0026#34; instanziieren bausteinsicht add-from-pattern microservice \\ --id notificationservice \\ --title \u0026#34;Notification Service\u0026#34; # Mit Namespace-Präfix bausteinsicht add-from-pattern microservice \\ --id emailworker \\ --prefix notification # → erstellt \u0026#34;notification-emailworker\u0026#34; als Top-Level-ID Das Pattern expandiert alle definierten Elemente und Beziehungen auf einmal.\nPattern auflisten bausteinsicht add pattern list Zeigt alle in specification.patterns definierten Patterns mit Element- und Beziehungsanzahl.\nbausteinsicht add specification Neue Typen zur Spezifikation hinzufügen:\n# Neuen Element-Typ definieren bausteinsicht add specification element \\ --kind \u0026#34;cache\u0026#34; \\ --notation \u0026#34;Cylinder\u0026#34; \\ --description \u0026#34;In-Memory Cache\u0026#34; # Neuen Beziehungstyp definieren bausteinsicht add specification relationship \\ --kind \u0026#34;event\u0026#34; \\ --notation \u0026#34;Event\u0026#34; \\ --dashed Kommentare bleiben erhalten Alle add-Befehle verwenden einen Comment-Preserving-Patcher: JSONC-Kommentare in architecture.jsonc werden nicht entfernt. Neue Einträge werden präzise an der richtigen Stelle eingefügt — ohne die bestehende Formatierung zu zerstören.\nFalls der Patch fehlschlägt (z.B. bei komplexer Formatierung), fällt Bausteinsicht auf einen vollständigen Save zurück — der Inhalt ist dann korrekt, aber Kommentare könnten verloren gehen.\nNach jedem add-Befehl empfiehlt sich ein bausteinsicht sync damit das neue Element im draw.io-Diagramm erscheint. Typischer Workflow per CLI # 1. Neues Element hinzufügen bausteinsicht add element --id cacheservice --kind cache --title \u0026#34;Redis Cache\u0026#34; --technology Redis # 2. Beziehung hinzufügen bausteinsicht add relationship --from shop.api --to cacheservice --label \u0026#34;read/write\u0026#34; --kind tcp # 3. In bestehende View aufnehmen bausteinsicht add view system-overview --include cacheservice # 4. Sync: draw.io aktualisieren bausteinsicht sync # 5. Validieren bausteinsicht validate Beispiel-Modell Das Beispiel für diesen Teil (per CLI schrittweise aufgebautes Modell) liegt unter teil_18.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_18.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 19: Health Score — Architekturqualität objektiv messen und mit A–F bewerten\nTeil 20: Element-Lifecycle — Status von proposed bis archived im Modell verfolgen\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-cli-modellierung/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-sequenzdiagramme/\"\u003esiebzehnten Teil\u003c/a\u003e fort.\nDas Modell lässt sich nicht nur manuell in \u003ccode\u003earchitecture.jsonc\u003c/code\u003e bearbeiten — alle strukturellen Änderungen gehen auch über die CLI.\nDas ist besonders nützlich für Skripte, LLM-Workflows (→ \u003ca href=\"../bausteinsicht-llm-ai-workflows/\"\u003eTeil 10\u003c/a\u003e) und CI-Pipelines.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_bausteinsicht_add_element\"\u003ebausteinsicht add element\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eNeues Element zum Modell hinzufügen:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e# Top-Level-Element\nbausteinsicht add element \\\n  --id paymentservice \\\n  --kind service \\\n  --title \u0026#34;Payment Service\u0026#34; \\\n  --technology \u0026#34;Go\u0026#34; \\\n  --description \u0026#34;Verarbeitet Zahlungen\u0026#34;\n\n# Verschachteltes Element (child von paymentservice)\nbausteinsicht add element \\\n  --id ledger \\\n  --kind database \\\n  --title \u0026#34;Payment Ledger\u0026#34; \\\n  --technology \u0026#34;PostgreSQL\u0026#34; \\\n  --parent paymentservice\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 18: CLI-Modellierung — Architektur direkt per Kommandozeile aufbauen"},{"content":" Dieser Post setzt den achtzehnten Teil fort. bausteinsicht validate und bausteinsicht lint prüfen ob das Modell korrekt ist. bausteinsicht health geht weiter: es bewertet wie gut das Modell ist — Vollständigkeit, Konformität, Komplexität und mehr.\nbausteinsicht health bausteinsicht health --model architecture.jsonc Ausgabe:\nArchitecture Health Report ========================== Overall Score: 78.5/100 [B] Summary: Good architecture documentation with room for improvement Timestamp: 2025-06-11T06:00:00Z Model Statistics ---------------- Elements: 18 Relationships: 14 Views: 4 Category Scores --------------- Completeness: 82.0/100 (weight: 40%) Details: 15/18 elements have descriptions Conformance: 95.0/100 (weight: 30%) Details: 1 constraint violation Complexity: 65.0/100 (weight: 20%) Details: High relationship density detected Deprecation: 70.0/100 (weight: 5%) Details: 2 deprecated elements still in use Documentation: 80.0/100 (weight: 5%) Details: 3 elements without title Findings -------- Completeness (3 findings): [MAJOR] Missing descriptions shop.legacy, shop.legacy.api, eventbus: description is empty Complexity (1 finding): [MINOR] High coupling shop.api has 6 outgoing relationships — consider splitting Deprecation (1 finding): [MAJOR] Deprecated element referenced shop.legacy: status=deprecated but still used by shop.frontend Bewertungskategorien Kategorie Gewichtung Was wird bewertet Completeness\n40 %\nAnteil der Elemente mit Beschreibung, Title, Technology\nConformance\n30 %\nConstraint-Verstöße aus bausteinsicht lint\nComplexity\n20 %\nRelationship-Dichte, maximale Tiefe, Zyklen\nDeprecation\n5 %\nDeprecated/Archived-Elemente die noch referenziert werden\nDocumentation\n5 %\nElemente ohne title-Feld\nNotenskala Score Note ≥ 97\nA+\n≥ 93\nA\n≥ 90\nB+\n≥ 87\nB\n≥ 80\nC+\n≥ 70\nC\n≥ 60\nD\n\u0026lt; 60\nF\nKurzansicht für Dashboards bausteinsicht health --model architecture.jsonc --summary # → Overall Score: 78.5/100 [B] # Als JSON (für CI-Auswertung) bausteinsicht health --model architecture.jsonc --summary --format json { \u0026#34;overall\u0026#34;: 78.5, \u0026#34;grade\u0026#34;: \u0026#34;B\u0026#34;, \u0026#34;summary\u0026#34;: \u0026#34;Good architecture documentation with room for improvement\u0026#34;, \u0026#34;timestamp\u0026#34;: \u0026#34;2025-06-11T06:00:00Z\u0026#34; } Report in Datei schreiben bausteinsicht health --model architecture.jsonc \\ --output docs/architecture-health.txt Vollständige JSON-Ausgabe bausteinsicht health --model architecture.jsonc --format json Gibt das vollständige HealthScore-Objekt zurück mit categories, findings, Element-Zählern und ISO8601-Timestamp.\nCI-Integration - name: Architecture health (informational) run: | bausteinsicht health --model architecture.jsonc --summary continue-on-error: true # health bricht nicht den Build - name: Architecture health (enforce minimum grade) run: | GRADE=$(bausteinsicht health --model architecture.jsonc \\ --summary --format json | jq -r \u0026#39;.grade\u0026#39;) if [[ \u0026#34;$GRADE\u0026#34; == \u0026#34;D\u0026#34; || \u0026#34;$GRADE\u0026#34; == \u0026#34;F\u0026#34; ]]; then echo \u0026#34;Architecture health below minimum threshold: $GRADE\u0026#34; exit 1 fi Im Gegensatz zu bausteinsicht lint blockiert health den Build nicht per Exit-Code — es ist eine Qualitätsmessung, kein Gate. Den Exit-Code kann man selbst über den Grade-Schwellenwert steuern (wie im Beispiel oben). Unterschied zu validate und lint Befehl Zweck Exit-Code bei Problem validate\nStrukturelle Korrektheit (Referenzen, Schema)\n1\nlint\nConstraint-Verletzungen (Architekturregeln)\n1\nhealth\nQualitätsbewertung (Score, Note)\n0 (immer erfolgreich)\nBeispiel-Modell Das Beispiel für diesen Teil (Modell mit unterschiedlicher Dokumentationsqualität — legacy-Service ohne Description/Status) liegt unter teil_19.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_19.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 20: Element-Lifecycle — Status von proposed bis archived im Modell verfolgen\nTeil 21: As-Is / To-Be — Zielarchitektur direkt im Modell definieren\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-health-score/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-cli-modellierung/\"\u003eachtzehnten Teil\u003c/a\u003e fort.\n\u003ccode\u003ebausteinsicht validate\u003c/code\u003e und \u003ccode\u003ebausteinsicht lint\u003c/code\u003e prüfen ob das Modell korrekt ist.\n\u003ccode\u003ebausteinsicht health\u003c/code\u003e geht weiter: es bewertet wie \u003cstrong\u003egut\u003c/strong\u003e das Modell ist — Vollständigkeit, Konformität, Komplexität und mehr.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_bausteinsicht_health\"\u003ebausteinsicht health\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003ebausteinsicht health --model architecture.jsonc\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAusgabe:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre\u003eArchitecture Health Report\n==========================\n\nOverall Score: 78.5/100 [B]\nSummary: Good architecture documentation with room for improvement\nTimestamp: 2025-06-11T06:00:00Z\n\nModel Statistics\n----------------\nElements:      18\nRelationships: 14\nViews:          4\n\nCategory Scores\n---------------\nCompleteness:    82.0/100 (weight: 40%)\n  Details: 15/18 elements have descriptions\nConformance:     95.0/100 (weight: 30%)\n  Details: 1 constraint violation\nComplexity:      65.0/100 (weight: 20%)\n  Details: High relationship density detected\nDeprecation:     70.0/100 (weight: 5%)\n  Details: 2 deprecated elements still in use\nDocumentation:   80.0/100 (weight: 5%)\n  Details: 3 elements without title\n\nFindings\n--------\nCompleteness (3 findings):\n  [MAJOR] Missing descriptions\n          shop.legacy, shop.legacy.api, eventbus: description is empty\n\nComplexity (1 finding):\n  [MINOR] High coupling\n          shop.api has 6 outgoing relationships — consider splitting\n\nDeprecation (1 finding):\n  [MAJOR] Deprecated element referenced\n          shop.legacy: status=deprecated but still used by shop.frontend\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 19: Health Score — Architekturqualität mit A–F bewerten"},{"content":" Dieser Post setzt den neunzehnten Teil fort. Architektur ist kein statisches Bild — Elemente werden vorgeschlagen, implementiert, deployed und irgendwann abgelöst. Das status-Feld in Bausteinsicht-Elementen macht diesen Lebenszyklus sichtbar.\nStatus-Werte Status Bedeutung proposed\nNeu vorgeschlagen, noch nicht entschieden oder begonnen\ndesign\nIn der Designphase, noch nicht implementiert\nimplementation\nAktuell in Entwicklung\ndeployed\nProduktiv im Einsatz\ndeprecated\nVeraltet, soll nicht mehr genutzt werden — aber noch aktiv\narchived\nAbgeschaltet, nur noch historisch im Modell\nStatus im Modell setzen Das status-Feld gehört direkt ins Element:\n{ \u0026#34;model\u0026#34;: { \u0026#34;authservice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34; }, \u0026#34;paymentservice-v2\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Service v2\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Rust\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;implementation\u0026#34; }, \u0026#34;shop-monolith\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Legacy Monolith\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deprecated\u0026#34; }, \u0026#34;old-auth-session\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Session-basierter Auth (alt)\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;archived\u0026#34; } } } Elemente ohne status-Feld gelten als unset.\nbausteinsicht status Alle Elemente mit ihrem Status:\nbausteinsicht status Ausgabe:\nElement Lifecycle Status ================================================== proposed (0): design (1): paymentservice-v2 [service ] \u0026#34;Payment Service v2\u0026#34; implementation (2): notificationservice [service ] \u0026#34;Notification Service\u0026#34; shop.checkout-v2 [component ] \u0026#34;Checkout v2\u0026#34; deployed (8): authservice [service ] \u0026#34;Auth Service\u0026#34; shop.api [service ] \u0026#34;Shop API\u0026#34; ... deprecated (1): shop-monolith [system ] \u0026#34;Legacy Monolith\u0026#34; archived (1): old-auth-session [service ] \u0026#34;Session-basierter Auth (alt)\u0026#34; unset (3): eventbus [queue ] \u0026#34;Event Bus\u0026#34; ... Gefiltert nach Status # Nur Elemente in Entwicklung bausteinsicht status --filter implementation # Nur veraltete Elemente bausteinsicht status --filter deprecated JSON-Ausgabe bausteinsicht status --format json { \u0026#34;summary\u0026#34;: { \u0026#34;proposed\u0026#34;: 0, \u0026#34;design\u0026#34;: 1, \u0026#34;implementation\u0026#34;: 2, \u0026#34;deployed\u0026#34;: 8, \u0026#34;deprecated\u0026#34;: 1, \u0026#34;archived\u0026#34;: 1, \u0026#34;unset\u0026#34;: 3 }, \u0026#34;elements\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;authservice\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34; } ] } Das summary-Objekt gibt auf einen Blick die Verteilung wieder — nützlich als Dashboard-Metrik.\nLifecycle im Kontext anderer Features Health Score bausteinsicht health wertet deprecated und archived Elemente in der Deprecation-Kategorie aus: Wenn ein deprecated-Element noch als Quelle oder Ziel in relationships erscheint, ist das ein Major-Finding (→ Teil 19).\nLSP / Editor Der Language Server zeigt den Status als CodeLens über jedem Element an (→ Teil 9):\n// service | status: deprecated | views: 2 \u0026#34;shop-monolith\u0026#34;: { ... } Overlay Status-Werte lassen sich als Metriken-JSON exportieren und als Heatmap visualisieren (→ Teil 12): Deprecated-Elemente rot, deployed-Elemente grün.\nSprint-basierter Workflow Zeitpunkt Status-Änderung Architekturentscheidung getroffen\nproposed → design\nImplementierung beginnt\ndesign → implementation\nProduktiv-Deployment\nimplementation → deployed\nAblösung beschlossen (ADR erstellt)\ndeployed → deprecated\nSystem abgeschaltet\ndeprecated → archived\nStatus-Änderungen als Git-Commit dokumentieren: git commit -m \u0026#34;mark shop-monolith as deprecated (ADR-007)\u0026#34;. Zusammen mit bausteinsicht changelog (→ Teil 7) entsteht so eine vollständige Architekturhistorie. Beispiel-Modell Das Beispiel für diesen Teil (alle Status-Werte von proposed bis archived) liegt unter teil_20.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_20.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 21: As-Is / To-Be — Zielarchitektur direkt im Modell definieren und visualisieren\nTeil 22: find \u0026amp; show — Das Modell gezielt navigieren und Elemente erkunden\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-element-lifecycle/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-health-score/\"\u003eneunzehnten Teil\u003c/a\u003e fort.\nArchitektur ist kein statisches Bild — Elemente werden vorgeschlagen, implementiert, deployed und irgendwann abgelöst.\nDas \u003ccode\u003estatus\u003c/code\u003e-Feld in Bausteinsicht-Elementen macht diesen Lebenszyklus sichtbar.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_status_werte\"\u003eStatus-Werte\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003ctable class=\"tableblock frame-all grid-all stretch\"\u003e\n\u003ccolgroup\u003e\n\u003ccol style=\"width: 25%;\"/\u003e\n\u003ccol style=\"width: 75%;\"/\u003e\n\u003c/colgroup\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eStatus\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eBedeutung\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003eproposed\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eNeu vorgeschlagen, noch nicht entschieden oder begonnen\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003edesign\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eIn der Designphase, noch nicht implementiert\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003eimplementation\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eAktuell in Entwicklung\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003edeployed\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eProduktiv im Einsatz\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003edeprecated\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eVeraltet, soll nicht mehr genutzt werden — aber noch aktiv\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003earchived\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eAbgeschaltet, nur noch historisch im Modell\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Teil 20: Element-Lifecycle — Status von proposed bis archived verfolgen"},{"content":" Dieser Post setzt den zwanzigsten Teil fort. Architekturmigrationen sind komplex: man muss verstehen wo man gerade steht (As-Is) und wo man hin will (To-Be). Bausteinsicht unterstützt das direkt im Modell — als zwei parallele Snapshots.\nDas Konzept architecture.jsonc kann neben dem Hauptmodell zwei optionale Sektionen enthalten:\nasIs — aktueller Zustand (Ist-Architektur)\ntoBe — Zielzustand (Soll-Architektur)\nBeide haben die gleiche Struktur: elements und relationships.\n{ \u0026#34;model\u0026#34;: { ... }, \u0026#34;asIs\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;shop-monolith\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop Monolith\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Java/Spring\u0026#34; }, \u0026#34;shop-db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Monolith DB\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;MySQL\u0026#34; } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;shop-monolith\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop-db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads/writes\u0026#34; } ] }, \u0026#34;toBe\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;shop-api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;auth-service\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;payment-service\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Rust\u0026#34; }, \u0026#34;shop-db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop DB\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;shop-api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;auth-service\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;authenticate\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop-api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;payment-service\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop-api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop-db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads/writes\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;payment-service\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;shop-db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;audit\u0026#34; } ] } } bausteinsicht diff diff vergleicht asIs mit toBe und gibt die Unterschiede aus:\nbausteinsicht diff --model architecture.jsonc Ausgabe:\nArchitecture Diff ================= Added (3): + shop-api [service ] \u0026#34;Shop API\u0026#34; + auth-service [service ] \u0026#34;Auth Service\u0026#34; + payment-service [service ] \u0026#34;Rust\u0026#34; Removed (1): - shop-monolith [system ] \u0026#34;Shop Monolith\u0026#34; Changed (1): ~ shop-db [database] technology: \u0026#34;MySQL\u0026#34; → \u0026#34;PostgreSQL\u0026#34; Added Relationships (3): + shop-api → auth-service (authenticate) + shop-api → payment-service (charge) + payment-service → shop-db (audit) Removed Relationships (1): - shop-monolith → shop-db (reads/writes) JSON-Ausgabe bausteinsicht diff --model architecture.jsonc --format json Gibt ein strukturiertes DiffResult-Objekt zurück mit summary (Zählungen) und elements-Array mit ChangeAdded, ChangeRemoved, ChangeChanged-Einträgen.\nNur eine View vergleichen bausteinsicht diff --model architecture.jsonc --view shop-overview Filtert den Diff auf Elemente die in der genannten View sichtbar sind.\nUnterschied zu snapshot diff Aspekt bausteinsicht diff bausteinsicht snapshot diff Vergleicht\nasIs vs. toBe im gleichen Modell\nZwei Snapshots zu verschiedenen Zeitpunkten\nZweck\nMigrationsplanung (Ziel definieren)\nRückblick (was hat sich verändert?)\nDatenspeicherung\nIm Modell selbst\nIn .bausteinsicht-snapshots/\nWorkflow: Migrationsplanung asIs mit dem aktuellen Systemzustand füllen\ntoBe mit der Zielarchitektur füllen\nbausteinsicht diff — zeigt genau welche Schritte nötig sind\nErgebnis in PR-Beschreibung oder ADR dokumentieren\nNach der Migration: asIs auf toBe aktualisieren, toBe leeren oder nächste Migrationsstufe definieren\n# Diff für PR-Beschreibung bausteinsicht diff --model architecture.jsonc --format json \\ | jq \u0026#39;{ added: .summary.added_elements, removed: .summary.removed_elements, changed: .summary.changed_elements }\u0026#39; asIs und toBe können auch schrittweise befüllt werden — für iterative Migrationen mit mehreren Zwischenzuständen. Zwischen den Sprints jeweils asIs aktualisieren wenn Elemente tatsächlich migriert wurden. Beispiel-Modell Das Beispiel für diesen Teil (Monolith → Microservices Migration mit asIs/toBe-Sektionen) liegt unter teil_21.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_21.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram (aktuelle Migrationsphase):\nWas als nächstes kommt Teil 22: find \u0026amp; show — Das Modell gezielt navigieren und einzelne Elemente erkunden\nTeil 23: Tags \u0026amp; View-Filterung — Elemente taggen und Views gezielt filtern\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-as-is-to-be/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-element-lifecycle/\"\u003ezwanzigsten Teil\u003c/a\u003e fort.\nArchitekturmigrationen sind komplex: man muss verstehen wo man gerade steht (As-Is) und wo man hin will (To-Be).\nBausteinsicht unterstützt das direkt im Modell — als zwei parallele Snapshots.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_konzept\"\u003eDas Konzept\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003earchitecture.jsonc\u003c/code\u003e kann neben dem Hauptmodell zwei optionale Sektionen enthalten:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003easIs\u003c/code\u003e — aktueller Zustand (Ist-Architektur)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003etoBe\u003c/code\u003e — Zielzustand (Soll-Architektur)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBeide haben die gleiche Struktur: \u003ccode\u003eelements\u003c/code\u003e und \u003ccode\u003erelationships\u003c/code\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e{\n  \u0026#34;model\u0026#34;: { ... },\n\n  \u0026#34;asIs\u0026#34;: {\n    \u0026#34;elements\u0026#34;: {\n      \u0026#34;shop-monolith\u0026#34;: {\n        \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;,\n        \u0026#34;title\u0026#34;: \u0026#34;Shop Monolith\u0026#34;,\n        \u0026#34;technology\u0026#34;: \u0026#34;Java/Spring\u0026#34;\n      },\n      \u0026#34;shop-db\u0026#34;: {\n        \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;,\n        \u0026#34;title\u0026#34;: \u0026#34;Monolith DB\u0026#34;,\n        \u0026#34;technology\u0026#34;: \u0026#34;MySQL\u0026#34;\n      }\n    },\n    \u0026#34;relationships\u0026#34;: [\n      { \u0026#34;from\u0026#34;: \u0026#34;shop-monolith\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;shop-db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads/writes\u0026#34; }\n    ]\n  },\n\n  \u0026#34;toBe\u0026#34;: {\n    \u0026#34;elements\u0026#34;: {\n      \u0026#34;shop-api\u0026#34;: {\n        \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;,\n        \u0026#34;title\u0026#34;: \u0026#34;Shop API\u0026#34;,\n        \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;\n      },\n      \u0026#34;auth-service\u0026#34;: {\n        \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;,\n        \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;,\n        \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34;\n      },\n      \u0026#34;payment-service\u0026#34;: {\n        \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;,\n        \u0026#34;title\u0026#34;: \u0026#34;Payment Service\u0026#34;,\n        \u0026#34;technology\u0026#34;: \u0026#34;Rust\u0026#34;\n      },\n      \u0026#34;shop-db\u0026#34;: {\n        \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;,\n        \u0026#34;title\u0026#34;: \u0026#34;Shop DB\u0026#34;,\n        \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34;\n      }\n    },\n    \u0026#34;relationships\u0026#34;: [\n      { \u0026#34;from\u0026#34;: \u0026#34;shop-api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;auth-service\u0026#34;,     \u0026#34;label\u0026#34;: \u0026#34;authenticate\u0026#34; },\n      { \u0026#34;from\u0026#34;: \u0026#34;shop-api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;payment-service\u0026#34;,  \u0026#34;label\u0026#34;: \u0026#34;charge\u0026#34; },\n      { \u0026#34;from\u0026#34;: \u0026#34;shop-api\u0026#34;,      \u0026#34;to\u0026#34;: \u0026#34;shop-db\u0026#34;,          \u0026#34;label\u0026#34;: \u0026#34;reads/writes\u0026#34; },\n      { \u0026#34;from\u0026#34;: \u0026#34;payment-service\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;shop-db\u0026#34;,         \u0026#34;label\u0026#34;: \u0026#34;audit\u0026#34; }\n    ]\n  }\n}\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 21: As-Is / To-Be — Zielarchitektur direkt im Modell definieren"},{"content":" Dieser Post setzt den einundzwanzigsten Teil fort. In wachsenden Modellen verliert man schnell den Überblick. bausteinsicht find und bausteinsicht show sind die zwei Navigationsbefehle: suchen und inspizieren.\nbausteinsicht find find durchsucht alle Elemente, Beziehungen und Views nach einem Begriff. Die Suche ist case-insensitiv, partiell und verwendet AND-Semantik bei mehreren Wörtern.\n# Alle Treffer für \u0026#34;payment\u0026#34; bausteinsicht find payment # AND-Suche: alle Treffer die \u0026#34;payment\u0026#34; UND \u0026#34;service\u0026#34; enthalten bausteinsicht find payment service # Nur Elemente (keine Relationships oder Views) bausteinsicht find payment --type element # Nur Beziehungen bausteinsicht find charge --type relationship # Nur Views bausteinsicht find overview --type view Ausgabe:\nSearch results for \u0026#34;payment\u0026#34; (4 matches) ======================================== Elements (2): paymentservice [service ] \u0026#34;Payment Service\u0026#34; technology: Rust score: 95 paymentservice.ledger [database ] \u0026#34;Payment Ledger\u0026#34; technology: PostgreSQL score: 72 Relationships (1): shop.api→paymentservice shop.api → paymentservice \u0026#34;charge\u0026#34; score: 60 Views (1): payment-view \u0026#34;Payment System\u0026#34; score: 45 Ergebnisse sind nach Relevanz-Score sortiert — das relevanteste Ergebnis steht zuerst.\nJSON-Ausgabe bausteinsicht find payment --format json { \u0026#34;query\u0026#34;: \u0026#34;payment\u0026#34;, \u0026#34;total\u0026#34;: 4, \u0026#34;results\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;element\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Rust\u0026#34;, \u0026#34;score\u0026#34;: 95 }, { \u0026#34;type\u0026#34;: \u0026#34;relationship\u0026#34;, \u0026#34;id\u0026#34;: \u0026#34;shop.api→paymentservice\u0026#34;, \u0026#34;from\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;charge\u0026#34;, \u0026#34;score\u0026#34;: 60 } ] } bausteinsicht show show zeigt alle Details eines einzelnen Elements — inklusive aller Beziehungen und Views. Die Element-ID verwendet Punkt-Notation für verschachtelte Elemente.\nbausteinsicht show paymentservice bausteinsicht show paymentservice.ledger Ausgabe:\nElement: paymentservice ======================= Kind: service Title: Payment Service Technology: Rust Status: deployed Description: Verarbeitet alle Zahlungsvorgänge Relationships (3): ← shop.api charge → paymentservice.ledger INSERT payment → shop.db audit log Views (2): payment-view system-overview JSON-Ausgabe bausteinsicht show paymentservice --format json { \u0026#34;id\u0026#34;: \u0026#34;paymentservice\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Payment Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Rust\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Verarbeitet alle Zahlungsvorgänge\u0026#34;, \u0026#34;relationships\u0026#34;: [ { \u0026#34;direction\u0026#34;: \u0026#34;←\u0026#34;, \u0026#34;other\u0026#34;: \u0026#34;shop.api\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;charge\u0026#34; }, { \u0026#34;direction\u0026#34;: \u0026#34;→\u0026#34;, \u0026#34;other\u0026#34;: \u0026#34;paymentservice.ledger\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;INSERT payment\u0026#34; }, { \u0026#34;direction\u0026#34;: \u0026#34;→\u0026#34;, \u0026#34;other\u0026#34;: \u0026#34;shop.db\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;audit log\u0026#34; } ], \u0026#34;views\u0026#34;: [\u0026#34;payment-view\u0026#34;, \u0026#34;system-overview\u0026#34;] } find + show: Typische Kombination Ein unbekanntes Modell erkunden:\n# 1. Wonach suche ich? bausteinsicht find auth # 2. Interessantes Element gefunden — Details anzeigen bausteinsicht show authservice # 3. Abhängige Elemente erkunden bausteinsicht show shop.frontend # hat authservice als Beziehung Für LLM-Workflows (→ Teil 10):\n# Kontext für LLM aufbauen bausteinsicht find payment --format json | \\ xargs -I{} bausteinsicht show {} --format json Unterschied zu bausteinsicht status find status Freitext-Suche über alle Felder\nListe nach Lifecycle-Status gefiltert\nGut für: unbekannte Modelle erkunden\nGut für: \u0026#34;Welche Elemente sind gerade in Entwicklung?\u0026#34;\nBeispiel-Modell Das Beispiel für diesen Teil (Modell mit aussagekräftigen Beschreibungen für bausteinsicht find) liegt unter teil_22.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_22.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWas als nächstes kommt Teil 23: Tags \u0026amp; View-Filterung — Elemente mit Tags organisieren und Views gezielt filtern\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-find-show/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-as-is-to-be/\"\u003eeinundzwanzigsten Teil\u003c/a\u003e fort.\nIn wachsenden Modellen verliert man schnell den Überblick.\n\u003ccode\u003ebausteinsicht find\u003c/code\u003e und \u003ccode\u003ebausteinsicht show\u003c/code\u003e sind die zwei Navigationsbefehle: suchen und inspizieren.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_bausteinsicht_find\"\u003ebausteinsicht find\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003efind\u003c/code\u003e durchsucht alle Elemente, Beziehungen und Views nach einem Begriff.\nDie Suche ist case-insensitiv, partiell und verwendet AND-Semantik bei mehreren Wörtern.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e# Alle Treffer für \u0026#34;payment\u0026#34;\nbausteinsicht find payment\n\n# AND-Suche: alle Treffer die \u0026#34;payment\u0026#34; UND \u0026#34;service\u0026#34; enthalten\nbausteinsicht find payment service\n\n# Nur Elemente (keine Relationships oder Views)\nbausteinsicht find payment --type element\n\n# Nur Beziehungen\nbausteinsicht find charge --type relationship\n\n# Nur Views\nbausteinsicht find overview --type view\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 22: find \u0026 show — Das Modell navigieren und Elemente erkunden"},{"content":" Dieser Post setzt den zweiundzwanzigsten Teil fort. In komplexen Modellen mit vielen Elementen wird include in Views schnell zur langen Liste. Tags lösen das: Elemente bekommen semantische Labels, Views filtern nach diesen Labels.\nTags in der Specification definieren Tags werden in specification.tags definiert — mit optionalem Style für draw.io:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;team-backend\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Elemente des Backend-Teams\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;team-frontend\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Elemente des Frontend-Teams\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Externe Systeme und Drittanbieter\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#dae8fc\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#6c8ebf\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;critical\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Kritische Systeme im Zahlungspfad\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#ffe6cc\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#d6b656\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;gdpr\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Verarbeitet personenbezogene Daten\u0026#34; } ] } } Das style-Feld überschreibt die draw.io-Farben für alle Elemente mit diesem Tag — ein visuelles Team-Coding direkt aus der Spezifikation.\nElemente taggen Tags werden als Array im Element gesetzt:\n{ \u0026#34;model\u0026#34;: { \u0026#34;authservice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;team-backend\u0026#34;, \u0026#34;critical\u0026#34;, \u0026#34;gdpr\u0026#34;] }, \u0026#34;shop-frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;frontend\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop Frontend\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;team-frontend\u0026#34;] }, \u0026#34;stripe\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Stripe\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;, \u0026#34;critical\u0026#34;] }, \u0026#34;shop-api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop API\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;team-backend\u0026#34;, \u0026#34;critical\u0026#34;] } } } bausteinsicht validate prüft dass alle verwendeten Tag-IDs in specification.tags definiert sind.\nViews mit Tags filtern Statt include mit expliziten Element-IDs können Views Tags als Filter nutzen:\nfilter-tags: Nur Elemente MIT diesen Tags { \u0026#34;views\u0026#34;: { \u0026#34;backend-team-view\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Backend-Team Architektur\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;team-backend\u0026#34;] }, \u0026#34;critical-payment-path\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Kritischer Zahlungspfad\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;critical\u0026#34;] }, \u0026#34;gdpr-scope\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;DSGVO-relevante Elemente\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;gdpr\u0026#34;] } } } filter-tags verwendet AND-Semantik bei mehreren Tags:\n{ \u0026#34;critical-backend\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Kritische Backend-Services\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;team-backend\u0026#34;, \u0026#34;critical\u0026#34;] } } exclude-tags: Elemente OHNE diese Tags { \u0026#34;internal-only\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Interne Systeme\u0026#34;, \u0026#34;exclude-tags\u0026#34;: [\u0026#34;external\u0026#34;] } } Kombiniert mit include und scope Tags-Filter können mit include, scope und exclude kombiniert werden:\n{ \u0026#34;shop-backend-detail\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Shop Backend Detail\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;team-backend\u0026#34;], \u0026#34;exclude-tags\u0026#34;: [\u0026#34;archived\u0026#34;] } } Diese View zeigt: Elemente unter shop.* die team-backend haben aber nicht archived sind.\nTags als Cross-Cutting Concerns Tags eignen sich besonders für Querschnittsthemen die sich über Team- und Systemgrenzen ziehen:\nTag Typische Verwendung gdpr\nDatenschutz-Review: alle datenverarbeitenden Elemente auf einen Blick\ncritical\nIncident-Response: sofort sehen welche Systeme zum kritischen Pfad gehören\nteam-X\nTeam-spezifische Views ohne manuelle Pflege der include-Listen\ndeprecated\nAblösungs-Planung: alle veralteten Elemente gezielt anzeigen\nTags in specification.tags müssen explizit definiert werden — validate lehnt unbekannte Tag-IDs in Elementen ab. Das verhindert Tippfehler und hält die Tag-Liste konsistent. Tags im Exportformat Beim Export (→ Teil 6) werden Tags in der Tabellen-Ausgabe mitgeführt:\nbausteinsicht export-table --format csv # → id, kind, title, technology, tags, status, ... So lassen sich DSGVO-Audits, Team-Inventare oder Security-Reviews direkt aus dem Modell als CSV generieren.\nBeispiel-Modell Das Beispiel für diesen Teil (Tags mit Styles, filter-tags und exclude-tags in Views) liegt unter teil_23.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_23.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram (Context View mit externen Systemen):\nWeiter geht es mit CI/CD Tags und Filterung sind mächtig — aber ein Modell das nur lokal validiert wird, ist erst halb abgesichert. Im nächsten Teil geht es darum wie validate, diff und export in GitHub Actions eingebunden werden: automatische Prüfung als Build-Gate, Modell-Diff im Pull Request und SVG-Export nach jedem Push.\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-tags-view-filterung/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-find-show/\"\u003ezweiundzwanzigsten Teil\u003c/a\u003e fort.\nIn komplexen Modellen mit vielen Elementen wird \u003ccode\u003einclude\u003c/code\u003e in Views schnell zur langen Liste.\nTags lösen das: Elemente bekommen semantische Labels, Views filtern nach diesen Labels.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_tags_in_der_specification_definieren\"\u003eTags in der Specification definieren\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eTags werden in \u003ccode\u003especification.tags\u003c/code\u003e definiert — mit optionalem Style für draw.io:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e{\n  \u0026#34;specification\u0026#34;: {\n    \u0026#34;tags\u0026#34;: [\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;team-backend\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;Elemente des Backend-Teams\u0026#34;\n      },\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;team-frontend\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;Elemente des Frontend-Teams\u0026#34;\n      },\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;external\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;Externe Systeme und Drittanbieter\u0026#34;,\n        \u0026#34;style\u0026#34;: {\n          \u0026#34;fillColor\u0026#34;: \u0026#34;#dae8fc\u0026#34;,\n          \u0026#34;strokeColor\u0026#34;: \u0026#34;#6c8ebf\u0026#34;\n        }\n      },\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;critical\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;Kritische Systeme im Zahlungspfad\u0026#34;,\n        \u0026#34;style\u0026#34;: {\n          \u0026#34;fillColor\u0026#34;: \u0026#34;#ffe6cc\u0026#34;,\n          \u0026#34;strokeColor\u0026#34;: \u0026#34;#d6b656\u0026#34;\n        }\n      },\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;gdpr\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;Verarbeitet personenbezogene Daten\u0026#34;\n      }\n    ]\n  }\n}\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 23: Tags \u0026 View-Filterung — Elemente organisieren und Views gezielt befüllen"},{"content":" Dieser Post setzt den dreiundzwanzigsten Teil fort. Ein Architekturmodell das nur lokal validiert wird, ist erst halb abgesichert. Sobald mehrere Personen am Modell arbeiten, braucht es CI: automatische Prüfung bei jedem Push, sichtbarer Diff bei jedem Pull Request.\nBausteinsicht in der Pipeline installieren GitHub Actions stellt keine Bausteinsicht-Action bereit — die Installation erfolgt manuell per curl:\n- name: Install Bausteinsicht run: | curl -Lo bausteinsicht.tar.gz \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz tar xzf bausteinsicht.tar.gz sudo mv bausteinsicht /usr/local/bin/ bausteinsicht --version Für reproduzierbare Builds empfiehlt sich eine fixe Version statt latest:\nhttps://github.com/docToolchain/Bausteinsicht/releases/download/v0.5.0/bausteinsicht_linux_amd64.tar.gz validate als Build-Gate bausteinsicht validate gibt Exit-Code 1 zurück wenn das Modell Fehler enthält — GitHub Actions bricht den Job ab:\nname: Architecture Validation on: [push, pull_request] jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Bausteinsicht run: | curl -Lo bausteinsicht.tar.gz \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ - name: Validate architecture model run: bausteinsicht validate --format json working-directory: architecture/ Mit --format json landet die Ausgabe als strukturiertes JSON auf stdout — leichter zu parsen wenn man die Fehlerliste weiterverarbeiten will.\nWas validate prüft (→ Teil 8):\nAlle Element-IDs in Beziehungen und Views existieren im Modell\nAlle verwendeten Tag-IDs sind in specification.tags definiert\nKein Element referenziert einen unbekannten Typen\nViews haben keinen leeren include-Block\ndiff im Pull Request bausteinsicht diff vergleicht zwei Modellzustände und zeigt welche Elemente, Beziehungen und Views sich geändert haben. Im PR-Kontext ist HEAD~1 vs HEAD der sinnvolle Vergleich:\n- name: Compute model diff id: diff working-directory: architecture/ run: | DIFF=$(bausteinsicht diff HEAD~1 HEAD --format json 2\u0026gt;/dev/null || echo \u0026#39;{}\u0026#39;) echo \u0026#34;result=$DIFF\u0026#34; \u0026gt;\u0026gt; $GITHUB_OUTPUT - name: Comment diff on PR if: github.event_name == \u0026#39;pull_request\u0026#39; uses: actions/github-script@v7 with: script: | const diff = JSON.parse(\u0026#39;${{ steps.diff.outputs.result }}\u0026#39;); if (!diff.changes || diff.changes.length === 0) return; const body = [ \u0026#39;## 🏗 Architektur-Änderungen\u0026#39;, diff.changes.map(c =\u0026gt; `- **${c.type}** \\`${c.id}\\`: ${c.description}`).join(\u0026#39;\\n\u0026#39;) ].join(\u0026#39;\\n\u0026#39;); github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body }); Für das allererste Commit im Branch (HEAD~1 existiert nicht) gibt diff einen Fehler zurück — der || echo \u0026#39;{}\u0026#39; fängt das ab. SVG-Export nach jedem Push Architekturdiagramme als SVG im Repository zu haben bedeutet: Previews in GitHub, direkte Einbindung in Dokumentation, keine lokale Installation nötig um die Diagramme zu sehen.\n- name: Export architecture diagrams run: bausteinsicht export --format svg --output out/ working-directory: architecture/ - name: Upload SVG artifacts uses: actions/upload-artifact@v4 with: name: architecture-diagrams path: architecture/out/*.svg retention-days: 30 Optional: die exportierten SVGs direkt zurück in den Branch committen:\n- name: Commit exported SVGs if: github.ref == \u0026#39;refs/heads/main\u0026#39; \u0026amp;\u0026amp; github.event_name == \u0026#39;push\u0026#39; run: | git config user.name \u0026#34;github-actions[bot]\u0026#34; git config user.email \u0026#34;github-actions[bot]@users.noreply.github.com\u0026#34; git add architecture/out/*.svg git diff --staged --quiet || git commit -m \u0026#34;chore: update architecture diagrams [skip ci]\u0026#34; git push Das [skip ci] verhindert eine Endlosschleife: der Commit durch Actions triggert keinen neuen CI-Lauf.\nVollständiger Workflow name: Architecture CI on: push: paths: - \u0026#39;architecture/**\u0026#39; pull_request: paths: - \u0026#39;architecture/**\u0026#39; jobs: architecture: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v4 with: fetch-depth: 2 # für diff HEAD~1 - name: Install Bausteinsicht run: | curl -Lo bausteinsicht.tar.gz \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ - name: Validate model run: bausteinsicht validate --format json working-directory: architecture/ - name: Compute diff (PR only) if: github.event_name == \u0026#39;pull_request\u0026#39; id: diff working-directory: architecture/ run: | DIFF=$(bausteinsicht diff HEAD~1 HEAD --format json 2\u0026gt;/dev/null || echo \u0026#39;{}\u0026#39;) echo \u0026#34;result=$DIFF\u0026#34; \u0026gt;\u0026gt; $GITHUB_OUTPUT - name: Comment diff on PR if: github.event_name == \u0026#39;pull_request\u0026#39; uses: actions/github-script@v7 with: script: | const diff = JSON.parse(\u0026#39;${{ steps.diff.outputs.result }}\u0026#39;); if (!diff.changes || diff.changes.length === 0) return; const body = [ \u0026#39;## 🏗 Architektur-Änderungen\u0026#39;, diff.changes.map(c =\u0026gt; `- **${c.type}** \\`${c.id}\\`: ${c.description}`).join(\u0026#39;\\n\u0026#39;) ].join(\u0026#39;\\n\u0026#39;); github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body }); - name: Export SVGs run: bausteinsicht export --format svg --output out/ working-directory: architecture/ - name: Commit SVGs to main if: github.ref == \u0026#39;refs/heads/main\u0026#39; \u0026amp;\u0026amp; github.event_name == \u0026#39;push\u0026#39; run: | git config user.name \u0026#34;github-actions[bot]\u0026#34; git config user.email \u0026#34;github-actions[bot]@users.noreply.github.com\u0026#34; git add architecture/out/*.svg git diff --staged --quiet || git commit -m \u0026#34;chore: update architecture diagrams [skip ci]\u0026#34; git push paths: [\u0026#39;architecture/**\u0026#39;] sorgt dafür dass der Workflow nur läuft wenn tatsächlich etwas am Modell geändert wurde — nicht bei jedem Commit. Beispiel-Modell Das Beispiel für diesen Teil (Modell mit Developer- und CI/CD-Aktoren) liegt unter teil_24.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_24.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWeiter geht es mit Migration CI sichert das bestehende Modell ab. Aber was ist wenn man von einem anderen Tool kommt? Im nächsten Teil geht es darum wie man von draw.io, PlantUML und Structurizr zu Bausteinsicht migriert — was automatisch geht und was manuell überführt werden muss.\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-cicd-integration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-tags-view-filterung/\"\u003edreiundzwanzigsten Teil\u003c/a\u003e fort.\nEin Architekturmodell das nur lokal validiert wird, ist erst halb abgesichert.\nSobald mehrere Personen am Modell arbeiten, braucht es CI: automatische Prüfung bei jedem Push, sichtbarer Diff bei jedem Pull Request.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_bausteinsicht_in_der_pipeline_installieren\"\u003eBausteinsicht in der Pipeline installieren\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eGitHub Actions stellt keine Bausteinsicht-Action bereit — die Installation erfolgt manuell per curl:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e- name: Install Bausteinsicht\n  run: |\n    curl -Lo bausteinsicht.tar.gz \\\n      https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz\n    tar xzf bausteinsicht.tar.gz\n    sudo mv bausteinsicht /usr/local/bin/\n    bausteinsicht --version\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 24: CI/CD Integration — validate, diff und Export in GitHub Actions"},{"content":" Dieser Post setzt den vierundzwanzigsten Teil fort. In den meisten Projekten gibt es schon Architekturdokumentation — als draw.io-Datei im Wiki, als PlantUML im Repository oder als Structurizr-DSL. Migration bedeutet nicht: alles wegwerfen. Es bedeutet: den richtigen Anfang finden.\nDie Ausgangslage verstehen Bevor man migriert, lohnt sich eine ehrliche Bestandsaufnahme:\nTool Was ist da Aufwand Native draw.io (kein Modell dahinter)\nNur Diagramme, kein Datenmodell — die Elemente existieren nur als Shapes\nHoch: Modell muss von Grund auf aufgebaut werden\nPlantUML C4\nStrukturiertes Textmodell — Typen, Elemente, Beziehungen sind explizit\nMittel: Import-Script oder manueller Transfer möglich\nStructurizr DSL\nVollständiges Modell mit Elementen, Beziehungen, Views\nMittel: strukturell ähnlich zu Bausteinsicht JSONC\nConfluence-Diagramme / Powerpoint\nNur Bilder, kein maschinenlesbares Modell\nSehr hoch: Neuerstellen empfohlen\nSchritt 1: Bausteinsicht init als Startpunkt Unabhängig vom Ausgangstool immer zuerst:\nmkdir architecture \u0026amp;\u0026amp; cd architecture bausteinsicht init init erstellt ein Beispielmodell mit korrekter Grundstruktur — specification, model, views — und eine leere architecture.drawio. Das gibt einem die richtige Ausgangsbasis ohne von vorne anzufangen.\nDann: das generierte Beispielmodell löschen (aber specification.elements und specification.relationships als Vorlage behalten) und das eigene Modell aufbauen.\nVon draw.io migrieren Draw.io ohne Modell dahinter ist das häufigste Szenario. Der Ansatz: das bestehende Diagramm als visuelle Referenz nehmen, das JSONC-Modell davon ableiten.\nSchritt 1: Bestehende draw.io-Datei öffnen, alle vorhandenen Elementtypen und Beziehungsarten identifizieren.\nSchritt 2: Diese Typen in specification überführen:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;service\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Service\u0026#34; }, \u0026#34;database\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Database\u0026#34; }, \u0026#34;frontend\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Frontend\u0026#34; }, \u0026#34;external\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;External System\u0026#34; } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; }, \u0026#34;stores\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;stores data in\u0026#34; }, \u0026#34;calls\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;calls\u0026#34; } } } } Schritt 3: Elemente und Beziehungen aus dem Diagramm in model überführen:\n{ \u0026#34;model\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;shop-api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;shop-frontend\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;frontend\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Frontend\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;React\u0026#34; }, \u0026#34;shop-db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } } }, \u0026#34;payment\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Stripe\u0026#34; } } } Schritt 4: Views definieren die ungefähr den bestehenden Diagramm-Seiten entsprechen.\nSchritt 5: bausteinsicht sync — Bausteinsicht erstellt draw.io-Shapes für alle Elemente. Dann Positionen aus dem Originaldiagramm manuell übertragen. Das ist Handarbeit, aber einmalig.\nNicht versuchen, das Originallayout pixelgenau zu rekonstruieren. Auto-Layout (→ Teil 14) danach neu anwenden ist oft der schnellere Weg. Von PlantUML C4 migrieren PlantUML C4 hat bereits ein strukturiertes Modell. Der Transfer ist mechanisch:\nWird zu:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;person\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Person\u0026#34; }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;external\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;External System\u0026#34; } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; } } }, \u0026#34;model\u0026#34;: { \u0026#34;user\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;person\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Benutzer\u0026#34; }, \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34; }, \u0026#34;payment\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Stripe\u0026#34; } } } Für größere Modelle lohnt sich ein kleines Konvertier-Script (Python, awk) das die System(…​) und Rel(…​) Aufrufe parst und JSONC-Fragmente ausgibt.\nVon Structurizr DSL migrieren Structurizr DSL ist strukturell am nächsten an Bausteinsicht JSONC. Die Konzepte sind direkt übertragbar:\nStructurizr DSL Bausteinsicht JSONC softwareSystem \u0026#34;Name\u0026#34;\n{ \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Name\u0026#34; }\ncontainer \u0026#34;Name\u0026#34; \u0026#34;Description\u0026#34; \u0026#34;Technology\u0026#34;\n{ \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Name\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Technology\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Description\u0026#34; }\nrelationship → target \u0026#34;Label\u0026#34;\n{ \u0026#34;from\u0026#34;: \u0026#34;source\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;target\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Label\u0026#34; }\nsystemContext view { include * }\n{ \u0026#34;include\u0026#34;: [\u0026#34;*\u0026#34;] } in Views\nstyles { element \u0026#34;System\u0026#34; { …​ } }\nspecification.elements.system.style: { …​ }\nDas Haupt-Delta: Structurizr unterstützt implizite Elemente in Views (include *), Bausteinsicht arbeitet mit expliziten IDs oder Tags.\nView-by-View-Strategie statt Big Bang Der häufigste Fehler bei Migration: versuchen alles auf einmal zu überführen.\nBesser:\nEine View migrieren — die wichtigste System-Context-View\nbausteinsicht sync und validate — prüfen dass das Modell konsistent ist\nIm Parallelbetrieb arbeiten — Bausteinsicht-Modell und altes Tool parallel pflegen bis das neue stabil ist\nNächste View migrieren — schrittweise, nach Priorität\nDas kostet mehr Zeit über die gesamte Migration, aber minimiert das Risiko: zu jedem Zeitpunkt gibt es eine funktionierende Dokumentation.\nFallstricke Relationship Lifting: Bausteinsicht hebt Beziehungen automatisch auf das nächste sichtbare Elternelement an (→ Teil 3). In PlantUML oder draw.io gibt es das nicht — Beziehungen die im Originaltool explizit eingetragen waren, erscheinen in Bausteinsicht in einer abstrakteren View eventuell zusammengefasst. Das ist kein Bug, sondern Feature — aber man muss es bei der Überprüfung kennen.\nFehlende Typdefinitionen: Wenn das Originaltool keine Typen erzwingt (draw.io), ist die specification schnell unvollständig. validate hilft dabei alle verwendeten aber undeklarierten Typen zu finden.\nIDs sind stabil, Titel nicht: In Bausteinsicht ist die Element-ID der stabile Schlüssel. Titel können geändert werden. In Migrationen aus Tools ohne IDs (draw.io) muss man IDs bewusst vergeben — und sie dann konsequent beibehalten.\nBeispiel-Modell Das Beispiel für diesen Teil (aus Structurizr/draw.io migriertes Modell mit Legacy-ERP-Anbindung) liegt unter teil_25.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_25.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWeiter geht es mit Team-Workflows Eine Migration ist selten ein Solo-Projekt. Im nächsten Teil geht es darum wie mehrere Personen gleichzeitig am Modell arbeiten — Merge-Konflikte in JSONC, Ownership-Conventions und der Review-Prozess für Architekturänderungen.\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-migration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-cicd-integration/\"\u003evierundzwanzigsten Teil\u003c/a\u003e fort.\nIn den meisten Projekten gibt es schon Architekturdokumentation — als draw.io-Datei im Wiki,\nals PlantUML im Repository oder als Structurizr-DSL.\nMigration bedeutet nicht: alles wegwerfen. Es bedeutet: den richtigen Anfang finden.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_die_ausgangslage_verstehen\"\u003eDie Ausgangslage verstehen\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBevor man migriert, lohnt sich eine ehrliche Bestandsaufnahme:\u003c/p\u003e\n\u003c/div\u003e\n\u003ctable class=\"tableblock frame-all grid-all stretch\"\u003e\n\u003ccolgroup\u003e\n\u003ccol style=\"width: 25%;\"/\u003e\n\u003ccol style=\"width: 50%;\"/\u003e\n\u003ccol style=\"width: 25%;\"/\u003e\n\u003c/colgroup\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eTool\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eWas ist da\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eAufwand\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eNative draw.io (kein Modell dahinter)\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eNur Diagramme, kein Datenmodell — die Elemente existieren nur als Shapes\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eHoch: Modell muss von Grund auf aufgebaut werden\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003ePlantUML C4\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eStrukturiertes Textmodell — Typen, Elemente, Beziehungen sind explizit\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eMittel: Import-Script oder manueller Transfer möglich\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eStructurizr DSL\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eVollständiges Modell mit Elementen, Beziehungen, Views\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eMittel: strukturell ähnlich zu Bausteinsicht JSONC\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eConfluence-Diagramme / Powerpoint\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eNur Bilder, kein maschinenlesbares Modell\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eSehr hoch: Neuerstellen empfohlen\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Teil 25: Migration — Von draw.io, PlantUML und Structurizr zu Bausteinsicht"},{"content":" Dieser Post setzt den fünfundzwanzigsten Teil fort. Ein Architekturmodell das nur eine Person pflegt, hat kein Merge-Problem. Sobald mehrere Teams am gleichen Repository arbeiten, ändert sich das. Bausteinsicht bringt dafür gute Voraussetzungen mit — aber man muss wissen wo die Grenzen liegen.\nWas in JSONC gut mergebar ist JSONC ist ein Textformat. Git merged Textdateien zeilenbasiert. Das bedeutet:\nGut mergebar:\nNeue Elemente hinzufügen in model — solange die Elemente unterschiedliche IDs haben, sind das verschiedene Zeilen ohne Überschneidung\nNeue Views hinzufügen in views — analoges Prinzip\nNeue Tags in specification.tags ergänzen\nKonfliktanfällig:\nDasselbe Element gleichzeitig ändern (title, description, technology)\nDie Reihenfolge von Elementen ändern — Git sieht das als Löschung + Einfügung\nspecification.elements und specification.relationships — diese Bereiche werden seltener geändert, aber wenn, dann oft von mehreren gleichzeitig\ndraw.io XML ist schwieriger: Die .drawio-Datei enthält XML mit IDs und Positionen. Merge-Konflikte dort sind schwerer aufzulösen als JSONC. Faustregel: das JSONC-Modell ist der Wahrheitsspeicher, die draw.io-Datei ist regenerierbar per sync.\nOwnership-Conventions In einem größeren System hat jedes Team einen Bereich im Modell den es pflegt. Conventions helfen dabei Konflikte strukturell zu vermeiden, nicht nur zu reparieren.\nEmpfehlung: Element-IDs mit Team-Präfix:\n{ \u0026#34;model\u0026#34;: { \u0026#34;backend.auth-service\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34; }, \u0026#34;backend.user-service\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;User Service\u0026#34; }, \u0026#34;frontend.shop-ui\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;frontend\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Shop UI\u0026#34; }, \u0026#34;infra.postgres\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } } } Das Backend-Team ändert backend., das Frontend-Team ändert frontend.. Beziehungen zwischen Teams — backend.auth-service → infra.postgres — liegen im Einflussbereich des Consumers (wer die Beziehung initiiert, definiert sie).\nCODEOWNERS-Datei: In GitHub lässt sich das mit CODEOWNERS durchsetzen:\n# CODEOWNERS architecture/ @architecture-team # jede Änderung braucht Review Oder feiner (wenn das Modell aufgeteilt ist):\narchitecture/specification/ @all-teams architecture/model/backend/ @backend-team architecture/model/frontend/ @frontend-team Bausteinsicht speichert alles in einer JSONC-Datei. Wenn Teams wirklich unabhängig arbeiten wollen, ist das Workspace-Feature (Teil 16) die Lösung — separate Modelle mit expliziten Querverweisen. Merge-Konflikte auflösen Ein typischer JSONC-Konflikt sieht so aus:\n{ \u0026#34;model\u0026#34;: { \u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt;\u0026lt; HEAD \u0026#34;backend.auth-service\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Authentication Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, ======= \u0026#34;backend.auth-service\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;service\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Auth Service\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go 1.22\u0026#34; }, \u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u0026gt; feature/update-auth } } Strategie:\nKonflikt in einem JSON-Editor öffnen (kein reines Text-Merge)\nInhaltliche Entscheidung treffen — welcher Titel, welche Technology-Version?\nManuell zusammenführen, bausteinsicht validate ausführen\nWenn draw.io-Datei ebenfalls Konflikt hat: verwerfen und bausteinsicht sync neu ausführen — die JSONC-Seite ist der Wahrheitsspeicher\nbausteinsicht validate --format json nach jedem Merge ausführen. Der Exit-Code 1 bei Fehlern verhindert dass ein kaputtes Modell in main landet. Architektur-Review im Pull Request Architekturänderungen im PR sichtbar zu machen ist der eigentliche Vorteil von Architecture-as-Code.\nWorkflow:\nEntwickler öffnet Feature-Branch, ändert das Modell\nCI führt bausteinsicht validate und bausteinsicht diff aus (→ Teil 24)\nDiff-Output erscheint als PR-Kommentar: welche Elemente wurden hinzugefügt, geändert, entfernt\nReviewer sieht die Architekturänderung direkt im PR ohne lokale Installation\nWas ein guter Architektur-PR enthält:\nNur Änderungen am Modell die zum Feature passen — kein Refactoring im gleichen PR\nvalidate-Ergebnis ist grün\nBeschreibung die erklärt warum das Modell so geändert wurde, nicht nur was\nWann braucht eine Änderung ein Review?\nÄnderung Review nötig? Neues Blatt-Element im bestehenden System\nOptional — Team-internes Review reicht\nNeue externe Abhängigkeit\nJa — betrifft andere Teams\nÄnderung in specification (neue Elementtypen)\nJa — ändert das Schema für alle\nView hinzufügen oder entfernen\nOptional — betrifft keine Logik\nElement löschen das andere referenzieren\nJa — validate wird es sowieso anmeckern\nEin realistischer Team-Workflow git checkout -b feature/add-notification-service # Modell ändern: notification-service zu model hinzufügen # Beziehungen: shop-api → notification-service, notification-service → sendgrid bausteinsicht validate # lokal prüfen bausteinsicht sync # draw.io aktualisieren git add architecture/ git commit -m \u0026#34;arch: add notification service\u0026#34; git push \u0026amp;\u0026amp; gh pr create CI validiert, diff zeigt: - ` Element `notification-service` (kind: service) - ` Element sendgrid (kind: external) - ` Relationship `shop-api` → `notification-service` - ` Relationship notification-service → sendgrid\nReviewer sieht genau was sich architektonisch geändert hat — ohne die draw.io-Datei öffnen zu müssen.\nBeispiel-Modell Das Beispiel für diesen Teil (Team-Ownership per Tags, separate Team-Views) liegt unter teil_26.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_26.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWeiter geht es mit Custom Notations Sobald Teams eigene Sprache mitbringen — AUTOSAR-Komponenten, Hardware-Elemente, Domain-spezifische Konzepte — reicht die Standard-C4-Notation nicht mehr. Im nächsten Teil geht es darum wie man eigene Elementtypen mit eigenen Shapes in draw.io definiert.\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-team-workflows/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-migration/\"\u003efünfundzwanzigsten Teil\u003c/a\u003e fort.\nEin Architekturmodell das nur eine Person pflegt, hat kein Merge-Problem.\nSobald mehrere Teams am gleichen Repository arbeiten, ändert sich das.\nBausteinsicht bringt dafür gute Voraussetzungen mit — aber man muss wissen wo die Grenzen liegen.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_in_jsonc_gut_mergebar_ist\"\u003eWas in JSONC gut mergebar ist\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eJSONC ist ein Textformat. Git merged Textdateien zeilenbasiert. Das bedeutet:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cstrong\u003eGut mergebar:\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eNeue Elemente hinzufügen in \u003ccode\u003emodel\u003c/code\u003e — solange die Elemente unterschiedliche IDs haben, sind das verschiedene Zeilen ohne Überschneidung\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eNeue Views hinzufügen in \u003ccode\u003eviews\u003c/code\u003e — analoges Prinzip\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eNeue Tags in \u003ccode\u003especification.tags\u003c/code\u003e ergänzen\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Teil 26: Team-Workflows — Merge-Konflikte, Ownership und Architektur-Reviews im PR"},{"content":" Dieser Post setzt den sechsundzwanzigsten Teil fort. C4 ist ein guter Ausgangspunkt — aber viele Domänen haben eigene Konzepte die sich in Software System, Container und Component nicht sauber abbilden. AUTOSAR hat SWCs, Ports und Runnables. Embedded-Hardware hat MCUs, Peripherals und Busse. Bausteinsicht lässt sich auf diese Sprachen erweitern.\nNeue Elementtypen in specification definieren Jeder neue Elementtyp wird in specification.elements deklariert:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34; }, \u0026#34;swc\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software Component\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;port\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Port\u0026#34; }, \u0026#34;runnable\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Runnable Entity\u0026#34; }, \u0026#34;bsw\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Basic Software Module\u0026#34; }, \u0026#34;mcu\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Microcontroller\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;peripheral\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Peripheral\u0026#34; }, \u0026#34;bus\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Communication Bus\u0026#34; } }, \u0026#34;relationships\u0026#34;: { \u0026#34;provides\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;provides\u0026#34; }, \u0026#34;requires\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;requires\u0026#34; }, \u0026#34;triggers\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;triggers\u0026#34; }, \u0026#34;mapped-to\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;mapped to\u0026#34; } } } } container: true bedeutet dass der Typ Kind-Elemente haben kann. notation ist der Label-Text der in draw.io unter dem Shape erscheint.\nEin AUTOSAR-Modell { \u0026#34;model\u0026#34;: { \u0026#34;ecu\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;mcu\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;ECU — AM335x\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;eth-driver\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;bsw\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;EthIf Driver\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;eth-rx\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;port\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;RxIndication\u0026#34; }, \u0026#34;eth-tx\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;port\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;TxConfirmation\u0026#34; } } }, \u0026#34;ethtrcv-drv\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;swc\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;EthTrcv Driver\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;mdio-port\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;port\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;MDIO Interface\u0026#34; }, \u0026#34;ctrl-port\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;port\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Control Port\u0026#34; } } }, \u0026#34;phy-init\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;runnable\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;EthTrcv_Init\u0026#34; }, \u0026#34;phy-setmode\u0026#34;:{ \u0026#34;kind\u0026#34;: \u0026#34;runnable\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;EthTrcv_SetTransceiverMode\u0026#34; } } }, \u0026#34;phy-chip\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;peripheral\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;PHY TJA1100\u0026#34; }, \u0026#34;mdio-bus\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;bus\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;MDIO Bus\u0026#34; } } } Die Relationships zwischen Ports nutzen die eigenen Typen:\n{ \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;ecu.ethtrcv-drv.mdio-port\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mdio-bus\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;provides\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;mdio-bus\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;phy-chip\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;provides\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;ecu.phy-init\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;phy-chip\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;triggers\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;ecu.ethtrcv-drv\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;ecu.eth-driver\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;requires\u0026#34; } ] } Shapes in draw.io anpassen Bausteinsicht rendert jeden Elementtyp mit einem Standard-Shape (Rechteck). Eigene Shapes kommen über zwei Wege:\nStyle in specification.elements Der einfachste Weg — Style direkt in der Spezifikation:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;mcu\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Microcontroller\u0026#34;, \u0026#34;container\u0026#34;: true, \u0026#34;style\u0026#34;: { \u0026#34;shape\u0026#34;: \u0026#34;mxgraph.cisco.computers_and_peripherals.pc\u0026#34;, \u0026#34;fillColor\u0026#34;: \u0026#34;#1ba1e2\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#006EAF\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, \u0026#34;peripheral\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Peripheral\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;shape\u0026#34;: \u0026#34;mxgraph.cisco.computers_and_peripherals.generic_processor\u0026#34;, \u0026#34;fillColor\u0026#34;: \u0026#34;#d5e8d4\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#82b366\u0026#34; } }, \u0026#34;bus\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Communication Bus\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;shape\u0026#34;: \u0026#34;mxgraph.cisco.network_management.generic_manageable_hub\u0026#34;, \u0026#34;fillColor\u0026#34;: \u0026#34;#fff2cc\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#d6b656\u0026#34; } } } } } Die Shape-Namen kommen aus der draw.io Shape-Library — im draw.io-Editor ein Shape suchen, Rechtsklick → \u0026#34;Edit Style\u0026#34; zeigt den Namen.\nTags für visuelle Codierung Wenn Shapes zu aufwändig sind, reicht oft ein Tag mit Farbe (→ Teil 23):\n{ \u0026#34;specification\u0026#34;: { \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;autosar-ap\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;AUTOSAR Adaptive Platform\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#dae8fc\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#6c8ebf\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;autosar-cp\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;AUTOSAR Classic Platform\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#d5e8d4\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#82b366\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;hardware\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Hardware-Element\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#ffe6cc\u0026#34;, \u0026#34;strokeColor\u0026#34;: \u0026#34;#d6b656\u0026#34; } } ] } } Elemente bekommen dann \u0026#34;tags\u0026#34;: [\u0026#34;autosar-cp\u0026#34;] und werden automatisch in der richtigen Farbe dargestellt.\nGrenzen der Custom Notation Was Bausteinsicht heute nicht unterstützt:\nEigene Validation-Regeln für neue Typen (z.B. \u0026#34;jede SWC muss mindestens einen Port haben\u0026#34;) — das muss extern geprüft werden\nTypabhängige Beziehungsregeln (z.B. \u0026#34;Port darf nur zu Bus verbunden werden, nicht zu System\u0026#34;) — validate prüft nur ob IDs existieren, nicht ob Typen zusammenpassen\nHierarchieregeln (z.B. \u0026#34;Runnable nur innerhalb SWC\u0026#34;) — container: true erlaubt beliebige Kinder-Typen\nFür diese Prüfungen kann man bausteinsicht export-table --format json verwenden und die Ausgabe in einem separaten Script validieren.\nEine vollständige Domain-Notation: Embedded-Hardware { \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;board\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;PCB\u0026#34;, \u0026#34;container\u0026#34;: true, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#1ba1e2\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, \u0026#34;mcu\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;MCU\u0026#34;, \u0026#34;container\u0026#34;: true, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#0e6655\u0026#34; , \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, \u0026#34;peripheral\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Peripheral\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#d5e8d4\u0026#34; } }, \u0026#34;memory\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Memory\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#fff2cc\u0026#34; } }, \u0026#34;bus\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Bus\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;shape\u0026#34;: \u0026#34;mxgraph.cisco.network_management.generic_manageable_hub\u0026#34; } }, \u0026#34;connector\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Connector\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;shape\u0026#34;: \u0026#34;rhombus\u0026#34; } } }, \u0026#34;relationships\u0026#34;: { \u0026#34;connected-via\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;via\u0026#34; }, \u0026#34;controls\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;controls\u0026#34; }, \u0026#34;mapped-to\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;mapped to\u0026#34; } } } } Damit lassen sich Hardware-Architekturen mit denselben Werkzeugen beschreiben wie Software-Architekturen — sync, validate, diff, export funktionieren identisch.\nBeispiel-Modell Das Beispiel für diesen Teil (benutzerdefinierte Notationen: Browser, Hexagon, Gear, Queue, Cylinder, Cloud) liegt unter teil_27.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_27.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram:\nWeiter geht es mit Performance Eigene Notationen führen oft zu größeren Modellen — mehr Typen, mehr Elemente. Im nächsten Teil geht es darum wie man mit 50+ Elementen umgeht ohne die Übersicht zu verlieren.\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-custom-notations/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-team-workflows/\"\u003esechsundzwanzigsten Teil\u003c/a\u003e fort.\nC4 ist ein guter Ausgangspunkt — aber viele Domänen haben eigene Konzepte die sich in Software System, Container und Component nicht sauber abbilden.\nAUTOSAR hat SWCs, Ports und Runnables. Embedded-Hardware hat MCUs, Peripherals und Busse.\nBausteinsicht lässt sich auf diese Sprachen erweitern.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_neue_elementtypen_in_specification_definieren\"\u003eNeue Elementtypen in specification definieren\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eJeder neue Elementtyp wird in \u003ccode\u003especification.elements\u003c/code\u003e deklariert:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"listingblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cpre class=\"highlight\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e{\n  \u0026#34;specification\u0026#34;: {\n    \u0026#34;elements\u0026#34;: {\n      \u0026#34;system\u0026#34;:      { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true },\n      \u0026#34;container\u0026#34;:   { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34; },\n\n      \u0026#34;swc\u0026#34;:         { \u0026#34;notation\u0026#34;: \u0026#34;Software Component\u0026#34;, \u0026#34;container\u0026#34;: true },\n      \u0026#34;port\u0026#34;:        { \u0026#34;notation\u0026#34;: \u0026#34;Port\u0026#34; },\n      \u0026#34;runnable\u0026#34;:    { \u0026#34;notation\u0026#34;: \u0026#34;Runnable Entity\u0026#34; },\n      \u0026#34;bsw\u0026#34;:         { \u0026#34;notation\u0026#34;: \u0026#34;Basic Software Module\u0026#34; },\n\n      \u0026#34;mcu\u0026#34;:         { \u0026#34;notation\u0026#34;: \u0026#34;Microcontroller\u0026#34;, \u0026#34;container\u0026#34;: true },\n      \u0026#34;peripheral\u0026#34;:  { \u0026#34;notation\u0026#34;: \u0026#34;Peripheral\u0026#34; },\n      \u0026#34;bus\u0026#34;:         { \u0026#34;notation\u0026#34;: \u0026#34;Communication Bus\u0026#34; }\n    },\n    \u0026#34;relationships\u0026#34;: {\n      \u0026#34;provides\u0026#34;:    { \u0026#34;notation\u0026#34;: \u0026#34;provides\u0026#34; },\n      \u0026#34;requires\u0026#34;:    { \u0026#34;notation\u0026#34;: \u0026#34;requires\u0026#34; },\n      \u0026#34;triggers\u0026#34;:    { \u0026#34;notation\u0026#34;: \u0026#34;triggers\u0026#34; },\n      \u0026#34;mapped-to\u0026#34;:   { \u0026#34;notation\u0026#34;: \u0026#34;mapped to\u0026#34; }\n    }\n  }\n}\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Teil 27: Custom Notations — Eigene Elementtypen, Shapes und Domain-Sprachen"},{"content":" Dieser Post setzt den siebenundzwanzigsten Teil fort. Ein Modell mit 10 Elementen ist einfach. Bei 50+ Elementen stellt sich die Frage: was sieht wer, wann, in welcher View? Und ab wann wird sync und draw.io langsam?\nWann wird ein Modell \u0026#34;groß\u0026#34;? Praktische Grenzwerte:\nElementanzahl Symptom Lösung \u0026lt; 30\nAlles in einer View zeigbar\nEine Hauptview reicht\n30–80\nEine View wird unlesbar — zu viele Shapes\nMehrere fokussierte Views, scope + include\n80–200\nsync braucht Sekunden, draw.io ruckelt\nViews gezielt klein halten, Workspace prüfen\n\u0026gt; 200\ndraw.io mit einer Page mit 200+ Shapes ist nicht mehr nutzbar\nWorkspace mit separaten Modellen (→ Teil 16)\nViews klein halten: scope und include Das wirksamste Mittel gegen große Views ist konsequentes Scoping.\nSchlechte View:\n{ \u0026#34;views\u0026#34;: { \u0026#34;everything\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Gesamtsystem\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;*\u0026#34;] } } } Besser: fokussierte Views:\n{ \u0026#34;views\u0026#34;: { \u0026#34;system-context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;System Context\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop\u0026#34;, \u0026#34;payment\u0026#34;, \u0026#34;user\u0026#34;] }, \u0026#34;backend-containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Backend Container\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop.api\u0026#34;, \u0026#34;shop.db\u0026#34;, \u0026#34;shop.cache\u0026#34;, \u0026#34;shop.queue\u0026#34;] }, \u0026#34;payment-flow\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Zahlungsfluss\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] } } } Faustregel: eine View sollte maximal 15–20 Elemente zeigen. Mehr als das ist für Menschen nicht mehr auf einen Blick erfassbar.\nRelationship Lifting als Feature nutzen Relationship Lifting (→ Teil 3) hebt Beziehungen automatisch auf das nächste sichtbare Elternelement an. Das bedeutet: in einer abstrakten View (nur shop und payment) werden alle internen Beziehungen zwischen shop. und payment. automatisch als eine Verbindung zwischen shop und payment dargestellt.\nMan muss also keine separaten Beziehungen für verschiedene Abstraktionsebenen definieren — das Lifting erledigt das automatisch.\n{ \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;shop.checkout-service\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;payment.stripe-adapter\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;calls\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;shop.order-service\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;payment.stripe-adapter\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;calls\u0026#34; } ] } Tags als dynamisches Scoping Statt jede View mit expliziten IDs zu pflegen, können Tags als dynamischer Filter verwendet werden (→ Teil 23).\nDas skaliert besonders gut: wenn ein neues Element mit \u0026#34;tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] hinzugefügt wird, erscheint es automatisch in allen Views mit \u0026#34;filter-tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] — ohne die View-Definition anzufassen.\n{ \u0026#34;views\u0026#34;: { \u0026#34;critical-path\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Kritischer Zahlungspfad\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] }, \u0026#34;team-backend\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Backend-Team View\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;team-backend\u0026#34;], \u0026#34;exclude-tags\u0026#34;: [\u0026#34;archived\u0026#34;] } } } draw.io Performance: Ursachen und Gegenmittel draw.io wird träge wenn eine Page zu viele Shapes hat. Konkrete Maßnahmen:\nShapes reduzieren: * Hierarchische Elemente (container: true) zusammenklappen — draw.io zeigt nur das Container-Shape, nicht die Kinder * Views aufteilen statt eine große Page zu haben\ndraw.io-Datei bereinigen:\n# draw.io-Datei enthält manchmal veraltete Shapes aus gelöschten Views # Sync bereinigt das: bausteinsicht sync # Danach draw.io neu laden — veraltete Shapes wurden entfernt Separate draw.io-Dateien per View: Aktuell speichert Bausteinsicht alle Views als Pages in einer .drawio-Datei. Bei sehr vielen Views (20+) kann es helfen die Views in Gruppen aufzuteilen — das ist aber eine manuelle Entscheidung.\nWann Workspace die richtige Lösung ist Das Workspace-Feature (Teil 16) ist die Lösung wenn:\nDas System aus wirklich unabhängigen Subsystemen besteht die von verschiedenen Teams verantwortet werden\nEin einzelnes JSONC-Modell über 200 Elemente wächst\nTeams wollen ihr Modell ohne Koordination mit anderen ändern können\nDer Workspace erlaubt separate Modelle mit Cross-Referenzen:\n{ \u0026#34;workspace\u0026#34;: { \u0026#34;models\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;path\u0026#34;: \u0026#34;shop/architecture.jsonc\u0026#34;, \u0026#34;prefix\u0026#34;: \u0026#34;shop\u0026#34; }, \u0026#34;payment\u0026#34;: { \u0026#34;path\u0026#34;: \u0026#34;payment/architecture.jsonc\u0026#34;, \u0026#34;prefix\u0026#34;: \u0026#34;pay\u0026#34; }, \u0026#34;infra\u0026#34;: { \u0026#34;path\u0026#34;: \u0026#34;infra/architecture.jsonc\u0026#34;, \u0026#34;prefix\u0026#34;: \u0026#34;inf\u0026#34; } } } } Jedes Team pflegt sein Modell unabhängig. Im Workspace-Kontext können Views Elemente aus mehreren Modellen kombinieren.\nEntscheidungshilfe: wann was Situation Empfehlung Ein Team, ein System, \u0026lt; 100 Elemente\nFokussierte Views, Tags-Filter, scope\nMehrere Teams, ein System, 100–200 Elemente\nOwnership-Conventions, Workspace prüfen\nMehrere Teams, mehrere unabhängige Systeme\nWorkspace mit separaten Modellen\nDraw.io träge, Modell noch klein\nViews aufteilen, überflüssige Shapes entfernen, sync neu ausführen\nValidate dauert \u0026gt; 5 Sekunden\nBekanntes Performance-Problem — als Issue melden\nBeispiel-Modell Das Beispiel für diesen Teil (größeres Modell mit Gateway, Microservices, Event Bus) liegt unter teil_28.jsonc.\nSo sieht das Ergebnis in draw.io aus (bausteinsicht sync):\nDas draw.io-File dafür findest du hier: teil_28.drawio\nGenerierte PNG-Dateien via bausteinsicht export --image-format png:\nGenerierte PlantUML-Diagramme via bausteinsicht export-diagram (Order-Flow View):\nWas als nächstes kommt Teil 29: Real-Life-Beispiel — das Big Bank Example von Simon Brown (Structurizr) vollständig nach Bausteinsicht JSONC transformiert\nDas war die erweiterte Tutorial-Serie Mit Teil 28 schließt die Bausteinsicht-Tutorial-Serie — von der Projektvorstellung in Teil 1 bis zu Performance und Skalierung in Teil 28.\nDie wichtigsten Einstiegspunkte für schnelles Nachschlagen:\nNeu starten? → Teil 2: Getting Started\nArchitekturregeln? → Teil 8: Validation \u0026amp; Linting\nMit KI arbeiten? → Teil 10: LLM/AI Workflows\nTeam-Architektur? → Teil 16: Workspace\nIn CI/CD einbinden? → Teil 24: CI/CD Integration\nVon anderen Tools? → Teil 25: Migration\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-performance/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post setzt den \u003ca href=\"../bausteinsicht-custom-notations/\"\u003esiebenundzwanzigsten Teil\u003c/a\u003e fort.\nEin Modell mit 10 Elementen ist einfach. Bei 50+ Elementen stellt sich die Frage: was sieht wer, wann, in welcher View? Und ab wann wird \u003ccode\u003esync\u003c/code\u003e und draw.io langsam?\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_wann_wird_ein_modell_groß\"\u003eWann wird ein Modell \u0026#34;groß\u0026#34;?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003ePraktische Grenzwerte:\u003c/p\u003e\n\u003c/div\u003e\n\u003ctable class=\"tableblock frame-all grid-all stretch\"\u003e\n\u003ccolgroup\u003e\n\u003ccol style=\"width: 25%;\"/\u003e\n\u003ccol style=\"width: 50%;\"/\u003e\n\u003ccol style=\"width: 25%;\"/\u003e\n\u003c/colgroup\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eElementanzahl\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eSymptom\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eLösung\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u0026lt; 30\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eAlles in einer View zeigbar\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eEine Hauptview reicht\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e30–80\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eEine View wird unlesbar — zu viele Shapes\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eMehrere fokussierte Views, \u003ccode\u003escope\u003c/code\u003e + \u003ccode\u003einclude\u003c/code\u003e\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e80–200\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u003ccode\u003esync\u003c/code\u003e braucht Sekunden, draw.io ruckelt\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eViews gezielt klein halten, Workspace prüfen\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003e\u0026gt; 200\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003edraw.io mit einer Page mit 200+ Shapes ist nicht mehr nutzbar\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eWorkspace mit separaten Modellen (→ \u003ca href=\"../bausteinsicht-workspace/\"\u003eTeil 16\u003c/a\u003e)\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Teil 28: Performance bei großen Modellen — Scoping, Partial Views und Subsysteme"},{"content":" Dieser Post baut auf dem achtundzwanzigsten Teil auf. Alle bisherigen Beispiele im Tutorial zeigten fiktive Systeme. Hier kommt ein echtes Referenzmodell: das Big Bank Example von Simon Brown — dem Erfinder des C4-Modells und Hauptentwickler von Structurizr.\nUnd zum ersten Mal wird es nicht von Hand geschrieben, sondern direkt aus Structurizr DSL importiert.\nbausteinsicht import --from structurizr ist ab dem Release nach v1.1.0 verfügbar (gemergt in PR #331). Mit der aktuell installierten v1.1.0 funktioniert der Befehl noch nicht — wer es schon jetzt ausprobieren will, baut Bausteinsicht lokal aus main.\nWas ist das Big Bank Example? Das Big Bank Example ist das offizielle Referenzmodell der Structurizr-Dokumentation. Es zeigt eine fiktive Retail-Bank mit einem Internet Banking System auf drei C4-Ebenen:\nSystem Context — Kunden, Bankmitarbeiter, ATM, externe Systeme\nContainer — Web App, SPA, Mobile App, API Application, Oracle-Datenbank\nComponent — Sechs Komponenten der API Application\nDas Modell ist komplex genug um alle Features von Bausteinsicht zu zeigen, und bekannt genug um es sofort einordnen zu können.\nOriginal in Structurizr DSL: https://structurizr.connectedpdf.com/share/3/dsl Structurizr Container-Diagramm live: https://structurizr.com/embed/39258?diagram=Containers\u0026amp;diagramSelector=false\nVoraussetzungen # Bausteinsicht aus main (solange v1.2.0 noch nicht released): go install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@main # Oder bei installiertem Node.js: npm install -g @doctoolchain/bausteinsicht@next Ein leeres Verzeichnis für das Experiment:\nmkdir bigbank \u0026amp;\u0026amp; cd bigbank Schritt 1: DSL herunterladen Das kombinierte Big Bank DSL (System Landscape + Internet Banking System) direkt von Structurizr holen:\ncurl -o bigbank.dsl https://structurizr.connectedpdf.com/share/3/dsl workspace \u0026#34;Big Bank plc\u0026#34; \u0026#34;This is an example workspace...\u0026#34; { model { customer = person \u0026#34;Personal Banking Customer\u0026#34; \u0026#34;...\u0026#34; enterprise \u0026#34;Big Bank plc\u0026#34; { supportStaff = person \u0026#34;Customer Service Staff\u0026#34; \u0026#34;...\u0026#34; backoffice = person \u0026#34;Back Office Staff\u0026#34; \u0026#34;...\u0026#34; mainframe = softwaresystem \u0026#34;Mainframe Banking System\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Existing System\u0026#34; email = softwaresystem \u0026#34;E-mail System\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Existing System\u0026#34; atm = softwaresystem \u0026#34;ATM\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Existing System\u0026#34; internetBankingSystem = softwaresystem \u0026#34;Internet Banking System\u0026#34; \u0026#34;...\u0026#34; { webApplication = container \u0026#34;Web Application\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Java and Spring MVC\u0026#34; spa = container \u0026#34;Single-Page Application\u0026#34; \u0026#34;...\u0026#34; \u0026#34;JavaScript and Angular\u0026#34; mobileApp = container \u0026#34;Mobile App\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Xamarin\u0026#34; apiApplication = container \u0026#34;API Application\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Java and Spring MVC\u0026#34; { signinController = component \u0026#34;Sign In Controller\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Spring MVC\u0026#34; accountsSummaryController = component \u0026#34;Accounts Summary Controller\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Spring MVC\u0026#34; resetPasswordController = component \u0026#34;Reset Password Controller\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Spring MVC\u0026#34; securityComponent = component \u0026#34;Security Component\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Spring Bean\u0026#34; mainframeBankingSystemFacade = component \u0026#34;Mainframe Banking System Facade\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Spring Bean\u0026#34; emailComponent = component \u0026#34;E-mail Component\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Spring Bean\u0026#34; } database = container \u0026#34;Database\u0026#34; \u0026#34;...\u0026#34; \u0026#34;Oracle Database Schema\u0026#34; } } customer -\u0026gt; internetBankingSystem \u0026#34;Views account balances, and makes payments using\u0026#34; customer -\u0026gt; supportStaff \u0026#34;Asks questions to\u0026#34; \u0026#34;Telephone\u0026#34; customer -\u0026gt; atm \u0026#34;Withdraws cash using\u0026#34; ... } } Schritt 2: Vorschau mit --dry-run Bevor eine Datei geschrieben wird, den Import als Vorschau ausführen:\nbausteinsicht import --from structurizr bigbank.dsl --dry-run Der Befehl gibt das generierte JSONC auf stdout aus — ohne etwas zu schreiben. So lässt sich prüfen ob das Parsing korrekt ist, bevor man eine vorhandene architecture.jsonc überschreibt.\n{ \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34;, \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;person\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Person\u0026#34; }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;component\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Component\u0026#34;, \u0026#34;container\u0026#34;: true } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; } }, \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;existing-system\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;bank-staff\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;web-browser\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;mobile-app\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;database\u0026#34; } ] }, \u0026#34;model\u0026#34;: { ... }, \u0026#34;relationships\u0026#34;: [ ... ], \u0026#34;views\u0026#34;: { ... } } Falls das Parsing eines bestimmten DSL-Konstrukts nicht unterstützt wird, gibt bausteinsicht import eine Warnung auf stderr aus — der Import läuft aber weiter durch. Deployment-Diagramme (deploymentEnvironment) werden übersprungen und als Warnung gemeldet.\nSchritt 3: Import ausführen bausteinsicht import --from structurizr bigbank.dsl Ergebnis:\n✓ Parsed 3 persons, 4 systems, 5 containers, 6 components ✓ Resolved 25 relationships ⚠ Skipped: deploymentEnvironment \u0026#34;Development\u0026#34; (not supported) ⚠ Skipped: deploymentEnvironment \u0026#34;Live\u0026#34; (not supported) ✓ Written architecture.jsonc architecture.jsonc liegt jetzt im Verzeichnis. Das generierte File für das Big Bank Example siehst du hier:\n{ // Teil 29: Big Bank Example — transformiert von Structurizr DSL nach Bausteinsicht JSONC // Original DSL: https://structurizr.connectedpdf.com/share/3/dsl // Quelle: Simon Brown, Big Bank plc (kombiniert aus workspace 28201 + 36141) \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34;, \u0026#34;config\u0026#34;: { \u0026#34;author\u0026#34;: \u0026#34;Simon Brown (Original), Paul Fleischmann (Bausteinsicht-Transformation)\u0026#34;, \u0026#34;metadata\u0026#34;: true, \u0026#34;legend\u0026#34;: true }, \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;actor\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Person\u0026#34; }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;component\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Component\u0026#34;, \u0026#34;container\u0026#34;: true } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; }, \u0026#34;sends\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;sends\u0026#34;, \u0026#34;dashed\u0026#34;: true } }, \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Existing System — nicht unter unserer Kontrolle\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#999999\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;bank-staff\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Bankmitarbeiter (intern)\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#08427b\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;web-browser\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Läuft im Web-Browser des Kunden\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;mobile\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Läuft auf dem Mobilgerät des Kunden\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Datenbank\u0026#34; } ] }, \u0026#34;model\u0026#34;: { // ── Personen ───────────────────────────────────────────────────────────── \u0026#34;customer\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Personal Banking Customer\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;A customer of the bank, with personal bank accounts.\u0026#34; }, \u0026#34;support-staff\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Customer Service Staff\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Customer service staff within the bank.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;bank-staff\u0026#34;] }, \u0026#34;backoffice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Back Office Staff\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Administration and support staff within the bank.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;bank-staff\u0026#34;] }, // ── Externe Systeme ─────────────────────────────────────────────────────── \u0026#34;mainframe\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Mainframe Banking System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Stores all of the core banking information about customers, accounts, transactions, etc.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] }, \u0026#34;email\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;E-mail System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;The internal Microsoft Exchange e-mail system.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] }, \u0026#34;atm\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;ATM\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows customers to withdraw cash.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] }, // ── Internet Banking System (intern, mit Containern) ────────────────────── \u0026#34;internet-banking\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Internet Banking System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows customers to view information about their bank accounts, and make payments.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;web-app\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Application\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Java and Spring MVC\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Delivers the static content and the Internet banking single page application.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34; }, \u0026#34;spa\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Single-Page Application\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;JavaScript and Angular\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides all of the Internet banking functionality to customers via their web browser.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;web-browser\u0026#34;] }, \u0026#34;mobile-app\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Mobile App\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Xamarin\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides a limited subset of the Internet banking functionality to customers via their mobile device.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;mobile\u0026#34;] }, \u0026#34;api-app\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;API Application\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Java and Spring MVC\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides Internet banking functionality via a JSON/HTTPS API.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;sign-in\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Sign In Controller\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring MVC Rest Controller\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows users to sign in to the Internet Banking System.\u0026#34; }, \u0026#34;accounts-summary\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Accounts Summary Controller\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring MVC Rest Controller\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides customers with a summary of their bank accounts.\u0026#34; }, \u0026#34;reset-password\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Reset Password Controller\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring MVC Rest Controller\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows users to reset their passwords with a single use URL.\u0026#34; }, \u0026#34;security\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Security Component\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring Bean\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides functionality related to signing in, changing passwords, etc.\u0026#34; }, \u0026#34;mainframe-facade\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Mainframe Banking System Facade\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring Bean\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;A facade onto the mainframe banking system.\u0026#34; }, \u0026#34;email-component\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;E-mail Component\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring Bean\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Sends e-mails to users.\u0026#34; } } }, \u0026#34;database\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Oracle Database Schema\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Stores user registration information, hashed authentication credentials, access logs, etc.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;database\u0026#34;] } } } }, \u0026#34;relationships\u0026#34;: [ // ── System Context ──────────────────────────────────────────────────────── { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;views account balances, and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;support-staff\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;asks questions to\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;atm\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;withdraws cash using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;support-staff\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;backoffice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;atm\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;gets account information from, and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;sends e-mail using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;sends\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;sends e-mails to\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;sends\u0026#34; }, // ── Container: Customer → Frontend ──────────────────────────────────────── { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.web-app\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;visits bigbank.com/ib using [HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;views account balances, and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;views account balances, and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.web-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;delivers to the customer\u0026#39;s web browser\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, // ── Container: Frontend → Components ───────────────────────────────────── { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, // ── Component: intern ───────────────────────────────────────────────────── { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.mainframe-facade\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.email-component\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.database\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads from and writes to [JDBC]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.mainframe-facade\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [XML/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.email-component\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;sends e-mail using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;sends\u0026#34; } ], \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;System Context — Big Bank plc\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Akteure und Systeme rund um das Internet Banking System\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;support-staff\u0026#34;, \u0026#34;backoffice\u0026#34;, \u0026#34;internet-banking\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34;, \u0026#34;atm\u0026#34;] }, \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container — Internet Banking System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Interne Container des Internet Banking Systems und ihre Nachbarn\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;internet-banking\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;internet-banking.*\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34;] }, \u0026#34;components\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Component — API Application\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Interne Komponenten der API Application\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;internet-banking.api-app\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;internet-banking.api-app.*\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34; ] } } } Was der Importer automatisch macht Hierarchie erhalten — Structurizr-Blöcke ({ }) werden zu children-Objekten in JSONC. Der vollständig gepunktete Pfad (internet-banking.api-app.sign-in) wird aus den DSL-Variablennamen abgeleitet.\nBeziehungen auflösen — Structurizr erlaubt Beziehungen die vor der Element-Definition stehen (a → b). Der Importer löst alle Referenzen verzögert auf (deferred resolution) — das Ergebnis ist immer ein konsistentes JSONC.\nTags übernehmen — Structurizr-Tags (\u0026#34;Existing System\u0026#34;, \u0026#34;Bank Staff\u0026#34;, \u0026#34;Web Browser\u0026#34;) werden 1:1 in specification.tags übernommen und an die Elemente angehängt.\nViews konvertieren — systemContext, container und component Views werden in Bausteinsicht-Views übersetzt. include * wird in eine explizite include-Liste aufgelöst.\nWas nachzubessern ist Der Import ist ein Einmalvorgang — kein Mapping für alles. Folgendes muss manuell ergänzt werden:\nNicht importiert Wie nachrüsten Deployment-Diagramme\nSeparate Views in views anlegen oder in draw.io modellieren\nStyles / Themes\nspecification.tags[].style mit draw.io-Farben befüllen\n!include-Direktiven\nLokale Includes werden aufgelöst, HTTP-Includes nicht\nproperties auf Containern\nmetadata-Feld in Bausteinsicht verwenden\nDifferenzierte Beziehungstypen\nAlle Beziehungen werden als uses importiert — sends, reads etc. manuell anpassen\nDas Wichtigste bei externen Systemen: Structurizr nutzt den String-Tag \u0026#34;Existing System\u0026#34;. Der Importer übernimmt das als Tag existing-system. Für farbiges Styling in draw.io fügt man in specification.tags einfach eine style-Sektion ein:\n\u0026#34;specification\u0026#34;: { \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;existing-system\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Externes System — nicht unter unserer Kontrolle\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#999999\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } } ] } Schritt 4: Sync und Diagramme bausteinsicht sync Bausteinsicht generiert architecture.drawio mit drei Tabs:\ncontext — System Context: Kunden, Bankmitarbeiter, ATM, externe Systeme\ncontainers — Alle Container des Internet Banking Systems\ncomponents — Sechs Komponenten der API Application\nDas draw.io-File dafür findest du hier: teil_29.drawio\nGenerierte PNG-Dateien:\nGenerierte PlantUML-Diagramme:\nStructurizr vs. Bausteinsicht — Kurzvergleich Aspekt Structurizr Bausteinsicht Modell-Format\nEigene DSL\nJSONC\nDiagramm-Output\nSVG via Structurizr-Server\ndraw.io (bearbeitbar, bidirektional)\nBidirektional\nNein — DSL ist Quelle der Wahrheit\nJa — draw.io Änderungen fließen zurück ins JSONC\nOffline\nStructurizr Lite nötig\nVollständig lokal\nDeployment-Diagramme\nNativ in DSL\nKein eingebautes Konzept\nImport aus Structurizr\n—\nbausteinsicht import --from structurizr\nConstraint-Prüfung\n!rules in DSL\nconstraints im JSONC, bausteinsicht lint\nDie Migration in eine Richtung ist mit bausteinsicht import jetzt trivial. Zurück nach Structurizr gibt es keinen Importer — aber das ist in der Praxis selten nötig.\nWas als nächstes kommt Teil 30: Mehr Views aus einem Modell — wie man aus dem Big Bank Modell 7 fokussierte Diagramme für verschiedene Publikumsgruppen erzeugt\nDie wichtigsten Einstiegspunkte zum Nachschlagen:\nNeu starten? → Teil 2: Getting Started\nArchitekturregeln? → Teil 8: Validation \u0026amp; Linting\nMit KI arbeiten? → Teil 10: LLM/AI Workflows\nTeam-Architektur? → Teil 16: Workspace\nVon anderen Tools? → Teil 25: Migration\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-structurizr-big-bank-beispiel/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post baut auf dem \u003ca href=\"../bausteinsicht-performance/\"\u003eachtundzwanzigsten Teil\u003c/a\u003e auf.\nAlle bisherigen Beispiele im Tutorial zeigten fiktive Systeme.\nHier kommt ein echtes Referenzmodell: das \u003cstrong\u003eBig Bank Example\u003c/strong\u003e von Simon Brown — dem Erfinder des C4-Modells und Hauptentwickler von Structurizr.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eUnd zum ersten Mal wird es nicht von Hand geschrieben, sondern \u003cstrong\u003edirekt aus Structurizr DSL importiert\u003c/strong\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"admonitionblock note\"\u003e\n\u003ctable\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd class=\"icon\"\u003e\n\u003ci class=\"fa icon-note\" title=\"📝 Hinweis\"\u003e\u003c/i\u003e\n\u003c/td\u003e\n\u003ctd class=\"content\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003ebausteinsicht import --from structurizr\u003c/code\u003e ist ab dem Release nach v1.1.0 verfügbar (gemergt in PR #331).\nMit der aktuell installierten v1.1.0 funktioniert der Befehl noch nicht — wer es schon jetzt ausprobieren will, baut Bausteinsicht lokal aus \u003ccode\u003emain\u003c/code\u003e.\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 29: Real-Life-Beispiel — Structurizr Big Bank mit bausteinsicht import"},{"content":" Dieser Post baut direkt auf Teil 29 auf. Das Big Bank Example hat 3 Views erzeugt: System Context, Container, Components. Das reicht für eine Dokumentationsseite — aber nicht für ein reales Projekt.\nEin Security-Architect braucht ein anderes Diagramm als ein Mobile-Entwickler. Ein Manager sieht gern die Kundenperspektive, kein Backend. Alle drei wollen aber aus demselben Modell schöpfen — nicht drei separate Dateien pflegen.\nDieses Kapitel zeigt wie.\nDas Problem: eine View für alle Wenn alle Elemente in einer View landen, passiert das:\n20+ Shapes in einem Diagramm — niemand kann es auf einen Blick erfassen\nJede Änderung betrifft das einzige Diagramm — alle Stakeholder müssen sich damit auseinandersetzen\nKeine klare Aussage: \u0026#34;was will dieses Diagramm zeigen?\u0026#34;\nDas Big Bank Example hat 3 Akteure, 4 Systeme, 5 Container, 6 Komponenten. In einer einzigen \u0026#34;alles\u0026#34;-View wären das 18 Shapes — schon zu viel.\nDie Lösung: ein Modell, viele Views Bausteinsicht trennt Modell (was existiert) von Views (was gezeigt wird).\n// Modell: einmal definieren \u0026#34;model\u0026#34;: { ... }, \u0026#34;relationships\u0026#34;: [ ... ], // Views: beliebig viele Linsen auf dasselbe Modell \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { ... }, // für Management \u0026#34;containers\u0026#34;: { ... }, // für Architekten \u0026#34;components\u0026#34;: { ... }, // für alle Entwickler \u0026#34;api-internals\u0026#34;: { ... }, // für Backend-Team \u0026#34;mobile-flow\u0026#34;: { ... }, // für Mobile-Entwickler \u0026#34;customer-touchpoints\u0026#34;: { ... }, // für Product Owner \u0026#34;security-flow\u0026#34;: { ... } // für Security-Team } Jede View erzeugt einen eigenen Tab in architecture.drawio — also ein eigenes Diagramm. Das Modell bleibt genau einmal vorhanden.\nFaustregel: wann braucht man eine neue View? Signal Reaktion Ein Diagramm hat mehr als 12–15 Shapes\nAufteilen in fokussierte Views\nVerschiedene Teams fragen nach unterschiedlichen Ausschnitten\nPro Team eine View\nEin Diagramm zeigt zu viel Kontext für seinen Zweck\nexclude oder engeres include verwenden\nMeetings: \u0026#34;kannst du kurz die Auth-Flows zeigen?\u0026#34;\nEigene security-flow View anlegen\nJemand fragt: \u0026#34;was sieht der Kunde?\u0026#34;\nEigene customer-touchpoints View\nDie 4 neuen Views im Detail api-internals — Zoom-In ohne Frontend-Rauschen Die Standard components-View zeigt SPA und Mobile App als Aufrufer der Komponenten. Das ist korrekt — aber für das Backend-Team ist das Rauschen. Sie wollen sehen wie die 6 Komponenten untereinander und mit externen Systemen interagieren.\n\u0026#34;api-internals\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;API Internals (Zoom-In)\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur API App + direkte externe Abhängigkeiten — ohne Frontend-Rauschen\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;internet-banking.api-app\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;internet-banking.api-app.*\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34; ] } Kein customer, kein spa, kein mobile-app — nur die 6 Komponenten, Database, Mainframe und E-Mail. Der Unterschied zu components: kein Frontend in der View.\nmobile-flow — nur der mobile Pfad Web App und SPA sind für mobile Entwickler irrelevant. Diese View zeigt den kompletten Pfad von customer über mobile-app bis zu den relevanten Komponenten und externen Systemen:\n\u0026#34;mobile-flow\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Mobile App Flow\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur der mobile Pfad — Web App und SPA ausgeblendet\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;customer\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;, \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;internet-banking.api-app.mainframe-facade\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;mainframe\u0026#34; ] } email-component fehlt absichtlich — Mobile App triggert keinen direkten E-Mail-Versand außer beim Reset Password. Für den generellen Mobile Flow ist das kein relevanter Pfad.\ncustomer-touchpoints — was der Kunde sieht Product Owner und UX-Designer fragen: \u0026#34;wo interagiert der Kunde mit dem System?\u0026#34; Diese View zeigt genau das — kein Backend, keine API Application:\n\u0026#34;customer-touchpoints\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Customer Touchpoints\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alles was der Kunde direkt sieht und berührt — kein Backend\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;customer\u0026#34;, \u0026#34;internet-banking.web-app\u0026#34;, \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;atm\u0026#34;, \u0026#34;support-staff\u0026#34; ] } Nur 6 Shapes. Auf einen Blick verständlich — auch für Nicht-Techniker.\nsecurity-flow — Auth und Passwort-Reset Security-Reviews brauchen den Authentifizierungspfad isoliert: wer ruft den Sign-In Controller auf, wo liegt die Datenbank, welche Komponente sendet E-Mails?\n\u0026#34;security-flow\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Security \u0026amp; Auth Flow\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Authentifizierungs- und Passwort-Reset-Pfad — für das Security-Team\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;internet-banking.api-app.email-component\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;email\u0026#34; ] } accounts-summary und mainframe-facade sind hier bewusst ausgeblendet — sie spielen im Auth-Flow keine Rolle.\nViews und Relationship Lifting Eine wichtige Eigenschaft: wenn eine View Komponenten zeigt, aber deren Parent-Container nicht, hebt Bausteinsicht die Beziehungen automatisch an.\nIn der customer-touchpoints View ist internet-banking.spa direkt sichtbar. Die Beziehung customer → internet-banking.spa wird direkt gezeichnet — nicht hochgehoben.\nIn der context View ist nur internet-banking sichtbar (kein spa). Alle Beziehungen von customer zu internet-banking.* werden zu einer einzigen Linie customer → internet-banking zusammengefasst.\nDasselbe Modell, automatisch auf die richtige Abstraktionsebene gehoben — ohne manuelle Doppel-Definitionen.\nDas vollständige teil_30.jsonc { // Teil 30: Mehr Views aus einem Modell — dasselbe Big Bank Modell wie Teil 29, // aber mit 7 fokussierten Views statt 3. \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34;, \u0026#34;config\u0026#34;: { \u0026#34;author\u0026#34;: \u0026#34;Paul Fleischmann\u0026#34;, \u0026#34;metadata\u0026#34;: true, \u0026#34;legend\u0026#34;: true }, \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;actor\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Person\u0026#34; }, \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;component\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Component\u0026#34;, \u0026#34;container\u0026#34;: true } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; }, \u0026#34;sends\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;sends\u0026#34;, \u0026#34;dashed\u0026#34;: true } }, \u0026#34;tags\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Existing System\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#999999\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;bank-staff\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Bankmitarbeiter\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#08427b\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } }, { \u0026#34;id\u0026#34;: \u0026#34;web-browser\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Läuft im Browser\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;mobile\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Läuft auf Mobilgerät\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;database\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Datenbank\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;security\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Security-Komponente\u0026#34;, \u0026#34;style\u0026#34;: { \u0026#34;fillColor\u0026#34;: \u0026#34;#d73a4a\u0026#34;, \u0026#34;fontColor\u0026#34;: \u0026#34;#ffffff\u0026#34; } } ] }, \u0026#34;model\u0026#34;: { \u0026#34;customer\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Personal Banking Customer\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;A customer of the bank, with personal bank accounts.\u0026#34; }, \u0026#34;support-staff\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Customer Service Staff\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Customer service staff within the bank.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;bank-staff\u0026#34;] }, \u0026#34;backoffice\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;actor\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Back Office Staff\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Administration and support staff within the bank.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;bank-staff\u0026#34;] }, \u0026#34;mainframe\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Mainframe Banking System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Stores all core banking information.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] }, \u0026#34;email\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;E-mail System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;The internal Microsoft Exchange e-mail system.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] }, \u0026#34;atm\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;ATM\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows customers to withdraw cash.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;external\u0026#34;] }, \u0026#34;internet-banking\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Internet Banking System\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows customers to view information about their bank accounts, and make payments.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;web-app\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Web Application\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Java and Spring MVC\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Delivers static content and the SPA.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34; }, \u0026#34;spa\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Single-Page Application\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;JavaScript and Angular\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Full Internet banking in the browser.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;web-browser\u0026#34;] }, \u0026#34;mobile-app\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Mobile App\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Xamarin\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Limited banking on mobile devices.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;mobile\u0026#34;] }, \u0026#34;api-app\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;API Application\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Java and Spring MVC\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides Internet banking functionality via JSON/HTTPS API.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;sign-in\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Sign In Controller\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring MVC Rest Controller\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows users to sign in.\u0026#34; }, \u0026#34;accounts-summary\u0026#34;:{ \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Accounts Summary Controller\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring MVC Rest Controller\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Provides account summaries.\u0026#34; }, \u0026#34;reset-password\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Reset Password Controller\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring MVC Rest Controller\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Allows password reset via single-use URL.\u0026#34; }, \u0026#34;security\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Security Component\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring Bean\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Handles sign-in, password changes.\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;security\u0026#34;] }, \u0026#34;mainframe-facade\u0026#34;:{ \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Mainframe Banking System Facade\u0026#34;,\u0026#34;technology\u0026#34;: \u0026#34;Spring Bean\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;A facade onto the mainframe.\u0026#34; }, \u0026#34;email-component\u0026#34;:{ \u0026#34;kind\u0026#34;: \u0026#34;component\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;E-mail Component\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Spring Bean\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Sends e-mails to users.\u0026#34; } } }, \u0026#34;database\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Oracle Database Schema\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Stores user registration info, credentials, access logs.\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;deployed\u0026#34;, \u0026#34;tags\u0026#34;: [\u0026#34;database\u0026#34;] } } } }, \u0026#34;relationships\u0026#34;: [ { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;views account balances, and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;support-staff\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;asks questions to\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;atm\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;withdraws cash using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;support-staff\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;backoffice\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;atm\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;gets account information from, and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;sends e-mail using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;sends\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;sends e-mails to\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;sends\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.web-app\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;visits bigbank.com/ib using [HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;views account balances and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;customer\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;views account balances and makes payments using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.web-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;delivers to the customer\u0026#39;s web browser\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;,\u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [JSON/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.mainframe-facade\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.api-app.email-component\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;internet-banking.database\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;reads from and writes to [JDBC]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.mainframe-facade\u0026#34;,\u0026#34;to\u0026#34;: \u0026#34;mainframe\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;makes API calls to [XML/HTTPS]\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34; }, { \u0026#34;from\u0026#34;: \u0026#34;internet-banking.api-app.email-component\u0026#34;, \u0026#34;to\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;label\u0026#34;: \u0026#34;sends e-mail using\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;sends\u0026#34; } ], \u0026#34;views\u0026#34;: { // ── Die 3 Standard-Views aus Teil 29 ──────────────────────────────────── \u0026#34;context\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;System Context\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle Akteure und Systeme — der klassische C4 Level-1-Überblick\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;support-staff\u0026#34;, \u0026#34;backoffice\u0026#34;, \u0026#34;internet-banking\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34;, \u0026#34;atm\u0026#34;] }, \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle 5 Container des Internet Banking Systems\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;internet-banking\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;customer\u0026#34;, \u0026#34;internet-banking.*\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34;] }, \u0026#34;components\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Components (alle)\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alle 6 Komponenten der API Application — volle Übersicht\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;internet-banking.api-app\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;internet-banking.api-app.*\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34; ] }, // ── 4 fokussierte Views — das Thema von Teil 30 ────────────────────────── \u0026#34;api-internals\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;API Internals (Zoom-In)\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur API App + direkte externe Abhängigkeiten — ohne Frontend-Rauschen\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;internet-banking.api-app\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;internet-banking.api-app.*\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;mainframe\u0026#34;, \u0026#34;email\u0026#34; ] }, \u0026#34;mobile-flow\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Mobile App Flow\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Nur der mobile Pfad — Web App und SPA ausgeblendet\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;customer\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;internet-banking.api-app.accounts-summary\u0026#34;, \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;internet-banking.api-app.mainframe-facade\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;mainframe\u0026#34; ] }, \u0026#34;customer-touchpoints\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Customer Touchpoints\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Alles was der Kunde direkt sieht und berührt — kein Backend\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;customer\u0026#34;, \u0026#34;internet-banking.web-app\u0026#34;, \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;atm\u0026#34;, \u0026#34;support-staff\u0026#34; ] }, \u0026#34;security-flow\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Security \u0026amp; Auth Flow\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Authentifizierungs- und Passwort-Reset-Pfad — für das Security-Team\u0026#34;, \u0026#34;include\u0026#34;: [ \u0026#34;internet-banking.spa\u0026#34;, \u0026#34;internet-banking.mobile-app\u0026#34;, \u0026#34;internet-banking.api-app.sign-in\u0026#34;, \u0026#34;internet-banking.api-app.reset-password\u0026#34;, \u0026#34;internet-banking.api-app.security\u0026#34;, \u0026#34;internet-banking.api-app.email-component\u0026#34;, \u0026#34;internet-banking.database\u0026#34;, \u0026#34;email\u0026#34; ] } } } Ergebnis: 7 Tabs in draw.io bausteinsicht sync erzeugt 7 draw.io Tabs:\nTab Titel Zielgruppe context\nSystem Context\nManagement, Stakeholder\ncontainers\nContainer\nArchitekten\ncomponents\nComponents (alle)\nAlle Entwickler\napi-internals\nAPI Internals\nBackend-Team\nmobile-flow\nMobile App Flow\nMobile-Entwickler\ncustomer-touchpoints\nCustomer Touchpoints\nProduct Owner, UX\nsecurity-flow\nSecurity \u0026amp; Auth Flow\nSecurity-Team, Auditor\nDas draw.io-File dafür findest du hier: teil_30.drawio\nGenerierte PNG-Dateien:\nGenerierte PlantUML-Diagramme:\nViews benennen: Tab-Reihenfolge in draw.io Die Reihenfolge der Views im JSONC bestimmt die Tab-Reihenfolge in draw.io. Am sinnvollsten: von abstrakt nach konkret — wie in C4.\n\u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { ... }, // Tab 1: abstrakt \u0026#34;containers\u0026#34;: { ... }, // Tab 2 \u0026#34;components\u0026#34;: { ... }, // Tab 3: konkret \u0026#34;api-internals\u0026#34;: { ... } // Tab 4: Zoom-In } View-Keys werden zu draw.io Tab-Namen. Sprechende Keys (security-flow, mobile-flow) machen draw.io direkt navigierbar — auch ohne Titel zu lesen.\nWas als nächstes kommt Das war Teil 30 — das letzte Kapitel der Bausteinsicht-Tutorial-Serie.\nDie wichtigsten Einstiegspunkte zum Nachschlagen:\nNeu starten? → Teil 2: Getting Started\nTags für View-Filterung? → Teil 23: Tags \u0026amp; View-Filterung\nPerformance bei großen Modellen? → Teil 28: Performance\nStructurizr migrieren? → Teil 29: Big Bank Import\nOffizielle Dokumentation: User Manual · Tutorial auf doctoolchain.org\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/bausteinsicht-multi-view-design/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieser Post baut direkt auf \u003ca href=\"../bausteinsicht-structurizr-big-bank-beispiel/\"\u003eTeil 29\u003c/a\u003e auf.\nDas Big Bank Example hat 3 Views erzeugt: System Context, Container, Components.\nDas reicht für eine Dokumentationsseite — aber nicht für ein reales Projekt.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eEin Security-Architect braucht ein anderes Diagramm als ein Mobile-Entwickler.\nEin Manager sieht gern die Kundenperspektive, kein Backend.\nAlle drei wollen aber aus demselben Modell schöpfen — nicht drei separate Dateien pflegen.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDieses Kapitel zeigt wie.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_eine_view_für_alle\"\u003eDas Problem: eine View für alle\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eWenn alle Elemente in einer View landen, passiert das:\u003c/p\u003e\n\u003c/div\u003e","title":"Teil 30: Mehr Views aus einem Modell — fokussierte Diagramme pro Publikum"},{"content":" Angaben gemäß § 25 MedienG (Österreich) Paul Fleischmann Kreuzgartengasse 19 7024 Hirm Burgenland, Österreich\n📧 paul.fleischmann@paul-fleischmann.com\nZweck der Webseite Private, nicht-kommerzielle Webseite. Inhalt: Technische Artikel, persönliche Projekte und Erfahrungsberichte aus dem Bereich Embedded Software Engineering.\nHaftungsausschluss Haftung für Inhalte Die Inhalte dieser Webseite wurden mit größtmöglicher Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte wird jedoch keine Gewähr übernommen.\nHaftung für Links Diese Webseite enthält Links zu externen Webseiten Dritter, auf deren Inhalte kein Einfluss besteht. Für die Inhalte verlinkter Seiten ist stets der jeweilige Anbieter verantwortlich.\nUrheberrecht Die auf dieser Webseite veröffentlichten Inhalte unterliegen dem österreichischen Urheberrecht. Beiträge Dritter sind als solche gekennzeichnet. Die Vervielfältigung, Bearbeitung oder Verbreitung der Inhalte außerhalb der Grenzen des Urheberrechts bedarf der schriftlichen Zustimmung des Autors.\nDatenschutz Diese Webseite erhebt und speichert keine personenbezogenen Daten. Es werden keine Cookies gesetzt. Es werden keine Analyse- oder Tracking-Dienste verwendet.\nHosting — Hetzner Online GmbH Der Server dieser Webseite wird betrieben von: Hetzner Online GmbH Industriestr. 25 91710 Gunzenhausen, Deutschland\nBeim Aufruf dieser Webseite werden durch Hetzner technisch notwendige Verbindungsdaten (IP-Adresse, Zeitstempel, aufgerufene Seite) im Rahmen des regulären Serverbetriebs protokolliert. Datenschutzerklärung Hetzner: hetzner.com/de/rechtliches/datenschutz\nDomain — IONOS SE Die Domain dieser Webseite wird verwaltet von: IONOS SE Elgendorfer Str. 57 56410 Montabaur, Deutschland\nDatenschutzerklärung IONOS: ionos.de/terms-gtc/datenschutzerklaerung\n","permalink":"https://paul-fleischmann.com/impressum/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_angaben_gemäß_25_medieng_österreich\"\u003eAngaben gemäß § 25 MedienG (Österreich)\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cstrong\u003ePaul Fleischmann\u003c/strong\u003e\u003cbr/\u003e\nKreuzgartengasse 19\u003cbr/\u003e\n7024 Hirm\u003cbr/\u003e\nBurgenland, Österreich\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e📧 \u003ca href=\"mailto:paul.fleischmann@paul-fleischmann.com\"\u003epaul.fleischmann@paul-fleischmann.com\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003chr/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_zweck_der_webseite\"\u003eZweck der Webseite\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003ePrivate, nicht-kommerzielle Webseite.\u003cbr/\u003e\nInhalt: Technische Artikel, persönliche Projekte und Erfahrungsberichte\naus dem Bereich Embedded Software Engineering.\u003c/p\u003e\n\u003c/div\u003e\n\u003chr/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_haftungsausschluss\"\u003eHaftungsausschluss\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"sect2\"\u003e\n\u003ch3 id=\"_haftung_für_inhalte\"\u003eHaftung für Inhalte\u003c/h3\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDie Inhalte dieser Webseite wurden mit größtmöglicher Sorgfalt erstellt.\nFür die Richtigkeit, Vollständigkeit und Aktualität der Inhalte\nwird jedoch keine Gewähr übernommen.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect2\"\u003e\n\u003ch3 id=\"_haftung_für_links\"\u003eHaftung für Links\u003c/h3\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDiese Webseite enthält Links zu externen Webseiten Dritter,\nauf deren Inhalte kein Einfluss besteht.\nFür die Inhalte verlinkter Seiten ist stets der jeweilige Anbieter verantwortlich.\u003c/p\u003e\n\u003c/div\u003e","title":"Impressum"},{"content":" Warum ein self-hosted VS Code Server? Als Embedded-Software-Entwickler arbeite ich an verschiedenen Stellen: zu Hause am Desktop, auf dem Notebook, manchmal auch nur über ein Tablet. Eine IDE, die überall gleich konfiguriert, mit denselben Extensions bestückt und direkt am Projekt dran ist , das ist kein Luxus, das ist Effizienz.\nCloud-Lösungen wie GitHub Codespaces oder Gitpod lösen das Problem prinzipiell, bringen aber Abhängigkeiten und laufende Kosten mit sich. Mein Ansatz ist anders: ein kleines Debian-System im Heimnetz (oder VPS), darauf Podman ohne Root-Rechte, und code-server als Container. Verwaltung über Cockpit , das ist die schlanke, webbasierte Systemverwaltung, die Debian seit Version 12 beinahe von Haus aus mitbringt.\nDas Konzept auf einen Blick Browser (überall) → HTTPS:8080 → code-server Container (Podman, rootless) ↓ ~/code-server/projects/ (Host) Browser (lokal) → HTTPS:9090 → Cockpit (Systemverwaltung + Podman UI) Der Stack besteht aus 3 Kernkomponenten:\nDebian 12 Bookworm Minimal — schlanke Basis, kein grafischer Overhead\nCockpit — webbasierte Serververwaltung inklusive Podman-Integration\ncode-server — VS Code als Web-App, läuft rootless im Podman-Container\nClaude Code — KI-Assistent direkt im Terminal innerhalb von code-server\nVoraussetzungen Bevor es losgeht, sollte folgendes bereitstehen:\nDebian 12 (Bookworm) Minimal Installation , physisch, als VM oder VPS\nRoot-Zugriff oder sudo-Berechtigung\nInternetzugang auf dem Server\nMindestens 2 GB RAM und 10 GB freier Speicher\nDer Stack ist bewusst sparsam ausgelegt. Auf meinem BeagleBone-Testsetup läuft er, auf einem Raspberry Pi 4 läuft er, auf einem kleinen Proxmox-Node sowieso.\nBasisinstallation: Debian Minimal vorbereiten Nach einer frischen Minimal-Installation das System aktualisieren und die nötigsten Pakete installieren:\n# System aktualisieren apt update \u0026amp;\u0026amp; apt upgrade -y # Grundlegende Werkzeuge apt install -y sudo curl wget gnupg2 ca-certificates \\ apt-transport-https software-properties-common Falls noch kein regulärer Benutzer vorhanden ist, diesen anlegen und mit sudo-Rechten ausstatten:\nuseradd -m -s /bin/bash \u0026lt;UserName\u0026gt; passwd \u0026lt;UserName\u0026gt; usermod -aG sudo \u0026lt;UserName\u0026gt; \u0026lt;UserName\u0026gt; durch den gewünschten Benutzernamen ersetzen, z.B. paul. (In den obigen Befehlen \u0026lt;UserName\u0026gt; durch den tatsächlichen Benutzernamen ersetzen.)\nAlle weiteren Schritte werden als normaler Benutzer (nicht root) ausgeführt, außer es ist ausdrücklich anders angegeben. Das ist besonders für Podman wichtig, da rootless Containers einer der Kernvorteile gegenüber Docker sind.\nCockpit: Serververwaltung per Browser Cockpit ist ein webbasiertes Admin-Interface, das direkt auf dem Server läuft. Kein zusätzlicher Management-Server, keine Datenbank , Cockpit kommuniziert direkt mit systemd, NetworkManager und natürlich Podman.\nInstallation # Cockpit installieren apt install -y cockpit # Dienst aktivieren und starten systemctl enable --now cockpit.socket # Falls UFW aktiv ist: Port freigeben ufw allow 9090/tcp Erster Zugriff https://\u0026lt;SERVER-IP\u0026gt;:9090 Beim ersten Aufruf erscheint eine Zertifikatswarnung (selbst-signiertes Zertifikat). Diese einmalig bestätigen, dann mit dem Linux-Benutzernamen und Passwort anmelden.\nCockpit zeigt danach einen Überblick über CPU, RAM, Netzwerk und laufende Dienste. Klar, kompakt, ohne Schnickschnack.\nPodman-Integration nachrüsten apt install -y cockpit-podman Nach der Installation erscheint im linken Menü der Punkt „Podman containers\u0026#34;. Dort lassen sich Container grafisch starten, stoppen, Logs einsehen und Volumes verwalten , alles ohne Terminal.\nFigure 1. Cockpit mit Podman-Übersicht Podman: Rootless Containers ohne Daemon Podman ist die daemonlose Alternative zu Docker. Der entscheidende Vorteil im Heimserver-Kontext: Containers laufen unter dem eigenen Benutzeraccount, ohne Root-Rechte und ohne permanenten System-Daemon.\nInstallation und Aktivierung # Podman installieren apt install -y podman # Version prüfen podman --version # User-Socket aktivieren (für rootless Betrieb) systemctl --user enable --now podman.socket Der User-Socket unter /run/user/\u0026lt;UID\u0026gt;/podman/podman.sock ist der Schlüssel für die Integration mit Drone CI oder anderen CI-Systemen, die einen Docker-kompatiblen Socket erwarten. Einfach einen Symlink nach /var/run/docker.sock anlegen oder den Socket-Pfad in der CI-Konfiguration direkt angeben.\nWarum Podman statt Docker? Docker Podman Benötigt Root-Daemon (dockerd)\nKein Daemon, komplett rootless\nContainers laufen standardmäßig als root\nContainers laufen als Benutzer\nDocker Socket = Sicherheitsrisiko\nKein Socket auf Root-Ebene nötig\nSystemd-Integration komplex\nNative systemd --user Integration\nDocker Compose erforderlich\nPods als Konzept eingebaut\nFür einen Heimserver, auf dem ich auch produktive Daten habe, ist das kein akademischer Unterschied , das ist ein echtes Sicherheitsargument.\ncode-server: VS Code im Browser code-server ist das Open-Source-Projekt von Coder, das VS Code als Webserver ausliefert. Der offizielle Docker-Container funktioniert 1:1 mit Podman.\nVerzeichnisse anlegen # Als normaler Benutzer (nicht root) mkdir -p ~/code-server/config mkdir -p ~/code-server/projects Das projects-Verzeichnis auf dem Host wird in den Container gemountet. Alle Projektdaten liegen damit auf dem Host und ein Container-Neustart ändert nichts daran.\nContainer starten podman run -d \\ --name code-server \\ -p 8080:8080 \\ -e PASSWORD=meinPasswort \\ -u $(id -u):$(id -g) \\ -v ~/code-server/config:/home/coder/.config/code-server:Z \\ -v ~/code-server/projects:/home/coder/project:Z \\ docker.io/codercom/code-server:latest Parameter erklärt Parameter Bedeutung -d\nContainer im Hintergrund starten (detached)\n--name code-server\nEindeutiger Container-Name für spätere Befehle\n-p 8080:8080\nPort-Weiterleitung Host:Container\n-e PASSWORD=…​\nLogin-Passwort für die VS Code Web-UI\n-u $(id -u):$(id -g)\nContainer läuft als aktueller Benutzer dass ist wichtig für Datei-Permissions\n-v …​:Z\nVolume-Mount mit SELinux-Relabeling (:Z ist auf Debian zwar nicht strikt nötig, schadet aber nicht)\nVS Code aufrufen http://\u0026lt;SERVER-IP\u0026gt;:8080 Passwort eingeben und fertig. VS Code läuft im Browser, vollständig funktionsfähig inklusive Terminal, Git-Integration und Extension-Support.\nFigure 2. VS Code Web mit Claude Code CLI im integrierten Terminal Autostart via Systemd Ein Container, der nach jedem Reboot manuell gestartet werden muss, ist kein produktiver Container. Podman bringt einen Generator für systemd-Units mit:\n# Unit-Datei generieren (im aktuellen Verzeichnis) podman generate systemd --name code-server --files --new # In den Benutzer-Systemd-Ordner verschieben mkdir -p ~/.config/systemd/user/ mv container-code-server.service ~/.config/systemd/user/ # Dienst aktivieren und starten systemctl --user enable container-code-server.service systemctl --user start container-code-server.service # Linger aktivieren: Benutzer-Dienste laufen auch ohne aktive Session loginctl enable-linger $(whoami) loginctl enable-linger ist der entscheidende Schritt. Ohne ihn werden Benutzer-Systemd-Units erst gestartet, wenn sich der Benutzer einloggt und nicht beim Serverstart. Mit Linger laufen sie permanent.\nHTTPS: Ohne TLS fehlen Features Manche VS Code Features , darunter die Markdown Preview , funktionieren nur über HTTPS. Für den internen Betrieb genügt ein selbst-signiertes Zertifikat.\nZertifikat erstellen mkdir -p ~/code-server/certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \\ -keyout ~/code-server/certs/cert.key \\ -out ~/code-server/certs/cert.crt \\ -subj \u0026#34;/CN=$(hostname -I | awk \u0026#39;{print $1}\u0026#39;)\u0026#34; \\ -addext \u0026#34;subjectAltName=IP:$(hostname -I | awk \u0026#39;{print $1}\u0026#39;),IP:127.0.0.1\u0026#34; Konfigurationsdatei anlegen cat \u0026gt; ~/code-server/config/config.yaml \u0026lt;\u0026lt; EOF bind-addr: 0.0.0.0:8080 auth: password password: meinPasswort cert: /home/coder/.config/code-server/certs/cert.crt cert-key: /home/coder/.config/code-server/certs/cert.key EOF Container neu starten mit TLS # Alten Container entfernen podman rm -f code-server # Neu starten mit Zertifikat-Volume podman run -d \\ --name code-server \\ -p 8080:8080 \\ -e PASSWORD=meinPasswort \\ -u $(id -u):$(id -g) \\ -v ~/code-server/config:/home/coder/.config/code-server:Z \\ -v ~/code-server/projects:/home/coder/project:Z \\ -v ~/code-server/certs:/home/coder/.config/code-server/certs:Z \\ docker.io/codercom/code-server:latest Aufruf danach über:\nhttps://\u0026lt;SERVER-IP\u0026gt;:8080 Die Zertifikatswarnung einmalig bestätigen und danach läuft alles reibungslos.\nClaude Code: KI-Assistent direkt im Terminal Claude Code ist ein terminal-basierter KI-Coding-Assistent von Anthropic. Er läuft direkt im integrierten Terminal von code-server und weder ein Browser-Plugin, noch ein Cloud-IDE-Lock-in, oder ein anderer Umweg ist nötig.\nVoraussetzungen Ein Anthropic-Account: Pro, Max, Teams, Enterprise oder API über die Console\nOptional: Amazon Bedrock, Google Vertex AI oder Microsoft Foundry als Backend\nInstallation auf dem Host oder im Container # Empfohlen: Native Install mit Auto-Update curl -fsSL https://claude.ai/install.sh | bash Alternativ via Homebrew (kein automatisches Update):\nbrew install --cask claude-code Erster Start und Login # Im Projektverzeichnis starten cd ~/code-server/projects/mein-projekt claude Beim ersten Start erscheint ein Login-Prompt. Nach einmaliger Authentifizierung werden die Credentials unter ~/.claude/ gespeichert und kein erneuter Login ist nötig.\nWichtige Befehle Befehl Funktion claude\nInteraktiven Modus starten\nclaude \u0026#34;Aufgabe\u0026#34;\nEinmalige Aufgabe direkt ausführen\nclaude -p \u0026#34;Frage\u0026#34;\nEinzelne Abfrage, dann beenden (pipe-freundlich)\nclaude -c\nLetzte Konversation fortsetzen\nclaude -r\nFrühere Konversation wieder aufnehmen\nclaude commit\nAutomatisch Git-Commit mit sinnvoller Message erstellen\n/clear\nKonversationsverlauf löschen\n/help\nAlle verfügbaren Slash-Commands anzeigen\nexit oder Ctrl+C\nClaude Code beenden\nBeispiele aus der Praxis # Projekt verstehen what does this project do? # Eingabevalidierung ergänzen add input validation to the user registration form # Tests schreiben lassen write unit tests for the calculator functions # Commit erstellen commit my changes with a descriptive message # Code-Review review my changes and suggest improvements Integration: Claude Code im Container Claude Code kann entweder auf dem Host oder direkt im code-server Container laufen. Für eine nahtlose Integration im Container gibt es zwei Ansätze:\nVariante A: Installation direkt im Container # Shell im Container öffnen podman exec -it code-server bash # Claude Code im Container installieren curl -fsSL https://claude.ai/install.sh | bash # Claude starten claude Credentials landen unter ~/.claude/ im Container-Dateisystem. Um sie über Neustarts hinweg zu erhalten, das Volume beim podman run einbinden: -v ~/.claude:/home/coder/.claude:Z\nVariante B: Credentials per Dockerfile einbinden Für eine reproduzierbare, versionierbare Umgebung empfehle ich einen eigenen Container:\nFROM docker.io/codercom/code-server:latest ENV DEBIAN_FRONTEND=noninteractive USER root # Basis-Pakete RUN apt-get update \u0026amp;\u0026amp; apt-get install -y \\ bash curl wget git jq tree unzip zip tar \\ openssh-client ca-certificates gnupg sudo \\ build-essential procps findutils diffutils \\ libicu-dev zstd \\ \u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/* # Node.js und Python RUN apt-get update \u0026amp;\u0026amp; apt-get install -y nodejs npm python3 \\ python3-pip python3-venv # Claude Code als Benutzer \u0026#39;coder\u0026#39; installieren USER coder RUN curl -fsSL https://claude.ai/install.sh | bash ENV PATH=\u0026#34;/home/coder/.local/bin:${PATH}\u0026#34; # Credentials vom Host in den Container kopieren COPY --chown=coder:coder .claude/ /home/coder/.claude/ COPY --chown=coder:coder .claude.json /home/coder/.claude.json Die Credentials-Dateien (.claude/ und .claude.json) enthalten API-Tokens. Niemals in ein öffentliches Repository committen. In .gitignore aufnehmen und ggf. über CI/CD-Secrets oder ein Secret-Mount zur Build-Zeit einbinden.\nNützliche Alltags-Befehle Container-Management # Status aller Container podman ps # Logs live verfolgen podman logs -f code-server # Container stoppen / starten / neu starten podman stop code-server podman start code-server podman restart code-server # Container vollständig entfernen (Daten bleiben auf Host-Volumes erhalten) podman rm -f code-server # Shell im Container öffnen podman exec -it code-server bash # VS Code Extension installieren podman exec -it code-server \\ code-server --install-extension ms-python.python Verwaltung über Cockpit Wer das Terminal vermeiden möchte: Cockpit bietet nach Installation von cockpit-podman eine vollständige grafische Oberfläche.\nBrowser öffnen: https://\u0026lt;SERVER-IP\u0026gt;:9090\nMit Linux-Benutzer anmelden\nIm linken Menü: „Podman containers\u0026#34; auswählen\nContainer starten, stoppen, Logs lesen , alles per Klick\nZusammenfassung und Schnellreferenz Komponente URL / Befehl Cockpit Web-UI\nhttps://\u0026lt;IP\u0026gt;:9090\nVS Code Web-UI\nhttps://\u0026lt;IP\u0026gt;:8080\nPasswort ändern\n-e PASSWORD=neuesPasswort in podman run\nProjekte (Host-Pfad)\n~/code-server/projects/\nExtension installieren\npodman exec -it code-server code-server --install-extension \u0026lt;id\u0026gt;\nClaude Code starten\nclaude im integrierten Terminal\nFazit Der Stack ist kompakt, sicher und vollständig ohne Cloud-Abhängigkeit betreibbar. Was mich persönlich am meisten überzeugt hat:\nRootless Podman eliminiert eine ganze Klasse von Sicherheitsrisiken\nCockpit macht den Server auch ohne permanentes SSH-Terminal handhabbar\nSystemd-Linger sorgt für zuverlässigen Autostart ohne Root-Konfiguration\nClaude Code im Terminal ist effizienter als jedes Browser-Plugin , es sieht den Code, den Projekt-Kontext und das Git-Repository direkt\nDas vollständige Repository mit allen Konfigurationsdateien: * https://github.com/paul-fleischmann-com/selfhosted-vscode-stack\nWeiterführende Links code-server auf Docker Hub\ncode-server GitHub Repository\nCockpit Project\nPodman – daemonless container engine\nClaude Code Quickstart\n","permalink":"https://paul-fleischmann.com/toolssetup/selfhosted-vscode-stack-podman-cockpit/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_warum_ein_self_hosted_vs_code_server\"\u003eWarum ein self-hosted VS Code Server?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAls Embedded-Software-Entwickler arbeite ich an verschiedenen Stellen: zu Hause am Desktop,\nauf dem Notebook, manchmal auch nur über ein Tablet. Eine IDE, die überall gleich konfiguriert,\nmit denselben Extensions bestückt und direkt am Projekt dran ist , das ist kein Luxus,\ndas ist Effizienz.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eCloud-Lösungen wie GitHub Codespaces oder Gitpod lösen das Problem prinzipiell,\nbringen aber Abhängigkeiten und laufende Kosten mit sich. Mein Ansatz ist anders:\nein kleines Debian-System im Heimnetz (oder VPS), darauf Podman ohne Root-Rechte,\nund \u003ccode\u003ecode-server\u003c/code\u003e als Container. Verwaltung über Cockpit , das ist die schlanke,\nwebbasierte Systemverwaltung, die Debian seit Version 12 beinahe von Haus aus mitbringt.\u003c/p\u003e\n\u003c/div\u003e","title":"VS Code im Browser: Mein self-hosted Dev-Stack mit Podman, Cockpit und Claude Code"},{"content":" Das Problem, das Bausteinsicht löst Architekturdokumentation veraltet. Das ist kein Meinungsproblem, das ist Praxis. Man zeichnet ein schönes C4-Diagramm, das System entwickelt sich weiter, und drei Monate später stimmt das Bild nicht mehr. Textbasierte Tools wie Structurizr oder LikeC4 lösen das Problem von der einen Seite: Text liegt im Git, ist versionierbar, diffbar, reviewbar. Aber man verliert die direkte visuelle Editierbarkeit.\nBausteinsicht versucht beide Seiten gleichzeitig zu halten: das Modell liegt als JSONC-Datei im Repository, draw.io ist das visuelle Frontend — und die Synchronisation läuft in beide Richtungen.\nDas Datenmodell: drei Formate, ein Wahrheitsmodell Intern arbeitet Bausteinsicht mit drei Formaten gleichzeitig:\nFormat Rolle architecture.jsonc\nDas Modell — Quelle für Elemente, Beziehungen, Views\narchitecture.drawio\nDas Draw.io-XML — mehrere Pages, eine pro View\nGo-Structs intern\nLaufzeitrepräsentation für Sync-Logik und CLI-Output\nDas JSONC-Modell hat drei Hauptbereiche: specification definiert die erlaubten Element-Typen und Beziehungsarten; model enthält die konkreten Elemente mit optionalem children-Baum für Hierarchien; views steuert, welche Elemente in welchem Diagramm auftauchen. Hier ein minimales Beispiel:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34; } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; } } }, \u0026#34;model\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } } } }, \u0026#34;views\u0026#34;: { \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container View\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop.*\u0026#34;] } } } Bidirektionale Synchronisation: das eigentlich schwierige Teil Der sync-Befehl ist das Herzstück. Er muss Änderungen aus beiden Richtungen erkennen und zusammenführen — ohne Konflikte zu verlieren und ohne Layoutinformation zu zerstören, die der Benutzer manuell gesetzt hat.\nKonkret: Fügt man im JSONC ein neues Element hinzu, erstellt sync den entsprechenden Knoten im Draw.io-XML. Verschiebt man umgekehrt einen Knoten in draw.io und speichert, liest sync die neue Position und schreibt sie ins Modell zurück. Was nicht überschrieben wird: manuell gesetzte Positionen und Größen, die nicht aus dem Modell stammen. Das ist das Merge-Problem, und es ist nicht trivial.\nEin weiteres Feature ist das Relationship Lifting. Wenn eine Beziehung zwischen zwei Elementen existiert, die beide nicht direkt in einer View sichtbar sind, hebt Bausteinsicht den Connector automatisch auf das nächste sichtbare Elternelement an. Das hält Views sauber, ohne Beziehungen aus dem Modell zu entfernen.\nDas CLI: vollständig, LLM-tauglich Die CLI ist von Anfang an so gebaut, dass sie nicht nur für Menschen, sondern auch für KI-Agenten benutzbar ist. Jeder Befehl unterstützt --format json, was maschinenlesbaren Output auf stdout und Fehler als strukturiertes JSON auf stderr liefert.\nBefehl Was er tut init\nLegt Beispielmodell + Template an\nsync\nBidirektionale Synchronisation JSONC ↔ draw.io\nvalidate\nPrüft Modellkonsistenz, gibt Fehler/Warnungen aus\nwatch\nKontinuierlicher Sync bei Dateiänderungen\nadd element\nElement per CLI ins Modell einfügen (LLM-freundlich)\nadd relationship\nBeziehung per CLI einfügen\nexport\nPNG/SVG-Export über draw.io CLI\nexport-diagram\nPlantUML-C4 oder Mermaid-C4 aus Views generieren\nexport-sequence\nSequenzdiagramme als PlantUML oder Mermaid\nexport-table\nElementattribute als AsciiDoc- oder Markdown-Tabelle\nDas --format json-Flag an jedem Befehl war für meine Claude-Code-Workflows besonders nützlich: ich konnte Modellzustand maschinell abfragen und Issues direkt als strukturierte Änderungen einspielen, ohne Textparsing. Meine Mitarbeit: Beta, Bugs, und 33 Issues Ich war beim ersten Release als Beta-Tester dabei — Tool ausprobieren, Edge-Cases finden, kleine Fixes einbringen. Das lehrreiche daran: Man lernt die Grenzen eines Tools kennen, bevor man Features baut.\nDanach habe ich systematisch GitHub-Issues erstellt — Feature-Requests, UX-Überlegungen, fehlende Exportformate, CLI-Ergonomie. 33 Issues, jedes mit klarem Scope. Den nächsten Schritt habe ich mit Claude Code gemacht: Issues als Arbeitsgrundlage nehmen, im Watch-Modus iterieren, Implementierungen direkt im Repository durchführen. In etwa zwei Tagen waren alle davon als Pull Requests umgesetzt.\nWas das Experiment gezeigt hat: Der Engpass ist nicht das Schreiben von Code, sondern das klare Denken davor. Ein Issue mit eindeutigem Scope und Akzeptanzkriterium funktioniert mit Claude Code hervorragend. Eine vage Idee ohne Kontext funktioniert nicht. Die Qualität des Inputs bestimmt die Qualität des Outputs — das gilt für KI-gestützte Entwicklung genauso wie für jede andere Art von Delegation.\nTutorial: Schritt für Schritt durch alle Features Ich begleite das Release von Bausteinsicht mit einer 23-teiligen Tutorial-Serie — vom ersten Modell bis zu Health Score, Workspace-Setup und LLM-Workflows. Jeden Tag ein neuer Teil, ab 2026-06-11.\nZur Tutorial-Übersicht →\nAusprobieren curl -Lo bausteinsicht.tar.gz \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ bausteinsicht init bausteinsicht sync Weitere Infos und Dokumentation: https://github.com/docToolchain/Bausteinsicht\n","permalink":"https://paul-fleischmann.com/blogs/bausteinsicht/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_das_bausteinsicht_löst\"\u003eDas Problem, das Bausteinsicht löst\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eArchitekturdokumentation veraltet. Das ist kein Meinungsproblem, das ist Praxis. Man zeichnet ein schönes C4-Diagramm, das System entwickelt sich weiter, und drei Monate später stimmt das Bild nicht mehr. Textbasierte Tools wie Structurizr oder LikeC4 lösen das Problem von der einen Seite: Text liegt im Git, ist versionierbar, diffbar, reviewbar. Aber man verliert die direkte visuelle Editierbarkeit.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBausteinsicht versucht beide Seiten gleichzeitig zu halten: das Modell liegt als JSONC-Datei im Repository, draw.io ist das visuelle Frontend — und die Synchronisation läuft in beide Richtungen.\u003c/p\u003e\n\u003c/div\u003e","title":"Bausteinsicht: Beta-Tester, 33 Issues, und was das Tool technisch interessant macht"},{"content":" Das Problem, das Bausteinsicht löst Architekturdokumentation veraltet. Das ist kein Meinungsproblem, das ist Praxis. Man zeichnet ein schönes C4-Diagramm, das System entwickelt sich weiter, und drei Monate später stimmt das Bild nicht mehr. Textbasierte Tools wie Structurizr oder LikeC4 lösen das Problem von der einen Seite: Text liegt im Git, ist versionierbar, diffbar, reviewbar. Aber man verliert die direkte visuelle Editierbarkeit.\nBausteinsicht versucht beide Seiten gleichzeitig zu halten: das Modell liegt als JSONC-Datei im Repository, draw.io ist das visuelle Frontend — und die Synchronisation läuft in beide Richtungen.\nDas Datenmodell: drei Formate, ein Wahrheitsmodell Intern arbeitet Bausteinsicht mit drei Formaten gleichzeitig:\nFormat Rolle architecture.jsonc\nDas Modell — Quelle für Elemente, Beziehungen, Views\narchitecture.drawio\nDas Draw.io-XML — mehrere Pages, eine pro View\nGo-Structs intern\nLaufzeitrepräsentation für Sync-Logik und CLI-Output\nDas JSONC-Modell hat drei Hauptbereiche: specification definiert die erlaubten Element-Typen und Beziehungsarten; model enthält die konkreten Elemente mit optionalem children-Baum für Hierarchien; views steuert, welche Elemente in welchem Diagramm auftauchen. Hier ein minimales Beispiel:\n{ \u0026#34;specification\u0026#34;: { \u0026#34;elements\u0026#34;: { \u0026#34;system\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Software System\u0026#34;, \u0026#34;container\u0026#34;: true }, \u0026#34;container\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;Container\u0026#34; } }, \u0026#34;relationships\u0026#34;: { \u0026#34;uses\u0026#34;: { \u0026#34;notation\u0026#34;: \u0026#34;uses\u0026#34; } } }, \u0026#34;model\u0026#34;: { \u0026#34;shop\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;system\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Online Shop\u0026#34;, \u0026#34;children\u0026#34;: { \u0026#34;api\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;REST API\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;Go\u0026#34; }, \u0026#34;db\u0026#34;: { \u0026#34;kind\u0026#34;: \u0026#34;container\u0026#34;, \u0026#34;title\u0026#34;: \u0026#34;Database\u0026#34;, \u0026#34;technology\u0026#34;: \u0026#34;PostgreSQL\u0026#34; } } } }, \u0026#34;views\u0026#34;: { \u0026#34;containers\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Container View\u0026#34;, \u0026#34;scope\u0026#34;: \u0026#34;shop\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;shop.*\u0026#34;] } } } Bidirektionale Synchronisation: das eigentlich schwierige Teil Der sync-Befehl ist das Herzstück. Er muss Änderungen aus beiden Richtungen erkennen und zusammenführen — ohne Konflikte zu verlieren und ohne Layoutinformation zu zerstören, die der Benutzer manuell gesetzt hat.\nKonkret: Fügt man im JSONC ein neues Element hinzu, erstellt sync den entsprechenden Knoten im Draw.io-XML. Verschiebt man umgekehrt einen Knoten in draw.io und speichert, liest sync die neue Position und schreibt sie ins Modell zurück. Was nicht überschrieben wird: manuell gesetzte Positionen und Größen, die nicht aus dem Modell stammen. Das ist das Merge-Problem, und es ist nicht trivial.\nEin weiteres Feature ist das Relationship Lifting. Wenn eine Beziehung zwischen zwei Elementen existiert, die beide nicht direkt in einer View sichtbar sind, hebt Bausteinsicht den Connector automatisch auf das nächste sichtbare Elternelement an. Das hält Views sauber, ohne Beziehungen aus dem Modell zu entfernen.\nDas CLI: vollständig, LLM-tauglich Die CLI ist von Anfang an so gebaut, dass sie nicht nur für Menschen, sondern auch für KI-Agenten benutzbar ist. Jeder Befehl unterstützt --format json, was maschinenlesbaren Output auf stdout und Fehler als strukturiertes JSON auf stderr liefert.\nBefehl Was er tut init\nLegt Beispielmodell + Template an\nsync\nBidirektionale Synchronisation JSONC ↔ draw.io\nvalidate\nPrüft Modellkonsistenz, gibt Fehler/Warnungen aus\nwatch\nKontinuierlicher Sync bei Dateiänderungen\nadd element\nElement per CLI ins Modell einfügen (LLM-freundlich)\nadd relationship\nBeziehung per CLI einfügen\nexport\nPNG/SVG-Export über draw.io CLI\nexport-diagram\nPlantUML-C4 oder Mermaid-C4 aus Views generieren\nexport-sequence\nSequenzdiagramme als PlantUML oder Mermaid\nexport-table\nElementattribute als AsciiDoc- oder Markdown-Tabelle\nDas --format json-Flag an jedem Befehl war für meine Claude-Code-Workflows besonders nützlich: ich konnte Modellzustand maschinell abfragen und Issues direkt als strukturierte Änderungen einspielen, ohne Textparsing. Meine Mitarbeit: Beta, Bugs, und 33 Issues Ich war beim ersten Release als Beta-Tester dabei — Tool ausprobieren, Edge-Cases finden, kleine Fixes einbringen. Das lehrreiche daran: Man lernt die Grenzen eines Tools kennen, bevor man Features baut.\nDanach habe ich systematisch GitHub-Issues erstellt — Feature-Requests, UX-Überlegungen, fehlende Exportformate, CLI-Ergonomie. 33 Issues, jedes mit klarem Scope. Den nächsten Schritt habe ich mit Claude Code gemacht: Issues als Arbeitsgrundlage nehmen, im Watch-Modus iterieren, Implementierungen direkt im Repository durchführen. In etwa zwei Tagen waren alle davon als Pull Requests umgesetzt.\nWas das Experiment gezeigt hat: Der Engpass ist nicht das Schreiben von Code, sondern das klare Denken davor. Ein Issue mit eindeutigem Scope und Akzeptanzkriterium funktioniert mit Claude Code hervorragend. Eine vage Idee ohne Kontext funktioniert nicht. Die Qualität des Inputs bestimmt die Qualität des Outputs — das gilt für KI-gestützte Entwicklung genauso wie für jede andere Art von Delegation.\nTutorial: Schritt für Schritt durch alle Features Ich begleite das Release von Bausteinsicht mit einer 23-teiligen Tutorial-Serie — vom ersten Modell bis zu Health Score, Workspace-Setup und LLM-Workflows. Jeden Tag ein neuer Teil, ab 2026-06-11.\nZur Tutorial-Übersicht →\nAusprobieren curl -Lo bausteinsicht.tar.gz \\ https://github.com/docToolchain/Bausteinsicht/releases/latest/download/bausteinsicht_linux_amd64.tar.gz tar xzf bausteinsicht.tar.gz \u0026amp;\u0026amp; sudo mv bausteinsicht /usr/local/bin/ bausteinsicht init bausteinsicht sync Weitere Infos und Dokumentation: https://github.com/docToolchain/Bausteinsicht\n","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/bausteinsicht/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_das_problem_das_bausteinsicht_löst\"\u003eDas Problem, das Bausteinsicht löst\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eArchitekturdokumentation veraltet. Das ist kein Meinungsproblem, das ist Praxis. Man zeichnet ein schönes C4-Diagramm, das System entwickelt sich weiter, und drei Monate später stimmt das Bild nicht mehr. Textbasierte Tools wie Structurizr oder LikeC4 lösen das Problem von der einen Seite: Text liegt im Git, ist versionierbar, diffbar, reviewbar. Aber man verliert die direkte visuelle Editierbarkeit.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBausteinsicht versucht beide Seiten gleichzeitig zu halten: das Modell liegt als JSONC-Datei im Repository, draw.io ist das visuelle Frontend — und die Synchronisation läuft in beide Richtungen.\u003c/p\u003e\n\u003c/div\u003e","title":"Bausteinsicht: Beta-Tester, 33 Issues, und was das Tool technisch interessant macht"},{"content":" Ich bin Paul Fleischmann — Embedded Software Architekt, Dipl.-Ing. (FH) Ingenieurinformatik, wohnhaft in Hirm im Burgenland.\nÜber 15 Jahre habe ich bei Elektrobit Austria in Wien AUTOSAR Classic Platform entwickelt und verantwortet. Vom ersten MCAL-Treiber bis zur Rolle als Bundle Software Architect, der für mehrere basic software module die technische Verantwortung trägt.\nWas ich tue Was mich antreibt: hardwarenahe Software auf echter Hardware nutzbar machen — so dass der Kunde ein Produkt in den Händen hält, das funktioniert.\nEin sauber geschnittenes Softwaremodul beginnt bei der Architektur: Es braucht klar definierte Modulgrenzen und generische APIs, sowie eine Hardware Abstraction Layer (HAL), die alles Chipspezifische kapselt — Register, Timing und Hardware-Eigenheiten bleiben hinter der HAL verborgen.\nDas ist für mich der Maßstab: der Nutzer merkt nichts von der darunterliegenden Hardware, und der nächste Chip-Wechsel wird keine Überraschung. Was sich ändert, ist die HAL. Der Rest bleibt.\nUnd wenn etwas nicht funktioniert: Debugger ans Target, Oszilloskop ans Board, Schaltplan aufschlagen — und den Grund finden. Architektur und Debugging sind für mich zwei Seiten derselben Arbeit.\nWomit ich arbeite Mein Kern ist der AUTOSAR Classic Platform Stack — von MCAL-Treibern für CAN, LIN, SPI und Ethernet bis zu Complex Device Drivers für hardwarenahe Protokollschichten.\nIm Bereich automotive Ethernet kenne ich den Stack von der Hardware bis zum Applikationsprotokoll: Switch Management, IEEE 1722, J1939, konfiguriert und integriert mit EB tresos.\nDer Weg von der Hardware-Spezifikation zur Implementierung gehört für mich dazu: die relevanten Register und Timing-Anforderungen verstehen — und daraus eine saubere Treiberarchitektur ableiten, die den Rest des Stacks nicht mit Hardware-Details belastet.\nASPICE und MISRA-C sind für mich kein Beiwerk, sondern Teil der täglichen Arbeit.\nPrimärsprache ist C. Daneben Rust, Go und Python dort, wo sie das bessere Werkzeug sind.\nMeine Projekte Beruflich Beruflich bin ich in zwei klar unterschiedlichen Rollen gewachsen.\nGestartet als AUTOSAR-Integrator: Portierung und Qualifizierung des EB AUTOSAR Stacks auf mehreren Chip-Plattformen, sowie Integration im Kundenprojekt — Absicherung der AUTOSAR-Konfiguration und Integration nach Kundenanforderungen.\nDann der Wechsel in die AUTOSAR-Modulentwicklung: hardwarenahe Kommunikationstreiber und Module im Kommunikationsstack, mit direkter Nähe zu den Hardware-Treibern. Genau der Bereich, wo Architektur und Debugging ineinandergreifen.\nPrivat Ein Embedded-Projekt auf dem BeagleBone Black — weil Embedded-Entwicklung für mich auch ohne Auftraggeber interessant bleibt. Details dazu im BeagleBone Projekt.\nDazu eine vollständig selbst gehostete Entwicklungsumgebung: Podman, Gitea, Drone CI, code-server — weil funktionierende Infrastruktur kein Zufallsprodukt sein sollte.\nWarum dieser Blog Weil 15 Jahre AUTOSAR-Entwicklung Meinungen hinterlassen — über Architektur, über Tooling, über die Stellen, an denen Theorie und Praxis auseinandergehen.\nWissen das nicht geteilt wird, bleibt nutzlos. Was ich in 15 Jahren gelernt habe — über Architektur, Tooling, das Zusammenspiel von Software und Hardware — das schreibe ich hier auf, damit andere davon profitieren.\nKontakt Ich bin aktuell offen für neue Herausforderungen im Bereich Embedded Software Engineering und AUTOSAR Classic Platform — bevorzugt im österreichischen Automotive-Umfeld.\n📧 paul.fleischmann@paul-fleischmann.com 🔗 LinkedIn · GitHub\n","permalink":"https://paul-fleischmann.com/ueber-mich/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eIch bin Paul Fleischmann — Embedded Software Architekt,\nDipl.-Ing. (FH) Ingenieurinformatik, wohnhaft in Hirm im Burgenland.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eÜber 15 Jahre habe ich bei Elektrobit Austria in Wien AUTOSAR Classic Platform\nentwickelt und verantwortet. Vom ersten MCAL-Treiber bis zur Rolle als\nBundle Software Architect, der für mehrere basic software module die technische\nVerantwortung trägt.\u003c/p\u003e\n\u003c/div\u003e\n\u003chr/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_was_ich_tue\"\u003eWas ich tue\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eWas mich antreibt: hardwarenahe Software auf echter Hardware nutzbar machen —\nso dass der Kunde ein Produkt in den Händen hält, das funktioniert.\u003c/p\u003e\n\u003c/div\u003e","title":"Über mich"},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_10_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_10_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_10_services.png\" alt=\"services\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_10_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9UU1rAjEQvedXTHNSKHjxWES7lCJIa03vS9yMdWicSDJrkdL_3qleVl16GeZ9MS9kWsRnaXfR3BE3sQ0ID9V4VI3rKrF4YswTY9yxCO7qx9Ry8Pk4KNu0vwf7ylEN4BTZIXwbgLPxpNd-T-pZPbl3mC3nVvfn9Dft8NrYyrZgPlCDKs8UgTvDf0JhrewyFfnI6N4W9gbdJDgJbajxQolVf-nAizs_xqwwdt7QU_LgIwUvCJI-kTXUkzg1zOhDGX1lEiz9tqtaBTlAl9PUVDn9ol8G6Y0q\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKSC0qzs_TSEktS83JL0gt0lFQcoGxlYAcJU2u4MriktRcjeKM_AKggH9eTmZeqkIwkAeV5wpKzUE2AKowNa-kPDM5OzWnBKjGITUvBegQAN_dL_U=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_11_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_11_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_11_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_11_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVj7EKwjAQhvc8RczUguDSUaS1iggOtXEvsTlsoE1KchGK-O6mtoJd7vj4P37uUofCou9aslK6br0Eus2TTZ5UudEolAa7I4QPDqGLhMfGgX2qGtaUZYEon5AFPplxsni2q73xWgo7RK4xfUh4WHTKWExfhM7wzSvRq-CUR36jWXFe9C1Fef91HfajUBiHDwv8epn1NyEltH-ty7NHAo2qFgjBTkHL8P4HBq1UJQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVj7EKAjEMhvc-Re10guByo8hJB1exDyClF7liL5U2FX17U9pBlyT_ny8hmTLZRGUNYuPRhTKDPOhxr8ebjkjwpqMQ5pMJ1sEWWjKkl3ewk-rESpomFetzrFFtxQVSjji4kimukNjUvexAX5eX-GTDcJLN6n1xhfAz3rmHLXeS4JGJCjT7_6aqAMk7S8DYBDjzZ18SBEp4\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_12_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_12_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_12_services.png\" alt=\"services\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_12_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kTFrwzAQhXf9iqumBgpZMpaSxpAshabx0NEo0jUWkaUgnQqm9L_3XBec2O4i-O7eu3uS1olUpNw4cWe9dtkgPBarZbGqiuBJWY_xSYiyTYRNtQnZGxXb-1SHywPIV-9YACWTXMCXAOiFv_1KZaoTxk-rkbXPTFD2KJl3oTvlYmQyR67uQ6JTxPLtRU5o4viIHBS94d47HmH7h532gErTrOmi2gY9DfH2fWE24bcQB3TjbTN37IiHWK0I2fefabJc16jPIdO152by8DQRlQEKZ_TpWj0eORhUNpbAhRPL15yBv_oH3aipYw==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKSC0qzs_TSC4tLsnPTS3SUVByhjKVgGwlTa7gyuKS1FyN4oz8AqCAf15OZl6qQjCQB5XnCkrNQdIOVZedWJpWopCamQdU4ZCalwJ0BAAbwy42\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_13_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_13_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_13_graph.png\" alt=\"graph\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_13_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKSC0qzs_TSC4tLsnPTS3SUVByhjKVgGwlTa7gyuKS1FyN4oz8AqCAf15OZl6qQjCQB5XnCkrNQdIOVZedWJpWopCamQdU4ZCalwJ0BAAbwy42\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9ktFLwzAQxt_zV8Q-ORD2skeRzaIyEDdbwceSJTcXliUluSpF_N-9tOLWLuyl5Lv7Hfm-S-cBhcfmYNiVttI0CvhtPpvmsyp3FoW24O8YK9uAcKjuXWOV8O112Ln6hmcrawjgJalswr8Z5z3Y9StRa2KKh_KNL9bLjM5PLn6zyRhscBfAf2oJ1F6Q4mUvLwypDVXXLuCHh_L1OTtTZxNbT4nAKuq9w4Y__snIFiAkJoesQ73VUqB2lvovJ_KCOecV-GOkVZTJTD-MFWDG_sbrk8KYQPQ_2vUSu4sKLEaDkOZHzmrvJITAu3J6YrSBTrZptHsTD0KF6ZfXCAPPw5uPfE1VHbC3MEx5mm14AUe3BxvpOW2Mft9fuZDtsw==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_14_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_14_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_14_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_14_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9UTtrwzAQ3vUrrp5sKHTJWEpa05YujbELGYUqXxuBLJmTnMSE_veciaAxmIzffY97rUNUFIfOijvjtB1ahMdy9VCuZOldVMYhPQnRjCFil-MxIjllZa_GDl2UPfm9aZHuIasuJahSKeNaViSnfPGDaxWNedj5npmNsxwNDaOsgJMASC0mXqresKZ-bb7gufqYkt59ypsLf4iHRNcyt8VveEtw0taodFw0OTwEpL3RyOwnHqC5oBt9PPFG_6bNBBdtf0LUaK-2WLLz1TSGwPIF7Ww6ray9ls2Dbr1D7xT9Yl6we80X4QefAQhho9I=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9j0EKwjAQRfc5ReyqBcFNlyKFHMBiD1BCO9pgMgnJROztHW0WunH35837DNMl0pGys2JncLJ5BnlU7UG1o_JI8KSTED3E5LGeciLvIO5lpUqsOFeNGNZE4Gq2IaK2Y9CrA6QxRP8w86fRb0j2Bf020-IDgzNagyAHnspeXMB-HS7eXecrSTDIxlvY8L_z06LjDeqGCx3gzP--AFyDVGI=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_15_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_15_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_15_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_15_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqV0s1LwzAUAPB7_orYUwuilx1FZuvwoGDXCh7LW_K2BdMk5GNSxP_dxJWusl08JeT98j5Ils6D9aGX5EooJgNHelctbqtFV2nlQSi094S0g_PY5waGHpW_plnrrTBI8_p4UmTxLCtG15U6KA52yN1em6TjQmsJfqttnxX0i1A6pkyiAyOierUcLW3RHgTDlPBJj2n_ar6Z8GOZRK2d31ls1y-Tn5pfBwx4vIeH2KmLYpU2tAwu8WfYfsDFOp-YCr3jhj4Yk0SDwPxIvwlpUM7gbJBm1b5RBlK6CCf1GzsNYNA64fxlMbWq05g3zCJ45Gf29B5sD3aHeTEj_2kpZYjBGFui4vE3_AANm6wG\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVj00KwyAQhfeewrpSKHSTZSkBLyDNAYqYSSP1Dx2huX0NEdqu5vG9Dx4zFtQZq3fkZINxdQZ6lcNFDg8ZA8Ibb4QoyCUGbmrB6CGfKZM9spaZINNWEDxPevMQsLEJs01AuTqI-PfKGtMutUOV07jE7LtB7uB-hrr50nVBCjY0YxcO_J0zq85P4KLVI4S5ffMByiRFpw==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_16_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_16_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_16_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_16_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNjr0KwkAQhPt7ijVVBMEmpUjwXkAM2ErIjRpy2ZO7XX_e3hVSWM0wfMxMW6TPonN0q5GHqAG0883WNxefWPCWvXNH5JK4HrRImpE3VPnFVuartes-RTDX5Z4eFnQm1CE_xwE_4Iz86qNA6ADjYlS-gUk50DGnoJPAOtwJ8W9i6Zp6vQphZCNacLCjXw1mPD0=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp90E0KwjAQBeB9ThG7UhC66VJErSCCi2oOUGIyaLBNwkyqiHh3Y634g7jJPJiPl5AJBYmhqSvWM1ZVjQY-yrM0z8rc2SCNBRwzJs4UoC5nrrFa4rlPe-eHPBFxcAF4NAqSAb8wzh-yBaX05ommxTKJeeHuZzL4gmoP6uCaEHd5F_9ovX22zmd3UDgKOwSxXnX8ytgGqrc3fF_i0SkgivSHa-sRpKb0hCbAB3uVvKwHJEMhsglYHb_yBujwbnI=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_17_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_17_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_17_services.png\" alt=\"services\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_17_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNj70OwjAMhPc8RehUJARLR4QqIiYGfvoAKDSuqJo6KLERvD2OyMB2vvtOJ7eJbCSevVqM2Ht2oLem2ZjmZgISvGmn1BliClj3nCjMEFe6MkVWoqulyqgdEeKFgaGGFyDdOUl4yFLvOWXyaIfJlkr3SQRznR7hKcYJvdR1J1fJ1RX832LhJssDaRhRiAz87L-9EB3EdR_BEjiBWkAnz30BE1BLIQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9Uk1rg0AQve-vmHpSKM0lx1KSSFpKD7Fa6FEm7qRKdFf2Q5DS_95RQxoS6W3evjfz5u3uyjo0zje1uKtUUXtJ8BgvF_Eyj7VyWCkyT0Kc63dPnkLqSLm9t_cQbIcSNt4GDN7wcMShCCKR9dZRk2-0VxJNH9pSt8zsVM1zIGMURPAtACbhyOfYVqxJt9kHrJPXYdKLPs27EnpXWjJdVRDTa0aQTfCfpoPhGKQkc5-0h-cTHLQpYeFmm1rsG474Z5ZMB7N-P0KkVF-7XURLdhxtoY0kY1l_Fo_sTLIO60qiI3D6SGq-42bDokTzRSE2fPcuumm6eL1xkYfCEFtIFq54X_4Lv7HIsCU=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_18_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_18_payment.png\" alt=\"payment\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_18_system-overview.png\" alt=\"system-overview\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_18_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kE8LgkAUxO_7KTZPCkEXjxGSRARSpt2XxX2ooLvydg0k-u7tpvS_y4MZ5scML9KGo-nbhsxqWTS9ALqMw0UcslhJw2sJuCIkH7SB1teV6phCAagBz3UBc-odnKT5qD1rbJW7XjBBbK16KTgOfseHFqR5ouloPOCAXgilU9d7mjUgSsAXKLkbripV2pQI-TGZiq-EZND8Wvs1oag4luDz1o40gWUd-Jn6N2W3zzfZyUIRSGFfeAOb0nMH\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNplkL0KgzAUhXefInVSKLg4lmLJULqJQocuJY0HDcQoybWtb9-IlUC75OYevnP_CkfC0tTraKeM1FMDduB5xvM7HwzhTccoqmdH6BMpZAcH-1QSexZXaJRjfBHjLV0-cboZRjH3MBQs5SqwelUW-jws7xVW2AcUgdhNdHoyLUwo5Lph9FTtAzuVl-DzSFRBf4G_frITtkUi-mEylHo4sD_LWIgme1k_gKcKmMZf5APJtF0j\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_19_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_19_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_19_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_19_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNTr0KwjAQ3vMUMVMFxaWjSOFwttgHkJBeMZjcleQC-vae0MHt--cbqvgiLSezixRSm9GeoT9B_wAmwbdcjBmxVKYutCqcsRysgw06xW5vpk8VzF198qrCjVIktJOyn389AmfNBrRj8iILl6wdc8f0N7l1X74tYjGSJgakWY99AS-CNaw=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kc9KxDAQxu95irEnF4S97FFku_U_C9ZW8Fhmm7EG0rRMUqWIb-Ob-GJOu1KhxUsyH_P7Mt-QrQ_IoautOjGutJ0mOE8262RTJI0LaBzxhVJ57wPVxa7pnEbuT_1r055B9OCsAJCLilbwoQCO4NgvsDXCZFf5E8TpXST1TTOct9i1gYzzLXeuilYzmz4IkzY-VEz54z5aKjb19xcTXO4W5heW1OS0YM90gOtfOdgywjJMBeRpvHBbqrDsBdmPBcQaJSkPpnt8w-EWz6dSGdn5vPnKJVrrhZ7Qsfe3IRNqv35nE-gfbEqDxxjjk4JuZZ582A_yVZDJ\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_1_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_1_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_1_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_1_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKriwuSc3VKM7IL9BRUPLPy8nMS1UIBvKUgFwlTS6H1LwUoAkAwCwYeQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNplj7EKwjAQhvc8xZnJguDSUaQaVJyUVHAssbliIE1Kkg5FfHevUhzqctzH__0cV8SkQupbyxbG1bbXCBuRr0VeCe-SMg7DlrFyiAnbau97p1UYlvHpuxXwi7MkQEnEM3gxgF_pq1SqM6TJQ3mD3fXMaT_5cfLs320CMTpN8R0fcJxw1CWqOk29N2MS7bwyv1YrayPZBaX03AffekoM\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_20_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_20_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_20_lifecycle.png\" alt=\"lifecycle\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_20_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKSC0qzs_TSC4tLsnPTS3SUVByhjKVgGwlTa7gyuKS1FyN4oz8AqCAf15OZl6qQjCQB5XnCkrNQdIOVZedWJpWopCamQdU4ZCalwJ0BAAbwy42\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9kk1PAjEQhu_7K-qeJDHhwtEYlChqUJaticfN0A5sk24H2wLZGP-7sysgX-HS9O37zEen7YcIPi4rm1wZp-xSo7gd9LqDXjEgF8E49HdJIusQsSoeaOk0-Po6lLS4EenYWQaEZJV2xHcixB_Y-gUsDDP5o_wQ99lLyvshNWvaOQL1lE8zCnHuUU5G6Yk6iZh5bg6dZu8Tp-JpIxs2R1DxbNDcw6L8sk0fzW4yEkOIuIb6QmsW56DqIgRid9QKIeW4YV9hBWdjHEUzMwqiIcf--54UcqUuVCOri4ocWRPLZrxWi7eNbIfynJ0N86ioqvj-25L5wcG2aFbHktwmw0-S5GiPp3n8bgqsDUzv0Nb7fzSPoEN37U3EA2w36r2E21x9rsT_7Rew6Mvc\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_21_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_21_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_21_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_21_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9kMEKwjAMhu99itrTBoKXHUU2dxBBcdoHGHUNrrC1o82EIb672XYRFS8hX_v9JCQNqDz2bcMWxlZNr4Gv82SVJ2XuLCpjwW8Yk0NAaMut661WfohC7bolFyfbkMAlEY-O5uYVGmdjEfMH43wOTW6pOkP-JGbFXlC_c2MV8afYYx3A300F9J0RcTnjn5C-0mvhAt48yPNBfBElnoxdoHnb5se4kcCiqRQCRVKwmi7zAhdIXoI=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNjrEKAjEQRPv9ipgqB4LNlSIHqUXxPkDC3arBZPdINqB_7xYp7GaGN8NMVUKRlhPsIi2prWiOfjz48e6ZBD9yArhiqUxuaVU4Y9kb67u0qu0A87cKZldfvGlwoRQJzazOuHN8liCRaegs3DD9TfXOO7SHGIykxIS06qEfc-4yUQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_22_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_22_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_22_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_22_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNptkk1OwzAQhfc5hcmqkUDddIlQS_gXEqGpqMSmmthDYtVxLP9QVYjbcBMuxqRBVCTZWH72N8_zRp47D9aHWkUnUnMVBLLzdDZNZ5u00R6kRnsRRfneeaw3l03QAux-4qrGnLL4SSsCWE4qTthHxFgHHu43YCQxy-t8xRbZfUz726Zd7yAYj1I7Y4Mu46RfFnzl0L5LjgQvSLG8k0eLh_Xq7AWUFBJHPURBUNY4X1rMnx_jobKy_v6yyK7Aoy5Abwceb5YGgFoQvcaC3fzKtnqJwH27yaUuFbIMSmQLYwYeBvY1an-Mk3UHw0SvUClK4qDYSb5VXajPKFqi6rfTHy4HpRzRf-jhbmSWraLHJafM4_ygX16BLXGSjOOHMVsE4aY7Kz3-66LvdayAIKRnqmkjzikS_b4fX_Ha7Q==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKSC0qzs_TSC4tLsnPTS3SUVByhjKVgGwlTa7gyuKS1FyN4oz8AqCAf15OZl6qQjCQB5XnCkrNQdIOVZedWJpWopCamQdU4ZCalwJ0BAAbwy42\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_23_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_23_backend.png\" alt=\"backend\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_23_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_23_critical.png\" alt=\"critical\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_23_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9kEELwjAMhe_9FbEnB4KXHUWcQ0UQnKvgcdQtusHWjrYThvjfjU4Q3PBS-vK-F5IsrJPGNVXJRoVKyyZDmIX-NPSTUCsnC4VmzphorcMqWepGZdK0Y5vregJ8r0oCQJDiHtwZQAe-_UTWBTHxShwhiLac_hv9ern3CzYut2huRYpkB6RAdPJPKDtTNdLWXQ2Kw473VC9xMbQRqoy8E55h_ZEvNkaZusFQLdsKlfuOF3WFwQkfbEEN6ZhPi3FsrA==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpdkMsKwjAQRff5ithVC4qbLkUKQVyJxX6AhHbUYDIpyQTs3zvV4qO7kzuHyyVVJB0oOSsWBlubOpAbVa5VeVYeCR60FaKGED3mbYrkHYSlzNSEGXNWiGaIBC6PgN01mI7DhnHPKPPd6qCNLWbmzfccHNEaBNnwa3anYHoYe14gaz04QJokcQL7s2Yqu-t0IQkG2RiFd_xp6oNvIcb_43fwiNLxUhYqZv6RJ9doW4M=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpdkMsKwjAQRff5ithVC4qbLkUKQVyJxX6AhHbUYDIpyQTs3zvV4qO7kzuHyyVVJB0oOSsWBlubOpAbVa5VeVYeCR60FaKGED3mbYrkHYSlzNSEGXNWiGaIBC6PgN01mI7DhnHPKPPd6qCNLWbmzfccHNEaBNnwa3anYHoYe14gaz04QJokcQL7s2Yqu-t0IQkG2RiFd_xp6oNvIcb_43fwiNLxUhYqZv6RJ9doW4M=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_24_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_24_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_24_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_24_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNptkM9qAjEQh-95imlOFQpePBZRt6V_KGiN0OMSN4MGdifLZNIipW_TN-mLOeqhpXoJ-fh9v8mQSRbPUrrWXEVq2hIQbqvRsBrVVSLxkZDHxrhdFuzqWSoUPO-u8zb1N2Dn1KoATskO4NMAnMRjXvs-qrO8dyuYLp6s3h_S4Xz0pReMlHsutLGD_7Ui24z8HhtUeaoE7oS_I57fdKYmZ-Ww1nSRsmwY3euLPSeO3c83I9zNtPxlzBLbP-te2OBASBIbL6iVC_7xUUYf8vCDo2BWbYIU9Ff3ezp0cw==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNj0ELgzAMhe_9FZ0nB4NePI4h1MtOk_kDhtjAijGVNrrt3y8dCrsl733vkdSJ-8jLhOrgacDFgT7bytjqYQMxvPmiVAsxBSoHf9KFvRrb6NbPgJ6gEKU47oCDFTDMEEVt9nlDuk9imMr0DLMIN8pp3cmW_TYGt4zsA6X04ySg7oD_jVsSiF9-GAFZmIzkqzZv7dG7nsFIebZrICeffQHcAEqi\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_25_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_25_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_25_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_25_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVkMFOAzEMRO_5CrOnXYnCpUeEirbcClTdD6iirNlGTRzkOMDy9Ti0iHKw5LGeZjReZbEsJQZz5cmFMiLc9cvbfrnvEwl-yr0xW-ScqHUlS4rI19D057XRvenMMGfB2AacrJv3yG963vwIeNxtK_QQBHMVixMLrS0ZRrYfNz4t1t5ObGOE6Cf2yNL9meZDqnYvFDwhDKqg_cWgmgzCxUlh_8VdjXq27gBPSljxieBd5wKB9bBRc7PDcFHoHHK05VUAPSlRgdP5X608k4PEo75EoRXSqL_7BsyvbhM=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpdkEFLxDAQhe_5FWNOWxB62aPIsgURUdTNgscyTcY1mKbLJFGq-N9NN0uV3vLevG_mkU2IyDH1TlxYr10yBFfNum7WbTP4iNYTXwuhxhCpb7dD8gZ5XIW34XgJ8tG7HACVFax6e2BLHAFTABU56ZjYfnElK_gWAPO-E912qN_Jm7xFHdn6A2yLIbNzhx9YF3uSssp4qVBY02X3YVTP9_L_45RbnHnlrMudF-rg5iyn-I5QxzP3I8SO3BJZFL3d759Ao3MhE3N8nv9VY0IT6k-2kaboJo_zD_8C-_d3yg==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_26_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_26_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_26_team-payment.png\" alt=\"team-payment\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_26_team-shop.png\" alt=\"team-shop\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_26_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNkk9Lw0AQxe_7KdacGlB66VGkNVQRPMRE8Bimm2mzsH_C7kQJ4nd30kjFpAUvw76Z94M3w64jQaDOGnGlnTJdjfI2Wy2zVZV5R6Adhjshyj4S2ured66G0C9i49trmWxvMm8tBoUyN0B7H2ySyk8h5QgcfRV01EQM71ohMxtWshxlwvrRDzVJJ1C9427uIx0Cli_PyUzNiH3gwOhqnr3hTj78yMFbICg6C7XQW3T0Gy8fG_9IOBRoNY9KfslN_vTH_CVEgWYabUIW2_JVKjAmMnGyn-ZnzjcozqcVEF5mZmupBsIBF-ll5HjwgFDH5UfQhEOiNWfmr_ENSma2ag==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNkk9Lw0AQxe_7KdacGlB66VGkNVQRPMRE8Bimm2mzsH_C7kQJ4nd30kjFpAUvw76Z94M3w64jQaDOGnGlnTJdjfI2Wy2zVZV5R6Adhjshyj4S2ured66G0C9i49trmWxvMm8tBoUyN0B7H2ySyk8h5QgcfRV01EQM71ohMxtWshxlwvrRDzVJJ1C9427uIx0Cli_PyUzNiH3gwOhqnr3hTj78yMFbICg6C7XQW3T0Gy8fG_9IOBRoNY9KfslN_vTH_CVEgWYabUIW2_JVKjAmMnGyn-ZnzjcozqcVEF5mZmupBsIBF-ll5HjwgFDH5UfQhEOiNWfmr_ENSma2ag==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNjrEKAjEQRPt8RUx1gmJzpcjBYn_oB0jI7eFhdleyG9C_N0UKu8fMY5hJLRarlN1u45Trgv4M4wnGBwgbfuzi3IxFhYdU1YSwHHyAjqFx2Lv7Vw1p0Ke8W3A9glArE_o5R1ulUPfcDfPfTPdfsa7mceNmTMhLO_MDqwAxGQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_27_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_27_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_27_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_27_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVj00KwjAQhfc5RcwqBcFNlyKFXKDYA0hIpxrMT5lMQG_vKEHr7uO9jwdvKGSRagxi55MLdQZ5NP3B9BeTE8GDTkKMgCUn7WqhHAH3UpmGill1YnoWgqjXYGnJGDkcG_4LhdCvwNH0gVaKM4TN-GblbutCEnxi6y39qu-Su1m8gu7YGCDNfOQFmYRE0Q==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNks1qwzAQhO9-CtUnB0pzybGU_BBKaQ9JXMgxrKVNIiJbYiXVhNJ3r5S6Jokd2pNn2fl2JHnH1gE5X6rkTlZceYHscTYazkabma4cyArpKUnyo3VYZtaRNHjP0vwk0qDSQdPcTLWvBNAxMwrcVlMZuotGpgP2mTDWjPk1bEQRPdq6HWG-fEs7VZjepbAEqWpNB6RgmceKrU9lRJ51C7Y3WHr0eDbgAytXeBvpKNnU2wi9wvYAN2MJhYzIKn7Tc9Frt3ttwMj4WEGxyeLl6nTXQI0FGBO6ayzYxJifCOCuIb6SZIWq6-9JXM3zd8ZBKRu4C6j1dK7Fge-RKa0P3vxNnf4cIQg7rEk6_EfQ2atrEkgPPPAOxU2y3Ta-B9phNrh2XixCX471heUkCwzkGCsR1vwbAjz-LQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_28_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_28_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_28_gateway.png\" alt=\"gateway\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_28_order-flow.png\" alt=\"order-flow\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_28_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNjrEKAjEQRPv9ipjqBMXmSpGDxf7QD5CQ24PD7EaSDejfu0WK64bHm2GmqqFo4wSHTWJqC7krjhccX5hF6as3gJlKzTLEVjUzlZPz2KO37I_w_FUlHj4p6JoLG7yfMbMJkdzcaXfhQWk3teu8Q1vV0SZmTSSLnfoDZ3o0bw==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNksFKxDAQhu95itiTC8pe9iiyWmTxttgHKEMyusUms0wmK0V8d6dWpC2V3UvIF_Jl_mSyTQIsObTmqomuzR7tXblZl5u6pCjQROR7Y6ouCYb6kXL0wN31sQV5JQ43tni6LSkEZId2_7tarOynsXaQ_vbWkOWQkE-NQ_UelGw1YKG8o34sVgviGwh-QNdL-2e7G-iMkxDYjcpVP3xhwXSg40hVWhS_jHnBdiHnPwcxZUH1zkjTd-oJozQOLnHn1x547k1ijXqpU20jsUeeK5NQI4URvBV6x5hU2WL0-pe-Ae4izq4=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqN0sFOwzAMBuB7niL0tEkILjsiNFFNHEBiow8wZcm_raJNKseZ2NvjdEhlQKXeYsdfLMtZRjbEqW3UTe1tkxz0Q7m4LxfbMnjGJz8qVZ0jo511jeF9oHbrdre6WIfIB0K1eS3-RMVcZW1qD9okJAwWJ3jepShVq3zUTylm8mL2H-bb_u4XyIEi6FRbSMVbDnV1iTN5DiOwM-dWegx0fUlMwvEYukFWEv3L1DuaETQ2gOQtdJ-UB678deX4IPZo6IDZfKLvN9bJTR15IvmxqL7izhIMwwlfwjv5MV8M7cc1\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_29_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_29_components.png\" alt=\"components\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_29_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_29_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_29_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqFVE1v2zAMvftXcDl1QNZdehyGrkEPOwQblt4DRaETIfpIRbpp__0oWXblJkFPsSi-x8dHMffEKnLnbPPFeG27LcKPxd33xd16ETzjK_9smtUbMbobxW4Os19Py1n6sTacCHRHHBxGAg5wMrzfRnUCrWh_O_va_JWL4G82Sh9C2xqNAnyQA_zJJ1ixatvMtnXGG-Ko2AQPym-BuuMxRAZKOZnaeOA9wkb5Q0U-KBCWPqIsPEiK8TtYlLtcYtQKoR2J5pkZjgMyxUBpHTrPlKqU3tEpY4Xl8Vv6gD6aaJ-EyIhRMaGXRsdAoWV4fNV75XcI2AMoAyrCHoO83vRahep3CY3y36tccvvF4ElKtyG64tomdJw6M3Haxzwb6tQB4ajeHE5bE32-jcql4SyH7wsaVhwiEihrBwO1BKDov6BkVDuvlMiIPSmd0uSErKtRlpGv88il4jA-WGF8mbyX8YbKzdVX0vxDW72RC7YnH2lQKDirvMbKMxpNg44EIqRTzo-yFR0Injuk3KSM6gzRb9KwLpT3ZUL-gbIeUUdIJaveqyspudKVu3Mv6sQd8rsr9XDbGNyn7pxzDxtE6Lc0rEUNKQnVPtepxcd7Ccmf1X_KvKit\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqtVttO20AQffdXTHkplQK88FhVQEAqqClRg1okhKLxeuKsWO9au2unUdV_76zvlFwQ4gHJHs-cOXPmEs6cR-uLTEUfpBaqSAg-j09PxqfzsdEepSb7JYqmZJ3Rh6Jw3mRkR3BQW1DBBeonqVMYN98O-OM5tJ5gFuCXBDF7jWAl_RLyNjLYAIUwhfbu-OBTNFs7T9khZSgVo1wdhQeorQH2joGk9mRD9EQKa5xZeLj6LZaoUwKqA1wVMABkq15YzIgxJu1zR7zHn3ljyQEq1dIWbKh4BkcONDZDL40GjE3huyrdqKtjBN6idiiCG7-RFz2T-QX7JGjXh3UZ5OcNOGe_bkz_E_sEfyKArhsvQueYS_7Lg-7TazjPcyVFxTLUdIMlAuoEZrkNoJOf42CeWlPKhIvtsrZVLgpdcUcl_RpKydFwM7v9fvL17m46A04R6tlJKEGPMbog92XzGHLeWhSKoDXBTCy51QPhC8cDYymVjjWsZB5IPoIluiUlgAV3RvumRhCWkvCKqu4COQfKpL30O6lmJpaKGvkm1UtQMJC6xwxZsmdqISiZSc8sXBE7Vq2Zkz0qetOPSiUpx0gLdXJIqJSC9lJ1OQap-FHR0RRT2tTqmbAy91XDz3VaKLTP-fej_TbKK4ohtmbFndpLmH0bYX9x1Ovm8pKULEPKQJFPE7eZl5CRdV3URuau0gTyoAn2aQLBv1H0g9TgcG1YvFLSyrULzKAKNU_RqMqX4RPLluM6YwZhQjmEYQPmS6ThnUnJ95jDy7GwJnsDdnsUHenEtZduGNI4DE700JUFNY3jdi0GHSulk8wplmn4dixMdiLjOh88VJfgcT9cPbFvlHcH7rOlfafu9bVvKSPpJtPUPw0Nv49uuBTb0CuMHZe7Zhrut-AdrZI89Ff3cRvsUIn3R-8Adl14S8hTFqa6knxl-Tw2GS4vxvuxh0uzief95Ntrae7ckTM28r85_wCCNS3d\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNq1Vt9P2zAQfu9fceMJJBgvPE4TbWEaiI6qYRPSNEVX55paOHZkO3TVtP99ZydNC-VHGPBmX3x3n7_77uJj59H6qlC9D1ILVWUEn4ZHh8OjdGiK0mjS_nOvlyydp2KXCpRqH3ZOD8ICausOG67mBFJ7shoVjKSwxpmZh9PfYo46J6DawUWHjzt7vaHRHqUmu1u7kU-nqG-kztMMPU7REYc9aZYhxaVFoQhWJkjEnOGEL4k3lhxUjixYyqXzFr00mhHNjC3ieh_m6OaUAVZ-zneSoj4iLGVhi8rtAwpBzoEyOW_Ii2eAFmYqFaVYlgxiFDfQL8sA6RoLtFKH5diaW5kxPgQlC-kZg6umjjyYGTAWOGviQhMXZpUWARwq6ZfgDYjKeVOQdXArMfhIC3VyyOhWCnoGqCsx0MRLRQdjzCNM1VAQMJ7jLSbCytID6gz6Oq8U2rvolXod4AVNYWrNgqsU4DaKYlnomcUiVHu0WsOgCbwWWFPjDRSCDS2CjUoDTk3l1xBiWU2lPa9YGNphxPpAhdMBH8vQLrcZxFI2de6Pz-6wtwd_egBtrzzqmq5QpK4qWBzLEKsxQVKbIECxRimK3CelDXcb_RjChJy_97WtzJrshfRzllmToCGKqQ9QWhbClTsBjs2eitXBddu3vhsgB4RRSQnpzDXt7oIUQld2z9nKIZ2hwOwpVcCXeOIBDH2onYH5MlErbdhWMOtJ1AkXa4-tJTq3MDbjHJNggHFjeFHh-kpxF9TEBIZi7KZSqwzrWsamDYfh--SiM15HorLcjLEi9fLJsrViutvKlhSGgcUoncx13Wn7EId62LRw22bqho5jpSEQz6Rc8zx5FX8hGsOCptbtdLorlwDub683IfXIfOyAtsAbpihMAMGDKCb_eZ5cfjv8enU1Tn5xhv8I_8BceJc8WxL-zyybf73346xTlrejrlO6t2Jwi6Qubcxyd88F3ObjJYO2S4b7FLwV8s5xt39KXcKv0Tz12rSEPHhn1hTxFbRgD2qKejIYPlvObUo3HzcPaeV6dNFRKlvXXr3E3cb_lkci-3CoYzbyi_4fm7VLXQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_2_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_2_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_2_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_2_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpzKC5JLCopzc3hUszMS84pTUlVsHE20Xc2iXfOzytJrSix4-IKSC0qzs_TSC4tLsnPTS3SUVByhjKVgGwlTa7gyuKS1FyN_LyczLzU4oz8AqCwP5ijEAzkQVVxBaXmIBmCojo7sTStRCE1Mw-oziE1LwXoIACdBTNA\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNkkFLw0AQhe_7K8acWlB66VGkGqMIijERPIZJMm0XN7tlZ6MU8b87W4O0tUpv82bf93Z57IwD-tB3Rp1o25i-JThPp5N0WqXOBtSW_IVSOXl2dtT0HFxH_hSSdBgTmZOxKtccqKuuXG9b9OuRs0ZQXrqVnD9uBJSikjF8KICf7C1jhSst5iIrn-Eyv4vBt26I_4Noazm-xoA1MkVr7jgsPJVP9_-D1KE2TP5NNyTGLEoov_UxF8-9bMm2YnqhGm4GGaGCsAkD_alUQWartp1aXrGfByBtxRltB_MP99OgMfwb2zj2-_GELU_evQ50BLLXDMsjKEB29hDXgs9kIb_lCxPFv3I=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_30_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_api-internals.png\" alt=\"api-internals\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_components.png\" alt=\"components\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_customer-touchpoints.png\" alt=\"customer-touchpoints\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_mobile-flow.png\" alt=\"mobile-flow\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_30_security-flow.png\" alt=\"security-flow\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_30_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNq1VU1vGjEQvfMrppyoRJpLjlUV2KhKKmgQm1aRqmo1eAew4o-Vxwvi39feD0AhIpu0PSCZsee9mTfP3mv26HypVe-DNEKVOcHn5OoyucoSqwtryPgvvd6MHFszECV7q8kNoV9HUMEYzZM0K0iavX7YHEF7EuwS_JpgEU4NYSv9Goo2M8YAhbCl8fyp_7G3ZxxI48kZ8tmiRs-wkOFXZO3xjEut0e0iWROCtA5BYo13Vqm6lrRwsbzpzwTmxP7Z7szZjcyJ2zqgxpXUtSCN0iwdasqWKDCngDltQ3tt0h170vC1OnFU1JjQ1HrVyRBqs5Vee9iOZTjiEC2QeWtdHiDnMQCzJvAmTUZK2S1DCwYVNmwkAocsRRclE_yYTzqWxiRKJ30cVdosYZ_2ghi3aHIVJsJyZS6kGR4KEWs0q86TiflZzO-nYQV35j0ihFYdQxhKRANpam7jw3jInXLn6HGBHF1w0ywj2L1DoQjaEKRiTRqrIrwN8lY0QeeVZO_QSxuplnYIwlEempSoeBgtSsyg7IpfKUPbhVQUVYh2rP7AqCgi4SNGe1dCT6SWnnJosoL5oE6EnDZS1ELX1h3s_XjG30f9oFIgwmqPHdtxumotovbmpI5ek_MNbCRtDxd0gQqNiBwmD9fkiaJTd5riC1BGgwb4iH4Ws4NpaujR7A5E6KbywK9v6f33y9uHh1n6-69YXnjF_ifdyePwTrITkbrc-WBtfg3wVI-3vLddGJ5L8K8qPxw_9xY4wpxh6ayuXLsNGdSofjNOXtX7tOfj6_jSMB-nk8Msr8nk4QP_B4Gu3WQ=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqdVMGO0zAQvfcrhl4o0sJe9ojQdoMQICpVpAIkhKKJM21HdWxjO6n27xk7SdWFXYo41fX4vTdv5rW3IaKPXatnz9go3TUEr4ub6-KmKqyJyIb8m9msvA-R2gXG9grmy81qnj60tscAqgvRtuQDRAtHjvvG4xEUhv2r-YvZWgrWLKZHAhtuUMMdmgObHRRjLXOe6MBuIe4Janl1lXnBTch0B6iU7UwMSeXU6oJNJG8oVvXAXrW2Zk0VOif0q_wFls4lsW_YomeTjp-45UgNjCiwBgYgNNSzoksqwaGwlHLU9HKNu6yhWWFkmwU-Yo-l8uwioGlgaXadxmz5Xac1fBgJTw2wGdx7GTH5C-pHqkeDX6l-TDlrls4n5tWXIl2_Jc192prsP7ICJfRkhu6Scrlenu0vdM5ZHyt5vN0KetoZlOTTfKBMhfl5JYyVDMkLnDxJ14l69pn0WTB-l8BwCPCzo5CMpHAJ5CFiSOMUuZAzB10Qk388_cvIeg4cA9S8y40p215zPdDA9_ebzbr8cZlu2H_PJG2MwRSfGo1EJ4-0xYOcHN63MuTwr10-CO__sT_t_AkTzRQM-TmndU3tPQ8g0CmRwn5LppH_jV9whoKd\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNq9VU1v2zAMvedXcDl1QLJeehyGpmmHtmjWIO6GAcNgMDLjCJUlQ1SS9d-PkvOFBmuMYNvBgEz7vUc-StQlB_RhUZnOO22VWRQEH4cX58OLfOiq2lmy4VOnk71woOqMKtSmB92bflxAE-1K4GlOoG0gb9HASCvv2M0C3PxSc7QlATUAToAP3fedLflZA6OQT9E-a1vmWGt56jyJ5Wrz4052i43KWe0FBFeENr2SLXgtxxAcLJg8t1T0xBKtkXnlfCFskxiA8TogwjZ4Zwz5PeXRtyHIf-HV14ExbsWwIYPEDUuNwIIy1JfE4OvkoWVqTGrhdXhJJTbLN324RVsYYhErbV_b3i6RpiNtLYn4POK7mazgzp5iQupBbEZkk33SaNuA2pI_1C4w4BSZhOB6vYxkjx6VIdiEIFNz2SIpieDE3iQjPpeag8egXZSauR4oT4UUqdFwD1ApYgbjSj6SRuWm2lB0QSRG6QUGdR0Fv2OFUndcPuhKBypgjQJRbYBQ0FIrOqbCNSZz054YY5k0jFapgChwj0vMlNd1AOkpDGy5MJjc_bwwRjrSEG4T0BaCnMapF-fJR_XOhMwfhFv0vcJn8XYwvgOFpjlTP-6zxy_nt09P4-yn8J9Af3DSTlTZ79G_q6WVyt8q6SDrNjNBtj4fI3yd4H_nPRzobeh32bw1KDyhzP2Zd1U6JStB0Nry66vhUbMPUtvcdLx3n8iAEYxQXUpQbszfYPCcPg==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqFVE1v2zAMvftXcDl1QNZdehyGrkEPOwQblt4DRqETIfpIRbpp__0kWXblJkFPkUm-x8dHKfcsGKSzpvminTLdluDH4u774m698E7oVX42zeqNhewNip3D7NfTcpZ-jPEnBtWxeEuBQTyctOy3AU-gkPe3s6_N35jw7maD6uDbViuKwIf4AX_yF6wE2zazba12miWgaO8A3Ra4Ox59EOBUk6m1A9kTbNAdKvJBQWTpI2jgIZZot4NFyeUWo1bw7Ug0z8xwHJApBqiU75xw6lJmJ4vaRJbHb-kAfTTRPkUiHY0KCb3UKnj2rcDjq9qj2xFQD-AMqAh7DMl602uNVL9LaJT_3uWS2y-aTrF164Mtrm18J2kyHaZzzLOhFg8ER3yzNB0t6nNtQJuWsxzOFzSsxAdiQGNAxRMU4bWEai1lfeu8vogeVgErCi-T3Y8ZLpmrG2_-kan2fcHC5AkPc0ecQaeomp9HA6DjCImkU86PspEPDM8dcRov2X6G6F_FcPU53_0J-QfK2u6OiUtV_UaulOROV3LnXtSFO5J3V-or0wZvP3XnnHt4DUxuy8MVryGloHqbdWnx8T6G4h_Pf3xFlX4=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqtVdtOGzEQfd-vmPJSkAK88FhVhEBVEClRF7VICEWz3snGwmuvbO-mUdV_Z7yXZFtyQagPSGbWc87xmUvOnUfry1xFH6QWqkwJPo3OTkdn05HRHqUm-zmKJmSd0YeidN7kZAdw0ERQwQXqZ6kzGLXfDvjjELqbYGbg5wQJ3xrAQvo5FF1miAEKYUrt3cnBURQvnaf8kHKUilGujsMBmmiAvWcgqT3ZkD2WwhpnZh6ufok56oyAmgRXJ_QAOapnFnNijHF3Xglf48feWHKASoHgUy0w3OAMY3P00ug16vSCdadol4eNJPLT9j4jXbehf0mO4HcEsHL2VeoUC8l_RfBwcg3DolBS1MRB3w1WCKhTiAsbQMc_RiE8saaSKQtfsXbCZ6UWIRmV9EuoJMJNfPft9Ov9_SQGJgiv2SknRY8JumDcZXsMjHcWhSLoQhCLORetZ2HpuPSWMum8reXXHg5AWEpJe4nKDULpyTlQJnN7heQmkYpaa8b1P8GdQPmAObId4Xgrc-kpXb2feZtESKmSzLaXxxUYXsFHRccTzGhTDWJhZeHrSgx1Viqsm_5LyX3zqgRSN_1vzYI92cu_oKR95E9K3lj_S1Ky4qECHmUvBfcuo-pGX-COJ8PA-yeKvpPqzfCGvq0kLVw3k_wGhZpdG9RQOT5zZQtc5gweSswpDBswXyP1Ry4jv8bszRLMrMnfgd3tB0c6dd3Q91PaC71t1b_qwJv24nYveoWopJOsKZFZ-HYiTH4qk4YPHutRetoP1_TVZnv3ObAD9q-xeB_69pdveUTatZs3dXt18j464NSu07eh1xg71l6jNCw_wXu4JnlcL62nbbB9I_4_-gpg14K0hNxjoadryxeWV1HLcHkx2o_dH5lNOh_Gt2-VuXNCzjnIv_cvAkrQyg==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNq1Vk1P20AQvedXTDmBFMqFY1WRBBAgUqIYKqSqsibriVmx3rV216FR1f_e2bXzAQFiENw248x7b97M2HvkPFpfFarzRWqhqozg2-DwYHCYDkxRGk3af-90krnzVOxSgVJ1YedkPxygju5w4PqOQGpPVqOCoRTWODP1cPJH3KHOCahOcDHh685eZ2C0R6nJ7tZp5NMJ6nup8zRDjxN0xLDHzTFQXFkUimARgkTcsZzwJPHGkoPKkQVLuXTeopdGs6Kp6YKwlHEVEpXrAgpBzoEyudsiozATqSjFsmSKYfwBvbIMhLdYoJU6HC9lIT1l0GQBs9aJkNFMMtcWFldiqICPivZHmEcOJUUsIBBc4AwTYWXpAXUGPZ1XCm14clopBecN4FKA1OC5GRNrHtiPwN70jhugpxaL4OtwcYZ-k7ZqZeMmMrjg0xrw1Ngi6npUU9o3lc7QzjeLw1I2_vVG548K24O_HYDlhL2YmnK_GN671FUFmz4PWE0IkjoEQYo1SlG0JSltkDv8OYAxOf_k6ciamcxCfTUK1LiyblQrSXEJUrH442odlrlrMvqEsY0J6cw1a-DAmzit7TmXzUunKDB7rYdwGv_xjIYe1Mk8pCwgTMkStrUQHg2Olujcg7EZg45DAEZN4E296CnFQwoLMIjYMJMIrt4H9ghuxpetxTkSlZV-Hv2uj6825Yw3SvEsOJnrfam7Kyn1a6t9fwJCGhB4lXPNW_keI-JIhNkIaLxvgf1fpzMm9cJ7o4WcAu-5wLB-gjc6ov-6SK5-HJxdX4-S38zwDvhnlvJTeDaG7Z0s66_yz_OsFcvHWdeK7qMc3DCpzQ7yPLttgJt-vOUd2IbhqQUfpbw17ub3og38Ss1rFyRLyJ-VqTVFvB08cAY1TT3uD7a2c9PS9VvCc7NyO7xsOSobZS8uj27tU8jvPM5hqCMO8iX0P8VOzjE=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqtVU1v2zAMvftXcDm1QLJeehyGJmmHdmiwIOmKAcNgsDKTCJUlQ1SaBcP--yjZ-Vizpe6wQwCGNt97JJ_kCw7ow7I02RttlVkWBO-G52fD83zoyspZsuF9lk3XHKg8oRK16ULnqhcDqLMdSdwtCLQN5C0aGGnlHbtZgKvvaoF2TkB1AaeCt53TbOhsQG3Jn9RlFPIHtI_azvMCAz4gk8BeNmGk-ORRGYJNCqZqIXLik2lwnhiWTB48zTUHj0E7K4pmrgvKUyFdaDTcBVSKmMG4OUcZTV8izs48lpFztIlhUAvaa7NhQmNASQSN5ETky0T6W3P5wC1tgX592CVWWn6VgPbHN9CvKqNVAuicwo8MYDv9v5bm0ovAB855WZZCErGaFEzrFEQp3hlDPumvfJQ7uh_ChDg8ezr27kkXsb8aBWpcTWlUrSQlg-Rq8-LOKtvaPRkDQpv-ki24sQhDcGmT7Tm3y8tnqLA4tkP4kN74g4Y-1MUgE3EQxM5b2NZCxBqSrZB55XwhoJOYgHGTeNUu-sa4FcMGDBI2PGkElipDPZkRfJ7cthbHpJZeh3Wadx0eXco12sKIF1jPbU_b7k5KfaTb7yci5BGhM5UIbuy_DCJZInojosl5i-w_s2xCpgVxm6EIAQvmUcDDA_caU7ZheG6h_6W8Ne7hAW4Dv1Nz7Db3hHLOZ96VIOaClVRQ2unXj5eD4beXSA5Hun9tl_goYPEuVXI917BfRrdn13d34-mL2Adtb750vHc3iQmlRqAuJClfzF9Wtpy5\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_3_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_3_backend.png\" alt=\"backend\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_3_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_3_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNTjsKAjEQ7XOKMdUKgs2WIguxs1DcA8iyeWIwmUhmAnp7I25h9_68QXQqWlM0q8BzrB60c_3W9VeXWfHSvTFnFMnczVU0J5QNWbdA27Bdm_EtitTJPT-bcOIYGDQ29vUPKHREYfIQ-iWldcwF8W9y6T6melNC4JYYwL4d-wAkRjV1\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNkU0KwjAUhPc5xbMrBcGNSxGxW8GqOzclbR41mCYleRFEvI038WJGIxZ_cZeZzDcDycQRt-RrxTpSl8oLhFE6HKTDPDV1YzRqGjOWGk1carRdtzFNLoo-JJlxVFlcLWbJm0p6LZJPjdeC231kC15uUYsQmsZT0oMDA3jMPcVyYwVah3YnSwzM_CphFfV96Svb8H0dzJbOovHCHxlbovo1-7u1QEfnE8mKYM03yusqlP7TeHvGJrjSEcT7T-TrYMtyLySBMtfBSYiGb7wAqZikWQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_4_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_4_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_4_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kVtLxDAQhd_zK8Y-tSAsyD6KrNYLgmDdCj6WaTNug2lSknSliP_dabe7wpY-hTPnO3MhGx_Qha7R4kKZSneS4Dpdr9J1kVoTUBlyN0LkvQ_UxC32DZnQOrtXktwlRNmhAtlUirgWJRNf3NnOSHR97GvbsvNqNDeEnFWUwI8AOA0ZkQJbxdj2IX-H2-wZ9ldDvyc7dZ3hFVY1DQGSykM6qOgolzKyZOMeA5boRzqzPuwc5W8vS5FPx5qMZPuDSnic5GEUVmHK_QqxJX0eOb-rQq090yd09P5Xc4TSr76dCrSAHa8eX9DWfnXtjJx_VVWj21GcMLrhzfjL_wAnHqW6\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_5_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_5_api-components.png\" alt=\"api-components\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_5_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_5_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_5_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVkEEKwjAQRfc9ReyqBcFNlyJKDmCxB5DQjjaYTMpkWu3tHW1EXeXnvz_MZ_aRDfHoXbay2LqxA7XV1UZXZx2Q4cG7LKuBYsDCdN7iWuWH15uLyMsPasfIwQOJqZNMgWaODL4YzOwBWbx6UaqmMNkOSBWyBAjL_4HYh0GMIzqLoBr5JZ6dwP3sS7mbGS-sQHqV70DqmugEdDeOgRNd7G-ntjd0haIUvAfs5BpPhaJaMA==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kkFPwzAMhe_9FaanVkLaZUeENipASEiUFYnjlCXeGi1NKifdmBD_HbfL2NjgFL-8z8mL24kPgkLXmORKW2k6hXBTjEfFeF44G4S2SLdJUiJ5ZzOhGm2vIZ32a8pFmh8s2fngGiTeLGIZgWrnAzZZK3YN2sB75b6CktxGKyTI8CMg2fxXw_zOdVYJ2mW-di07L9ZwGqhYpTl8JgA_CQdkLlrN2Oy-eoNp-dQf9ujikQAxxQBKIWvsUVTaQ9Gr9CD_bFCLPrbzYUVYvT6nF2roOIuzJNZoFdvvuICHKPc3CRli31eSzNCczC8-dy26ZQDkOecDEGcf3Q3SVpiAIbpnN57PQwpj_Ck6eMe3EQrlR1vSAf_BDjMbVjDOrbv2gjx-Y1kLWmGWMzLhRPx_fQOd4cc4\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNqNkkFLxDAQhe_5FWNPLgh72aPIrkVQEKxb7yU2gw2bJmEyURbxv5tud7e23YOn5E3eN3kZsg4siWNrxJW2tYkK4TZfLfNVlbvWO4uW74Qo94GxvQ6N81Ut6wZvINui0gHyTmUn2W2yxciu3lOtcIE_CMvX52ymkj93lqW2SNW9i1ZJ2ves9Lrr_FC-waZ4yhbwLQDOuc6eSkZuGmmVQUr-TVLw2MvjBRcpRwppwF46-R_Ok1Ox5oEs-sKE_RFii-bPQ4ZxEEoVll-kGUNyXrCdhnxYwTi3i37inOQfunukoAPD4Xzaf5Z-nAqOxzNsNOJRxE9ptJKMwG6HNnFrtCp9qF_vIM1a\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_6_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_6_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_6_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_6_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpVj0EKwjAQRfc5RewqBcFNlyKFHMBiDyChHW0wmZTJROztHWlB3f15_898ps3siEsMaudxCGUEfbTNwTZXm5DhxSelOqCc0Awlc4pAe13ZTVaiq1r1S2aIZnZLBGRh3ap0R-npRyBt5BIQ1v8LeUqzgDMGj6B7mTZfXSD89G25hys31uBREp_Air-tw-ToDqYWuwUc5ak3ABhIUQ==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kU1LxEAMhu_zK8aeWhD2skeR1fqBIFhbwWNJO9ndwelMyaTqIv5307W4X3hL5n2SvMksIgPx0Dl1Zn3rBoP6Ip_P8nmdB89gPdKlUgVSDD5th8ihQzrXST6FicRJpqpNZOzSHjYdepa34jfSBYV3a5B0ip-M5LODgvo6DN4AbdK4Dr0oT97JSF1JlmT6S2n9Z2OL1NBbwcrb6kVfFQ9js_swtTxhTSPCDTA0EHGEihB5RVg9P_5XsiTJ0RuRX7HRd1M64iVCy1Pdt1Ilur17TPbfYFiyRuuFGYGjnscbtOBc3Ee32s47IZg4-yDLeIrtbt2ugVaYZoIsZI585g-RhpiR\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_7_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_7_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_7_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_7_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9kUFrwzAMhe_-FWpOCRR26XGMtqEbO60khR2D6qiNwXGCrRRC2X-vsmYraaEXw_P7nmTJy8DouautmhmnbVcSvKaLl3RRpI1jNI78m1J5H5jqGDuuAvmT0TSHaCUK8quMRH80wxklf3SLfU2Ob4Ht9eJJplg3nSvR93GomlacL2flCZCLihI4K4Cx-OAX2Bphsk2-g9X2c1JvCh68DEOuFO-b9vA-yoHNCDWPoR-lMrL3kftWGq0NQv-jv950N4OSUY1Gpgf0YTG6Qn-kGGuZnhPhl9JY_uQCqXOHeg==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNptkMEKwjAMhu99irrTBoKXHUUmO3h0uAeQ0kVXXNPRpuLe3owVdOil5P_z9U_aKpDyFO0gNgb1EDuQ-7rc1eW1dkjwooMQ7RQIbK4i9QH802jYyuzISraLzFif3HxmhWjAB4e5joGcBc9mncoEpLhRTRaQPonNYvwNTXdC70Y2zjgYBNmySn1xgeFrZOIeKt5IgkEmZmCx1--YFU81WhGssJ_9dK_8HXJlXUQqmK0AO_65Nwv5aq4=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_8_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_8_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_8_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_8_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp9kUGLwjAQhe_5FbM5WVjw4nERsbiysKzaCB5LbIa1UJMySRUR_7uTKloseAm8N1_y5pGJD5pCs6_ER2mLqjEIX-lomI7y1NmgS4s0FkKdfMB9PnWNNZpOA79z9SfIha0YAMVKJnAWADewnee6LiNDBgkU0qEsULIxd_GUyQtttuwunQ__hGr1K3uqd8PFlwlr90jJWLyJOGLM2OAWvonLoTURy1AX4c5fhMiw6tCdIsuFWsOwDfWMPrh22lvI6wMOWiPpwh3k2frnT82yNWMTXom_4gr7qIIf\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNTr0KwjAQ3vMUMVMFxaWjSOFwttgHkJBeMZjcleQC-vae0MHt--cbqvgiLSezixRSm9GeoT9B_wAmwbdcjBmxVKYutCqcsRysgw06xW5vpk8VzF198qrCjVIktJOyn389AmfNBrRj8iILl6wdc8f0N7l1X74tYjGSJgakWY99AS-CNaw=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_9_drawio_png_images/","summary":"\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_9_containers.png\" alt=\"containers\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"/images/drawio/teil_9_context.png\" alt=\"context\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""},{"content":" ","permalink":"https://paul-fleischmann.com/projekte/bausteinsicht/tutorial/examples/teil_9_plantuml_views/","summary":"\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNpNTr0KwjAQ3vMUMVMFxaWjSOFwttgHkJBeMZjcleQC-vae0MHt--cbqvgiLSezixRSm9GeoT9B_wAmwbdcjBmxVKYutCqcsRysgw06xW5vpk8VzF198qrCjVIktJOyn389AmfNBrRj8rJwyVoxd0x_i1v15dsiFiNpYkCa9dcX89w1OA==\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"imageblock kroki\"\u003e\n\u003cdiv class=\"content\"\u003e\n\u003cimg src=\"https://kroki.io/plantuml/svg/eNp1kU0LAiEQhu_-islTQdClY0S1VARBHxt0XEynkkxDXSKi_97s9gXVXtSHeV7G0V6Iwsf8aFhNW2lyhdBJ2q2knSXORqEt-i5j6SVEPGYDl1sl_KUe9u7UBD6zhgRIiXgDrgzgHSqVTJw0acthuoL-fMLpPHbFyhu_rhRyj4WNSgdICuIvrMqoDRXmLsSdx3Qx5T_0L7T1xGgVlde4gdETH82EjM_cjbElmu_I91hSGBPIfqtl7XM5j0KF1tnriBXaa-5yB-PcIafXZD1qR99yB2kFhi4=\" alt=\"Diagram\"/\u003e\n\u003c/div\u003e\n\u003c/div\u003e","title":""}]