[{"content":" The Core Problem: Documentation Goes Stale Software architecture is usually documented once — at the start of the project, when the architect is still motivated and the system is still manageable. Three months later, reality looks different. A new service has been added. A dependency has been moved. The old diagram still shows the original idea, not the current system.\nThe problem is structural: diagrams live in presentations, wikis, or Draw.io files. Code lives in the repository. The two worlds do not synchronize automatically — so they drift apart.\nArchitecture-as-Code: Text as the Source of Truth The answer from the Architecture-as-Code movement: architecture belongs in the repository, alongside the code. Text-based description, versionable, reviewable, diffable. When a service is added, the architecture model changes too — in the same commit, in the same pull request.\nThe principle works. What makes it harder: text models are not diagrams. Architects and teams think visually. A YAML file describing a graph is correct — but not intuitively navigable.\nThe Two Camps: Text-first vs. Visual-first Existing tools each solve the problem from one side:\nTool Strength Weakness Structurizr\nOwn DSL, structured C4 model, many export formats\nNo visual editing — text is the only source\nLikeC4\nModern DSL, VS Code extension, live preview\nDiagram is output, not an editable frontend\nC4 model\nClear methodology (Context, Container, Component, Code)\nNot a tool, just a framework\nC4InterFlow\nExtends C4 with interface and flow concepts\nVery specifically focused on interaction modeling\nThe common denominator: text is the source, diagram is the output. The diagram itself cannot be edited, at least not in a way that flows back into the model.\nWhat Bausteinsicht Does Differently: Bidirectional Synchronization Bausteinsicht flips the question: why do you have to choose?\nThe model lives as a JSONC file in the repository — text-based, versionable, LLM-readable. draw.io is the visual frontend — a widely used, mature diagramming tool. Both sides are equal. Changes in the text flow into the diagram. Changes in the diagram flow back into the text.\n# Change model → update diagram bausteinsicht sync # Edit diagram in draw.io → update model bausteinsicht sync # Continuously on every file change bausteinsicht watch This is not an export. It is a merge: positions, labels, new elements — the sync command detects what has changed and reconciles both sides, without overwriting either.\nThe Model: JSONC with Three Sections The heart of it is an architecture.jsonc — JSON with comments. Three sections define everything:\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 defines the language: which kinds of elements and relationships can exist in the model. model contains the concrete system elements with arbitrarily deep hierarchy. views controls which elements appear in which diagram — an element can appear in multiple views.\nWhy draw.io as the Frontend? draw.io is not a random candidate:\nWidely used — many teams already have it in place\nWorks offline, no cloud dependency\nXML-based format that can be read and written programmatically\nFree positioning and visual customization possible\nThe decisive point is the format: draw.io files are uncompressed XML. Bausteinsicht can read the XML selectively, match elements, merge positions, and write the result back — without opening the draw.io application.\nThat makes bidirectional synchronization technically possible. With a proprietary binary format, it would not be.\nExample Model The example for this part is stored as a runnable JSONC file at teil_1.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_1.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next This post gives an overview — the following posts go into depth:\nGetting Started — from an empty folder to the first diagram\nThe Data Model — specification, model, views in detail\nBidirectional Synchronization — how the merge algorithm works\nFor those who want to get started right away:\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/ # First project mkdir my-architecture \u0026amp;\u0026amp; cd my-architecture bausteinsicht init bausteinsicht sync Official documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-projektvorstellung/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_core_problem_documentation_goes_stale\"\u003eThe Core Problem: Documentation Goes Stale\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eSoftware architecture is usually documented once — at the start of the project, when the architect is still motivated and the system is still manageable.\nThree months later, reality looks different.\nA new service has been added.\nA dependency has been moved.\nThe old diagram still shows the original idea, not the current system.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThe problem is structural: diagrams live in presentations, wikis, or Draw.io files.\nCode lives in the repository.\nThe two worlds do not synchronize automatically — so they drift apart.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 1: What is Architecture-as-Code — and what makes Bausteinsicht different?"},{"content":" This post is part of the EthTrcv series and builds on the AUTOSAR basics post. It is aimed at software developers who configure EthTrcv on a daily basis but have never wanted to know exactly what happens at PCB level.\nAnyone who sets an ARXML parameter like EthTrcvBusIdx to ETHTRCV_BUS_TYPE_RGMII is making a hardware decision — even if it may not feel that way. This post makes visible what lies behind these parameters.\nThe PHY Chip as Mediator An Ethernet PHY chip sits exactly in the middle between two worlds:\nSoC / Microcontroller Cable ┌─────────────────┐ ┌────────┐ │ Ethernet MAC │◄── MII/RMII/RGMII ─►│ PHY │◄── MDI ──► Twisted Pair │ │◄── MDIO ────────── ─►│ Chip │ └─────────────────┘ └────────┘ On the left side: digital interfaces to the MAC in the SoC. On the right side: analog interface to the cable. In the middle: everything that makes up the conversion — encoding, scrambling, signal shaping.\nEthTrcv_Init initializes this chip. What exactly happens during that process, this post explains from left to right.\nThe MAC-Side Interfaces (MII Family) The MAC-side interface between SoC and PHY is standardized. IEEE 802.3 defines several variants — all under the umbrella term MII family.\nMII — Media Independent Interface The original from IEEE 802.3u (1995). Rarely found in new designs today, but essential for understanding its successors.\nSignals: TX_CLK, TXD[3:0], TX_EN, TX_ER RX_CLK, RXD[3:0], RX_DV, RX_ER, CRS, COL Clock: 25 MHz (100 Mbit/s) / 2.5 MHz (10 Mbit/s) Data width: 4 bits parallel (nibble) Lines: ~16 data lines + control/clock lines Why it is rarely built anymore: 16+ lines on the PCB, high routing effort, and on modern SoCs the GPIO pins are too valuable.\nRMII — Reduced MII Reduced variant with only 9 lines instead of 16+. Typical for smaller microcontrollers where GPIO pins are scarce.\nSignals: REF_CLK (50 MHz, from PHY or external), TXD[1:0], TX_EN RXD[1:0], CRS_DV, RX_ER Clock: 50 MHz fixed (one clock for both directions) Data width: 2 bits parallel Note: MAC and PHY share a common 50 MHz reference clock The 50 MHz REF_CLK must either be supplied by the PHY or fed in externally. Forgetting the clock or wiring it incorrectly means no link — and wondering why.\nRGMII — Reduced Gigabit MII The dominant standard today for automotive Ethernet at 1 Gbit/s and for many modern 100 Mbit/s designs.\nSignals: TXC, TXD[3:0], TX_CTL RXC, RXD[3:0], RX_CTL Clock: 125 MHz (1 Gbit/s) / 25 MHz (100 Mbit/s) / 2.5 MHz (10 Mbit/s) Data width: 4 bits, DDR (Double Data Rate — data on rising AND falling edge) Lines: 12 signals instead of MII\u0026#39;s 16+ DDR at 125 MHz delivers effectively 8 bits per clock cycle → 1 Gbit/s. This sounds elegant but has a catch: RGMII Timing Delays.\nThe specification requires that data must be delayed by 1.5–2 ns relative to the clock. This delay can be implemented in the PHY, in the MAC, or via PCB trace lengths — and is a common cause of sporadic transmission errors when the PCB layout is wrong.\nIn AUTOSAR this is not directly visible, but the EthTrcvBusIdx parameter selects among other things whether internal PHY delays are activated or whether the MAC driver handles them.\nSGMII / SerDes For scenarios where PHY and MAC are further apart — typically with switch chips that aggregate multiple PHYs.\nSignals: TX+ / TX- (differential), RX+ / RX- (differential) Clock: 1.25 GBaud serial (8b/10b encoded → 1 Gbit/s payload) Lines: 4 (two differential pairs) Advantage: Longer PCB runs possible, fewer lines In EthSwt configurations SGMII is more common than in simple EthTrcv setups.\nDecision Guide: Which Interface for What? Interface Max. Speed Lines Typical Use Automotive Relevance MII\n100 Mbit/s\n16+\nLegacy\nRarely new\nRMII\n100 Mbit/s\n9\nSmall MCUs\nMedium (ECUs)\nRGMII\n1 Gbit/s\n12\nApplication SoCs, 1000BASE-T1\nHigh (ADAS, Gateway)\nSGMII\n1 Gbit/s\n4\nSwitch aggregation\nHigh in zonal architecture\nThe MDIO Bus MDIO (Management Data Input/Output) is the control bus to the PHY. This is where EthTrcv_Init runs — not over MII/RGMII.\nSoC │ ├── MDC (Management Data Clock) ────────────► PHY 1 └── MDIO (Management Data I/O, bidirectional) ─► PHY 1 ► PHY 2 (same line) ► PHY 3 (same line) Electrical Specification Voltage: typically 3.3 V LVCMOS (or 1.8 V on modern SoCs) MDC frequency: max. 2.5 MHz per IEEE, many PHYs tolerate up to 25 MHz Pull-up: MDIO requires a pull-up resistor (typically 1.5 kΩ – 4.7 kΩ) Bus load: up to 32 PHY addresses per MDIO bus possible The pull-up is critical: if it is missing, MDIO stays permanently low and all register reads return 0xFF or 0x00 — which looks exactly like a misconfigured PHY.\nClause 22 vs. Clause 45 IEEE 802.3 defines two frame formats for MDIO:\nClause 22 (classic):\nST | OP | PHYAD[4:0] | REGAD[4:0] | TA | DATA[15:0] 2 2 5 5 2 16 bits 32 PHY addresses, 32 registers per PHY. Sufficient for simple PHYs.\nClause 45 (extended):\nST | OP | PRTAD[4:0] | DEVAD[5:0] | TA | ADDR/DATA[15:0] 2 2 5 5 2 16 bits Clause 45 introduces a DEVAD (Device Address) — enabling 32 address spaces of 65536 registers each. Mandatory for 1000BASE-T1 PHYs and all PHYs with safety or MACsec features.\nSome SoC MAC drivers only natively support Clause 22. Clause 45 on such systems requires a workaround via \u0026#34;Clause 22 Preamble Suppression\u0026#34; — a common pitfall with newer PHY chips.\nTiming and MDC Frequency MDC ───┐ ┌──┐ ┌──┐ ┌──┐ ┌── └──┘ └──┘ └──┘ └──┘ MDIO ════╪═════╪═════╪════ Setup↑ ↑Hold Setup time (MDIO stable before rising MDC edge): min. 10 ns\nHold time (MDIO stable after rising MDC edge): min. 10 ns\nWith too high an MDC frequency or long PCB traces these times are violated. Symptom: register reads return corrupted values, PHY does not respond to init.\nMultiple PHYs on One MDIO Bus Each PHY has a 5-bit PHY address (0–31), often configured via hardware pins. In ARXML this corresponds to the parameter EthTrcvPhyAddress.\nSoC MDIO bus ├── PHY @ address 1 (PHYAD pins: 00001) ├── PHY @ address 2 (PHYAD pins: 00010) └── PHY @ address 3 (PHYAD pins: 00011) Address conflicts (two PHYs with the same address) are a classic hardware bug: both PHYs respond simultaneously, the bus is corrupted, all MDIO reads return garbage.\nThe Line-Side Interfaces On the other side of the PHY chip: the connection to the cable.\nMDI — Medium Dependent Interface MDI is the physical connection of the PHY to the transmission medium. The name says it all: from here everything is medium-dependent — the PHY standard defines the electrical properties of the signal on the line.\n100BASE-T1 — The Automotive Single-Pair Interface Classic 100BASE-TX uses two twisted wire pairs (TX and RX separate). 100BASE-T1 manages with a single twisted pair.\n100BASE-TX: ──[TX+/TX-]── ──[RX+/RX-]── (2 pairs, ≈ RJ45 connector) 100BASE-T1: ──[T1+/T1-]── (1 pair, differential, bidirectional) Bidirectional operation on one pair is possible because the signal uses echo cancellation in the PHY — the chip subtracts its own transmit signal to isolate the receive signal.\nCable specification:\nImpedance: 100 Ω (±15 %) Maximum length: 15 m (standard), up to 40 m at reduced data rate Cable type: Unshielded Twisted Pair (UTP), automotive-approved AWG: typically AWG 22–24 1000BASE-T1 Same philosophy as 100BASE-T1, but at 1 Gbit/s over a single-pair cable. Uses PAM3 with a higher symbol rate, shorter maximum cable length (approx. 15 m). Increasingly used in vehicles for backbone connections (zonal controller → domain controller).\nConnectors in the Vehicle The cable has to be connected somewhere. In the automotive world there are established connector standards for this:\nConnector Use Relevance for Ethernet FAKRA\nHigh-frequency coaxial, classically for antennas and cameras\nNot for twisted-pair Ethernet — a common mix-up\nHSD (High Speed Data)\n4-pin connector, for data transmission in the vehicle\nUsed for 100BASE-T1 and USB, widely deployed\nMATEnet\nTE Connectivity standard specifically for automotive Ethernet\nOptimized for 100BASE-T1 / 1000BASE-T1, low insertion loss\nH-MTD\nCompact, for tight installation situations\nIncreasingly used for 1000BASE-T1 in compact ECUs\nThe connector affects signal integrity. An HSD connector with incorrect impedance matching can cause link issues at 1000BASE-T1 just as reliably as a defective cable.\nEMC Aspects Software developers rarely think about EMC — hardware developers always do. The interface sits in the vehicle close to other interference sources (ignition system, DC/DC converters).\nCommon-Mode Filter (CMF): Mounted directly at the MDI connection. Suppresses common-mode interference on the line. Wrong or missing CMF → PHY has increased noise → sporadic bit errors.\nESD Protection: Transient Voltage Suppressor (TVS) or similar components at the connector. Protects the PHY from electrostatic discharge when plugging/unplugging. Mandatory in production applications — often omitted on development boards.\nPCB Layout: The differential trace routing (T1+ / T1-) must be routed with exactly equal length (differential pair matching). Length mismatch \u0026gt; 150 mil → measurable signal quality degradation.\nPower Supply and Voltage Levels A modern automotive PHY chip typically has multiple supply domains:\nVDD_IO 3.3 V — I/O level for MII/MDIO signals to MAC/SoC VDD_Core 1.8 V — Internal core logic VDD_PLL 1.8 V — PLL for clock generation (often separate rail) VDD_MDI 3.3 V — Analog side, line coupling Power Sequencing The power-on sequence is specified in the PHY datasheet and must be followed. Typical sequence:\n1. Power up VDD_Core 2. Power up VDD_IO (≥ 100 µs after Core) 3. Power up VDD_MDI 4. Deassert hardware reset (RST_N) 5. Wait for PHY boot time (typically 1–5 ms) 6. MDIO access possible → EthTrcv_Init can start Violating the sequence → PHY boots in an undefined state. Symptom: EthTrcv_Init returns but the link never comes up.\nWakeUp Pin and INH Pin Two pins that software developers should know, even if they never directly control them:\nWakeUp Pin (WU): Input on the PHY for an external WakeUp pulse. When the ECU is in sleep and supports Ethernet WakeUp, a specific pulse on this pin can wake the ECU up. On the AUTOSAR side this is evaluated in EthTrcv_CheckWakeup.\nINH Pin (Inhibit): Output of the PHY that controls the ECU’s voltage regulator. When the PHY goes to sleep it pulls INH low → voltage regulator shuts down → ECU sleeps. When WakeUp is detected the PHY asserts INH → voltage regulator starts → system wakes up.\nWakeUp pulse on line → PHY detects pulse → PHY asserts INH → voltage regulator starts → SoC boots → EcuM calls EthTrcv_CheckWakeup → AUTOSAR WakeUp validation runs through From Bit to Signal — a Frame Through the PHY Finally, the complete path of an Ethernet frame through the PHY chip, from MAC handoff to differential signal on the line.\nStep 1: MAC Hands Over Frame via RGMII SoC MAC hands over: TXD[3:0] = nibble, TX_CTL = 1 (valid), TXC = 125 MHz PHY receives 4 bits per clock edge (DDR) → 8 bits per clock cycle At 125 MHz: 8 bits × 125,000,000 = 1,000,000,000 bits/s = 1 Gbit/s Step 2: PCS — Physical Coding Sublayer The PCS prepares the bits for transmission:\nScrambling — pseudo-randomly shuffles the bit sequence, prevents DC bias\nEncoding — for 100BASE-T1: no 8b/10b, instead direct PAM3 mapping with trellis code\nStep 3: PMA — Physical Medium Attachment The PMA converts the encoded bits into physical symbols:\nPAM3 for 100BASE-T1:\nThree voltage levels: +1 (positive), 0 (zero), -1 (negative) Symbol rate: 66.67 MBaud (66.67 million symbols/second) Each symbol: carries ~1.58 bits of information (log₂(3)) Payload: 100 Mbit/s after overhead Three levels instead of two — that is why 100 Mbit/s over a single-pair cable at only 66 MBaud symbol rate is possible.\nStep 4: Echo Cancellation Since transmitting and receiving happen on the same wire pair, the PHY must subtract its own transmit signal from the receive signal. This happens digitally inside the PHY with an adaptive filter — and is why 100BASE-T1 PHYs are significantly more complex than classic PHYs.\nStep 5: Signal on the Line Differential signal: T1+ and T1- with 100 Ω impedance Amplitude: typically ±1 V (differential) Frequency range: DC to ~66 MHz (main energy) Latency Through the PHY RGMII → PCS → PMA → cable: typically 150–500 ns (depends on PHY chip and implementation) Cable (15 m @ ~0.6c): approx. 80 ns Receive side (cable → MAC): another 150–500 ns Total latency for one frame: approx. 500 ns – 1.5 µs. Relevant for gPTP (Issue #14) where sub-microsecond accuracy is required.\nSummary Interface Key takeaway for software developers MII/RMII/RGMII\nChoice affects the EthTrcvBusIdx parameter; RGMII timing delays are a common PCB bug\nMDIO\nMissing pull-up → all reads return garbage; check Clause 45 for modern PHY chips\nMDI / 100BASE-T1\nSingle-pair, bidirectional via echo cancellation; cable impedance and connector are signal quality factors\nEMC\nCommon-mode filter at the connector is mandatory — if missing, problems only show up in vehicle EMC testing\nPower sequencing\nWrong order → PHY does not respond to init, no obvious error code\nWakeUp/INH pin\nThese pins control the ECU’s voltage regulator — AUTOSAR EcuM must be configured correctly\nNext in the EthTrcv series: EthTrcv Part 1 — Basics \u0026amp; Classification\n","permalink":"https://paul-fleischmann.com/en/autosar/ethtrcv/ethtrcv-hardware-deep-dive/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post is part of the EthTrcv series and builds on the \u003ca href=\"/en/autosar/\"\u003eAUTOSAR basics post\u003c/a\u003e.\nIt is aimed at software developers who configure EthTrcv on a daily basis\nbut have never wanted to know exactly what happens at PCB level.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAnyone who sets an ARXML parameter like \u003ccode\u003eEthTrcvBusIdx\u003c/code\u003e to \u003ccode\u003eETHTRCV_BUS_TYPE_RGMII\u003c/code\u003e\nis making a hardware decision — even if it may not feel that way.\nThis post makes visible what lies behind these parameters.\u003c/p\u003e\n\u003c/div\u003e","title":"EthTrcv Hardware Deep Dive — The Physical Interfaces of the PHY Chip"},{"content":" Why? Anyone developing AUTOSAR stacks day in and day out knows the problem: the actual hardware is far away. Between the code I write and the chip it runs on sit configuration tools, build systems, integration processes, and usually an evaluation board that I share with the rest of the team.\nPrivately, I wanted something different. A board that belongs to me. A project I own from start to finish — requirements, architecture, implementation, CI/CD. No client, no process overhead, no compromise.\nThe BeagleBone Black was the obvious choice: ARM Cortex-A8, AM335x, Linux-capable, well documented, and established in the embedded community for years. Not a Raspberry Pi — the BeagleBone is closer to the hardware, and that was exactly the point.\nWhat This Project Is It is not a product and not a tutorial project. It is a platform where I try out things that interest me professionally — but under conditions that I fully control.\nConcretely: an embedded system with a strict 5-layer architecture, a multi-language stack, and a complete CI/CD pipeline — the way I would build it in a professional project, just without the constraints of a client engagement.\nThe Hardware Board: BeagleBone Black\nProcessor: Texas Instruments AM335x, ARM Cortex-A8, 1 GHz\nRAM: 512 MB DDR3\nStorage: 4 GB eMMC + microSD\nInterfaces: GPIO, I2C, UART, SPI, USB, Ethernet\nThe AM335x is interesting because besides the Cortex-A8 it also includes two PRU cores (Programmable Real-Time Units) — for deterministic real-time behavior directly on the SoC, without a separate microcontroller.\nThe Software Architecture The project follows a strict 5-layer architecture:\n┌─────────────────────────────┐ │ Application │ ← Python / Go ├─────────────────────────────┤ │ Services │ ← Go ├─────────────────────────────┤ │ Hardware Abstraction │ ← C / Rust ├─────────────────────────────┤ │ Drivers │ ← C ├─────────────────────────────┤ │ Hardware │ ← AM335x / Linux └─────────────────────────────┘ Each layer only knows the layer directly below it — no bypass, no shortcuts. This is not an academic principle but a pragmatic decision: if I replace the driver for a peripheral six months from now, the rest of the system should not notice.\nThe Language Mix C — drivers and HAL, where control matters\nRust — Hardware Abstraction Layer, where memory safety without performance overhead is needed\nGo — services and REST API\nPython — application layer, scripting, test automation\nThis is not a language mix for its own sake. Each language is used where its strengths lie.\nThe Infrastructure A private project without proper infrastructure quickly degenerates into chaos. That is why the project has had a complete CI/CD pipeline from the start:\nGitHub — Git repository and issue tracking\nDrone CI — build pipeline, running as a Podman container\nCross-compilation — CMake with ARMv7 toolchain, build runs on x86\nDeployment — automatically to the BeagleBone Black after a successful build\nEvery commit triggers the pipeline. Build, tests, deployment — automatic, reproducible, without manual steps.\nDrone CI with Podman instead of Docker has its quirks — there is a dedicated post for that.\nRequirements Management What sometimes frustrates me in professional projects: requirements that live somewhere in a Word document and have nothing to do with the code.\nIn this project I use StrictDoc — a document-based requirements management tool that links requirements directly to the code. Every requirement has an ID, every implementation references it. Traceability from requirement to test.\nThis is overkill for a private project — and that is exactly why I do it. If it works here, it works everywhere.\nWhat Comes Next This is the first post in a series about this project. All posts in order:\nRust in the HAL — why and how\nThe REST API in Go — GPIO, I2C and UART over HTTP\nCross-compilation for ARMv7 with CMake\nDrone CI with Podman — pitfalls and solutions\nStrictDoc in practice — requirements that live with the code\nAll BeagleBone posts →\n","permalink":"https://paul-fleischmann.com/en/projekte/beaglebone/beaglebone-black-project-introduction/","summary":"\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_why\"\u003eWhy?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAnyone developing AUTOSAR stacks day in and day out knows the problem:\nthe actual hardware is far away. Between the code I write\nand the chip it runs on sit configuration tools,\nbuild systems, integration processes, and usually an evaluation board\nthat I share with the rest of the team.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003ePrivately, I wanted something different.\nA board that belongs to me. A project I own from start to finish —\nrequirements, architecture, implementation, CI/CD.\nNo client, no process overhead, no compromise.\u003c/p\u003e\n\u003c/div\u003e","title":"BeagleBone Black: My Private Embedded Project"},{"content":" This post continues from the first part. That covered what Architecture-as-Code is and what sets Bausteinsicht apart from other tools. Here it gets practical: installation, first project, first diagram.\nPrerequisites Bausteinsicht binary (Linux, macOS, or Windows)\ndraw.io Desktop or the draw.io VS Code extension\nAn editor with JSON support (VS Code recommended)\nInstallation # Automatically determine the latest version (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 (all platforms — always the latest version) go install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@latest Check that the installation works:\nbausteinsicht --version Step 1: Initialize a Project Create a new folder and initialize Bausteinsicht:\nmkdir my-architecture \u0026amp;\u0026amp; cd my-architecture bausteinsicht init init creates four files:\nFile Purpose architecture.jsonc\nThe architecture model — the single source of truth\narchitecture.drawio\nThe generated draw.io diagram\ntemplate.drawio\nVisual styles for element types (colors, shapes)\n.bausteinsicht-sync\nSync state file — belongs in git alongside the model\nStep 2: Understanding the Generated Model Bausteinsicht creates an example model of an online shop. Open architecture.jsonc in your editor — you will see the three main sections:\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 defines the language of the model. model describes the concrete system. views controls which elements appear in which diagram.\nValidate the model:\nbausteinsicht validate Output: Model is valid.\nStep 3: Open the Diagram Open architecture.drawio in draw.io. You will see two tabs:\nSystem Context — Customer and Online Shop at the top level\nContainer View — the internal containers of the Online Shop\nNew elements appear with a red dashed border as a visual marker. Positions can be adjusted by drag and drop — Bausteinsicht remembers the set positions on the next synchronization.\nThe layout is intentionally manual — and that is a feature, not a limitation. Bausteinsicht does not apply positions automatically, because no algorithm knows which spatial proximity carries meaning in your diagram. You decide which elements belong together and how the reading direction flows. Once set, positions are preserved on every sync — you never have to re-layout, as long as you do not add new elements. For those who still want automatic arrangement, bausteinsicht sync --relayout is available — it resets all positions and applies the hierarchical auto-layout. Details in Part 14: Auto-Layout. Step 4: Add an Element via CLI Add a new email service to the model:\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;Sends transactional emails\u0026#34; Output: Added element \u0026#39;onlineshop.emailservice\u0026#39; (kind: container) to model.\nNow create a relationship from the REST API to the Email Service:\nbausteinsicht add relationship \\ --from onlineshop.api \\ --to onlineshop.emailservice \\ --label \u0026#34;sends emails\u0026#34; \\ --kind uses Step 5: Sync Model → Diagram bausteinsicht sync Output:\nForward (model → draw.io): 2 added, 0 updated, 0 deleted Reload architecture.drawio in draw.io — the Email Service appears with a red border in the Container View.\nStep 6: Sync Diagram → Model Now the other direction: write a change from the diagram back into the model.\nOpen architecture.drawio in draw.io\nDouble-click on \u0026#34;Web Frontend\u0026#34;\nChange the title to \u0026#34;Web App\u0026#34;\nSave the file\nbausteinsicht sync Output:\nReverse (draw.io → model): 0 added, 1 updated, 0 deleted Open architecture.jsonc — the title has been updated to \u0026#34;Web App\u0026#34;. That is bidirectional synchronization in practice.\nStep 7: Watch Mode For continuous synchronization while working:\nbausteinsicht watch Bausteinsicht monitors both files and syncs automatically on every change. This allows you to work in the editor and in draw.io simultaneously — without manual sync. Ctrl+C exits watch mode.\nwatch works well for workshops and review sessions: multiple people can edit the model and diagram simultaneously, and the watch process keeps everything in sync. Example Model The example for this part is stored as a runnable JSONC file at teil_2.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_2.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 3: The Data Model in Detail — specification, model, views and all available fields\nPart 4: Bidirectional Synchronization — how the merge algorithm works and what happens when both sides were changed simultaneously\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-getting-started/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-projektvorstellung/\"\u003efirst part\u003c/a\u003e.\nThat covered what Architecture-as-Code is and what sets Bausteinsicht apart from other tools.\nHere it gets practical: installation, first project, first diagram.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_prerequisites\"\u003ePrerequisites\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, or 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 or the draw.io VS Code extension\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAn editor with JSON support (VS Code recommended)\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# Automatically determine the latest version (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 (all platforms — always the latest version)\ngo install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@latest\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Part 2: From Zero to Your First Architecture Diagram with Bausteinsicht"},{"content":" This post is part of the series about my private BeagleBone Black project. There I introduced the 5-layer architecture and the language mix — here I go into a concrete aspect that often raises questions: Why use Rust in the HAL at all, when C has been working there for decades?\nWhy Rust in the HAL? The honest answer: because I wanted to try it. Privately run projects are exactly what they are for. In my day job I make technology decisions under time pressure, with consideration for the team and the existing codebase. Rust had no place there so far.\nHere it does. This urge to truly understand something new — not just to have read about it, but to have built it, debugged it, and gotten it working — is one of the main reasons this project exists. Rust in the HAL is my learning lab for a language that has interested me for years but has not been required professionally yet.\nAnd then there are the technical reasons that justify the experiment.\nThe Problem with C in the HAL C gives you full control — and full responsibility. A wrongly set pointer, a forgotten free, an off-by-one when reading an I2C buffer: the compiler says nothing, the system stays silent until it crashes at runtime. In a private project that is manageable. In a safety-critical system it would be an incident report.\nWhat Rust Does Differently Rust enforces correctness at compile time instead of runtime:\nOwnership — every resource has exactly one owner, no double-free possible\nlet buf = vec![0u8; 64]; // buf owns the memory let buf2 = buf; // ownership is transferred // using buf here is a compile error — no double-free possible Borrow checker — simultaneous read and write access is prevented\nlet mut reg = 0u8; let r = \u0026amp;reg; // read reference // reg = 1; // compile error: write access while borrow is active println!(\u0026#34;{}\u0026#34;, r); No garbage collector — deterministic resource release, no pausing\n{ let fd = open_i2c_bus(1); // resource is opened // ... I2C operations ... } // Drop is called here exactly — no GC, no indeterminate waiting Zero-cost abstractions — iterators, traits, generics — without runtime overhead\n// This iterator chain compiles to the same machine code as a handwritten loop let sum: u32 = readings.iter() .filter(|\u0026amp;\u0026amp;v| v \u0026gt; 0) .map(|\u0026amp;v| v as u32) .sum(); For hardware code this means concretely: a register value that may only be written once, an I2C bus that should not be used by two threads simultaneously — Rust makes such invariants part of the type system, not a convention.\nRust is not a silver bullet. The borrow checker protects against memory errors, not logic errors. Wrong I2C command, wrong register address — it won’t catch those.\nBoundary with C The project has two layers below Services:\n┌─────────────────────────────┐ │ Hardware Abstraction │ ← Rust (this layer) ├─────────────────────────────┤ │ Drivers │ ← C (Linux sysfs / ioctl) ├─────────────────────────────┤ │ Hardware │ ← AM335x / Linux └─────────────────────────────┘ C stays in the driver layer:\nDirect access to Linux kernel APIs (ioctl, open, read, write)\n/dev/i2c-, /sys/class/gpio/, /dev/ttyO*\nMinimal, well-understood structures\nRust takes over HAL logic:\nType-safe API over the raw driver functions\nError handling with Result\u0026lt;T, E\u0026gt; instead of raw error codes\nState machines for peripheral protocols\nThe boundary is pragmatic: where the Linux kernel call ends, Rust begins.\nRust FFI to C Rust can call C functions directly — but not without effort. The keyword is unsafe and the attribute extern \u0026#34;C\u0026#34;.\nBinding a C Driver The C driver for I2C exposes this function:\n// i2c_driver.h int i2c_read(int bus_fd, uint8_t addr, uint8_t reg, uint8_t *buf, size_t len); In Rust the signature is declared:\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; } The call itself is unsafe — Rust cannot verify the correctness of the C function:\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) } } The unsafe block is kept deliberately minimal. The public API exposed to the outside is fully safe.\nLinker Configuration The C library must be linked in at build time. 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 as a Library for Go The services layer is written in Go. Go can link C-compatible libraries (cgo) — but not Rust directly. The trick: Rust compiles as a C-compatible shared library.\ncbindgen — Auto-generate Headers cbindgen reads the Rust code and generates a C header from it:\n# cbindgen.toml language = \u0026#34;C\u0026#34; include_guard = \u0026#34;BBB_HAL_H\u0026#34; For every pub extern \u0026#34;C\u0026#34; function 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, } } cbindgen automatically generates:\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 } Concrete Example: I2C Read End-to-End The complete path of an I2C read through all layers:\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 Each layer adds exactly one abstraction: * C: raw kernel call * Rust: Result-based error handling * Go: idiomatic Go interface\nCross-Compilation for ARMv7 The build runs on x86, the binary must run on the ARM Cortex-A8.\nInstall Rust Target 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 Command cargo build \\ --release \\ --target armv7-unknown-linux-gnueabihf The binary is then located at: target/armv7-unknown-linux-gnueabihf/release/libbbb_hal.so\nThe cross tool wraps cross-compilation in a Docker container — less setup, but a container dependency. I use the manual toolchain because it fits better into the Drone CI pipeline.\nOwnership and Lifetimes in a Hardware Context Hardware resources are exclusive by nature. An I2C bus cannot be written to by two threads simultaneously. A GPIO pin has exactly one driver.\nRust’s ownership system models this directly:\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 is neither Clone nor Copy. There can be exactly one instance that owns the bus. When the instance goes out of scope, the file descriptor is closed automatically.\nThis is not a pattern I invented — it is how Rust idiomatically models hardware access.\nConclusion Rust in the HAL is more work than C — that is honest. FFI bindings, cbindgen, cross-compilation setup, a borrow checker that occasionally clashes with the ARM linker.\nBut the gain is real:\nCompile-time guarantees instead of runtime crashes\nExplicit error handling with Result\u0026lt;T, E\u0026gt; instead of raw error codes\nResource management via ownership instead of manual close()\nFor a professional system where memory errors in the HAL would mean a recall, this is not overkill but a minimum. For a private project it is the best opportunity to practice the craft before you need it.\nNext post in the series: The REST API in Go — GPIO, I2C and UART over HTTP\n","permalink":"https://paul-fleischmann.com/en/projekte/beaglebone/rust-in-the-hal/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post is part of the series about my \u003ca href=\"/en/projekte/beaglebone/beaglebone-black-project-introduction/\"\u003eprivate BeagleBone Black project\u003c/a\u003e.\nThere I introduced the 5-layer architecture and the language mix —\nhere I go into a concrete aspect that often raises questions:\nWhy use Rust in the HAL at all, when C has been working there for decades?\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_why_rust_in_the_hal\"\u003eWhy Rust in the HAL?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThe honest answer: because I wanted to try it.\nPrivately run projects are exactly what they are for.\nIn my day job I make technology decisions under time pressure,\nwith consideration for the team and the existing codebase.\nRust had no place there so far.\u003c/p\u003e\n\u003c/div\u003e","title":"Rust in the HAL — why and how"},{"content":" This post continues from the second part. That introduced bausteinsicht init, sync, and watch. Here the focus is on the heart of it: the JSONC data model with all fields and extension points.\nThe Basic Structure An architecture.jsonc file has four required fields and several optional sections:\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 Global settings for diagram generation:\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/my-org/my-repo\u0026#34;, \u0026#34;metadata\u0026#34;: true, \u0026#34;legend\u0026#34;: true } specification The specification defines the language of the model — which element types and relationship kinds exist. It is the only section that needs to be set up once and then rarely changed.\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;A user or external 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 } } } The container flag controls whether an element may have children in the hierarchy. If the flag is missing (or is false), bausteinsicht validate rejects any model element of that type that has children.\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 are defined under specification.tags and can optionally carry draw.io styling:\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;External system outside our control\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;Legacy system — no active further development\u0026#34; } ] } specification.patterns Patterns are reusable topology templates — for example, a standard microservice pattern with frontend, API, and database:\n\u0026#34;specification\u0026#34;: { \u0026#34;patterns\u0026#34;: { \u0026#34;microservice\u0026#34;: { \u0026#34;description\u0026#34;: \u0026#34;Standard pattern: API + Database\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 references (Architecture Decision Records) can be managed directly in the specification:\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 as the primary database\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 The model describes the concrete elements of the system. Each key is the element ID — it must be unique within its hierarchy level.\nElement Fields \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;The core of the system\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;: { ... } } } } Nested Hierarchy Elements can be nested to any depth, as long as the respective kind has container: true:\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; } } } } } } The element ID in relationships and views uses dot notation for the path: shop.backend.orderservice.\nstatus Values Status Meaning draw.io Color proposed\nPlanned, not yet started\nYellow\ndesign\nIn design\nBlue\nimplementation\nUnder development\nOrange\ndeployed\nIn production\nGreen\ndeprecated\nOutdated, being replaced\nRed\narchived\nDecommissioned\nGray\nrelationships Relationships are defined as a flat array at the top level, not inside elements. This allows relationships between elements at different hierarchy levels:\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;confirms payment\u0026#34;, \u0026#34;kind\u0026#34;: \u0026#34;uses\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Synchronous 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 define which elements appear in which diagram tab. Each key becomes a tab in architecture.drawio.\nView Fields \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;Overview of all systems\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 with wildcards:\n\u0026#34;include\u0026#34;: [ \u0026#34;customer\u0026#34;, \u0026#34;shop.*\u0026#34;, \u0026#34;shop.**\u0026#34; ] Optional Extensions asIs / toBe For as-is/to-be comparisons, the current and target architecture can be stored directly in the model:\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 visualizes the difference between asIs and toBe as an annotated diagram.\ndynamicViews Sequence diagrams describe the temporal flow of interactions:\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;clicks Buy\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 values: sync (solid arrow) | async (open arrow) | return (dashed back). bausteinsicht export sequence generates PlantUML or Mermaid from this.\nconstraints Architecture rules are defined as machine-checkable constraints and evaluated with bausteinsicht lint:\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;Only services may access the database directly\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;All systems must have a description\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; } ] Available rule values: no-relationship, allowed-relationship, required-field, max-depth, technology-allowed.\nJSON Schema for IDE Auto-Completion Without a plugin, auto-completion works through the bundled JSON schema. Set the $schema entry in architecture.jsonc:\n{ \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34; } In VS Code (and any editor with JSON schema support), auto-completion for all fields appears immediately — without having to install an extension.\nExample Model The example for this part is stored as a runnable JSONC file at teil_3.jsonc and shows specification, model, views, and relationships with all optional fields.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_3.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 4: Bidirectional Synchronization — how the merge algorithm works and what happens when both sides were changed simultaneously\nPart 5: Multi-View — multiple diagram perspectives from one model\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-datenmodell/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-getting-started/\"\u003esecond part\u003c/a\u003e.\nThat introduced \u003ccode\u003ebausteinsicht init\u003c/code\u003e, sync, and watch.\nHere the focus is on the heart of it: the JSONC data model with all fields and extension points.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_basic_structure\"\u003eThe Basic Structure\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAn \u003ccode\u003earchitecture.jsonc\u003c/code\u003e file has four required fields and several optional sections:\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":"Part 3: The Bausteinsicht JSONC Data Model in Detail"},{"content":" This post continues from the third part. The unique selling point of Bausteinsicht is bidirectional synchronization: changes in the JSONC model end up in the draw.io diagram — and changes in the diagram end up in the model. This post explains how that works.\nThe Problem: Two Representations, One Truth Architecture diagrams have a fundamental problem: either the code is the source of truth and the diagram is generated automatically (good for consistency, bad for visual control), or the diagram is the source and is maintained manually (good for appearance, bad for consistency).\nBausteinsicht solves this through genuine bidirectionality: model and diagram are equal. The sync algorithm detects which side has changed, and transfers the change to the other side.\nThe .bausteinsicht-sync State File The foundation of the sync algorithm is the .bausteinsicht-sync file. It contains a snapshot of the state after the last successful 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 } } This state file is the three-way comparison: sync compares the current state of both the model and the diagram against the last known state — and thereby determines on which side something has changed.\nThe .bausteinsicht-sync file belongs in the git repository alongside architecture.jsonc. It is the only way Bausteinsicht can distinguish conflicts from legitimate changes. The Sync Cycle bausteinsicht sync runs every execution as an atomic five-step cycle:\n1. DetectChanges → ChangeSet (what changed on which side?) 2. ResolveConflicts → conflicting fields resolved (model wins) 3. ApplyForward → model changes → transferred to draw.io 4. ApplyReverse → draw.io changes → transferred to model 5. SaveState → .bausteinsicht-sync updated The entire cycle is a pure function without side effects — all I/O happens before and after. This makes the algorithm testable and deterministic.\nForward Sync: Model → draw.io The forward sync carries all model changes into the diagram.\nNew Elements New elements appear with a red dashed border as a visual marker:\nstrokeColor=#FF0000;dashed=1; The red border signals: \u0026#34;This element was just added — position it.\u0026#34; Once the element has been manually moved and sync runs again, the red border disappears.\nPositions Are Preserved Bausteinsicht remembers the positions set in the diagram. On every forward sync, only title, description, technology, and styles are updated — not the position. Manually arranged layouts are preserved.\nTag Styles Are Applied If an element has tags that are defined in specification.tags with style attributes, those styles are applied to the draw.io element:\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 with a status field automatically receive a colored badge in the diagram:\nStatus Color Meaning proposed\nYellow\nPlanned\ndesign\nBlue\nIn design\nimplementation\nOrange\nUnder development\ndeployed\nGreen\nIn production\ndeprecated\nRed\nOutdated\narchived\nGray\nDecommissioned\nReverse Sync: draw.io → Model The reverse sync transfers changes from the diagram back into the JSONC model.\nWhat Gets Written Back? The following changes in the diagram end up in the model:\ndraw.io Action Effect in the Model Rename an element (double-click → new title)\ntitle of the element is updated\nChange the technology label\ntechnology is updated\nDrag a new element into a container box\nNew element is added as children\nDelete an element from the diagram\nElement is removed from the model\nDraw a connection between two elements\nNew relationship is created in the relationships array\nReverse a connection arrow\nfrom and to of the relationship are swapped, metadata is preserved\nDelete a connection\nRelationship is removed from the model\nRelationship Lifting An important concept: Relationship Lifting. When a connection is drawn in draw.io between two elements that live at different levels in the model hierarchy, Bausteinsicht automatically \u0026#34;lifts\u0026#34; the relationship to the appropriate hierarchy level.\nExample: The diagram shows shop.frontend and shop.api (both container children of shop). You draw a connection from frontend to api — exactly this relationship lands in the model:\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; } ] If instead you draw a connection from customer (top-level actor) to shop.api (a nested container), it is correctly created as customer → shop.api — without manually correcting the IDs.\nConflict Detection and Resolution A conflict occurs when the same field has been changed on both sides simultaneously — that is, since the last sync.\nWhen Does This Happen? Typical scenario: you change title in the JSONC model and someone else simultaneously changes the same title directly in the draw.io diagram — without synchronizing first.\nResolution: Model Wins Bausteinsicht uses a simple and predictable strategy: the model always wins.\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. The conflict is reported as a warning — the change in the model is applied, the draw.io change is discarded.\nThis strategy is intentionally simple. The JSONC model is the primary source of truth — draw.io is a view on it.\nPractical Example: Complete Sync Cycle Starting Situation architecture.jsonc and architecture.drawio are in sync (last sync 10 minutes ago).\nStep 1: Change the Model Add a new container in the JSONC:\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; } } } } Step 2: Change the API Title in the Diagram Open architecture.drawio, double-click on \u0026#34;REST API\u0026#34;, rename it to \u0026#34;REST API v2\u0026#34;, save.\nStep 3: Run Sync bausteinsicht sync Output:\nForward (model → draw.io): 1 added, 0 updated, 0 deleted Reverse (draw.io → model): 0 added, 1 updated, 0 deleted Result:\ndraw.io: Redis Cache appears with a red dashed border in the Container View\narchitecture.jsonc: \u0026#34;title\u0026#34;: \u0026#34;REST API v2\u0026#34; for the API container\nBoth sides were updated in a single sync run.\nWatch Mode: Continuous Synchronization bausteinsicht watch monitors both files with a filesystem watcher and triggers the sync cycle automatically on every change.\nThe result: you can edit the model in the editor and adjust the diagram in draw.io at the same time — the watch process keeps everything in sync in real time.\nIn watch mode, a git commit after each completed change step is recommended. The .bausteinsicht-sync state shows in git diff exactly which elements were changed — a useful log. Example Model The example for this part is stored as a runnable JSONC file at teil_4.jsonc and shows the state after a complete sync cycle (including reverse sync: \u0026#34;REST API v2\u0026#34;).\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_4.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 5: Multi-View — multiple diagram perspectives from one model\nPart 8: Validation \u0026amp; Linting — enforcing architecture rules with bausteinsicht lint\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-bidirektionale-synchronisation/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-datenmodell/\"\u003ethird part\u003c/a\u003e.\nThe unique selling point of Bausteinsicht is bidirectional synchronization:\nchanges in the JSONC model end up in the draw.io diagram — and changes in the diagram end up in the model.\nThis post explains how that works.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_problem_two_representations_one_truth\"\u003eThe Problem: Two Representations, One Truth\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eArchitecture diagrams have a fundamental problem: either the code is the source of truth and the diagram is generated automatically (good for consistency, bad for visual control), or the diagram is the source and is maintained manually (good for appearance, bad for consistency).\u003c/p\u003e\n\u003c/div\u003e","title":"Part 4: Bidirectional Synchronization — How draw.io and JSONC Stay in Sync"},{"content":" This post continues from the fourth part. In the previous parts, each example model had one or two views. Here the focus is on how Bausteinsicht generates C4-like multi-level views from a single model.\nViews as Lenses on the Model The model in Bausteinsicht describes the complete system — all elements, all relationships, all hierarchy levels. A view is a lens that cuts out what is relevant in a specific context.\nThis means: the same elements can appear in multiple views. The model section in architecture.jsonc remains a single source of truth — views only determine the representation.\nThe C4 Pattern with Bausteinsicht The C4 model (Context → Container → Component → Code) maps directly onto Bausteinsicht views:\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 (external)\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;shops\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;manages\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;] } } } This produces three tabs in architecture.drawio: System Context, Container View, API Components.\nscope: The Bounding Box The scope field in a view is the key to structured diagrams.\nWhen a view defines a scope, the scope element is rendered as a bounding box (swimlane / container frame). All other elements of the view appear either inside this box (if they are children of the scope element) or outside (external actors and systems).\nExample: Container View with scope = \u0026#34;shop\u0026#34; ┌─────────────────────────────────────────────────────┐ │ Online Shop │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ Web Frontend │→ │ REST API │→ │PostgreSQL│ │ │ │ React │ │ Go │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────┘ │ │ ↓ │ │ ┌──────────────┐ │ │ │ Redis Cache │ │ │ └──────────────┘ │ └─────────────────────────────────────────────────────┘ ↑ customer, admin (outside the box) ↗ payment (outside) The bounding box visualizes the system boundary at a glance.\ninclude: Which Elements Appear? include accepts exact IDs and wildcards:\nPattern Meaning \u0026#34;shop\u0026#34;\nExactly the element shop\n\u0026#34;shop.*\u0026#34;\nAll direct children of shop (frontend, api, db, cache) — but not their children\n\u0026#34;shop.**\u0026#34;\nAll children and grandchildren of shop (recursive)\n\u0026#34;shop.api.*\u0026#34;\nAll components inside shop.api\nfilter-tags and exclude-tags Views can also be filtered by tags:\n\u0026#34;views\u0026#34;: { \u0026#34;external-systems\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;External Systems\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;Active Components\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 Between Views When an element is used as the scope of a view, Bausteinsicht automatically sets a drill-down link on that element in all other views.\nIn the Context View, shop is a normal rectangle. But since shop is the scope of the Container View, the rectangle in the Context View gets a clickable link — one click opens the Container View directly.\nThe same applies to shop.api as the scope of the API Components view: a click on the API box in the Container View opens the Components view.\nThis creates a navigable zoom hierarchy:\nSystem Context → [click \u0026#34;Online Shop\u0026#34;] → Container View → [click \u0026#34;REST API\u0026#34;] → API Components No manual link setting — Bausteinsicht derives this entirely from the scope configuration.\nBack Navigation: Return to the Parent View Views with scope automatically receive a back button in the upper left corner of the diagram. The button navigates to the parent view — the view from which you navigated here via drill-down.\nThis makes navigation bidirectional: zoom in and out without manually switching tabs.\nPractical Example: Generating Three Views With the model from the section above:\nbausteinsicht sync Output:\nForward (model → draw.io): 12 added, 0 updated, 0 deleted Open architecture.drawio — three tabs:\nSystem Context: Customer, Admin, Online Shop (a rectangle with a drill-down link), Payment Provider\nContainer View: Scope box \u0026#34;Online Shop\u0026#34; with Frontend, REST API, PostgreSQL, Redis Cache inside; Customer, Admin, and Payment outside\nAPI Components: Scope box \u0026#34;REST API\u0026#34; with the three handlers inside; PostgreSQL and Redis Cache outside\nThe three views share the same model. A relationship in the model changes — one sync updates all three tabs at once.\nInvisible Elements: A Useful Warning If an element exists in the model but does not appear in any view, bausteinsicht sync outputs a warning:\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 This is not an error — the element stays in the model and can be added to a view at any time. The warning prevents elements from \u0026#34;disappearing\u0026#34; from the model without being noticed.\nbausteinsicht status gives an overview of all elements and whether they are visible in a view. Example Model The example for this part is stored as a runnable JSONC file at teil_5.jsonc with all three views (context, containers, api-components).\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_5.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram — here the Container View:\nWhat Comes Next Part 6: Export Features — Mermaid, Structurizr DSL, PNG, and more\nPart 7: Snapshots \u0026amp; Changelog — versioning architecture over time\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-multi-view/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-bidirektionale-synchronisation/\"\u003efourth part\u003c/a\u003e.\nIn the previous parts, each example model had one or two views.\nHere the focus is on how Bausteinsicht generates C4-like multi-level views from a single model.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_views_as_lenses_on_the_model\"\u003eViews as Lenses on the Model\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThe model in Bausteinsicht describes the complete system — all elements, all relationships, all hierarchy levels.\nA \u003cstrong\u003eview\u003c/strong\u003e is a lens that cuts out what is relevant in a specific context.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 5: Multi-View — Multiple Diagram Perspectives from One Model"},{"content":" This post continues from the fifth part. The Bausteinsicht model is the single source of truth — and from it, many different output formats can be generated. This post shows all available export commands.\nOverview: The Four Export Commands Command Purpose bausteinsicht export\nPNG or SVG via draw.io CLI (visual output)\nbausteinsicht export-diagram\nText diagrams: PlantUML, Mermaid, DOT, D2, HTML5, Structurizr DSL\nbausteinsicht export-sequence\nSequence diagrams from dynamicViews\nbausteinsicht export-table\nElement tables as AsciiDoc or Markdown\nexport: PNG and SVG bausteinsicht export calls the draw.io CLI headlessly and renders each view as an image file.\n# Export all views as PNG (default format) bausteinsicht export --output docs/images/ # Export only a specific view bausteinsicht export --view containers --output docs/images/ # SVG instead of PNG (better for print and web) bausteinsicht export --image-format svg --output docs/images/ # Retina resolution for print (2x) bausteinsicht export --image-format png --scale 2.0 --output docs/images/ # With embedded draw.io XML (for further editing) bausteinsicht export --embed-diagram --output docs/images/ Output:\nExported: docs/images/context.png Exported: docs/images/containers.png Exported: docs/images/api-components.png export requires the draw.io Desktop application on the system. Bausteinsicht detects the path automatically. On CI systems, draw.io can be run headlessly as a Docker container. export-diagram: Text-Based Diagrams bausteinsicht export-diagram generates text-based diagram formats directly from the JSONC model — without draw.io.\nPlantUML bausteinsicht export-diagram --diagram-format plantuml --output docs/diagrams/ # → docs/diagrams/context.puml, containers.puml, ... # Single view to stdout bausteinsicht export-diagram --diagram-format plantuml --view context Example output (C4 context diagram):\nMermaid bausteinsicht export-diagram --diagram-format mermaid --output docs/diagrams/ # → docs/diagrams/context.mmd, containers.mmd, ... Mermaid diagrams can be embedded directly in GitHub Markdown:\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 # Directly to 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 The HTML export produces an interactive standalone HTML page:\nbausteinsicht export-diagram --diagram-format html --output docs/ # → docs/context.html, docs/containers.html, ... The HTML pages can be opened without a server — ideal for documentation reviews without a build pipeline.\nStructurizr DSL The Structurizr export produces a complete workspace.dsl file:\nbausteinsicht export-diagram --diagram-format structurizr --output docs/ # → docs/workspace.dsl --view is not supported for the Structurizr format — it always exports the entire workspace. JSON Output for CI Pipelines All export-diagram formats support --format json for structured output in CI pipelines:\nbausteinsicht export-diagram --diagram-format mermaid --format json Output:\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: Sequence Diagrams bausteinsicht export-sequence exports dynamicViews from the model as sequence diagrams.\n# PlantUML (default) 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 # Single dynamic view bausteinsicht export-sequence --view checkout --diagram-format plantuml For the checkout example from Part 3:\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_6.drawio\nexport-table: Element Tables bausteinsicht export-table exports the elements of a view as a structured table — useful for documentation and compliance reviews.\n# AsciiDoc table (default) for all views bausteinsicht export-table --output docs/ # Single view only bausteinsicht export-table --view containers --table-format adoc --output docs/ # Markdown table bausteinsicht export-table --table-format md --output docs/ # All elements deduplicated across all views bausteinsicht export-table --combined --output docs/ # → docs/elements.adoc Example output (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 | |=== For --format json:\nbausteinsicht export-table --view containers --format json Output:\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: From Structurizr and LikeC4 In addition to export, Bausteinsicht also supports importing from other formats:\n# Import Structurizr DSL bausteinsicht import --from structurizr workspace.dsl --output architecture.jsonc # Import LikeC4 DSL bausteinsicht import --from likec4 architecture.c4 --output architecture.jsonc # Preview without writing bausteinsicht import --from structurizr workspace.dsl --dry-run # Overwrite existing file bausteinsicht import --from likec4 architecture.c4 --force This is the migration path for existing projects: import once, then continue working with Bausteinsicht.\nWhen to Use Which Export? Scenario Recommendation Command Documentation in Confluence or AsciiDoc\nEmbed PNG/SVG\nexport --image-format png\nGitHub README or PR description\nEmbed Mermaid directly\nexport-diagram --diagram-format mermaid\nTeam without draw.io wants to review diagrams\nDistribute HTML5 viewer\nexport-diagram --diagram-format html\nMigration to Structurizr or LikeC4\nExport DSL\nexport-diagram --diagram-format structurizr\nArchitecture review with stakeholders\nPDF via PlantUML or PNG\nexport --scale 2.0\nCI pipeline, automated documentation\nProcess JSON output\nexport-diagram --format json\nCompliance documentation\nAsciiDoc table\nexport-table --combined\nExample Model The base model for all export commands in this part is located at teil_6.jsonc.\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 7: Snapshots \u0026amp; Changelog — Version architecture over time\nPart 8: Validation \u0026amp; Linting — Enforce architecture rules with bausteinsicht lint\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-export-features/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-multi-view/\"\u003efifth part\u003c/a\u003e.\nThe Bausteinsicht model is the single source of truth — and from it, many different output formats can be generated.\nThis post shows all available export commands.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_overview_the_four_export_commands\"\u003eOverview: The Four Export Commands\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\"\u003eCommand\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003ePurpose\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 or SVG via draw.io CLI (visual output)\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 diagrams: 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\"\u003eSequence diagrams from \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 tables as AsciiDoc or Markdown\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Part 6: Export Features — Mermaid, Structurizr DSL, PNG and More"},{"content":" This article is in preparation. Coming soon.\nPart of the series on my personal BeagleBone Black project.\n","permalink":"https://paul-fleischmann.com/en/projekte/beaglebone/yocto-tutorial-for-beaglebone-black/","summary":"\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\u003eThis article is in preparation. Coming soon.\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\u003ePart of the series on my \u003ca href=\"/en/projekte/beaglebone/beaglebone-black-project-introduction/\"\u003epersonal BeagleBone Black project\u003c/a\u003e.\u003c/em\u003e\u003c/p\u003e\n\u003c/div\u003e","title":"Yocto Tutorial for BeagleBone Black"},{"content":" This post continues from the sixth part. Architecture-as-Code has a decisive advantage over manual diagrams: the architecture lives in the Git repository. Bausteinsicht leverages this with two tools — snapshot and changelog.\nThe Problem: Architecture Drift Without Traceability In agile projects, architecture changes continuously. After six months of development, nobody often remembers: what was decided when? Why did we split the monolith into microservices back then? What happened between Sprint 5 and Sprint 10?\nGit solves this for code. bausteinsicht snapshot and changelog solve it for architecture.\nbausteinsicht snapshot Snapshots are named point-in-time captures of the architecture model, stored in .bausteinsicht-snapshots/. They are independent of Git commits — a snapshot can be saved at any point in time.\nSaving a Snapshot # Simple snapshot without a message bausteinsicht snapshot save # Snapshot with a descriptive message bausteinsicht snapshot save --message \u0026#34;Sprint 5 end: Payment service extracted\u0026#34; Output:\nSnapshot saved: 20250611-143022 Timestamp: 2025-06-11T14:30:22Z Elements: 12 Relationships: 8 Message: Sprint 5 Ende: Payment-Service extrahiert The ID is a timestamp (YYYYMMDD-HHMMSS) — this makes it easy to place snapshots in time.\nListing Snapshots bausteinsicht snapshot list Output:\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 As JSON for scripting:\nbausteinsicht snapshot list --format json Comparing Snapshots The key feature: compare two snapshots (or one snapshot against the current model).\n# Snapshot vs. current state bausteinsicht snapshot diff 20250301-090000 # Compare two snapshots bausteinsicht snapshot diff 20250301-090000 20250611-143022 Output:\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) As JSON for CI pipelines or further processing:\nbausteinsicht snapshot diff 20250301-090000 --format json Restoring a Snapshot A snapshot can be exported as a JSONC file — for inspection or as a starting point for a new branch:\n# Export to a new file bausteinsicht snapshot restore 20250301-090000 architecture-v1.jsonc # Overwrite existing file bausteinsicht snapshot restore 20250301-090000 architecture.jsonc --force restore overwrites the current model. Make sure the current state is committed in Git or saved as a snapshot beforehand. Deleting a Snapshot bausteinsicht snapshot delete 20250301-090000 bausteinsicht changelog changelog generates a readable architecture changelog from Git history — without requiring snapshots to have been created beforehand.\nThe command reads the model at two different Git refs (--since and --until) and calculates the difference.\nChangelog Since the Last Tag # Since the last Git tag to HEAD bausteinsicht changelog # Explicit references bausteinsicht changelog --since v1.0.0 --until HEAD # Since a specific commit bausteinsicht changelog --since abc1234 --until HEAD # Only the last sprint (branch-based) bausteinsicht changelog --since origin/main --until feature/sprint-6 Output Formats # Markdown (default) — for GitHub PRs, README bausteinsicht changelog --format markdown # AsciiDoc — for technical documentation bausteinsicht changelog --format asciidoc --output docs/architecture-changelog.adoc # JSON — for CI evaluation bausteinsicht changelog --format json Example output (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 Comparison For planned migrations, the model itself provides a comparison mechanism: the asIs and toBe sections (→ Part 3).\nbausteinsicht diff visualizes the difference between the current state (asIs) and the target architecture (toBe) as an annotated diagram:\nbausteinsicht diff In the draw.io diagram, the following appear:\nNew elements (only in toBe): highlighted in green\nElements to be removed (only in asIs): highlighted in red\nUnchanged elements: normal\nThis is the difference from snapshot diff: snapshot diff compares past states, diff visualizes the planned migration path.\nPractical Workflow in Agile Projects Point in Time Action Sprint start\nbausteinsicht snapshot save --message \u0026#34;Sprint N Start\u0026#34;\nMajor architecture decision\nChange model → commit → snapshot save --message \u0026#34;ADR-007: …​\u0026#34;\nSprint review\nbausteinsicht snapshot diff \u0026lt;sprint-start-id\u0026gt; as review input\nRelease\nbausteinsicht changelog --since \u0026lt;last-release-tag\u0026gt; --format markdown → into release notes\nArchitecture review every 3 months\nbausteinsicht changelog --since \u0026lt;quarter-start\u0026gt; → for review meeting\nPR description\nbausteinsicht changelog --since origin/main --until HEAD --format markdown\nBoth snapshots and .bausteinsicht-sync belong in the Git repository. This way, the complete architecture history is under version control — no external tool needed. Example Model The example for this part (Sprint 5: Payment service extracted) is located at teil_7.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_7.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 8: Validation \u0026amp; Linting — Automatically enforce architecture rules with bausteinsicht lint\nPart 9: Graph Analysis — Uncover cycles and dependencies\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-snapshots-changelog/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-export-features/\"\u003esixth part\u003c/a\u003e.\nArchitecture-as-Code has a decisive advantage over manual diagrams: the architecture lives in the Git repository.\nBausteinsicht leverages this with two tools — \u003ccode\u003esnapshot\u003c/code\u003e and \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=\"_the_problem_architecture_drift_without_traceability\"\u003eThe Problem: Architecture Drift Without Traceability\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eIn agile projects, architecture changes continuously.\nAfter six months of development, nobody often remembers: what was decided when?\nWhy did we split the monolith into microservices back then?\nWhat happened between Sprint 5 and Sprint 10?\u003c/p\u003e\n\u003c/div\u003e","title":"Part 7: Snapshots \u0026 Changelog — Versioning Architecture Over Time"},{"content":" This post continues from the seventh part. Architecture principles are easy to write down in ADRs. What is harder is ensuring that the code — and the architecture — actually adheres to those principles over months and across teams. Bausteinsicht solves this with machine-checkable constraints.\nWhat Is Architecture Linting? Linting is familiar from development: ESLint checks JavaScript code for style rules and errors, go vet checks Go code for antipatterns. Architecture linting does the same for the architecture model:\nNo direct database connections from the UI layer\nAll systems must have a description\nMaximum nesting depth of 3 levels\nNo circular dependencies\nOnly approved technologies\nThese rules are defined in the model as constraints and checked with bausteinsicht lint.\nDefining Constraints in the Model Constraints belong in the constraints array in architecture.jsonc (→ Part 3).\nEach constraint requires an id, description, and rule — plus rule-specific fields.\nno-relationship Prevents direct connections between certain element types:\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 components must not access the database directly\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 Positively defines which element types may connect to a specific type:\n{ \u0026#34;id\u0026#34;: \u0026#34;DB-ACCESS-ONLY-SERVICES\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Only services and repositories may access databases\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 Enforces that a field is set on all elements of a specific type:\n{ \u0026#34;id\u0026#34;: \u0026#34;SYSTEM-NEEDS-DESCRIPTION\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;All systems must have a description\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;All containers must specify a technology\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; } Supported fields: description, technology, title.\nmax-depth Limits the nesting depth of the model:\n{ \u0026#34;id\u0026#34;: \u0026#34;MAX-NESTING-3\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Maximum nesting depth is 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 Detects cycles in the dependency graph using depth-first search:\n{ \u0026#34;id\u0026#34;: \u0026#34;NO-CYCLES\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;No circular dependencies between elements\u0026#34;, \u0026#34;rule\u0026#34;: \u0026#34;no-circular-dependency\u0026#34; } technology-allowed Enforces an approved technology stack:\n{ \u0026#34;id\u0026#34;: \u0026#34;APPROVED-BACKEND-STACK\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Backend containers may only use approved technologies\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 Output when violations are found:\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 Output when all rules pass:\nAll constraints passed. Exit code: 0 on success, 1 on violations — making it directly usable in CI.\nJSON Output for CI Evaluation 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 is lighter than lint — it only checks the structural correctness of the model (schema, references):\nbausteinsicht validate Checks:\nAll kind values in model are defined in specification.elements\nAll kind values in relationships are defined in specification.relationships\nAll decisions references in elements exist in specification.decisions\nAll tags in elements are defined in specification.tags\ncontainer: true for elements with children\nvalidate runs implicitly before every sync — an invalid model will not be synchronized.\nbausteinsicht health health evaluates architecture quality across multiple dimensions and gives a score from 0–100 (grade A–F):\nbausteinsicht health Output:\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 Short view for CI dashboards:\nbausteinsicht health --summary # → Overall Score: 74.5/100 [B] # As JSON bausteinsicht health --format json --summary # Write report to file bausteinsicht health --output docs/health-report.txt CI/CD Integration lint and validate are designed directly for CI. GitHub Actions example:\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 does not break the build, it only informs lint returns exit code 1 on violations — the CI build fails. This is intentional: architecture rules should be just as binding as coding guidelines. Complete Constraint Set for a Layered Architecture \u0026#34;constraints\u0026#34;: [ { \u0026#34;id\u0026#34;: \u0026#34;NO-CYCLES\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;No circular dependencies\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 does not access DB directly\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;Only backend services access the DB\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;Maximum depth: 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;All systems need a description\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;All containers declare their technology\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;Only approved technologies\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;] } ] Example Model The example for this part with layered architecture and constraints is located at teil_8.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_8.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 9: Graph Analysis — Uncover cycles and dependencies with bausteinsicht graph\nPart 10: Overlay \u0026amp; Heatmap — Project metrics onto architecture diagrams\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-validation-linting/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-snapshots-changelog/\"\u003eseventh part\u003c/a\u003e.\nArchitecture principles are easy to write down in ADRs.\nWhat is harder is ensuring that the code — and the architecture — actually adheres to those principles over months and across teams.\nBausteinsicht solves this with machine-checkable constraints.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_what_is_architecture_linting\"\u003eWhat Is Architecture Linting?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eLinting is familiar from development: ESLint checks JavaScript code for style rules and errors, \u003ccode\u003ego vet\u003c/code\u003e checks Go code for antipatterns.\nArchitecture linting does the same for the architecture model:\u003c/p\u003e\n\u003c/div\u003e","title":"Part 8: Validation \u0026 Linting — Automatically Enforcing Architecture Rules"},{"content":" This post continues from the eighth part. bausteinsicht validate and bausteinsicht lint check the model on the command line. Even better: see errors directly in the editor — while typing, without leaving the terminal. This is made possible by the Language Server Protocol.\nWhat Is LSP? The Language Server Protocol (LSP) is an open standard from Microsoft. A language server runs in the background and analyzes source code (or configuration files) — the editor queries it and displays the results:\nRed underlines for errors\nAutocompletion for known values\nHover information\nCodeLens (small info lines above code)\nBecause LSP is a standard, bausteinsicht-lsp works with any LSP-capable editor: VS Code, Neovim, Emacs, Zed, IntelliJ.\nInstalling bausteinsicht-lsp bausteinsicht-lsp is a separate binary — it runs as a background process started by the editor:\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 Setup Option A: VS Code Extension (Recommended) The official Bausteinsicht VS Code extension installs and configures the LSP automatically:\nOpen the Extensions panel (Ctrl+Shift+X)\nSearch for \u0026#34;Bausteinsicht\u0026#34;\nInstall the extension\nThe extension activates automatically as soon as a *.jsonc file containing architecture in its filename is opened.\nOption B: Manual Configuration For other editors or manual control: register bausteinsicht-lsp via the editor’s LSP configuration.\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; } } Or via vscode-languageclient in an 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; } What the LSP Provides Inline Validation The LSP calls bausteinsicht validate --format json in the background and shows errors directly as red underlines in the 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 } Error messages appear on hover over the marked position — without opening a terminal.\nSeverity levels: * Error (red): structural errors that block validate * Warning (yellow): warnings from lint (constraint violations) * Info (blue): hints (e.g. element not visible in any view) * Hint (gray): style recommendations\nCodeLens: Inline Metadata Above each element definition, the LSP shows a CodeLens line with metadata:\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; } The CodeLens shows: * Element type (kind) * Lifecycle status (status, when set) * Number of views in which the element appears\nClicking on the CodeLens opens the draw.io diagram at the corresponding position.\nValidation on Save Every time architecture.jsonc is saved, validate and lint run automatically in the background. Violations appear immediately in VS Code’s Problems panel — no manual bausteinsicht lint needed.\nJSON Schema: The Lightweight Alternative Without LSP setup, autocompletion also works via JSON Schema. VS Code supports this natively.\nSet the $schema entry in architecture.jsonc (→ Part 3):\n{ \u0026#34;$schema\u0026#34;: \u0026#34;https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json\u0026#34;, ... } This immediately provides:\nAutocompletion for all known fields (kind, title, technology, etc.)\nType validation (e.g. container must be a Boolean)\nHover documentation for all fields\nJSON Schema only checks the structure, not semantic consistency (e.g. whether a kind value is defined in specification.elements). That is the responsibility of the LSP. Local Schema (Without Internet Connection) # Download schema curl -Lo schemas/bausteinsicht.schema.json \\ https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schemas/bausteinsicht.schema.json # Reference in architecture.jsonc # \u0026#34;$schema\u0026#34;: \u0026#34;./schemas/bausteinsicht.schema.json\u0026#34; LSP vs. JSON Schema: When to Use Which? Feature JSON Schema bausteinsicht-lsp Field documentation on hover\n✅\n✅\nAutocompletion (known fields)\n✅\n✅\nType validation\n✅\n✅\nConstraint checking (lint)\n✗\n✅\nModel consistency (validate)\n✗\n✅\nCodeLens (kind/status/views)\n✗\n✅\nSetup effort\nMinimal (1 line)\nLow (install binary)\nWorks offline\n✗ (remote URL) / ✅ (local)\n✅\nJSON Schema is sufficient for most projects. bausteinsicht-lsp is worthwhile when you work regularly with the model and want immediate constraint feedback in the editor.\nExample Model The example for this part (elements with status field for LSP CodeLens) is located at teil_9.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_9.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 10: Graph Analysis — Uncover cycles and dependencies\nPart 11: ADR Integration — Link Architecture Decision Records to the model\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-lsp-integration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-validation-linting/\"\u003eeighth part\u003c/a\u003e.\n\u003ccode\u003ebausteinsicht validate\u003c/code\u003e and \u003ccode\u003ebausteinsicht lint\u003c/code\u003e check the model on the command line.\nEven better: see errors directly in the editor — while typing, without leaving the terminal.\nThis is made possible by the 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=\"_what_is_lsp\"\u003eWhat Is LSP?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThe Language Server Protocol (LSP) is an open standard from Microsoft.\nA \u003cstrong\u003elanguage server\u003c/strong\u003e runs in the background and analyzes source code (or configuration files) — the editor queries it and displays the results:\u003c/p\u003e\n\u003c/div\u003e","title":"Part 9: LSP Integration — Autocompletion in the Editor"},{"content":" This post continues from the ninth part. The previous parts have shown how Bausteinsicht makes the architecture model readable for humans — in the editor, in diagrams, in reports. This part reverses that: how do you make the model readable for machines, so that LLM assistants like Claude Code can work with it?\nThe Problem: LLMs Don’t Know Your Architecture Claude Code, GitHub Copilot, and other AI assistants know nothing about the specific system you are working on. They have to guess: which services exist, how they communicate with each other, which technologies are allowed.\nBausteinsicht solves this: the architecture model is a machine-readable single source of truth. With --format json, all commands deliver structured output — exactly what an LLM needs as context.\n--format json: Machine-Readable Output Almost all Bausteinsicht commands support --format json:\nbausteinsicht export --format json # complete model as JSON bausteinsicht lint --format json # constraint violations structured bausteinsicht validate --format json # validation errors structured bausteinsicht health --format json # health score with details bausteinsicht find auth --format json # search results structured bausteinsicht status --format json # lifecycle status of all elements bausteinsicht snapshot list --format json # snapshot list structured bausteinsicht snapshot diff \u0026lt;id\u0026gt; --format json # diff structured bausteinsicht changelog --format json # changelog structured The difference from text output: JSON is deterministic, contains no whitespace formatting, and can be reliably parsed — by scripts and by LLMs.\nbausteinsicht find: Querying the Model find searches all elements, relationships, and views for a term. The search is case-insensitive, partial (pay matches payment-service), and uses AND semantics for multiple words.\n# All elements related to \u0026#34;auth\u0026#34; bausteinsicht find auth # Only elements (no relationships or views) bausteinsicht find auth --type element # Multiple search terms (AND) bausteinsicht find payment service # JSON output for LLM context bausteinsicht find auth --format json JSON output:\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 } ] } Results are sorted by relevance score — the LLM automatically receives the most relevant hits first.\nbausteinsicht status: Lifecycle Overview status lists all elements with their lifecycle status (→ Part 3).\n# All elements with status bausteinsicht status # Only elements in a specific status bausteinsicht status --filter proposed # As JSON bausteinsicht status --format json JSON output:\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; } ] } The summary gives an LLM an immediate overview: 2 elements are proposed, 8 are deployed — without loading the entire model.\nClaude Code as an Architecture Assistant With these tools, Claude Code can be integrated directly into the architecture workflow.\nProviding the Model as Context The simplest integration: pass a relevant slice of the model as context before asking a question.\n# In the terminal — then start Claude Code bausteinsicht export --format json \u0026gt; /tmp/architecture.json # In Claude Code: read the file and ask a question # \u0026#34;Read /tmp/architecture.json and explain the dependencies of the payment-service\u0026#34; Or more directly with find:\nbausteinsicht find payment --format json | \\ claude -p \u0026#34;Which elements are connected to the payment service and \\ are there obvious problems in this dependency structure?\u0026#34; Embedding the Architecture Model via CLAUDE.md A permanent architecture context can be defined in CLAUDE.md (or .claude/CLAUDE.md):\n## Architecture Model Query the current architecture model: - `bausteinsicht export --format json` — complete model - `bausteinsicht find \u0026lt;term\u0026gt; --format json` — targeted context - `bausteinsicht status --format json` — which elements are currently in development Before decisions with architectural impact: use `bausteinsicht find` first to check existing elements and their relationships. Claude Code reads these instructions automatically — from now on the assistant knows the commands and can execute them itself.\nWorkflow: Adding a New Element with AI Assistance A realistic example: a new element is to be added to the model.\n# 1. Find existing similar elements bausteinsicht find notification --format json # 2. Currently in development? bausteinsicht status --filter implementation --format json # 3. Check constraints before adding bausteinsicht lint --format json Claude Code can execute these commands in sequence and then suggest a consistent JSONC entry — with the right kind, appropriate technology, and without introducing constraint violations.\nWorkflow: Architecture Review Before a PR In .github/PULL_REQUEST_TEMPLATE.md or as a CLAUDE.md instruction:\n# Diff to the target branch bausteinsicht changelog --since origin/main --until HEAD --format json # New constraint violations? bausteinsicht lint --format json # Health change? bausteinsicht health --format json Claude Code can automatically include this review in the PR description.\nLimitations and Risks LLMs Hallucinate Elements An LLM can invent plausible-sounding element IDs, technology values, or relationships that do not exist in the model.\nAlways run bausteinsicht validate after AI-generated changes to the model. Validate checks references — hallucinated IDs will be detected. JSON Context Has Limits Large models (export --format json) can exceed the context window of an LLM. find and status exist precisely for this: targeted partial excerpts instead of the full model.\nRule of thumb: formulate LLM requests as precise queries → find → use the result as context, do not dump the entire model.\nThe Model Is the Single Source of Truth — Not the LLM The LLM can make suggestions, but the model in architecture.jsonc is the truth. bausteinsicht sync is the channel between the model and draw.io — not the LLM.\nThe LLM supports the architect; it does not replace them.\nStale Context An LLM assistant that was given JSON output from three sprints ago as context is working with an outdated architecture. Always run bausteinsicht export or find in the same terminal session — do not use cached snapshots.\nPractical Shortcuts Shell aliases are worthwhile for frequent queries:\n# ~/.bashrc or ~/.zshrc # Quick architecture context for 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 package for PR alias arch-review=\u0026#39;bausteinsicht changelog --since origin/main --format json \u0026amp;\u0026amp; bausteinsicht lint --format json\u0026#39; Example Model The example for this part (model with multiple queryable elements for bausteinsicht find) is located at teil_10.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_10.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 11: ADR Integration — Link Architecture Decision Records directly in the model\nPart 12: Overlay \u0026amp; Heatmap — Project metrics onto architecture diagrams\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-llm-ai-workflows/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-lsp-integration/\"\u003eninth part\u003c/a\u003e.\nThe previous parts have shown how Bausteinsicht makes the architecture model readable for humans — in the editor, in diagrams, in reports.\nThis part reverses that: how do you make the model readable for machines, so that LLM assistants like Claude Code can work with it?\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_problem_llms_dont_know_your_architecture\"\u003eThe Problem: LLMs Don’t Know Your Architecture\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eClaude Code, GitHub Copilot, and other AI assistants know nothing about the specific system you are working on.\nThey have to guess: which services exist, how they communicate with each other, which technologies are allowed.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 10: LLM/AI Workflows — AI-Assisted Architecture Modeling"},{"content":" This post continues from the tenth part. Architecture decisions often end up in Markdown files somewhere in the repository — and nobody remembers why the model looks the way it does. Bausteinsicht solves this: ADRs can be linked directly to elements and relationships in the model.\nWhat are ADRs? Architecture Decision Records (ADRs) document an architecture decision with context, options, and rationale. The format is intentionally lightweight — typically one short Markdown file per decision.\nThe problem: without direct linking, ADRs are isolated from the model. You can see in the diagram that an element exists, but not why it was designed that way.\nDefining ADRs in the Specification ADRs belong 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 as primary database\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 instead of 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; } ] } } Possible status values:\nStatus Meaning proposed\nDecision proposed, not yet final\nactive\nCurrent, valid decision\ndeprecated\nOutdated, but not yet replaced\nsuperseded\nReplaced by a newer ADR\nThe file field points to the actual ADR file in the repository. Bausteinsicht does not open it automatically — it is a pointer for developers and tools.\nLinking ADRs to Elements Each element can contain a decisions array with ADR IDs:\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;] } } } } } Linking ADRs to Relationships Relationships can also reference ADRs — for example when a decision concerns the communication architecture:\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 Show all ADRs in the model:\nbausteinsicht adr list Output:\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: ✓ active, ◯ proposed, ⚠ deprecated, ✗ superseded.\nADRs for a Specific Element bausteinsicht adr list --element shop.db Shows only ADRs directly linked to shop.db.\nJSON Output 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 for a single ADR — including which elements and relationships reference it:\nbausteinsicht adr show ADR-003 Output:\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 This shows at a glance: this decision affects the Auth Service and the connection from the frontend to the Auth Service.\nTypical ADR Workflow Documenting a New Decision Write the ADR file (e.g. docs/decisions/ADR-005-event-sourcing.md)\nAdd an entry to specification.decisions\nLink affected elements/relationships with \u0026#34;decisions\u0026#34;: [\u0026#34;ADR-005\u0026#34;]\nbausteinsicht validate — ensures that all referenced ADR IDs exist\nbausteinsicht validate # ✓ All ADR references are valid Validate checks that all ADR IDs in decisions arrays are also defined in specification.decisions.\nSuperseding a Decision When ADR-004 is superseded by ADR-007:\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 instead of 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 remains in the model — the superseded status indicates it is no longer valid. This keeps the decision history traceable.\nWhy Directly in the Model Instead of Separate Tools? ADR tools like adr-tools or Log4brains manage ADRs well — but they know nothing about the architecture model. The linking in Bausteinsicht brings both together:\nIn the draw.io diagram you can see which elements have ADRs (→ CodeLens via LSP, Part 9)\nbausteinsicht adr show displays the impact of a decision on the model\nLLMs receive the complete decision context via bausteinsicht adr list --format json (→ Part 10)\nBausteinsicht stores only metadata (ID, title, status, date, path) — not the ADR content itself. The actual files remain in the repository; Bausteinsicht only references them. Example Model The example for this part (elements and relationships with decisions references) is located at teil_11.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_11.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 12: Overlay \u0026amp; Heatmap — Overlay external metrics like error rate or coverage onto architecture diagrams\nPart 13: Graph Analysis — Uncover cycles and dependency patterns in the model graph\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-adr-integration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-llm-ai-workflows/\"\u003etenth part\u003c/a\u003e.\nArchitecture decisions often end up in Markdown files somewhere in the repository — and nobody remembers why the model looks the way it does.\nBausteinsicht solves this: ADRs can be linked directly to elements and relationships in the model.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_what_are_adrs\"\u003eWhat are ADRs?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eArchitecture Decision Records (ADRs) document an architecture decision with context, options, and rationale.\nThe format is intentionally lightweight — typically one short Markdown file per decision.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 11: ADR Integration — Linking Architecture Decision Records to the Model"},{"content":" This post continues from the eleventh part. Architecture diagrams show structure — but not how the system is currently doing. With the overlay feature, external metrics can be placed directly onto draw.io elements as a heatmap.\nThe Concept bausteinsicht overlay apply loads a JSON file with metrics and colors the draw.io elements accordingly. The original colors are saved in diagram metadata — overlay remove restores them exactly.\nTypical use cases:\nError rate per service after an incident\nTest coverage per module before a release\nLatency P99 from Prometheus/Datadog\nDeployment frequency from the CI system\nPreparing the Metrics File The metrics are stored in a JSON file with a fixed 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 (last 1h)\u0026#34;, \u0026#34;p99_latency_ms\u0026#34;: \u0026#34;P99 Latency in milliseconds\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 } } ] } The id fields must match the element IDs in the model. Elements without an entry in the metrics file remain unchanged.\nbausteinsicht overlay list Which metrics are available in the file?\nbausteinsicht overlay list metrics.json Output:\n📊 Metrics from: Datadog (2025-06-11T06:00:00Z) Available metrics (4 elements): • error_rate: HTTP 5xx Rate (last 1h) • p99_latency_ms: P99 Latency in milliseconds bausteinsicht overlay apply # Show error rate as heatmap bausteinsicht overlay apply metrics.json --metric error_rate # Show latency as heatmap bausteinsicht overlay apply metrics.json --metric p99_latency_ms # Use a different draw.io file as target bausteinsicht overlay apply metrics.json --metric error_rate \\ --output architecture-incident.drawio Bausteinsicht automatically calculates the color scale: low values are colored green, high values red (default color scheme).\nAfter applying, the diagram looks like this (color-wise):\nshop.frontend → light green (error_rate: 0.02 — low) authservice → yellow (error_rate: 0.08 — medium) paymentservice → red (error_rate: 0.41 — critical) shop.db → green (error_rate: 0.01 — very low) The diagram opens in draw.io with the heatmap colors. Elements without a metrics entry remain in their original color.\nJSON Output 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 Remove the heatmap and restore original colors:\nbausteinsicht overlay remove Bausteinsicht reads the saved original styles from the draw.io element metadata and restores each element’s style exactly. No manual color adjustment needed.\nOriginal colors are saved in draw.io element metadata on the first overlay apply. They remain there until overlay remove is executed — even if the draw.io file is committed to Git. Generating Metrics from External Sources The metrics JSON can come from any system. Examples:\nPrometheus / Grafana # Export HTTP error rate of the last hour as JSON 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) # Convert coverage report from Go Test into the overlay format go test ./... -coverprofile=coverage.out # Then aggregate coverage per service and write to metrics.json GitHub Actions: Automatic Overlay Before 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 Limitations Bausteinsicht does not generate metrics — it only visualizes external data\nThe color scale is linear (Min → Green, Max → Red); no logarithmic scaling\nOnly numeric metrics are supported — no categorical values\nThe --metric flag selects exactly one metric per apply; call multiple times for multiple metrics\nExample Model The base model for the overlay examples in this part is located at teil_12.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_12.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 13: Graph Analysis — Uncover cycles, centrality, and dependency patterns with bausteinsicht graph\nPart 14: Auto-Layout — Automatically arrange diagrams hierarchically\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-overlay-heatmap/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-adr-integration/\"\u003eeleventh part\u003c/a\u003e.\nArchitecture diagrams show structure — but not how the system is currently doing.\nWith the overlay feature, external metrics can be placed directly onto draw.io elements as a heatmap.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_concept\"\u003eThe Concept\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003ebausteinsicht overlay apply\u003c/code\u003e loads a JSON file with metrics and colors the draw.io elements accordingly.\nThe original colors are saved in diagram metadata — \u003ccode\u003eoverlay remove\u003c/code\u003e restores them exactly.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eTypical use cases:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eError rate per service after an incident\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTest coverage per module before a release\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eLatency P99 from Prometheus/Datadog\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDeployment frequency from the CI system\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Part 12: Overlay \u0026 Heatmap — Overlaying Metrics onto Architecture Diagrams"},{"content":" This post continues from the twelfth part. Architecture models grow — and with them the complexity of dependencies. bausteinsicht graph analyzes the relationship graph and makes problems visible that are hard to spot in diagrams.\nWhat is Graph Analysis? The architecture model is mathematically a directed graph: elements are nodes, relationships are edges. Graph analysis algorithms answer questions like:\nAre there cycles? (A → B → C → A)\nWhich elements are most heavily connected?\nIs the graph a DAG (Directed Acyclic Graph)?\nWhich components form tightly coupled clusters?\nbausteinsicht graph bausteinsicht graph --model architecture.jsonc Output:\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 Show Only Cycles bausteinsicht graph --model architecture.jsonc --cycles-only Quick check for CI: are there any cycles at all?\nShow Centrality Metrics bausteinsicht graph --model architecture.jsonc --centrality Shows for each element:\nMetric Meaning In-Degree\nNumber of incoming connections — high values: many dependents\nOut-Degree\nNumber of outgoing connections — high values: many dependencies\nBetweenness\nHow often the element lies on the shortest path between two others — high values: critical bottleneck\nCloseness\nHow close the element is to all others — high values: central position in the graph\nWrite Report to File bausteinsicht graph --model architecture.jsonc --centrality \\ --output docs/graph-report.txt JSON Output 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 } ] } Cycles in the Architecture A cycle (A → B → C → A) in the architecture means:\nDeployment dependencies are circular — none of the involved systems can be deployed independently\nTestability suffers — components cannot be tested in isolation\nHidden coupling — the systems cannot be evolved independently\nCircular dependencies can also be defined as a no-circular-dependency constraint (→ Part 8) and automatically checked in CI. bausteinsicht graph additionally outputs the concrete cycles — useful for analyzing which elements are affected. Resolving a Cycle Typical strategies:\nDependency Inversion: introduce a shared interface/abstraction\nEvent-based decoupling: replace direct calls with events\nIntroduce a new layer: extract shared logic into a separate element\nCentrality as an Architecture Signal High Out-Degree + high Betweenness = potential monolith or God Object. An element that knows many others and lies on many paths is an architecture risk:\nChanges there break many other components\nTesting becomes complex\nDeployment blocks others\nCentrality values combine well with the overlay feature (→ Part 12): export Betweenness values as a metrics JSON and visualize them as a heatmap. 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; Alternatively via the no-circular-dependency constraint (simpler, no jq needed):\n- name: Lint architecture run: bausteinsicht lint # fails if NO-CYCLES constraint is violated Example Model The example for this part (REST API as a central hub with high Out-Degree) is located at teil_13.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_13.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 14: Auto-Layout — Automatically arrange diagrams hierarchically\nPart 15: Templates — Define custom visual styles for element types\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-graph-analyse/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-overlay-heatmap/\"\u003etwelfth part\u003c/a\u003e.\nArchitecture models grow — and with them the complexity of dependencies.\n\u003ccode\u003ebausteinsicht graph\u003c/code\u003e analyzes the relationship graph and makes problems visible that are hard to spot in diagrams.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_what_is_graph_analysis\"\u003eWhat is Graph Analysis?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThe architecture model is mathematically a directed graph: elements are nodes, relationships are edges.\nGraph analysis algorithms answer questions like:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAre there cycles? (A → B → C → A)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWhich elements are most heavily connected?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eIs the graph a DAG (Directed Acyclic Graph)?\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eWhich components form tightly coupled clusters?\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Part 13: Graph Analysis — Uncovering Cycles and Dependencies"},{"content":" This post continues from the thirteenth part. When new elements are added to the model, they often end up stacked on top of each other or in unfavorable positions in draw.io. bausteinsicht layout calculates a hierarchical layout and writes the positions directly into the diagram.\nbausteinsicht layout bausteinsicht layout Bausteinsicht automatically detects the model (AutoDetect) and the associated architecture.drawio in the same directory.\nOutput:\nLayout applied (hierarchical): architecture.drawio The diagram is now arranged hierarchically — elements with many outgoing connections appear at the top, leaf elements at the bottom.\nChoosing a Direction # Top-to-Bottom (default) bausteinsicht layout --rank-dir TB # Left-to-Right (for wide diagrams) bausteinsicht layout --rank-dir LR LR is particularly well-suited for systems with many parallel services at the same level.\nPinning: Fixing Specific Elements Not all elements should be moved automatically. External systems, important core services, or manually positioned overview elements can be fixed with a metadata flag:\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; } } } } When running the layout command, this element stays in its position — all others are rearranged:\n# Default: pinned elements are not moved bausteinsicht layout --preserve-pinned true # Rearrange all elements (ignore pinning) bausteinsicht layout --preserve-pinned false Typical Workflow After adding new elements (e.g. via bausteinsicht add element or manual editing):\n# 1. Add new element bausteinsicht add element --id newservice --kind service --title \u0026#34;New Service\u0026#34; # 2. Sync: draw.io knows the new element bausteinsicht sync # 3. Recalculate layout bausteinsicht layout # 4. Open draw.io — neatly arranged layout only changes positions in architecture.drawio, not the model in architecture.jsonc. Position changes are not overwritten by sync — sync updates elements and styles, but not positions. Limitations Currently only the hierarchical algorithm is supported (Sugiyama-based)\nOverlaps possible with very dense diagrams — manual cleanup may be needed\nScope boxes (→ Part 5) are treated as containers and influence the layout\nExample Model The example for this part (model with a pinned external system) is located at teil_14.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_14.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 15: Templates — Generate custom visual styles for all element types as a draw.io template\nPart 16: Workspace — Combine multiple architecture models in one workspace\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-auto-layout/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-graph-analyse/\"\u003ethirteenth part\u003c/a\u003e.\nWhen new elements are added to the model, they often end up stacked on top of each other or in unfavorable positions in draw.io.\n\u003ccode\u003ebausteinsicht layout\u003c/code\u003e calculates a hierarchical layout and writes the positions directly into the diagram.\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 automatically detects the model (\u003ccode\u003eAutoDetect\u003c/code\u003e) and the associated \u003ccode\u003earchitecture.drawio\u003c/code\u003e in the same directory.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eOutput:\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\u003eThe diagram is now arranged hierarchically — elements with many outgoing connections appear at the top, leaf elements at the bottom.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 14: Auto-Layout — Automatically Arranging Diagrams"},{"content":" This post continues from Part 14. Every team has its own visual conventions — colors, shapes, notations. bausteinsicht generate-template generates a draw.io template file containing all element types from the specification with consistent styles.\nWhat is a draw.io Template? A template file is a draw.io file with predefined shapes for each element type. Instead of manually styling elements in the diagram, you simply drag the matching shape from the template panel.\ngenerate-template derives the shapes automatically from specification.elements in architecture.jsonc — for each kind, a styled shape is generated.\nbausteinsicht generate-template bausteinsicht generate-template Creates architecture-template.drawio with shapes for each element type.\nStyle Presets # Default preset (blue shapes, white labels) bausteinsicht generate-template --style default # C4 notation (colors per C4 standard: blue/grey/green) bausteinsicht generate-template --style c4 # Minimalist (outlines only, no fill color) bausteinsicht generate-template --style minimal # Dark mode (dark backgrounds, light text) bausteinsicht generate-template --style dark Choosing the Output File bausteinsicht generate-template --output docs/diagrams/team-template.drawio Using the Template in draw.io Run generate-template → architecture-template.drawio is created\nIn draw.io: Extras → Edit Templates → import the template file\nYour custom element shapes appear in the left panel\nEach shape already has the correct name and style — when dragged into the diagram, the element is immediately annotated with the correct kind value that bausteinsicht sync recognizes.\nTemplate from Your Own Specification The template always reflects the current 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;Persistence\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;External System\u0026#34; } } } } generate-template creates a shape for each of these types in the selected style. New element types → regenerate the template → immediately available in the panel.\nCommitting the Template to the Repository git add architecture-template.drawio git commit -m \u0026#34;update draw.io template for current element types\u0026#34; This ensures the entire team always has the current template — no manual distribution of style files.\nRegenerate the template whenever new kind values are added to the specification. A quick generate-template \u0026amp;\u0026amp; git add \u0026amp;\u0026amp; git commit is all it takes. Example Model The example for this part (custom element types: Browser, Hexagon, Cylinder, Parallelogram, Cloud) is available at teil_15.jsonc.\nHere is the result in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_15.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 16: Workspace — Combining multiple architecture models in one workspace\nPart 17: Sequence Diagrams — Exporting dynamic views as PlantUML and Mermaid\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-templates/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from \u003ca href=\"../bausteinsicht-auto-layout/\"\u003ePart 14\u003c/a\u003e.\nEvery team has its own visual conventions — colors, shapes, notations.\n\u003ccode\u003ebausteinsicht generate-template\u003c/code\u003e generates a draw.io template file containing all element types from the specification with consistent styles.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_what_is_a_draw_io_template\"\u003eWhat is a draw.io Template?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eA template file is a draw.io file with predefined shapes for each element type.\nInstead of manually styling elements in the diagram, you simply drag the matching shape from the template panel.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 15: Templates — Defining Custom Visual Styles"},{"content":" This post continues from the fifteenth part. In larger organizations, each team maintains its own architecture model. The workspace combines multiple models into a unified view — without giving up team autonomy.\nThe Problem: Team Boundaries in the Architecture Model Team A owns shop-model/architecture.jsonc, Team B owns auth-model/architecture.jsonc. Both want to maintain their models independently — but the platform architecture needs an overall view.\nThe workspace is the answer: a workspace.jsonc references both models and defines the connections between them.\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;Overall architecture of all 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 Overview\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;All teams, top-level elements only\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 Prefix The prefix field prevents ID collisions during merge: api from the shop model becomes shop.api, service from the auth model becomes auth.service.\nWithout an explicit prefix, the model’s id is used as the prefix.\nbausteinsicht workspace list List models in the workspace:\nbausteinsicht workspace list workspace.jsonc Output:\nWorkspace: E-Commerce Platform Description: Overall architecture of all 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 Load and validate all referenced models:\nbausteinsicht workspace validate workspace.jsonc Checks: * All model paths exist and are valid JSONC * Each individual model passes bausteinsicht validate * Cross-model references point to existing (prefixed) elements\nOn success:\n✓ Workspace configuration is valid (3 models) JSON output for CI:\nbausteinsicht workspace validate workspace.jsonc --format json # → {\u0026#34;valid\u0026#34;: true, \u0026#34;models\u0026#34;: 3} bausteinsicht workspace merge Merge all models into a single combined model:\nbausteinsicht workspace merge workspace.jsonc merged-architecture.jsonc The resulting merged-architecture.jsonc:\nContains all elements from all teams with prefixed IDs\nContains all cross-model relationships\nPasses bausteinsicht validate\nThe merged model can then be used for exports, graph analysis, or overlay visualization:\nbausteinsicht workspace merge workspace.jsonc /tmp/merged.jsonc # Graph analysis on the overall architecture bausteinsicht graph --model /tmp/merged.jsonc # Overlay on overall diagram bausteinsicht overlay apply metrics.json --model /tmp/merged.jsonc --metric error_rate Typical Workspace Structure in the Repository architecture/ ├── workspace.jsonc ← Workspace configuration ├── teams/ │ ├── shop/ │ │ ├── architecture.jsonc │ │ └── architecture.drawio │ ├── auth/ │ │ ├── architecture.jsonc │ │ └── architecture.drawio │ └── payment/ │ ├── architecture.jsonc │ └── architecture.drawio └── merged/ └── architecture.jsonc ← Generated, do not edit manually Add the merged/ directory to .gitignore or treat it as a build artifact — it is regenerated from the team models and should not be edited directly. CI: Workspace Validation - 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 Example Model The example for this part (team model \u0026#34;shop\u0026#34; — one of several models in the workspace) is located at teil_16.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_16.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 17: Sequence Diagrams — Export dynamic views as PlantUML and Mermaid\nPart 18: CLI Modeling — Build architecture directly from the command line\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-workspace/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-templates/\"\u003efifteenth part\u003c/a\u003e.\nIn larger organizations, each team maintains its own architecture model.\nThe workspace combines multiple models into a unified view — without giving up team autonomy.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_problem_team_boundaries_in_the_architecture_model\"\u003eThe Problem: Team Boundaries in the Architecture Model\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eTeam A owns \u003ccode\u003eshop-model/architecture.jsonc\u003c/code\u003e, Team B owns \u003ccode\u003eauth-model/architecture.jsonc\u003c/code\u003e.\nBoth want to maintain their models independently — but the platform architecture needs an overall view.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThe workspace is the answer: a \u003ccode\u003eworkspace.jsonc\u003c/code\u003e references both models and defines the connections between them.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 16: Workspace — Combining Multiple Architecture Models"},{"content":" This post continues from the sixteenth part. Static architecture diagrams show structure. Sequence diagrams show behavior — who communicates with whom, and in what order. Bausteinsicht calls these Dynamic Views.\nDynamic Views in the Model Dynamic Views are defined as an array dynamicViews in architecture.jsonc:\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;Flow of a successful order process\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; } ] } ] } Step Types Type Representation sync\nSolid arrow (synchronous call)\nasync\nDashed arrow (message / event)\nreturn\nDotted return arrow\nbausteinsicht export-sequence # Export all Dynamic Views as PlantUML (default) bausteinsicht export-sequence # As Mermaid bausteinsicht export-sequence --diagram-format mermaid # Only a specific view bausteinsicht export-sequence --view checkout-flow # Write to directory bausteinsicht export-sequence --output docs/sequences/ Output (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 Output (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 Embedding in Documentation PlantUML can be referenced directly in AsciiDoc:\n\\[plantuml, checkout-flow, svg] Unresolved directive in \u0026lt;stdin\u0026gt; - include::sequences/checkout-flow.puml[]\nMermaid works directly in GitHub Markdown and in wikis.\nDifference from Static Views Aspect Static View (Part 5) Dynamic View Shows\nWhich elements exist\nWho communicates in what order\nFormat\ndraw.io diagram\nPlantUML / Mermaid\nGood for\nStructural overview\nFlow documentation, API description\nThe elements in steps do not need to be visible in a static view — they only need to exist in the model. bausteinsicht validate checks all from/to references in Dynamic Views. Example Model The example for this part (model with dynamicViews for the checkout flow) is located at teil_17.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_17.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagram (static view) via bausteinsicht export-diagram:\nWhat Comes Next Part 18: CLI Modeling — Add elements, relationships, and views directly from the command line\nPart 19: Health Score — Rate architecture quality with A–F grades\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-sequenzdiagramme/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-workspace/\"\u003esixteenth part\u003c/a\u003e.\nStatic architecture diagrams show structure.\nSequence diagrams show behavior — who communicates with whom, and in what order.\nBausteinsicht calls these \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_in_the_model\"\u003eDynamic Views in the Model\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eDynamic Views are defined as an array \u003ccode\u003edynamicViews\u003c/code\u003e in \u003ccode\u003earchitecture.jsonc\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;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;Flow of a successful order process\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":"Part 17: Sequence Diagrams — Exporting Dynamic Views as PlantUML and Mermaid"},{"content":" This post continues from the seventeenth part. The model can be edited not only manually in architecture.jsonc — all structural changes can also be made via the CLI. This is particularly useful for scripts, LLM workflows (→ Part 10), and CI pipelines.\nbausteinsicht add element Add a new element to the model:\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;Processes payments\u0026#34; # Nested element (child of paymentservice) bausteinsicht add element \\ --id ledger \\ --kind database \\ --title \u0026#34;Payment Ledger\u0026#34; \\ --technology \u0026#34;PostgreSQL\u0026#34; \\ --parent paymentservice Validations: * --id may only contain letters, digits, hyphens, and underscores (no dots — dots are hierarchy separators) * --kind must be defined in specification.elements * Parent must exist and have container: true in its specification * Duplicates are rejected\nJSON output:\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 Add a relationship between two existing elements:\nbausteinsicht add relationship \\ --from shop.api \\ --to paymentservice \\ --label \u0026#34;charge(amount)\u0026#34; \\ --kind rest \\ --description \u0026#34;Initiates payment\u0026#34; Validations: * --from and --to must exist in the model * --kind must be defined in specification.relationships (if provided) * Duplicates (same from/to/kind combination) are rejected\nbausteinsicht add view Create a new view or extend an existing view with elements:\n# New view with scope bausteinsicht add view payment-view \\ --title \u0026#34;Payment System\u0026#34; \\ --scope paymentservice \\ --include \u0026#34;paymentservice.*\u0026#34; # Extend existing view with an element bausteinsicht add view payment-view \\ --include shop.api --include accepts element IDs and wildcards like paymentservice.* (all direct children).\nbausteinsicht add-from-pattern Patterns are reusable element topologies defined in specification.patterns. They are instantiated with add-from-pattern:\n# Instantiate the \u0026#34;microservice\u0026#34; pattern with ID \u0026#34;notificationservice\u0026#34; bausteinsicht add-from-pattern microservice \\ --id notificationservice \\ --title \u0026#34;Notification Service\u0026#34; # With namespace prefix bausteinsicht add-from-pattern microservice \\ --id emailworker \\ --prefix notification # → creates \u0026#34;notification-emailworker\u0026#34; as the top-level ID The pattern expands all defined elements and relationships at once.\nListing Patterns bausteinsicht add pattern list Lists all patterns defined in specification.patterns with their element and relationship counts.\nbausteinsicht add specification Add new types to the specification:\n# Define a new element type bausteinsicht add specification element \\ --kind \u0026#34;cache\u0026#34; \\ --notation \u0026#34;Cylinder\u0026#34; \\ --description \u0026#34;In-Memory Cache\u0026#34; # Define a new relationship type bausteinsicht add specification relationship \\ --kind \u0026#34;event\u0026#34; \\ --notation \u0026#34;Event\u0026#34; \\ --dashed Comments Are Preserved All add commands use a comment-preserving patcher: JSONC comments in architecture.jsonc are not removed. New entries are inserted precisely at the correct location — without destroying the existing formatting.\nIf the patch fails (e.g., due to complex formatting), Bausteinsicht falls back to a full save — the content will then be correct, but comments may be lost.\nAfter each add command, running bausteinsicht sync is recommended so the new element appears in the draw.io diagram. Typical CLI Workflow # 1. Add new element bausteinsicht add element --id cacheservice --kind cache --title \u0026#34;Redis Cache\u0026#34; --technology Redis # 2. Add relationship bausteinsicht add relationship --from shop.api --to cacheservice --label \u0026#34;read/write\u0026#34; --kind tcp # 3. Include in existing view bausteinsicht add view system-overview --include cacheservice # 4. Sync: update draw.io bausteinsicht sync # 5. Validate bausteinsicht validate Example Model The example for this part (model built incrementally via CLI) is located at teil_18.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_18.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 19: Health Score — Objectively measure architecture quality and rate it with A–F grades\nPart 20: Element Lifecycle — Track element status from proposed to archived in the model\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-cli-modellierung/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-sequenzdiagramme/\"\u003eseventeenth part\u003c/a\u003e.\nThe model can be edited not only manually in \u003ccode\u003earchitecture.jsonc\u003c/code\u003e — all structural changes can also be made via the CLI.\nThis is particularly useful for scripts, LLM workflows (→ \u003ca href=\"../bausteinsicht-llm-ai-workflows/\"\u003ePart 10\u003c/a\u003e), and 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\u003eAdd a new element to the model:\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;Processes payments\u0026#34;\n\n# Nested element (child of 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":"Part 18: CLI Modeling — Building Architecture Directly from the Command Line"},{"content":" This post continues from the eighteenth part. bausteinsicht validate and bausteinsicht lint check whether the model is correct. bausteinsicht health goes further: it evaluates how good the model is — completeness, conformance, complexity, and more.\nbausteinsicht health bausteinsicht health --model architecture.jsonc Output:\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 Evaluation Categories Category Weight What is evaluated Completeness\n40 %\nShare of elements with description, title, technology\nConformance\n30 %\nConstraint violations from bausteinsicht lint\nComplexity\n20 %\nRelationship density, maximum depth, cycles\nDeprecation\n5 %\nDeprecated/archived elements that are still referenced\nDocumentation\n5 %\nElements without a title field\nGrade Scale Score Grade ≥ 97\nA+\n≥ 93\nA\n≥ 90\nB+\n≥ 87\nB\n≥ 80\nC+\n≥ 70\nC\n≥ 60\nD\n\u0026lt; 60\nF\nSummary View for Dashboards bausteinsicht health --model architecture.jsonc --summary # → Overall Score: 78.5/100 [B] # As JSON (for CI evaluation) 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; } Writing the Report to a File bausteinsicht health --model architecture.jsonc \\ --output docs/architecture-health.txt Full JSON Output bausteinsicht health --model architecture.jsonc --format json Returns the complete HealthScore object with categories, findings, element counts, and an ISO 8601 timestamp.\nCI Integration - name: Architecture health (informational) run: | bausteinsicht health --model architecture.jsonc --summary continue-on-error: true # health does not break the 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 Unlike bausteinsicht lint, health does not block the build via exit code — it is a quality measurement, not a gate. You can control the exit code yourself via the grade threshold (as shown in the example above). Difference from validate and lint Command Purpose Exit code on problem validate\nStructural correctness (references, schema)\n1\nlint\nConstraint violations (architecture rules)\n1\nhealth\nQuality assessment (score, grade)\n0 (always succeeds)\nExample Model The example for this part (model with varying documentation quality — legacy service without description/status) is located at teil_19.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_19.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 20: Element Lifecycle — Track element status from proposed to archived in the model\nPart 21: As-Is / To-Be — Define the target architecture directly in the model\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-health-score/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-cli-modellierung/\"\u003eeighteenth part\u003c/a\u003e.\n\u003ccode\u003ebausteinsicht validate\u003c/code\u003e and \u003ccode\u003ebausteinsicht lint\u003c/code\u003e check whether the model is correct.\n\u003ccode\u003ebausteinsicht health\u003c/code\u003e goes further: it evaluates \u003cstrong\u003ehow good\u003c/strong\u003e the model is — completeness, conformance, complexity, and more.\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\u003eOutput:\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":"Part 19: Health Score — Rating Architecture Quality with A–F Grades"},{"content":" This post continues from the nineteenth part. Architecture is not a static picture — elements are proposed, implemented, deployed, and eventually replaced. The status field in Bausteinsicht elements makes this lifecycle visible.\nStatus Values Status Meaning proposed\nNewly proposed, not yet decided or started\ndesign\nIn the design phase, not yet implemented\nimplementation\nCurrently in development\ndeployed\nLive in production\ndeprecated\nOutdated, should no longer be used — but still active\narchived\nDecommissioned, kept in the model for historical reference only\nSetting Status in the Model The status field belongs directly in the 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-based Auth (legacy)\u0026#34;, \u0026#34;status\u0026#34;: \u0026#34;archived\u0026#34; } } } Elements without a status field are treated as unset.\nbausteinsicht status List all elements with their status:\nbausteinsicht status Output:\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-based Auth (legacy)\u0026#34; unset (3): eventbus [queue ] \u0026#34;Event Bus\u0026#34; ... Filtered by Status # Only elements in development bausteinsicht status --filter implementation # Only deprecated elements bausteinsicht status --filter deprecated JSON Output 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; } ] } The summary object provides an at-a-glance distribution — useful as a dashboard metric.\nLifecycle in the Context of Other Features Health Score bausteinsicht health evaluates deprecated and archived elements in the Deprecation category: If a deprecated element still appears as a source or target in relationships, that is a major finding (→ Part 19).\nLSP / Editor The language server displays the status as a CodeLens above each element (→ Part 9):\n// service | status: deprecated | views: 2 \u0026#34;shop-monolith\u0026#34;: { ... } Overlay Status values can be exported as a metrics JSON and visualized as a heatmap (→ Part 12): Deprecated elements in red, deployed elements in green.\nSprint-Based Workflow Point in Time Status Change Architecture decision made\nproposed → design\nImplementation begins\ndesign → implementation\nProduction deployment\nimplementation → deployed\nReplacement decided (ADR created)\ndeployed → deprecated\nSystem decommissioned\ndeprecated → archived\nDocument status changes as Git commits: git commit -m \u0026#34;mark shop-monolith as deprecated (ADR-007)\u0026#34;. Combined with bausteinsicht changelog (→ Part 7), this creates a complete architecture history. Example Model The example for this part (all status values from proposed to archived) is located at teil_20.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_20.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 21: As-Is / To-Be — Define and visualize the target architecture directly in the model\nPart 22: find \u0026amp; show — Navigate the model and explore elements with precision\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-element-lifecycle/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-health-score/\"\u003enineteenth part\u003c/a\u003e.\nArchitecture is not a static picture — elements are proposed, implemented, deployed, and eventually replaced.\nThe \u003ccode\u003estatus\u003c/code\u003e field in Bausteinsicht elements makes this lifecycle visible.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_status_values\"\u003eStatus Values\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\"\u003eMeaning\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\"\u003eNewly proposed, not yet decided or started\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 the design phase, not yet implemented\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\"\u003eCurrently in development\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\"\u003eLive in production\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\"\u003eOutdated, should no longer be used — but still active\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\"\u003eDecommissioned, kept in the model for historical reference only\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Part 20: Element Lifecycle — Tracking Status from proposed to archived"},{"content":" This post continues from the twentieth part. Architecture migrations are complex: you need to understand where you currently stand (As-Is) and where you want to go (To-Be). Bausteinsicht supports this directly in the model — as two parallel snapshots.\nThe Concept architecture.jsonc can contain two optional sections alongside the main model:\nasIs — current state (as-is architecture)\ntoBe — target state (to-be architecture)\nBoth have the same structure: elements and 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 compares asIs with toBe and outputs the differences:\nbausteinsicht diff --model architecture.jsonc Output:\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 Output bausteinsicht diff --model architecture.jsonc --format json Returns a structured DiffResult object with summary (counts) and an elements array containing ChangeAdded, ChangeRemoved, and ChangeChanged entries.\nComparing a Single View bausteinsicht diff --model architecture.jsonc --view shop-overview Filters the diff to elements that are visible in the specified view.\nDifference from snapshot diff Aspect bausteinsicht diff bausteinsicht snapshot diff Compares\nasIs vs. toBe in the same model\nTwo snapshots at different points in time\nPurpose\nMigration planning (defining the target)\nRetrospective (what has changed?)\nData storage\nIn the model itself\nIn .bausteinsicht-snapshots/\nWorkflow: Migration Planning Populate asIs with the current system state\nPopulate toBe with the target architecture\nbausteinsicht diff — shows exactly which steps are required\nDocument the result in a PR description or ADR\nAfter the migration: update asIs to match toBe, clear toBe or define the next migration stage\n# Diff for PR description 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 and toBe can also be populated incrementally — for iterative migrations with multiple intermediate states. Update asIs between sprints whenever elements have actually been migrated. Example Model The example for this part (monolith → microservices migration with asIs/toBe sections) is located at teil_21.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_21.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram (current migration phase):\nWhat Comes Next Part 22: find \u0026amp; show — Navigate the model and explore individual elements\nPart 23: Tags \u0026amp; View Filtering — Tag elements and filter views precisely\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/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\u003eThis post continues from the \u003ca href=\"../bausteinsicht-element-lifecycle/\"\u003etwentieth part\u003c/a\u003e.\nArchitecture migrations are complex: you need to understand where you currently stand (As-Is) and where you want to go (To-Be).\nBausteinsicht supports this directly in the model — as two parallel snapshots.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_the_concept\"\u003eThe Concept\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003ccode\u003earchitecture.jsonc\u003c/code\u003e can contain two optional sections alongside the main model:\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 — current state (as-is architecture)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003etoBe\u003c/code\u003e — target state (to-be architecture)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBoth have the same structure: \u003ccode\u003eelements\u003c/code\u003e and \u003ccode\u003erelationships\u003c/code\u003e.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 21: As-Is / To-Be — Defining the Target Architecture Directly in the Model"},{"content":" This post continues from the twenty-first part. In growing models it is easy to lose track of the big picture. bausteinsicht find and bausteinsicht show are the two navigation commands: search and inspect.\nbausteinsicht find find searches all elements, relationships, and views for a term. The search is case-insensitive, partial, and uses AND semantics for multiple words.\n# All matches for \u0026#34;payment\u0026#34; bausteinsicht find payment # AND search: all matches containing \u0026#34;payment\u0026#34; AND \u0026#34;service\u0026#34; bausteinsicht find payment service # Elements only (no relationships or views) bausteinsicht find payment --type element # Relationships only bausteinsicht find charge --type relationship # Views only bausteinsicht find overview --type view Output:\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 Results are sorted by relevance score — the most relevant result appears first.\nJSON Output 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 displays all details of a single element — including all relationships and views. The element ID uses dot notation for nested elements.\nbausteinsicht show paymentservice bausteinsicht show paymentservice.ledger Output:\nElement: paymentservice ======================= Kind: service Title: Payment Service Technology: Rust Status: deployed Description: Processes all payment transactions Relationships (3): ← shop.api charge → paymentservice.ledger INSERT payment → shop.db audit log Views (2): payment-view system-overview JSON Output 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;Processes all payment transactions\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: A Typical Combination Exploring an unfamiliar model:\n# 1. What am I looking for? bausteinsicht find auth # 2. Found an interesting element — show its details bausteinsicht show authservice # 3. Explore dependent elements bausteinsicht show shop.frontend # has authservice as a relationship For LLM workflows (→ Part 10):\n# Build context for an LLM bausteinsicht find payment --format json | \\ xargs -I{} bausteinsicht show {} --format json Difference from bausteinsicht status find status Free-text search across all fields\nList filtered by lifecycle status\nGood for: exploring unfamiliar models\nGood for: \u0026#34;Which elements are currently in development?\u0026#34;\nExample Model The example for this part (model with meaningful descriptions for bausteinsicht find) is located at teil_22.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_22.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nWhat Comes Next Part 23: Tags \u0026amp; View Filtering — Organize elements with tags and filter views precisely\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-find-show/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-as-is-to-be/\"\u003etwenty-first part\u003c/a\u003e.\nIn growing models it is easy to lose track of the big picture.\n\u003ccode\u003ebausteinsicht find\u003c/code\u003e and \u003ccode\u003ebausteinsicht show\u003c/code\u003e are the two navigation commands: search and inspect.\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 searches all elements, relationships, and views for a term.\nThe search is case-insensitive, partial, and uses AND semantics for multiple words.\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# All matches for \u0026#34;payment\u0026#34;\nbausteinsicht find payment\n\n# AND search: all matches containing \u0026#34;payment\u0026#34; AND \u0026#34;service\u0026#34;\nbausteinsicht find payment service\n\n# Elements only (no relationships or views)\nbausteinsicht find payment --type element\n\n# Relationships only\nbausteinsicht find charge --type relationship\n\n# Views only\nbausteinsicht find overview --type view\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Part 22: find \u0026 show — Navigating the Model and Exploring Elements"},{"content":" This post continues from the twenty-second part. In complex models with many elements, include in views quickly becomes a long list. Tags solve this: elements get semantic labels, and views filter by those labels.\nDefining Tags in the Specification Tags are defined in specification.tags — with an optional style for 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;Elements owned by the backend team\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;team-frontend\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;Elements owned by the frontend team\u0026#34; }, { \u0026#34;id\u0026#34;: \u0026#34;external\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;External systems and third-party providers\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;Critical systems in the payment path\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;Processes personal data\u0026#34; } ] } } The style field overrides draw.io colors for all elements with this tag — a visual team-coding scheme derived directly from the specification.\nTagging Elements Tags are set as an array on the 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;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 checks that all tag IDs used are defined in specification.tags.\nFiltering Views with Tags Instead of include with explicit element IDs, views can use tags as filters:\nfilter-tags: Only Elements WITH These Tags { \u0026#34;views\u0026#34;: { \u0026#34;backend-team-view\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Backend Team Architecture\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;Critical Payment Path\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;GDPR-Relevant Elements\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;gdpr\u0026#34;] } } } filter-tags uses AND semantics for multiple tags:\n{ \u0026#34;critical-backend\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Critical Backend Services\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;team-backend\u0026#34;, \u0026#34;critical\u0026#34;] } } exclude-tags: Elements WITHOUT These Tags { \u0026#34;internal-only\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Internal Systems\u0026#34;, \u0026#34;exclude-tags\u0026#34;: [\u0026#34;external\u0026#34;] } } Combined with include and scope Tag filters can be combined with include, scope, and exclude:\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;] } } This view shows: elements under shop.* that have team-backend but not archived.\nTags as Cross-Cutting Concerns Tags are particularly well suited for cross-cutting concerns that span team and system boundaries:\nTag Typical Usage gdpr\nPrivacy review: see all data-processing elements at a glance\ncritical\nIncident response: immediately see which systems belong to the critical path\nteam-X\nTeam-specific views without manually maintaining include lists\ndeprecated\nDecommissioning planning: display all outdated elements explicitly\nTags in specification.tags must be explicitly defined — validate rejects unknown tag IDs in elements. This prevents typos and keeps the tag list consistent. Tags in Export Format During export (→ Part 6) tags are included in the table output:\nbausteinsicht export-table --format csv # → id, kind, title, technology, tags, status, ... This allows GDPR audits, team inventories, or security reviews to be generated directly from the model as CSV.\nExample Model The example for this part (tags with styles, filter-tags and exclude-tags in views) is located at teil_23.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_23.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram (context view with external systems):\nUp Next: CI/CD Tags and filtering are powerful — but a model that is only validated locally is only half protected. The next part covers how validate, diff, and export are integrated into GitHub Actions: automatic validation as a build gate, model diff in pull requests, and SVG export after every push.\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-tags-view-filterung/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-find-show/\"\u003etwenty-second part\u003c/a\u003e.\nIn complex models with many elements, \u003ccode\u003einclude\u003c/code\u003e in views quickly becomes a long list.\nTags solve this: elements get semantic labels, and views filter by those labels.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_defining_tags_in_the_specification\"\u003eDefining Tags in the Specification\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eTags are defined in \u003ccode\u003especification.tags\u003c/code\u003e — with an optional style for 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;Elements owned by the backend team\u0026#34;\n      },\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;team-frontend\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;Elements owned by the frontend team\u0026#34;\n      },\n      {\n        \u0026#34;id\u0026#34;:          \u0026#34;external\u0026#34;,\n        \u0026#34;description\u0026#34;: \u0026#34;External systems and third-party providers\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;Critical systems in the payment path\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;Processes personal data\u0026#34;\n      }\n    ]\n  }\n}\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e","title":"Part 23: Tags \u0026 View Filtering — Organizing Elements and Populating Views Precisely"},{"content":" This post continues from the twenty-third part. An architecture model that is only validated locally is only half protected. As soon as multiple people work on the model, CI is needed: automatic validation on every push, a visible diff on every pull request.\nInstalling Bausteinsicht in the Pipeline GitHub Actions does not provide a Bausteinsicht action — installation is done manually via 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 For reproducible builds a fixed version is recommended instead of latest:\nhttps://github.com/docToolchain/Bausteinsicht/releases/download/v0.5.0/bausteinsicht_linux_amd64.tar.gz validate as a Build Gate bausteinsicht validate returns exit code 1 when the model contains errors — GitHub Actions aborts the job:\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/ With --format json the output lands as structured JSON on stdout — easier to parse when you want to further process the error list.\nWhat validate checks (→ Part 8):\nAll element IDs in relationships and views exist in the model\nAll tag IDs used are defined in specification.tags\nNo element references an unknown type\nViews do not have an empty include block\ndiff in Pull Requests bausteinsicht diff compares two model states and shows which elements, relationships, and views have changed. In the PR context, HEAD~1 vs HEAD is the sensible comparison:\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;## 🏗 Architecture Changes\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 }); For the very first commit in a branch (HEAD~1 does not exist), diff returns an error — the || echo \u0026#39;{}\u0026#39; handles this case. SVG Export After Every Push Having architecture diagrams as SVG in the repository means: previews in GitHub, direct embedding in documentation, no local installation needed to view the diagrams.\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 Optionally: commit the exported SVGs directly back to the branch:\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 The [skip ci] prevents an infinite loop: the commit created by Actions does not trigger a new CI run.\nComplete 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 # for 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;## 🏗 Architecture Changes\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;] ensures the workflow only runs when something in the model has actually changed — not on every commit. Example Model The example for this part (model with developer and CI/CD actors) is located at teil_24.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_24.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nUp Next: Migration CI protects the existing model. But what if you are coming from another tool? The next part covers how to migrate from draw.io, PlantUML, and Structurizr to Bausteinsicht — what can be done automatically and what needs to be transferred manually.\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-cicd-integration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-tags-view-filterung/\"\u003etwenty-third part\u003c/a\u003e.\nAn architecture model that is only validated locally is only half protected.\nAs soon as multiple people work on the model, CI is needed: automatic validation on every push, a visible diff on every 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=\"_installing_bausteinsicht_in_the_pipeline\"\u003eInstalling Bausteinsicht in the Pipeline\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eGitHub Actions does not provide a Bausteinsicht action — installation is done manually via 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":"Part 24: CI/CD Integration — validate, diff, and Export in GitHub Actions"},{"content":" This post continues from the twenty-fourth part. In most projects there is already architecture documentation — as a draw.io file in the wiki, as PlantUML in the repository, or as a Structurizr DSL. Migration does not mean throwing everything away. It means finding the right starting point.\nUnderstanding the Starting Point Before migrating, an honest inventory is worthwhile:\nTool What Is There Effort Native draw.io (no model behind it)\nOnly diagrams, no data model — elements exist only as shapes\nHigh: model must be built from scratch\nPlantUML C4\nStructured text model — types, elements, relationships are explicit\nMedium: import script or manual transfer possible\nStructurizr DSL\nComplete model with elements, relationships, views\nMedium: structurally similar to Bausteinsicht JSONC\nConfluence diagrams / PowerPoint\nOnly images, no machine-readable model\nVery high: recreation recommended\nStep 1: bausteinsicht init as a Starting Point Regardless of the source tool, always start with:\nmkdir architecture \u0026amp;\u0026amp; cd architecture bausteinsicht init init creates an example model with the correct base structure — specification, model, views — and an empty architecture.drawio. This gives you the right foundation without starting from zero.\nThen: delete the generated example model (but keep specification.elements and specification.relationships as a template) and build your own model.\nMigrating from draw.io Draw.io without a model behind it is the most common scenario. The approach: use the existing diagram as a visual reference and derive the JSONC model from it.\nStep 1: Open the existing draw.io file and identify all present element types and relationship types.\nStep 2: Transfer these types into specification:\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; } } } } Step 3: Transfer elements and relationships from the diagram into model:\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; } } } Step 4: Define views that roughly correspond to the existing diagram pages.\nStep 5: bausteinsicht sync — Bausteinsicht creates draw.io shapes for all elements. Then manually transfer positions from the original diagram. This is manual work, but only needs to be done once.\nDo not try to reconstruct the original layout pixel-perfectly. Reapplying auto-layout (→ Part 14) afterwards is often the faster path. Migrating from PlantUML C4 PlantUML C4 already has a structured model. The transfer is mechanical:\nBecomes:\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;User\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; } } } For larger models a small conversion script (Python, awk) is worthwhile — one that parses the System(…​) and Rel(…​) calls and outputs JSONC fragments.\nMigrating from Structurizr DSL Structurizr DSL is structurally the closest to Bausteinsicht JSONC. The concepts map directly:\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: { …​ }\nThe main delta: Structurizr supports implicit elements in views (include *), while Bausteinsicht works with explicit IDs or tags.\nView-by-View Strategy Instead of Big Bang The most common mistake in migration: trying to transfer everything at once.\nBetter:\nMigrate one view — the most important system context view\nbausteinsicht sync and validate — verify the model is consistent\nWork in parallel — maintain the Bausteinsicht model and the old tool side by side until the new one is stable\nMigrate the next view — incrementally, by priority\nThis takes more time across the full migration, but minimizes risk: at every point in time there is working documentation.\nPitfalls Relationship lifting: Bausteinsicht automatically promotes relationships to the next visible parent element (→ Part 3). PlantUML and draw.io do not have this — relationships that were explicitly listed in the original tool may appear aggregated in an abstract view in Bausteinsicht. This is not a bug but a feature — but you need to be aware of it during review.\nMissing type definitions: When the source tool does not enforce types (draw.io), the specification can quickly become incomplete. validate helps find all used but undeclared types.\nIDs are stable, titles are not: In Bausteinsicht the element ID is the stable key. Titles can be changed. In migrations from tools without IDs (draw.io), IDs must be assigned deliberately — and then kept consistent.\nExample Model The example for this part (model migrated from Structurizr/draw.io with a legacy ERP connection) is located at teil_25.jsonc.\nThis is what the result looks like in draw.io (bausteinsicht sync):\nThe draw.io file for this can be found here: teil_25.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nUp Next: Team Workflows A migration is rarely a solo project. The next part covers how multiple people can work on the model simultaneously — merge conflicts in JSONC, ownership conventions, and the review process for architecture changes.\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-migration/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from the \u003ca href=\"../bausteinsicht-cicd-integration/\"\u003etwenty-fourth part\u003c/a\u003e.\nIn most projects there is already architecture documentation — as a draw.io file in the wiki,\nas PlantUML in the repository, or as a Structurizr DSL.\nMigration does not mean throwing everything away. It means finding the right starting point.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_understanding_the_starting_point\"\u003eUnderstanding the Starting Point\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eBefore migrating, an honest inventory is worthwhile:\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\"\u003eWhat Is There\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eEffort\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 (no model behind it)\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eOnly diagrams, no data model — elements exist only as shapes\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eHigh: model must be built from scratch\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\"\u003eStructured text model — types, elements, relationships are explicit\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eMedium: import script or manual transfer possible\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\"\u003eComplete model with elements, relationships, views\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eMedium: structurally similar to 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 diagrams / PowerPoint\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eOnly images, no machine-readable model\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eVery high: recreation recommended\u003c/p\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e","title":"Part 25: Migration — From draw.io, PlantUML, and Structurizr to Bausteinsicht"},{"content":" This post continues from Part 25. An architecture model maintained by a single person has no merge problem. As soon as multiple teams work on the same repository, that changes. Bausteinsicht comes with good preconditions for this — but you need to know where the limits are.\nWhat merges well in JSONC JSONC is a text format. Git merges text files line by line. That means:\nMerges cleanly:\nAdding new elements in model — as long as the elements have different IDs, these are separate lines with no overlap\nAdding new views in views — same principle\nAdding new tags in specification.tags\nConflict-prone:\nModifying the same element simultaneously (title, description, technology)\nChanging the order of elements — Git sees this as a deletion + insertion\nspecification.elements and specification.relationships — these areas are changed less often, but when they are, often by multiple people at once\ndraw.io XML is harder: The .drawio file contains XML with IDs and positions. Merge conflicts there are harder to resolve than JSONC. Rule of thumb: the JSONC model is the source of truth, the draw.io file is regenerable via sync.\nOwnership Conventions In a larger system, each team owns a section of the model it maintains. Conventions help to structurally avoid conflicts rather than just repairing them.\nRecommendation: Element IDs with team prefix:\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; } } } The backend team changes backend., the frontend team changes frontend.. Relationships between teams — backend.auth-service → infra.postgres — fall in the consumer’s sphere of influence (whoever initiates the relationship defines it).\nCODEOWNERS file: In GitHub this can be enforced with CODEOWNERS:\n# CODEOWNERS architecture/ @architecture-team # every change requires review Or more granularly (if the model is split up):\narchitecture/specification/ @all-teams architecture/model/backend/ @backend-team architecture/model/frontend/ @frontend-team Bausteinsicht stores everything in a single JSONC file. If teams truly want to work independently, the Workspace feature (Part 16) is the solution — separate models with explicit cross-references. Resolving Merge Conflicts A typical JSONC conflict looks like this:\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 } } Strategy:\nOpen the conflict in a JSON editor (not a plain text merge)\nMake the content decision — which title, which technology version?\nMerge manually, then run bausteinsicht validate\nIf the draw.io file also has a conflict: discard it and rerun bausteinsicht sync — the JSONC side is the source of truth\nRun bausteinsicht validate --format json after every merge. Exit code 1 on errors prevents a broken model from landing in main. Architecture Review in the Pull Request Making architecture changes visible in PRs is the real advantage of Architecture-as-Code.\nWorkflow:\nDeveloper opens a feature branch and modifies the model\nCI runs bausteinsicht validate and bausteinsicht diff (→ Part 24)\nDiff output appears as a PR comment: which elements were added, changed, removed\nReviewer sees the architecture change directly in the PR without a local installation\nWhat a good architecture PR contains:\nOnly model changes that belong to the feature — no refactoring in the same PR\nvalidate result is green\nA description that explains why the model was changed this way, not just what\nWhen does a change need a review?\nChange Review needed? New leaf element in an existing system\nOptional — team-internal review is sufficient\nNew external dependency\nYes — affects other teams\nChange in specification (new element types)\nYes — changes the schema for everyone\nAdding or removing a view\nOptional — does not affect logic\nDeleting an element referenced by others\nYes — validate will flag it anyway\nA Realistic Team Workflow git checkout -b feature/add-notification-service # Modify model: add notification-service to model # Relationships: shop-api → notification-service, notification-service → sendgrid bausteinsicht validate # check locally bausteinsicht sync # update draw.io git add architecture/ git commit -m \u0026#34;arch: add notification service\u0026#34; git push \u0026amp;\u0026amp; gh pr create CI validates, diff shows: - ` Element `notification-service` (kind: service) - ` Element sendgrid (kind: external) - ` Relationship `shop-api` → `notification-service` - ` Relationship notification-service → sendgrid\nThe reviewer sees exactly what changed architecturally — without having to open the draw.io file.\nExample Model The example for this part (team ownership via tags, separate team views) is available at teil_26.jsonc.\nHere is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_26.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nUp Next: Custom Notations As soon as teams bring their own vocabulary — AUTOSAR components, hardware elements, domain-specific concepts — the standard C4 notation is no longer sufficient. The next part covers how to define custom element types with custom shapes in draw.io.\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-team-workflows/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from \u003ca href=\"../bausteinsicht-migration/\"\u003ePart 25\u003c/a\u003e.\nAn architecture model maintained by a single person has no merge problem.\nAs soon as multiple teams work on the same repository, that changes.\nBausteinsicht comes with good preconditions for this — but you need to know where the limits are.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_what_merges_well_in_jsonc\"\u003eWhat merges well in JSONC\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eJSONC is a text format. Git merges text files line by line. That means:\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003e\u003cstrong\u003eMerges cleanly:\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"ulist\"\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAdding new elements in \u003ccode\u003emodel\u003c/code\u003e — as long as the elements have different IDs, these are separate lines with no overlap\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAdding new views in \u003ccode\u003eviews\u003c/code\u003e — same principle\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAdding new tags in \u003ccode\u003especification.tags\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e","title":"Part 26: Team Workflows — Merge Conflicts, Ownership, and Architecture Reviews in PRs"},{"content":" This post continues from Part 26. C4 is a good starting point — but many domains have their own concepts that do not map cleanly onto Software System, Container, and Component. AUTOSAR has SWCs, Ports, and Runnables. Embedded hardware has MCUs, Peripherals, and Buses. Bausteinsicht can be extended to support these languages.\nDefining New Element Types in specification Every new element type is declared in specification.elements:\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 means the type can have child elements. notation is the label text that appears below the shape in draw.io.\nAn AUTOSAR Model { \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; } } } The relationships between ports use the custom types:\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; } ] } Customizing Shapes in draw.io Bausteinsicht renders every element type with a default shape (rectangle). Custom shapes come via two approaches:\nStyle in specification.elements The simplest way — style directly in the specification:\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; } } } } } Shape names come from the draw.io shape library — search for a shape in the draw.io editor, right-click → \u0026#34;Edit Style\u0026#34; to reveal the name.\nTags for Visual Encoding When custom shapes are too much effort, a tag with a color is often sufficient (→ Part 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; } } ] } } Elements then get \u0026#34;tags\u0026#34;: [\u0026#34;autosar-cp\u0026#34;] and are automatically rendered in the correct color.\nLimits of Custom Notation What Bausteinsicht does not support today:\nCustom validation rules for new types (e.g. \u0026#34;every SWC must have at least one port\u0026#34;) — this must be checked externally\nType-dependent relationship rules (e.g. \u0026#34;Port may only connect to Bus, not to System\u0026#34;) — validate only checks whether IDs exist, not whether types are compatible\nHierarchy rules (e.g. \u0026#34;Runnable only within SWC\u0026#34;) — container: true allows any child types\nFor these checks, you can use bausteinsicht export-table --format json and validate the output in a separate script.\nA Complete 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; } } } } This allows hardware architectures to be described with the same tools as software architectures — sync, validate, diff, export all work identically.\nExample Model The example for this part (custom notations: Browser, Hexagon, Gear, Queue, Cylinder, Cloud) is available at teil_27.jsonc.\nHere is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_27.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram:\nUp Next: Performance Custom notations often lead to larger models — more types, more elements. The next part covers how to work with 50+ elements without losing the overview.\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-custom-notations/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from \u003ca href=\"../bausteinsicht-team-workflows/\"\u003ePart 26\u003c/a\u003e.\nC4 is a good starting point — but many domains have their own concepts that do not map cleanly onto Software System, Container, and Component.\nAUTOSAR has SWCs, Ports, and Runnables. Embedded hardware has MCUs, Peripherals, and Buses.\nBausteinsicht can be extended to support these languages.\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_defining_new_element_types_in_specification\"\u003eDefining New Element Types in specification\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eEvery new element type is declared in \u003ccode\u003especification.elements\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;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":"Part 27: Custom Notations — Custom Element Types, Shapes, and Domain Languages"},{"content":" This post continues from Part 27. A model with 10 elements is simple. With 50+ elements the question becomes: what does who see, when, in which view? And at what point do sync and draw.io slow down?\nWhen Does a Model Become \u0026#34;Large\u0026#34;? Practical thresholds:\nElement count Symptom Solution \u0026lt; 30\nEverything can be shown in one view\nA single main view is sufficient\n30–80\nOne view becomes unreadable — too many shapes\nMultiple focused views, scope + include\n80–200\nsync takes seconds, draw.io stutters\nKeep views deliberately small, consider Workspace\n\u0026gt; 200\nA draw.io page with 200+ shapes is no longer usable\nWorkspace with separate models (→ Part 16)\nKeeping Views Small: scope and include The most effective measure against large views is consistent scoping.\nBad view:\n{ \u0026#34;views\u0026#34;: { \u0026#34;everything\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Entire System\u0026#34;, \u0026#34;include\u0026#34;: [\u0026#34;*\u0026#34;] } } } Better: focused 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 Containers\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;Payment Flow\u0026#34;, \u0026#34;filter-tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] } } } Rule of thumb: a view should show at most 15–20 elements. More than that is no longer graspable at a glance.\nUsing Relationship Lifting as a Feature Relationship Lifting (→ Part 3) automatically promotes relationships to the next visible parent element. This means: in an abstract view (only shop and payment) all internal relationships between shop. and payment. are automatically presented as a single connection between shop and payment.\nSo there is no need to define separate relationships for different abstraction levels — lifting handles this automatically.\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 as Dynamic Scoping Instead of maintaining every view with explicit IDs, tags can be used as a dynamic filter (→ Part 23).\nThis scales particularly well: when a new element with \u0026#34;tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] is added, it automatically appears in all views with \u0026#34;filter-tags\u0026#34;: [\u0026#34;payment-path\u0026#34;] — without touching the view definition.\n{ \u0026#34;views\u0026#34;: { \u0026#34;critical-path\u0026#34;: { \u0026#34;title\u0026#34;: \u0026#34;Critical Payment Path\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: Causes and Countermeasures draw.io slows down when a page has too many shapes. Concrete measures:\nReduce shapes: * Collapse hierarchical elements (container: true) — draw.io shows only the container shape, not its children * Split views instead of having one large page\nClean up the draw.io file:\n# The draw.io file sometimes contains outdated shapes from deleted views # Sync cleans this up: bausteinsicht sync # Then reload draw.io — outdated shapes have been removed Separate draw.io files per view: Currently Bausteinsicht stores all views as pages in a single .drawio file. With a very large number of views (20+) it can help to split the views into groups — but this is a manual decision.\nWhen Workspace Is the Right Solution The Workspace feature (Part 16) is the right solution when:\nThe system consists of truly independent subsystems owned by different teams\nA single JSONC model grows beyond 200 elements\nTeams want to change their model without coordinating with others\nThe Workspace allows separate models with cross-references:\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; } } } } Each team maintains its model independently. In the Workspace context, views can combine elements from multiple models.\nDecision Guide: When to Use What Situation Recommendation One team, one system, \u0026lt; 100 elements\nFocused views, tag filters, scope\nMultiple teams, one system, 100–200 elements\nOwnership conventions, consider Workspace\nMultiple teams, multiple independent systems\nWorkspace with separate models\ndraw.io sluggish, model still small\nSplit views, remove unnecessary shapes, rerun sync\nvalidate takes \u0026gt; 5 seconds\nKnown performance issue — report as a bug\nExample Model The example for this part (larger model with gateway, microservices, event bus) is available at teil_28.jsonc.\nHere is what the result looks like in draw.io (bausteinsicht sync):\nYou can find the draw.io file here: teil_28.drawio\nGenerated PNG files via bausteinsicht export --image-format png:\nGenerated PlantUML diagrams via bausteinsicht export-diagram (Order Flow view):\nWhat Comes Next Part 29: Real-Life Example — the Big Bank Example by Simon Brown (Structurizr) fully transformed into Bausteinsicht JSONC\nThat Was the Extended Tutorial Series With Part 28 the Bausteinsicht tutorial series closes — from the project introduction in Part 1 through to performance and scaling in Part 28.\nThe most important entry points for quick reference:\nStarting fresh? → Part 2: Getting Started\nArchitecture rules? → Part 8: Validation \u0026amp; Linting\nWorking with AI? → Part 10: LLM/AI Workflows\nTeam architecture? → Part 16: Workspace\nIntegrating into CI/CD? → Part 24: CI/CD Integration\nMigrating from other tools? → Part 25: Migration\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-performance/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post continues from \u003ca href=\"../bausteinsicht-custom-notations/\"\u003ePart 27\u003c/a\u003e.\nA model with 10 elements is simple. With 50+ elements the question becomes: what does who see, when, in which view? And at what point do \u003ccode\u003esync\u003c/code\u003e and draw.io slow down?\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"sect1\"\u003e\n\u003ch2 id=\"_when_does_a_model_become_large\"\u003eWhen Does a Model Become \u0026#34;Large\u0026#34;?\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003ePractical thresholds:\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\"\u003eElement count\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eSymptom\u003c/th\u003e\n\u003cth class=\"tableblock halign-left valign-top\"\u003eSolution\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\"\u003eEverything can be shown in one view\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eA single main view is sufficient\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\"\u003eOne view becomes unreadable — too many shapes\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eMultiple focused 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 takes seconds, draw.io stutters\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eKeep views deliberately small, consider Workspace\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\"\u003eA draw.io page with 200+ shapes is no longer usable\u003c/p\u003e\u003c/td\u003e\n\u003ctd class=\"tableblock halign-left valign-top\"\u003e\u003cp class=\"tableblock\"\u003eWorkspace with separate models (→ \u003ca href=\"../bausteinsicht-workspace/\"\u003ePart 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":"Part 28: Performance with Large Models — Scoping, Partial Views, and Subsystems"},{"content":" This post builds on Part 28. All previous examples in the tutorial showed fictional systems. Here comes a real reference model: the Big Bank Example by Simon Brown — the inventor of the C4 model and lead developer of Structurizr.\nAnd for the first time it is not written by hand, but imported directly from Structurizr DSL.\nbausteinsicht import --from structurizr is available from the release after v1.1.0 (merged in PR #331). With the currently installed v1.1.0 the command is not yet available — anyone who wants to try it now can build Bausteinsicht locally from main.\nWhat Is the Big Bank Example? The Big Bank Example is the official reference model for the Structurizr documentation. It shows a fictional retail bank with an Internet Banking System across three C4 levels:\nSystem Context — customers, bank staff, ATM, external systems\nContainer — Web App, SPA, Mobile App, API Application, Oracle database\nComponent — six components of the API Application\nThe model is complex enough to demonstrate all features of Bausteinsicht, and well-known enough to be immediately understood.\nOriginal in Structurizr DSL: https://structurizr.connectedpdf.com/share/3/dsl Structurizr Container diagram live: https://structurizr.com/embed/39258?diagram=Containers\u0026amp;diagramSelector=false\nPrerequisites # Bausteinsicht from main (until v1.2.0 is released): go install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@main # Or with Node.js installed: npm install -g @doctoolchain/bausteinsicht@next An empty directory for the experiment:\nmkdir bigbank \u0026amp;\u0026amp; cd bigbank Step 1: Download the DSL Fetch the combined Big Bank DSL (System Landscape + Internet Banking System) directly from Structurizr:\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; ... } } Step 2: Preview with --dry-run Before writing any file, run the import as a preview:\nbausteinsicht import --from structurizr bigbank.dsl --dry-run The command outputs the generated JSONC to stdout — without writing anything. This lets you check whether the parsing is correct before overwriting an existing architecture.jsonc.\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;: { ... } } If parsing a particular DSL construct is not supported, bausteinsicht import emits a warning on stderr — but the import continues to completion. Deployment diagrams (deploymentEnvironment) are skipped and reported as warnings.\nStep 3: Run the Import bausteinsicht import --from structurizr bigbank.dsl Result:\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 is now in the directory. The generated file for the Big Bank Example is shown here:\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; ] } } } What the Importer Does Automatically Hierarchy preserved — Structurizr blocks ({ }) become children objects in JSONC. The fully dotted path (internet-banking.api-app.sign-in) is derived from the DSL variable names.\nRelationships resolved — Structurizr allows relationships that appear before the element definition (a → b). The importer resolves all references with deferred resolution — the result is always a consistent JSONC.\nTags carried over — Structurizr tags (\u0026#34;Existing System\u0026#34;, \u0026#34;Bank Staff\u0026#34;, \u0026#34;Web Browser\u0026#34;) are transferred 1:1 into specification.tags and attached to the elements.\nViews converted — systemContext, container, and component views are translated into Bausteinsicht views. include * is resolved into an explicit include list.\nWhat Needs Manual Follow-Up The import is a one-time operation — not a mapping for everything. The following must be added manually:\nNot imported How to add Deployment diagrams\nCreate separate views in views or model them in draw.io\nStyles / Themes\nPopulate specification.tags[].style with draw.io colors\n!include directives\nLocal includes are resolved, HTTP includes are not\nproperties on containers\nUse the metadata field in Bausteinsicht\nDifferentiated relationship types\nAll relationships are imported as uses — adjust sends, reads, etc. manually\nThe most important thing for external systems: Structurizr uses the string tag \u0026#34;Existing System\u0026#34;. The importer carries this over as tag existing-system. For colored styling in draw.io, simply add a style section to specification.tags:\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;External system — not under our control\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; } } ] } Step 4: Sync and Diagrams bausteinsicht sync Bausteinsicht generates architecture.drawio with three tabs:\ncontext — System Context: customers, bank staff, ATM, external systems\ncontainers — All containers of the Internet Banking System\ncomponents — Six components of the API Application\nYou can find the draw.io file here: teil_29.drawio\nGenerated PNG files:\nGenerated PlantUML diagrams:\nStructurizr vs. Bausteinsicht — Quick Comparison Aspect Structurizr Bausteinsicht Model format\nCustom DSL\nJSONC\nDiagram output\nSVG via Structurizr server\ndraw.io (editable, bidirectional)\nBidirectional\nNo — DSL is the source of truth\nYes — draw.io changes flow back into JSONC\nOffline\nStructurizr Lite required\nFully local\nDeployment diagrams\nNative in DSL\nNo built-in concept\nImport from Structurizr\n—\nbausteinsicht import --from structurizr\nConstraint checking\n!rules in DSL\nconstraints in JSONC, bausteinsicht lint\nMigration in one direction is now trivial with bausteinsicht import. There is no importer back to Structurizr — but that is rarely needed in practice.\nWhat Comes Next Part 30: More Views from One Model — how to generate 7 focused diagrams for different audiences from the Big Bank model\nThe most important entry points for quick reference:\nStarting fresh? → Part 2: Getting Started\nArchitecture rules? → Part 8: Validation \u0026amp; Linting\nWorking with AI? → Part 10: LLM/AI Workflows\nTeam architecture? → Part 16: Workspace\nMigrating from other tools? → Part 25: Migration\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/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\u003eThis post builds on \u003ca href=\"../bausteinsicht-performance/\"\u003ePart 28\u003c/a\u003e.\nAll previous examples in the tutorial showed fictional systems.\nHere comes a real reference model: the \u003cstrong\u003eBig Bank Example\u003c/strong\u003e by Simon Brown — the inventor of the C4 model and lead developer of Structurizr.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eAnd for the first time it is not written by hand, but \u003cstrong\u003eimported directly from Structurizr DSL\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 is available from the release after v1.1.0 (merged in PR #331).\nWith the currently installed v1.1.0 the command is not yet available — anyone who wants to try it now can build Bausteinsicht locally from \u003ccode\u003emain\u003c/code\u003e.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 29: Real-Life Example — Structurizr Big Bank with bausteinsicht import"},{"content":" This post builds directly on Part 29. The Big Bank Example produced 3 views: System Context, Container, Components. That is enough for a documentation page — but not for a real project.\nA security architect needs a different diagram than a mobile developer. A manager prefers the customer perspective, not the backend. But all three want to draw from the same model — not maintain three separate files.\nThis chapter shows how.\nThe Problem: One View for Everyone When all elements end up in one view, this happens:\n20+ shapes in a single diagram — nobody can take it in at a glance\nEvery change affects the only diagram — all stakeholders have to deal with it\nNo clear statement: \u0026#34;what does this diagram want to show?\u0026#34;\nThe Big Bank Example has 3 actors, 4 systems, 5 containers, 6 components. In a single \u0026#34;everything\u0026#34; view that would be 18 shapes — already too many.\nThe Solution: One Model, Many Views Bausteinsicht separates model (what exists) from views (what is shown).\n// Model: defined once \u0026#34;model\u0026#34;: { ... }, \u0026#34;relationships\u0026#34;: [ ... ], // Views: any number of lenses onto the same model \u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { ... }, // for management \u0026#34;containers\u0026#34;: { ... }, // for architects \u0026#34;components\u0026#34;: { ... }, // for all developers \u0026#34;api-internals\u0026#34;: { ... }, // for the backend team \u0026#34;mobile-flow\u0026#34;: { ... }, // for mobile developers \u0026#34;customer-touchpoints\u0026#34;: { ... }, // for product owners \u0026#34;security-flow\u0026#34;: { ... } // for the security team } Each view produces its own tab in architecture.drawio — that is, its own diagram. The model exists exactly once.\nRule of Thumb: When Do You Need a New View? Signal Response A diagram has more than 12–15 shapes\nSplit into focused views\nDifferent teams ask for different slices\nOne view per team\nA diagram shows too much context for its purpose\nUse exclude or a narrower include\nMeetings: \u0026#34;can you quickly show the auth flows?\u0026#34;\nCreate a dedicated security-flow view\nSomeone asks: \u0026#34;what does the customer see?\u0026#34;\nCreate a dedicated customer-touchpoints view\nThe 4 New Views in Detail api-internals — Zoom-In Without Frontend Noise The standard components view shows SPA and Mobile App as callers of the components. That is correct — but for the backend team it is noise. They want to see how the 6 components interact with each other and with external systems.\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;Only API App + direct external dependencies — without frontend noise\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; ] } No customer, no spa, no mobile-app — just the 6 components, Database, Mainframe, and E-Mail. The difference from components: no frontend in the view.\nmobile-flow — Only the Mobile Path Web App and SPA are irrelevant for mobile developers. This view shows the complete path from customer through mobile-app to the relevant components and external systems:\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;Only the mobile path — Web App and SPA hidden\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 is intentionally omitted — the Mobile App does not trigger direct email sending except during Reset Password. For the general Mobile Flow, this is not a relevant path.\ncustomer-touchpoints — What the Customer Sees Product owners and UX designers ask: \u0026#34;where does the customer interact with the system?\u0026#34; This view shows exactly that — no backend, no 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;Everything the customer directly sees and touches — no 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; ] } Only 6 shapes. Understandable at a glance — even for non-technical audiences.\nsecurity-flow — Auth and Password Reset Security reviews need the authentication path in isolation: who calls the Sign-In Controller, where is the database, which component sends emails?\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;Authentication and password reset path — for the 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 and mainframe-facade are deliberately hidden here — they play no role in the auth flow.\nViews and Relationship Lifting An important property: when a view shows components but not their parent container, Bausteinsicht automatically promotes the relationships.\nIn the customer-touchpoints view, internet-banking.spa is directly visible. The relationship customer → internet-banking.spa is drawn directly — not promoted.\nIn the context view, only internet-banking is visible (no spa). All relationships from customer to internet-banking.* are collapsed into a single line customer → internet-banking.\nThe same model, automatically raised to the right abstraction level — without manual double-definitions.\nThe Complete 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; ] } } } Result: 7 Tabs in draw.io bausteinsicht sync generates 7 draw.io tabs:\nTab Title Audience context\nSystem Context\nManagement, Stakeholders\ncontainers\nContainer\nArchitects\ncomponents\nComponents (all)\nAll Developers\napi-internals\nAPI Internals\nBackend Team\nmobile-flow\nMobile App Flow\nMobile Developers\ncustomer-touchpoints\nCustomer Touchpoints\nProduct Owner, UX\nsecurity-flow\nSecurity \u0026amp; Auth Flow\nSecurity Team, Auditors\nYou can find the draw.io file here: teil_30.drawio\nGenerated PNG files:\nGenerated PlantUML diagrams:\nNaming Views: Tab Order in draw.io The order of views in the JSONC determines the tab order in draw.io. Most useful: from abstract to concrete — just like in C4.\n\u0026#34;views\u0026#34;: { \u0026#34;context\u0026#34;: { ... }, // Tab 1: abstract \u0026#34;containers\u0026#34;: { ... }, // Tab 2 \u0026#34;components\u0026#34;: { ... }, // Tab 3: concrete \u0026#34;api-internals\u0026#34;: { ... } // Tab 4: zoom-in } View keys become draw.io tab names. Descriptive keys (security-flow, mobile-flow) make draw.io directly navigable — even without reading the title.\nWhat Comes Next This was Part 30 — the final chapter of the Bausteinsicht tutorial series.\nThe most important entry points for quick reference:\nStarting fresh? → Part 2: Getting Started\nTags for view filtering? → Part 23: Tags \u0026amp; View Filtering\nPerformance with large models? → Part 28: Performance\nMigrating from Structurizr? → Part 29: Big Bank Import\nOfficial documentation: User Manual · Tutorial on doctoolchain.org\n","permalink":"https://paul-fleischmann.com/en/projekte/bausteinsicht/tutorial/bausteinsicht-multi-view-design/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis post builds directly on \u003ca href=\"../bausteinsicht-structurizr-big-bank-beispiel/\"\u003ePart 29\u003c/a\u003e.\nThe Big Bank Example produced 3 views: System Context, Container, Components.\nThat is enough for a documentation page — but not for a real project.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eA security architect needs a different diagram than a mobile developer.\nA manager prefers the customer perspective, not the backend.\nBut all three want to draw from the same model — not maintain three separate files.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eThis chapter shows how.\u003c/p\u003e\n\u003c/div\u003e","title":"Part 30: More Views from One Model — Focused Diagrams per Audience"},{"content":" I’m Paul Fleischmann — Embedded Software Architect, Dipl.-Ing. (FH) Computer Engineering, based in Hirm, Burgenland, Austria.\nFor over 15 years I worked at Elektrobit Austria in Vienna on AUTOSAR Classic Platform — from writing the first MCAL driver to the role of Bundle Software Architect, responsible for the technical direction of several basic software modules.\nWhat I do What drives me: making low-level software work on real hardware — so that the customer holds a product in their hands that actually works.\nA well-designed software module starts with architecture: clearly defined module boundaries, generic APIs, and a Hardware Abstraction Layer (HAL) that encapsulates everything chip-specific — registers, timing, and hardware quirks stay behind the HAL.\nThat is my standard: the user never notices the underlying hardware, and the next chip swap won’t be a surprise. What changes is the HAL. Everything else stays.\nAnd when something doesn’t work: debugger on the target, oscilloscope on the board, schematic open — and find the root cause. Architecture and debugging are two sides of the same work for me.\nWhat I work with My core is the AUTOSAR Classic Platform stack — from MCAL drivers for CAN, LIN, SPI, and Ethernet to Complex Device Drivers for low-level protocol layers.\nIn automotive Ethernet I know the stack from hardware to application protocol: Switch Management, IEEE 1722, J1939, configured and integrated with EB tresos.\nGoing from hardware specification to implementation is part of the job for me: understanding the relevant registers and timing requirements — and deriving a clean driver architecture that doesn’t leak hardware details into the rest of the stack.\nASPICE and MISRA-C are not checkboxes for me — they are part of daily work.\nPrimary language is C. Plus Rust, Go, and Python where they are the better tool.\nMy projects Professional Professionally I have grown in two clearly distinct roles.\nStarted as an AUTOSAR integrator: porting and qualifying the EB AUTOSAR stack on several chip platforms, and integrating it in customer projects — ensuring AUTOSAR configuration and integration against customer requirements.\nThen the move into AUTOSAR module development: low-level communication drivers and modules in the communication stack, close to the hardware drivers. Exactly the area where architecture and debugging intersect.\nPersonal An embedded project on the BeagleBone Black — because embedded development stays interesting without a customer. Details in the BeagleBone project.\nPlus a fully self-hosted development environment: Podman, Gitea, Drone CI, code-server — because working infrastructure should not be accidental.\nWhy this blog Because 15 years of AUTOSAR development leaves opinions — about architecture, tooling, and the places where theory and practice diverge.\nKnowledge that isn’t shared stays useless. What I have learned in 15 years — about architecture, tooling, the interplay of software and hardware — I write it down here so others can benefit from it.\nContact I am currently open to new challenges in Embedded Software Engineering and AUTOSAR Classic Platform — preferably in the Austrian automotive environment.\n📧 paul.fleischmann@paul-fleischmann.com 🔗 LinkedIn · GitHub\n","permalink":"https://paul-fleischmann.com/en/about/","summary":"\u003cdiv id=\"preamble\"\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eI’m Paul Fleischmann — Embedded Software Architect,\nDipl.-Ing. (FH) Computer Engineering, based in Hirm, Burgenland, Austria.\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eFor over 15 years I worked at Elektrobit Austria in Vienna on AUTOSAR Classic Platform —\nfrom writing the first MCAL driver to the role of Bundle Software Architect,\nresponsible for the technical direction of several basic software modules.\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=\"_what_i_do\"\u003eWhat I do\u003c/h2\u003e\n\u003cdiv class=\"sectionbody\"\u003e\n\u003cdiv class=\"paragraph\"\u003e\n\u003cp\u003eWhat drives me: making low-level software work on real hardware —\nso that the customer holds a product in their hands that actually works.\u003c/p\u003e\n\u003c/div\u003e","title":"About me"}]