arc42 Template

Unresolved directive in <stdin> - include::chapters/../../../common/styles/arc42-help-style.adoc[]

About arc42

arc42, the template for documentation of software and system architecture.

Template Version {revnumber}. {revremark}, {revdate}

Created, maintained and © by Dr. Peter Hruschka, Dr. Gernot Starke and contributors. See https://arc42.org.


Note

This version of the template contains some help and explanations. It is used for familiarization with arc42 and the understanding of the concepts. For documentation of your own system you use better the plain version.

1. Introduction and Goals

Bausteinsicht is an architecture-as-code tool that uses draw.io as its visual frontend. It maintains a structured architecture model in a JSON-based DSL and synchronizes it bidirectionally with draw.io diagrams.

1.1. Requirements Overview

Bausteinsicht addresses the gap between structured architecture models and widely adopted visual diagramming tools.

Requirement Description

Architecture Model

A JSON-based DSL serves as single source of truth for all architecture elements, relationships, and metadata.

draw.io Integration

draw.io serves as the visual frontend. Templates define the styling, fully customizable by the user.

Bidirectional Sync

Changes in the model are reflected in draw.io views and vice versa. New elements, updated descriptions, and relationships are synchronized in both directions.

Flexible Hierarchy

Element hierarchy is user-defined and not limited to the 4 C4 levels. Components of components are valid.

CLI & Watch Mode

A CLI provides commands for sync, validation, and watching. CLI commands also enable LLM-driven architecture maintenance.

Template System

Templates are draw.io files containing styled example elements. Users create and customize templates entirely within draw.io.

Architecture Analysis

Commands assess the model: constraint checking (lint), a health score (health), dependency-graph analysis (graph), stale-element detection (stale), lifecycle status (status), and full-text search (find).

Architecture Evolution

The architecture is versioned and comparable over time: snapshots with semantic diff (snapshot), as-is/to-be comparison (diff), and an architecture changelog (changelog).

Interoperability & Export

Models import from Structurizr DSL and LikeC4 (import) and export to C4-PlantUML, Mermaid, DOT, D2, HTML, Structurizr DSL, sequence diagrams, tables, and PNG/SVG.

IDE Integration

A Language Server (the separate bausteinsicht-lsp binary) and a VS Code extension provide in-editor diagnostics and code lenses for model files.

See PRD-001 for the full product requirements.

1.2. Quality Goals

The top three quality goals driving architectural decisions:

Priority Quality Goal Scenario

1

Learnability

A developer unfamiliar with Bausteinsicht creates a working architecture model with draw.io views within 30 minutes using only the documentation and IDE autocompletion.

2

IDE Support

When editing the JSON model in VS Code, IntelliJ, or Neovim, the editor provides autocompletion, validation, and hover documentation without installing any Bausteinsicht-specific plugin.

3

LLM Friendliness

An LLM agent (e.g., Claude) can read the architecture model, add a new element with relationships, and trigger synchronization using only CLI commands — without human intervention.

See Chapter 10 for the full quality requirements and scenarios.

1.3. Stakeholders

Role/Name Contact Expectations

Software Architect

Primary user

Maintains architecture models visually in draw.io with a structured model behind the scenes. Expects flexible hierarchy and easy template customization.

Developer

Team member

Consults architecture diagrams in draw.io. Expects diagrams to always reflect the current model state.

LLM Agent

AI assistant (e.g., Claude)

Modifies architecture models via CLI commands. Expects a machine-readable JSON format and predictable CLI behavior.

Bausteinsicht exists in the broader landscape of architecture-as-code and C4 modeling tools. The following projects solve similar or overlapping problems:

Project Description

Structurizr

The original C4 model tooling by Simon Brown. Provides a dedicated DSL, web-based renderer, and export to many formats. DSL is source-of-truth (no bidirectional sync with diagrams).

C4 model

The methodology behind the 4-level architecture abstraction (Context, Container, Component, Code). Bausteinsicht is C4-inspired but supports user-defined, unlimited nesting levels.

LikeC4

A modern C4-inspired tool with a custom DSL, VS Code extension, and live web preview. Supports user-defined element kinds and flexible nesting, similar to Bausteinsicht.

Isoflow

A visual-first architecture diagramming tool with isometric rendering. Focused on visual editing rather than text-based modeling.

C4InterFlow

Extends the C4 model with interface and flow concepts for documenting system interactions at a more granular level.

Bausteinsicht’s differentiator is bidirectional synchronization between a text model (JSONC) and draw.io diagrams — edits in either direction are merged. See ADR-001 for a detailed comparison of DSL formats.

2. Architecture Constraints

2.1. Technical Constraints

Constraint Description

Go as implementation language

The tool is implemented in Go to enable single-binary distribution without runtime dependencies. See ADR-002.

JSON as model format

The architecture model uses JSON (JSONC) with JSON Schema for validation. See ADR-001.

draw.io XML as output format

The visual representation uses draw.io’s mxGraph XML format. This constrains layout capabilities to what draw.io supports.

No JavaScript/Node.js in the product

The CLI and its libraries use no JavaScript/Node.js, avoiding npm supply-chain risk. Exception: the optional VS Code extension (vscode-extension/) is a separate TypeScript/npm artifact, not part of the released binary.

Cross-platform

The tool must run on Linux, macOS, and Windows.

Headless draw.io for image export

export (PNG/SVG) shells out to the draw.io desktop CLI; it must be installed (in containers: via xvfb + dbus). The text exports need no draw.io.

Git for history-based commands

stale and changelog invoke the git binary to derive element history; outside a git repository they degrade gracefully.

2.2. Organizational Constraints

Constraint Description

Open Source

The project is developed as open source software.

Documentation in English

All documentation is written in English.

Documentation in AsciiDoc

Architecture documentation uses arc42 template in AsciiDoc format.

ADR format

Architecture decisions follow the Nygard ADR format with a weighted Pugh matrix for option evaluation.

2.3. Conventions

Convention Description

Version control

All files (model JSON, draw.io XML, templates) are text-based and Git-friendly.

Version numbering

The tool displays a version number. Semantic versioning is used.

ADR naming

ADRs follow the pattern ADR-NNN-Name.adoc in src/docs/arc42/ADRs/.

3. Context and Scope

3.1. Business Context

Bausteinsicht sits between the architecture model (JSON files) and draw.io diagrams, synchronizing both bidirectionally.

3.1.1. Architecture Maintenance Process

The following activity diagram shows how Bausteinsicht fits into the daily architecture workflow. The architect chooses between editing the text model or the visual diagram — Bausteinsicht synchronizes both directions.

business context process

3.1.2. Extended Workflows

The core loop above covers day-to-day editing. Bausteinsicht’s other ~30 commands enter or feed off that loop at specific points rather than replacing it — grouped here by where they attach, not detailed step-by-step (chapter 6’s Runtime View has the sequence diagrams for that level of detail, themselves generated via bausteinsicht export-sequence from dynamicViews in architecture.jsonc).

business context extended

3.1.3. System Context

System Context
Figure 1. System Context (generated from architecture model)
Element Kind Technology Description

Bausteinsicht

system

Architecture-as-code tool with draw.io as visual frontend and bidirectional synchronization

Developer

actor

Developer using the Bausteinsicht CLI to manage architecture models

draw.io App

external_system

draw.io desktop or web application for visual diagram editing

IDE

external_system

IDE with JSON Schema support for JSONC editing with autocompletion

Note
The generated diagram above is itself produced from a Bausteinsicht model and shows the principal technical partners (developer, draw.io, IDE). The table below is the authoritative, complete set of communication partners — including the human architect, LLM agents, and git, which act on the system rather than appearing inside its own context view.
Communication Partner Input Output

Software Architect

Edits to architecture model (JSONC) or draw.io diagrams

Synchronized model and diagrams

Developer

Up-to-date architecture diagrams in draw.io

LLM Agent

CLI commands (add element, sync, validate)

Updated model files, validation results

draw.io

Visual edits to diagram elements and relationships

Generated/updated diagram XML

IDE (VS Code, IntelliJ, etc.)

JSON Schema

Autocompletion, validation, hover docs for model files

Git

Version-controlled model and diagram files

Diff-friendly text-based file changes

3.2. Technical Context

Interface Technology Description

Architecture Model

JSONC files on filesystem

The model is stored as .jsonc files in the project directory. Validated against a JSON Schema.

draw.io Diagrams

mxGraph XML files on filesystem

Standard .drawio files that can be opened in draw.io desktop, VS Code extension, or draw.io online.

Templates

mxGraph XML files on filesystem

draw.io files containing styled reference elements for each element kind.

CLI

Go binary (stdin/stdout)

Command-line interface for sync, validate, watch, and model manipulation commands.

File System Watcher

OS-native (inotify/FSEvents/ReadDirectoryChanges)

Watches model and diagram files for changes in watch mode.

JSON Schema

Published schema file (local or SchemaStore.org)

Enables IDE support without Bausteinsicht-specific plugins.

draw.io CLI

External process (auto-detected on PATH)

export invokes the headless draw.io binary to render diagram pages to PNG/SVG.

Git

External process (git log)

stale and changelog read element history from the repository; optional (graceful degradation outside git).

Import / export formats

Files on filesystem

In: Structurizr DSL (.dsl), LikeC4 (.c4). Out: C4-PlantUML, Mermaid, DOT, D2, HTML, Structurizr DSL, sequence diagrams, AsciiDoc/Markdown tables.

Language Server (LSP)

JSON-RPC over stdio

The bausteinsicht-lsp binary serves diagnostics and code lenses to editors (e.g. the VS Code extension).

Snapshot store

Files on filesystem (.bausteinsicht-snapshots/)

Versioned model captures written and read by the snapshot commands.

4. Solution Strategy

4.1. Technology Decisions

Decision Choice Rationale

Implementation language

Go (ADR-002)

Single-binary distribution, LLM-friendly code generation, compile-time type safety

Architecture model format

JSONC with JSON Schema (ADR-001)

Universal IDE support, zero parser effort, LLM-native read/write

draw.io XML processing

beevik/etree (with emicklei/mxgraph as optional accelerator)

Flexible DOM-style XML manipulation for dynamic attributes on <object> elements

CLI framework

Cobra

Battle-tested (kubectl, gh, terraform), built-in help generation, shell completion

File watching

fsnotify

Cross-platform file system events, no polling overhead

4.2. Top-Level Decomposition

Bausteinsicht follows a pipes-and-filters architecture with a clear separation between data formats:

solution decomposition
  • Model package reads/writes the JSON model. Knows nothing about draw.io XML.

  • DrawIO package reads/writes mxGraph XML. Knows nothing about the JSON model.

  • Sync Engine orchestrates the bidirectional sync between both formats, using a state file for three-way merge.

  • CLI layer is a thin shell delegating to these packages.

This decomposition ensures that model format changes (e.g., switching from JSONC to YAML) or draw.io format changes do not ripple across the codebase.

4.3. Quality Goal Strategies

Quality Goal Strategy

Learnability

bausteinsicht init scaffolds a working example. JSON Schema provides IDE autocompletion. draw.io template gives visual starting point. User is productive without reading documentation.

IDE Support

JSON Schema is published and referenced via $schema in the model file. Works out of the box in VS Code, IntelliJ, and any JSON Schema-aware editor. No plugin required.

LLM Friendliness

All CLI commands support --format json for structured output. add element and add relationship commands allow LLMs to modify the model without parsing JSON directly. The JSONC format is natively understood by all major LLMs.

4.4. Key Design Patterns

4.4.1. Three-Way Merge for Bidirectional Sync

Rather than simple overwrite, Bausteinsicht uses a .bausteinsicht-sync state file to detect which side changed. This prevents data loss when both the model and draw.io are edited between syncs. See Sync Specification for details.

4.4.2. Template-Based Styling

Visual styles are not hardcoded. A draw.io template file defines the appearance of each element kind via bausteinsicht_template attributes. Users can customize templates without modifying source code.

4.4.3. Thin CLI, Rich Library

The cmd/ layer contains only argument parsing and output formatting. All logic lives in internal/ packages that can be tested independently and reused (e.g., for a future LSP server or web API).

5. Building Block View

5.1. Level 1: Overall System

Container View
Figure 2. Container View (generated from architecture model)

5.1.1. Motivation

At the centre sits a small core enginemodel (the JSONC world), drawio (the XML world), and sync as the mediator between them, so changes to one format never leak into the other package. Around this core, a set of feature packages add analysis, evolution, interop, and styling, and a thin CLI layer (cmd/bausteinsicht) wires commands to them. A second binary (cmd/bausteinsicht-lsp) reuses the same library code to serve editors over the Language Server Protocol.

In total the system is two binaries over ~23 production packages (plus three test-only helper packages). The complete map is in the Package Map below; the core engine and the CLI layer are decomposed further in the Level 2 sections.

5.1.2. Building Blocks (core)

Element Kind Technology Description

Changelog

container

Go

Architecture changelog generation between two git refs

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

Constraints

container

Go

Validation constraints for model linting and consistency checking

Diagram

container

Go

Text-based diagram export to Mermaid C4 and PlantUML formats with markdown wrapping

Diff

container

Go

As-is vs. to-be architecture comparison

draw.io

container

Go / etree

draw.io XML document handling — elements, connectors, templates, and labels

Export

container

Go

Export diagrams to PNG, SVG, and other visual formats via draw.io CLI

Exporter

container

Go

Architecture export to Structurizr DSL and other formats

Graph

container

Go

Relationship graph analysis — cycle detection and dependency depth

Health

container

Go

Architecture health scoring — completeness, conformance, and complexity

Importer

container

Go

Import architecture from Structurizr DSL, LikeC4, and XMI/Enterprise Architect formats

Layout

container

Go

Auto-layout algorithms for positioning elements in draw.io diagrams

Language Server

container

Go

Language Server Protocol implementation for VS Code and other editors

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

Overlay

container

Go

Metric heatmap overlay application and removal on draw.io diagrams

Schema

container

Go

JSON Schema generation from Go model types for IDE autocompletion

Search

container

Go

Element and relationship search with filtering and pattern matching

Snapshot

container

Go

Versioned architecture snapshot storage and restore

Stale

container

Go

Detects unused or forgotten architecture elements via git history and ADR/status metadata

Sync Engine

container

Go

Bidirectional synchronization engine between JSONC model and draw.io diagrams

Table

container

Go

Export architecture to CSV and Markdown table formats

Template

container

Go

draw.io template generation from element specification (shapes, layout)

Watcher

container

Go / fsnotify

File system monitoring for automatic sync on model or diagram changes

Workspace

container

Go

Multi-model workspace configuration loading and merging

Developer

actor

Developer using the Bausteinsicht CLI to manage architecture models

draw.io App

external_system

draw.io desktop or web application for visual diagram editing

IDE

external_system

IDE with JSON Schema support for JSONC editing with autocompletion

5.1.3. Important Interfaces

Interface Description

model.Load(path) → BausteinsichtModel

Parses a JSONC file into the Go model struct. Validates against schema constraints.

model.Save(path, BausteinsichtModel)

Writes the model back to JSONC, preserving comments where possible.

drawio.LoadDocument(path) → Document

Parses a draw.io XML file into a manipulable document structure.

drawio.SaveDocument(path, Document)

Writes the document back to uncompressed draw.io XML.

drawio.LoadTemplate(path) → TemplateSet

Reads a template file and extracts styles keyed by bausteinsicht_template kind.

sync.Run(model, document, lastState, templates, newPageIDs, …​opts) → *SyncResult

Executes one full bidirectional sync cycle — a pure function with no I/O. newPageIDs marks pages created in this run (so their elements are not mistaken for deletions); opts are optional ForwardOptions (e.g. relayout). Returns a SyncResult describing all changes and conflicts.

sync.LoadState(path) → SyncState

Reads the .bausteinsicht-sync state file.

sync.SaveState(path, SyncState)

Writes the updated sync state after successful sync.

5.1.4. Package Map (all building blocks)

Every production package, grouped by role. Each row is a Level-1 building block: its responsibility and its source location. The core engine (model, drawio, sync) and the CLI layer (cli) are decomposed further in the Level 2 sections below.

Table 1. Core engine
Package Responsibility Source

model

DSL types, JSONC loader (comment-preserving patch + full save), validation, ID/wildcard resolution

internal/model/

drawio

Read/write draw.io XML: document, element, connector, template, HTML label

internal/drawio/

sync

Bidirectional sync: diff, forward/reverse apply, conflict resolution, state, layout, badges, metadata

internal/sync/

watcher

fsnotify file watcher driving --watch mode (300 ms debounce)

internal/watcher/

Table 2. Analysis
Package Responsibility Source

constraints

Evaluate architectural rules from the model (lint)

internal/constraints/

graph

Relationship-graph analysis: cycles, dependency depth, centrality (graph)

internal/graph/

health

Architecture health score across weighted categories (health)

internal/health/

stale

Detect unused/forgotten elements, using git history (stale)

internal/stale/

search

Full-text search over elements, relationships, views (find)

internal/search/

workspace

Group, merge, and validate multiple models together as one workspace (workspace)

internal/workspace/

Table 3. Evolution
Package Responsibility Source

snapshot

Versioned model captures, semantically diffable (snapshot)

internal/snapshot/

diff

As-is vs. to-be model comparison (diff)

internal/diff/

changelog

Architecture changelog between two git points (changelog)

internal/changelog/

Table 4. Layout & styling
Package Responsibility Source

layout

Hierarchical auto-layout engine (layout, sync --relayout)

internal/layout/

template

Generate a draw.io template from the specification (generate-template)

internal/template/

overlay

Apply/remove metric heatmap overlays on diagrams (overlay)

internal/overlay/

Table 5. Interop & export
Package Responsibility Source

importer

Import models from Structurizr DSL, LikeC4, and XMI/Enterprise Architect (import). The XMI sub-package buffers the entire file in memory and converts Windows-1252 to UTF-8 before parsing, so peak RSS is ~2× the raw file size (e.g. ~230 MB for a 114 MB AUTOSAR export); a 200 MB read cap is enforced.

internal/importer/ (structurizr/, likec4/, xmi/)

exporter

Export the model as Structurizr DSL

internal/exporter/structurizr/

diagram

Render views as text diagrams: C4-PlantUML, Mermaid, DOT, D2, HTML, sequence (export-diagram, export-sequence)

internal/diagram/

table

Render element attributes as AsciiDoc/Markdown tables (export-table)

internal/table/

export

Export diagram pages to PNG/SVG via headless draw.io (export)

internal/export/

schema

Generate the JSON Schema from the Go model types (schema)

internal/schema/

Table 6. IDE integration
Package Responsibility Source

lsp

Language Server Protocol server: diagnostics, code lenses; backs the cmd/bausteinsicht-lsp binary and the VS Code extension

internal/lsp/

Note
internal/chaos (fault-injection helper), internal/benchmarks, and internal/e2eplan (the e2e-test-plan report generator’s plan-ID registry, see #519) are test-only utilities, not production building blocks.

5.2. Level 2: Sync Engine

The sync engine is the most complex package. It decomposes into five sub-components.

Sync Engine Components
Figure 3. Sync Engine Components (generated from architecture model via draw.io export)

5.2.1. Building Blocks

Element Kind Technology Description

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

draw.io

container

Go / etree

draw.io XML document handling — elements, connectors, templates, and labels

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

Conflict

component

Go

Conflict detection and resolution when both model and diagram changed

Diff

component

Go

Three-way change detection comparing model, diagram, and last-sync state

Engine

component

Go

Main sync orchestrator coordinating diff, forward, reverse, and conflict resolution

Forward Sync

component

Go

Applies model changes to draw.io diagrams (model → drawio)

Reverse Sync

component

Go

Applies draw.io changes back to the JSONC model (drawio → model)

State

component

Go

Sync state persistence using SHA256 hashes for change detection

Watcher

container

Go / fsnotify

File system monitoring for automatic sync on model or diagram changes

5.3. Level 2: DrawIO Package

The draw.io package handles all mxGraph XML concerns.

draw.io Package Components
Figure 4. draw.io Package Components (generated from architecture model via draw.io export)

5.3.1. Building Blocks

Element Kind Technology Description

Connector

component

Go

Connector/relationship CRUD for edges between elements

Document

component

Go

XML parsing, page management, and file I/O for .drawio files

Element

component

Go

Element CRUD operations on mxGraphModel objects and mxCells

Label

component

Go

HTML label generation and parsing for element display text

Template

component

Go

Template loading and style lookup from .drawio template files

Export

container

Go

Export diagrams to PNG, SVG, and other visual formats via draw.io CLI

Sync Engine

container

Go

Bidirectional synchronization engine between JSONC model and draw.io diagrams

draw.io App

external_system

draw.io desktop or web application for visual diagram editing

5.4. Level 2: Model Package

Model Package Components
Figure 5. Model Package Components (generated from architecture model via draw.io export)

5.4.1. Building Blocks

Element Kind Technology Description

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

Loader

component

Go

JSONC read/write with comment stripping and trailing comma handling

Patch

component

Go

Comment-preserving JSONC mutations for reverse sync

Resolve

component

Go

Dot-notation element resolution and wildcard pattern matching

Types

component

Go

Core struct definitions for elements, relationships, views, and specification

Validate

component

Go

Model validation rules for elements, relationships, and views

Sync Engine

container

Go

Bidirectional synchronization engine between JSONC model and draw.io diagrams

IDE

external_system

IDE with JSON Schema support for JSONC editing with autocompletion

5.5. Level 2: CLI Package

The CLI is the thinnest layer (no business logic — see Conventions below), but at 41 files across ~15 subcommands it’s grouped into 7 components by concern rather than one component per file, for the same reason `model’s 7 files map to 5 components above: file-level granularity would be noise at this diagram’s zoom level.

CLI Package Components
Figure 6. CLI Package Components (generated from architecture model via draw.io export)

5.5.1. Building Blocks

Element Kind Technology Description

Add

component

Go

Add element/relationship/view/specification/pattern subcommands

Analysis

component

Go

find, show, status, stale, health, graph, and lint subcommands

Core

component

Go

Root command wiring, init, sync, validate, watch, and template resolution

Evolution

component

Go

snapshot (save/list/diff/restore/delete), diff, and changelog subcommands

Export Commands

component

Go

export, export-diagram, export-table, and export-sequence subcommands

Interactive

component

Go

repl, overlay, and adr subcommands

Tooling

component

Go

import, generate-template, layout, schema, and workspace subcommands

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

Sync Engine

container

Go

Bidirectional synchronization engine between JSONC model and draw.io diagrams

Watcher

container

Go / fsnotify

File system monitoring for automatic sync on model or diagram changes

5.6. Level 2: Diagram Package Components

Text-based diagram export components (Mermaid C4, PlantUML) and markdown wrapping.

Diagram Package Components
Figure 7. Diagram Package Components (generated from architecture model via draw.io export)

5.6.1. Building Blocks

Element Kind Technology Description

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

Markdown

component

Go

Markdown document wrapper for multiple diagram pages

Mermaid C4

component

Go

Mermaid C4 diagram generation with C4 level detection

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

5.7. Level 2: Importer Package Components

Import components for Structurizr DSL and LikeC4 format conversion to Bausteinsicht model.

Importer Package Components
Figure 8. Importer Package Components (generated from architecture model via draw.io export)

5.7.1. Building Blocks

Element Kind Technology Description

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

LikeC4

component

Go

LikeC4 DSL parsing and model conversion

Structurizr

component

Go

Structurizr DSL parsing and model conversion

XMI

component

Go

XMI/Enterprise Architect parsing and model conversion. Buffers the whole file in memory and converts Windows-1252 to UTF-8 before parsing (peak RSS ~2x file size); a 200MB read cap is enforced.

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

5.8. Level 2: Exporter Package Components

Export components for converting Bausteinsicht model to external formats (Structurizr DSL).

Exporter Package Components
Figure 9. Exporter Package Components (generated from architecture model via draw.io export)

5.8.1. Building Blocks

Element Kind Technology Description

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

Structurizr

component

Go

Structurizr DSL export with smart variable naming

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

5.9. Level 2: Search Package Components

Element and relationship search with pattern matching and filtering.

Search Package Components
Figure 10. Search Package Components (generated from architecture model via draw.io export)

5.9.1. Building Blocks

Element Kind Technology Description

CLI

container

Go / Cobra

Command-line interface providing validate, sync, export, and watch commands

Model

container

Go

JSONC architecture model management — loading, validation, and mutation

Search

container

Go

Element and relationship search with filtering and pattern matching

5.10. Go Package Layout

The directory structure maps directly to the building blocks above (packages, not every file):

bausteinsicht/
├── cmd/
│   ├── bausteinsicht/      // main CLI — one file per command (init, sync, add, repl, export*, …)
│   └── bausteinsicht-lsp/  // Language Server Protocol binary
├── internal/
│   ├── model/  drawio/  sync/  watcher/                          // core engine
│   ├── constraints/  graph/  health/  stale/  search/            // analysis
│   ├── snapshot/  diff/  changelog/                              // evolution
│   ├── layout/  template/  overlay/                              // layout & styling
│   ├── importer/  exporter/  diagram/  table/  export/  schema/  // interop & export
│   ├── lsp/                                                      // IDE integration
│   └── chaos/  benchmarks/  e2eplan/                              // test-only helpers
├── go.mod
└── go.sum

5.10.1. Conventions

  • cmd/bausteinsicht/ contains only CLI wiring — no business logic; all logic lives in internal/ packages (so the LSP binary can reuse it).

  • internal/ ensures packages cannot be imported by external code.

  • Each package has a clear single responsibility (see the Package Map).

  • Cross-package dependencies flow inward toward the core: cmd → feature packages → sync → model + drawio.

  • The model and drawio packages never depend on each other — sync is the only mediator.

  • chaos and benchmarks are imported only from _test.go files, so production code never depends on them. e2eplan is imported by the standalone scripts/e2e-test-report-gen tool (not a _test.go file, but also not shipped in the bausteinsicht/bausteinsicht-lsp binaries).

6. Runtime View

6.1. Sync Command

The most important runtime scenario. Shows what happens when the user runs bausteinsicht sync.

Sync Command
Figure 11. Sync Command (generated from dynamicViews.sync-command in architecture.jsonc via bausteinsicht export-sequence)

6.1.1. Key Observations

  • The sync engine receives all data as parameters — it performs no I/O itself

  • Forward sync runs before reverse sync in the same cycle

  • The state file is only written after both directions complete successfully

  • If any step fails, no files are written (atomic operation)

  • Forward sync adds metadata (title, source, author, timestamp) and a legend to each view page

6.2. Watch Mode

Shows the continuous sync loop triggered by file changes.

Watch Mode
Figure 12. Watch Mode (generated from dynamicViews.watch-mode in architecture.jsonc via bausteinsicht export-sequence)

6.2.1. Debounce Strategy

File editors often trigger multiple save events in rapid succession (write + metadata update). The watcher debounces events with a 300ms window: after the first change event, it waits 300ms for additional events before triggering a sync.

6.3. Init Command

Init Command
Figure 13. Init Command (generated from dynamicViews.init-command in architecture.jsonc via bausteinsicht export-sequence)

6.4. LLM-Driven Modification

Shows how an LLM agent uses CLI commands to modify the architecture.

LLM-Driven Modification
Figure 14. LLM-Driven Modification (generated from dynamicViews.llm-driven-modification in architecture.jsonc via bausteinsicht export-sequence)

6.4.1. Design Decision: Separate Add and Sync

The add commands only modify the JSON model. They do not trigger a sync automatically. This keeps commands predictable (single responsibility) and allows LLMs to batch multiple model changes before syncing.

6.5. Import from Structurizr / LikeC4 / XMI

Shows how an existing model is brought into Bausteinsicht (bausteinsicht import <file> --from structurizr|likec4|xmi).

Import from Structurizr / LikeC4 / XMI
Figure 15. Import from Structurizr / LikeC4 / XMI (generated from dynamicViews.import-from-external-formats in architecture.jsonc via bausteinsicht export-sequence)

The result is immediately syncable with bausteinsicht sync. The importer never touches draw.io — it only produces the model. The XMI path additionally buffers the whole file in memory and converts Windows-1252 to UTF-8 before parsing (peak RSS ~2× the raw file size, 200 MB read cap enforced) — a materially different cost profile from the other two formats, though the CLI-level flow shown above is the same for all three.

6.6. REPL Save: Patch vs. Full-Save Fallback

The REPL keeps the model in memory and, on save, chooses how to persist so JSONC comments survive when possible. This is the key data-integrity flow.

REPL Save
Figure 16. REPL Save: Patch vs. Full-Save Fallback (generated from dynamicViews.repl-save in architecture.jsonc via bausteinsicht export-sequence)

6.6.1. Key Observations

  • Validation runs before any write — an invalid model is never persisted.

  • Pure additions take the comment-preserving patch path; modifications/deletions conservatively fall back to a full rewrite with a visible warning about comment loss.

  • The same patch primitives back the non-interactive add commands.

6.7. Stale Detection

Shows how bausteinsicht stale flags forgotten elements using git history.

Stale Detection
Figure 17. Stale Detection (generated from dynamicViews.stale-detection in architecture.jsonc via bausteinsicht export-sequence)

When run outside a git repository the git lookups degrade gracefully (no date), and detection falls back to the view/relationship membership checks.

6.8. Error & Recovery: Failed Write During Sync

The contract requires at least one error/recovery scenario. This shows why a failed or interrupted sync never corrupts the working files.

Error and Recovery
Figure 18. Error & Recovery: Failed Write During Sync (generated from dynamicViews.error-recovery in architecture.jsonc via bausteinsicht export-sequence)
Note
dynamicViews/SequenceStep (the model type behind this generated diagram) only supports linear sync/async/return arrows — no alt/opt/group branching or notes, unlike hand-written PlantUML. The two write-outcome branches ("if write failed" / "if write succeeded") and the atomic-write grouping are represented as plain sequential steps with the condition folded into the label text instead of a true visual branch. If this loses too much clarity, this scenario is the best candidate in chapter 6 to stay hand-written rather than generated — see #535.

6.8.1. Key Observations

  • The engine computes everything in memory first; files are written only afterwards, each via a temp-file-plus-rename so a partial write cannot truncate a real file.

  • The state file is written last. If any earlier write fails, the state is left untouched, so the next run re-detects the same change and retries — the operation is effectively idempotent and self-healing.

  • The state file carries a SHA-256 checksum, so external tampering or truncation is detected on load rather than silently trusted.

6.9. Add: Relationship / View / Specification / From-Pattern

The non-element add subcommands — add relationship, add view, add specification (with its own add specification element and add specification relationship children, for extending the specification itself rather than the model), and add-from-pattern — cover relationships between existing elements, views, specification entries, and pattern-based bulk generation. bausteinsicht add-from-pattern doesn’t have its own list subcommand; the sibling add pattern list command (a separate group under add, not under add-from-pattern) lists the patterns available to apply. All are pure model edits, same shape as add element (see LLM-Driven Modification above).

Add Family
Figure 19. Add: Relationship / View / Specification / From-Pattern (generated from dynamicViews.add-family in architecture.jsonc via bausteinsicht export-sequence)

6.10. Snapshot: Save / List / Diff / Restore / Delete

Versioned model captures: snapshot save, snapshot list, snapshot diff, snapshot restore, and snapshot delete. snapshot restore is destructive (overwrites the live model), so it’s the one step here worth flagging as such.

Snapshot Management
Figure 20. Snapshot: Save / List / Diff / Restore / Delete (generated from dynamicViews.snapshot-management in architecture.jsonc via bausteinsicht export-sequence)

6.11. As-Is/To-Be Diff and Changelog Generation

diff compares two model states; changelog walks git history calling diff at each relevant commit to build a human-readable architecture changelog.

Diff and Changelog
Figure 21. As-Is/To-Be Diff and Changelog Generation (generated from dynamicViews.diff-and-changelog in architecture.jsonc via bausteinsicht export-sequence)

6.12. Export: Diagrams, Tables, and Rendered Images

The three export commands — export, export-diagram, and export-table — read the model (and, for export, the synced draw.io document) and render it to an external format — the output-side counterpart to import. None of them write back to the model or draw.io.

Export Family
Figure 22. Export: Diagrams, Tables, and Rendered Images (generated from dynamicViews.export-family in architecture.jsonc via bausteinsicht export-sequence)

6.13. Analysis: Health, Graph, Find, Lint

Read-only architecture-quality checks, all following the same shape as Stale Detection (load model, analyze, report) — shown together since the flow is structurally identical across all four.

Analysis Suite
Figure 23. Analysis: Health, Graph, Find, Lint (generated from dynamicViews.analysis-suite in architecture.jsonc via bausteinsicht export-sequence)

6.14. Validate as a Standalone Gate

validate runs the same check other commands run internally before writing (see REPL Save, LLM-Driven Modification above), but as its own entry point — typically in CI or a pre-commit hook, checked before any file is touched.

Validate Standalone
Figure 24. Validate as a Standalone Gate (generated from dynamicViews.validate-standalone in architecture.jsonc via bausteinsicht export-sequence)

6.15. Tooling: Workspace, Layout, Generate-Template, Schema

Cross-cutting setup/maintenance commands, not part of the daily edit-sync loop: multi-model workspaces (workspace merge, workspace validate, workspace list), auto-layout, template scaffolding, and JSON Schema regeneration (schema generate) for IDE support.

Tooling Commands
Figure 25. Tooling: Workspace, Layout, Generate-Template, Schema (generated from dynamicViews.tooling-commands in architecture.jsonc via bausteinsicht export-sequence)

6.16. Overlay and ADR

Two interactive-group commands outside the REPL itself: metric heatmap overlays on diagrams (overlay apply, overlay remove, overlay list), and ADR (Architecture Decision Record) scaffolding (adr list, adr show).

Overlay and ADR
Figure 26. Overlay and ADR (generated from dynamicViews.interactive-extras in architecture.jsonc via bausteinsicht export-sequence)

7. Deployment View

7.1. Infrastructure Level 1

Bausteinsicht is a single-binary CLI tool that runs on the developer’s local machine. There is no server, no database, and no network communication at runtime.

deployment overview

7.1.1. Motivation

Bausteinsicht intentionally has the simplest possible deployment: one binary, no dependencies. This directly serves the Learnability quality goal — download, run, be productive.

7.1.2. Quality and Performance Features

Feature Description

Startup time

< 10ms (native Go binary, no runtime to load)

Sync time

< 100ms for models with up to 200 elements (in-memory XML/JSON processing)

Binary size

~10-15 MB (single statically linked binary)

Zero dependencies

No runtime, no package manager, no database, no network

7.1.3. Mapping of Building Blocks to Infrastructure

Building Block Deployment

cmd/bausteinsicht

The compiled binary, distributed via GitHub Releases for Linux, macOS, Windows (amd64 + arm64)

internal/*

Compiled into the same binary. No separate deployment.

JSON Schema

Published to GitHub (raw URL) and referenced via $schema in model files. Downloaded once by the IDE.

Template

Bundled as a Go embed resource in the binary for init command. Users can override with a local template.

7.2. Distribution

7.2.1. GitHub Releases

Each tagged version produces compressed archives for all target platforms via GoReleaser. Archives are named bausteinsicht_v2.6.7_{Os}_{Arch}.tar.gz for Linux and macOS, .zip for Windows:

Platform Archive

Linux amd64

bausteinsicht_v2.6.7_linux_amd64.tar.gz

Linux arm64

bausteinsicht_v2.6.7_linux_arm64.tar.gz

Linux arm (v7)

bausteinsicht_v2.6.7_linux_arm.tar.gz

macOS amd64

bausteinsicht_v2.6.7_darwin_amd64.tar.gz

macOS arm64 (Apple Silicon)

bausteinsicht_v2.6.7_darwin_arm64.tar.gz

Windows amd64

bausteinsicht_v2.6.7_windows_amd64.zip

Windows arm64

bausteinsicht_v2.6.7_windows_arm64.zip

The authoritative build matrix is .goreleaser.yml: goos: [linux, darwin, windows] × goarch: [amd64, arm64, arm] (with goarm: 7). GoReleaser produces one archive per combination Go actually supports, skipping the rest (e.g. darwin/arm); the table above lists the primary targets and is not exhaustive. Each archive also ships with an SBOM (SPDX-JSON and CycloneDX-JSON); a checksums.txt covers all artifacts.

7.2.2. Installation

# Pick the archive for your platform from the releases page:
#   https://github.com/docToolchain/Bausteinsicht/releases/latest
# then download, unpack, and install (example: Linux amd64, release v1.2.3)
curl -L https://github.com/docToolchain/Bausteinsicht/releases/download/v1.2.3/bausteinsicht_1.2.3_linux_amd64.tar.gz -o bausteinsicht.tar.gz
tar -xzf bausteinsicht.tar.gz
sudo install -m 0755 bausteinsicht /usr/local/bin/bausteinsicht

# Or via Go install
go install github.com/docToolchain/Bausteinsicht/cmd/bausteinsicht@latest

7.2.3. Embedded Resources

The init command needs a default template and sample model. These are embedded into the binary using Go’s embed package:

//go:embed templates/default.drawio
var defaultTemplate []byte

//go:embed templates/sample-model.jsonc
var sampleModel []byte

This eliminates the need to distribute additional files alongside the binary.

8. Cross-cutting Concepts

8.1. 8.1 Threat Model (STRIDE)

Bausteinsicht is a local CLI tool that reads and writes files on the user’s workstation. The primary trust boundary is the filesystem: the tool processes user-supplied JSONC and draw.io files and writes results back to the same directory.

8.1.1. STRIDE Threat Table

ID STRIDE Category Severity Threat Mitigation

T-1

Tampering

Medium

Malicious JSONC or draw.io file in the workspace overwrites model data via sync

Atomic writes (os.Rename after temp-file write, SEC-002); 0600 file permissions (SEC-004); MaxElementDepth=50 prevents stack overflow (SEC-007)

T-2

Tampering

Low

CLI flags --model/--template/--output used to write outside the project directory

Reject .. traversal in all three flags (SEC-001); SafeViewKey() strips path components from view keys used in export filenames (SEC-015); output-dir boundary check (SEC-016)

T-3

Information Disclosure

Low

.bausteinsicht-sync state file exposes element IDs and file paths to co-located processes

File written at 0600; state contains no secrets, only structural metadata (SHA-256 checksums, element IDs)

T-4

Denial of Service

Low

Oversized JSONC model file causes OOM or slow parse

10 MB file size limit enforced before parsing (SEC-006)

T-5

Denial of Service

Low

Deeply nested element hierarchy causes stack overflow during FlattenElements

MaxElementDepth=50 enforced in internal/model/resolve.go:11 (SEC-007); returns error instead of panicking

T-6

Tampering

Low

sanitizeID passes dot and slash characters into draw.io attribute values (XSS-adjacent)

sanitizeID strips dots and slashes (SEC-013); stripTags fixes attribute-value quoting (SEC-008)

Spoofing and Repudiation are not applicable: the tool operates on local files under the user’s own identity; no authentication or audit log is required.

8.1.2. Risk Acceptance

Remaining accepted risks: * T-3 — sync state leaks structural metadata; acceptable because the file lives in the project directory alongside the model itself (same trust level). * Dockerfile script downloads without checksums (SEC-014) — deferred; upstream projects do not publish checksums.

See Security Review 2026-03-01 for the full SEC catalog.

8.2. 8.2 Security Mitigations

Security controls implemented across the codebase, keyed to threat IDs:

Control Threat Implementation

Atomic file writes

T-1

internal/model/save.go: write to .tmp, then os.Rename (ADR-002)

Path traversal guard

T-2

cmd/bausteinsicht/root.go: validatePaths rejects .. in --model/--template/--output

Safe view key

T-2

internal/export/export.go:SafeViewKey()filepath.Base strips directory components

File permissions

T-1/T-3

All model/sync files written at 0600

File size limit

T-4

internal/model/loader.go: reject JSONC files > 10 MB

Element depth limit

T-5

internal/model/resolve.go:MaxElementDepth=50; FlattenElements returns error on exceeded depth

HTML sanitization

T-6

internal/drawio/label.go:sanitizeID strips ./; stripTags quotes attribute values

Dependency scanning

All

govulncheck in CI (govulncheck job) and Makefile; no CVEs in called code (verified 2026-07-09)

Note
As of 2026-07-09, govulncheck, gitleaks (secret scanning), and go test -race run as blocking CI jobs in .github/workflows/go.yml (govulncheck, gitleaks, test-race), all verified clean against the current codebase (#550). gosec (SAST) and nilaway (nil-pointer analysis) also run in CI but non-blocking (continue-on-error: true) for now: gosec currently reports 35 pre-existing file-permission findings (tracked separately), and nilaway’s memory/time footprint on a GitHub-hosted runner hasn’t been validated as reliably fast/light enough to gate every PR on. `test-race excludes internal/importer/xmi — its ~118MB BigData.xmi test fixture makes race instrumentation’s memory overhead impractical; the other 33 packages are raced normally. See issue #550 for the follow-up to make gosec/nilaway blocking once their respective backlogs are addressed.

8.3. 8.3 Test Strategy

Decided in ADR-007. Three tiers:

Tier Volume Scope Characteristics

Unit tests

~70%

Pure functions: label parsing, ID resolution, XML element creation, validation

No I/O; <100 ms per test; co-located *_test.go

Integration tests

~25%

Package-level: full model load/save cycle, full XML round-trip

t.TempDir() for fixtures; real I/O; no mocks unless unavoidable; run with -race

E2E tests

~5%

Full CLI workflows: sync, export, add element

Execute compiled binary; real JSONC + draw.io files; <5 s per test

8.3.1. Property-Based Testing

pgregory.net/rapid is used for roundtrip and idempotency properties:

  • Label escaping / unescaping roundtrip (internal/drawio/)

  • escapeHTML / trimBrackets invariants

8.3.2. Test Fixtures

Packages use testdata/ directories for representative input files. Golden-file comparisons are done by committing expected output and checking with bytes.Equal in tests. There is no -update-golden flag; update expected files manually and recommit.

8.4. 8.4 Observability

8.4.1. User-Facing Output

Normal output goes to stdout:

  • text (default) — human-readable summaries

  • json (--format json) — machine-parseable; used by LLM agents

Warnings and errors go to stderr.

8.4.2. Verbose Mode

With --verbose, additional sync and export progress is printed to stderr (plain text, no [DEBUG] prefix):

Syncing model: architecture.jsonc
  42 elements, 18 relationships, 3 views
Forward sync: 2 elements created, 1 updated, 0 deleted; 3 connectors created, 0 updated, 0 deleted
Reverse sync: 0 elements created, 1 updated, 0 deleted; 0 relationships created, 0 updated, 0 deleted
Conflicts resolved: 0 (model wins)

Verbose output is suppressed in --format json mode to keep stdout machine-parseable.

8.4.3. No Logging Framework

Bausteinsicht uses fmt.Fprintf(stderr, …​) for verbose output and fmt for normal output. No external logging framework is used — log package is not imported in the CLI layer.

8.5. 8.5 Error Handling

8.5.1. Strategy

Errors propagate upward and are only formatted for the user at the CLI layer (cmd/bausteinsicht/).

Layer Error Handling

internal/*

Return error values with context using fmt.Errorf("loading model: %w", err). Never print to stdout/stderr.

cmd/*

Catch errors, format them for the user (plain text or JSON), and set the exit code via exitWithCode.

8.5.2. Exit Codes

Code Meaning

0

Success

1

Validation error or sync conflict

2

File not found or I/O error

8.5.3. Structured Error Output

With --format json, errors are emitted to stderr as:

{"error": "validation failed: model.webshop.api unknown kind", "code": 1}

The single error string contains the full wrapped error chain. This enables LLM agents to parse errors programmatically.

Note
The details array (multiple per-field errors) is not part of the JSON error format. Validation warnings are only available in text mode via bausteinsicht validate.

8.6. 8.6 JSONC Comment Preservation

Standard Go encoding/json does not support comments. Bausteinsicht strips comments before parsing and writes back selectively:

  1. Remove single-line comments (// …​) and trailing commas before parsing

  2. Parse the cleaned JSON with encoding/json

  3. On pure insertions (new elements, new relationships): model.PatchInsert / cmd/bausteinsicht/sync.go:saveModel patches only the changed lines, preserving existing comments and key ordering (ADR-011)

  4. On deletions or modifications of existing entries: full rewrite via model.Save — comments are lost

Note
The REPL’s save command follows the same patch-first/full-save-fallback strategy.

8.7. 8.7 File Atomicity

When writing files, Bausteinsicht uses a write-to-temp-then-rename pattern:

  1. Write to a temporary file in the same directory (e.g., .model.jsonc.tmp)

  2. os.Rename the temp file to the target path (atomic on most filesystems)

  3. On failure, the original file remains intact

This prevents corrupted files if the process is interrupted during write (mitigates T-1).

8.8. 8.8 Configuration Discovery

Bausteinsicht uses convention over configuration:

  1. Look for *.jsonc in the current directory. Exactly one match is used as the model file; multiple files require --model (the tool never silently picks one, since it mutates synchronized files — SEC-005).

  2. Look for *.drawio in the current directory (the diagram file)

  3. Look for .bausteinsicht-sync in the current directory

  4. Template: template.drawio in the current directory, or fall back to the embedded default

All paths can be overridden via CLI flags (--model, --template).

8.9. 8.9 Version Management

The binary version is injected at build time via ldflags:

go build -ldflags "-X main.version=0.1.0" ./cmd/bausteinsicht

GoReleaser handles this automatically for tagged releases.

9. Architecture Decisions

Architecture decisions are documented as ADRs (Architecture Decision Records) following the Nygard format with a weighted Pugh matrix for option evaluation.

All ADRs are located in src/docs/arc42/ADRs/.

ADR Title Status Summary

ADR-001

Choice of DSL Format

Accepted

JSON with JSON Schema (JSONC) chosen over TypeScript DSL and Custom DSL (Langium). Scored highest on learnability, IDE support, LLM friendliness, and bidirectional sync suitability.

ADR-002

Choice of Implementation Language

Accepted

Go chosen over Python and Kotlin/JVM. Single-binary distribution, LLM-friendly code generation, compile-time type safety, and dedicated mxGraph library support.

ADR-003

Risk Classification

Accepted

Tier 2 (Extended Assurance) — determined by Code Type = 2 (Business Logic). Existing toolchain covers most mitigations. Guides AI-assisted development quality requirements.

ADR-004

Sequence Diagram Export

Superseded by ADR-008

Originally rejected dynamicViews / sequence export for v1. Reversed in 2026-05; see ADR-008.

ADR-005

Auto-Layout Engine for New Diagram Pages

Accepted

Layered/grid/none placement modes for fresh diagram pages. Relationship-aware BFS ordering within scopes; manual positions preserved on incremental sync.

ADR-006

CLI Add Command Strategy

Accepted

add subcommands merge into existing items rather than replacing them, for safe LLM- and script-driven editing.

ADR-007

Testing Strategy

Accepted

Unit / integration / E2E classification, plus property-based tests (pgregory.net/rapid). Tests trace to issues and use cases.

ADR-008

Sequence Diagram Export (Revisited)

Accepted

Reverses ADR-004: implements dynamicViews + export-sequence (PlantUML/Mermaid). Behavioral views kept in one model with structure; sync engine ignores the section.

ADR-009

Drill-Down Navigation

Accepted

Page-based drill-down (one draw.io page per view + cross-page links + back button) over single-page semantic zoom. Uses native draw.io pages; keeps bidirectional sync simple.

10. Quality Requirements

10.1. Quality Requirements Overview

ISO 25010 Characteristic Quality Requirement Top-goal link

Usability / Learnability

New users productive within 30 minutes using only docs and IDE autocompletion

Concretises QG-1 (Learnability)

Usability / Operability

IDE autocompletion, validation, hover docs without tool-specific plugin

Concretises QG-2 (IDE Support)

Compatibility / Interoperability

LLM agents can reliably read, write, and manipulate architecture models

Concretises QG-3 (LLM Friendliness)

Functional Suitability / Correctness

Bidirectional sync never silently loses data

Derived (sync reliability enables QG-1–3)

Portability / Installability

Single binary, no runtime dependencies, install in under 1 minute

Derived (prerequisite for all three top goals)

Maintainability / Modifiability

Element hierarchy freely configurable, not hardcoded to C4 levels

Derived (enables diverse team adoption)

Performance Efficiency

10 MB JSONC model processed in under 5 seconds on commodity hardware

Derived (blocks usability at scale)

Reliability / Fault Tolerance

Corrupt or oversized input never corrupts the model file

Derived (trust prerequisite for QG-1)

Security

Path traversal via CLI flags rejected; model files written at 0600

Derived (operating in shared workspaces)

10.2. Quality Scenarios

The six-part scenario form used below: SourceStimulusArtifactEnvironmentResponseResponse Measure

10.2.1. QS-1: Learnability

Source Developer unfamiliar with Bausteinsicht, first contact with the project

Stimulus

Reads the getting-started documentation and opens their IDE

Artifact

Bausteinsicht CLI + JSON Schema + user manual

Environment

Normal developer workstation; IDE with JSON Schema support (VS Code, IntelliJ, or Neovim)

Response

Developer creates and validates an architecture model using IDE autocompletion

Response Measure

Within 30 minutes, the developer has created a valid model with ≥3 elements, ≥2 relationships, and ≥1 draw.io view — using only documentation and IDE features, no Bausteinsicht-specific help

Concretises QG-1. Driven by: ADR-001 (JSON chosen for universal familiarity and IDE support).

10.2.2. QS-2: IDE Support

Source Architect editing a .jsonc model file

Stimulus

Types a new element definition

Artifact

.jsonc model file with $schema reference

Environment

VS Code, IntelliJ, or Neovim with JSON Schema plugin; no Bausteinsicht plugin installed

Response

Editor shows autocompletion for property names, validates values, and displays hover documentation

Response Measure

0 additional plugins installed beyond JSON Schema association; all three named IDEs provide autocompletion and validation

Concretises QG-2. Driven by: ADR-001 (JSON Schema provides free IDE support via SchemaStore).

10.2.3. QS-3: LLM Friendliness

Source LLM agent (e.g., Claude Code)

Stimulus

Instructed to add a new microservice to an existing architecture model

Artifact

JSONC model file + Bausteinsicht CLI

Environment

Automated agent workflow; no human at the keyboard

Response

Agent reads the model, issues bausteinsicht add element and add relationship commands, then runs bausteinsicht sync

Response Measure

0 human interventions required; model remains valid JSON after agent edits; bausteinsicht validate reports no new errors

Concretises QG-3. Driven by: ADR-001 (JSON is the native output format of LLMs).

10.2.4. QS-4: Sync Reliability

Source Architect (working in draw.io) and developer (working in JSONC) simultaneously

Stimulus

bausteinsicht sync is executed after both sides made changes

Artifact

JSONC model file + draw.io diagram + .bausteinsicht-sync state

Environment

Normal development workflow; no true data conflict (different fields changed)

Response

Description change from draw.io is written to the model; new element from the model appears in the draw.io view; conflicts (same field changed on both sides) produce a warning and model wins

Response Measure

0 silent data losses; every changed field appears in the correct destination; conflicts logged to stderr with element ID and field name

Derived from reliability requirement (trust prerequisite for all top goals).

10.2.5. QS-5: Installability

Source Developer on macOS, Linux, or Windows

Stimulus

Downloads the binary from a GitHub Release and runs bausteinsicht --version

Artifact

Released binary (goreleaser cross-compiled archive)

Environment

Clean workstation; no Go, Python, Node.js, Java, or other runtime installed

Response

Command executes and prints the version string

Response Measure

Under 1 minute from download to first successful command; 0 runtime dependencies required

Driven by: ADR-002 (Go chosen for single-binary distribution).

10.2.6. QS-6: Flexible Hierarchy

Source Architect modeling a system with deep nesting (e.g., domain → subdomain → system → service → component)

Stimulus

Defines elements nested 4–49 levels deep in the JSON model

Artifact

JSONC model file

Environment

Normal model editing; bausteinsicht validate or bausteinsicht sync

Response

Model validates and renders correctly for all depths up to the enforced limit

Response Measure

Nesting depths 1–49 succeed without error; depth 50 returns a clear error message naming the offending element path (enforced by MaxElementDepth=50 in internal/model/resolve.go, introduced as SEC-007 to prevent stack-overflow DoS)

Note
Prior versions of this document stated "no artificial limit on hierarchy depth." This was corrected in the 2026-06-27 audit. A depth of 50 covers all realistic C4 and custom hierarchy depths while preventing denial-of-service (see SEC-007).

Driven by: ADR-001 (flexible element kinds).

10.2.7. QS-7: Performance at Scale

Source Developer with a large monolith model

Stimulus

Runs bausteinsicht sync on a JSONC model with 500+ elements and a 10 MB file

Artifact

JSONC model + draw.io diagram

Environment

Commodity developer laptop (≥4 cores, ≥8 GB RAM); no external network dependency

Response

Sync completes without timeout or OOM

Response Measure

Sync finishes in under 5 seconds wall time; benchmarks in internal/benchmarks/ enforce regression detection in CI

Derived from performance efficiency requirement.

10.2.8. QS-8: Reliability Under Bad Input

Source Attacker or misconfigured tool writing a corrupt/oversized JSONC file to the model path

Stimulus

bausteinsicht sync is invoked with a 50 MB malformed JSONC file

Artifact

JSONC model file

Environment

Developer workstation; tool runs with normal user permissions

Response

Tool rejects the file with an error; existing draw.io diagram and sync state are not modified

Response Measure

0 model mutations on parse failure; error returned with code 2; existing files intact (atomic write pattern ensures no partial overwrite)

Derived from reliability and security requirements (T-4 DoS mitigation, SEC-006).

10.2.9. QS-9: Security — Path Containment

Source Malicious JSONC model or untrusted script passing crafted CLI arguments

Stimulus

CLI invoked with --model ../../etc/passwd or --output /tmp/../../root/

Artifact

CLI argument parser (cmd/bausteinsicht/root.go)

Environment

Any OS; normal user privileges

Response

Tool rejects the path with an error before any file I/O

Response Measure

All paths containing .. are rejected with exit code 2; no reads or writes occur outside the project directory (verified by SEC-001, SEC-016 fixes)

Derived from security requirement (T-2 path traversal).

11. Risks and Technical Debts

This is the project’s living risk register. Its risk IDs (R-n) and debt IDs (D-n) are local to this chapter. The ATAM Architecture Review (2026-03-06) was the original input and remains the point-in-time analysis with its own separate numbering (sensitivity/tradeoff points); do not assume R-5 here equals R-5 there.

11.1. Risks

Priority is derived from likelihood × impact. The table is ordered by priority, resolved items last.

ID Risk Likelihood Impact Priority Mitigation / Status

R-3

draw.io XML format changes — the format is not formally versioned; a breaking change could break the sync engine.

Medium

High

High

Custom bausteinsicht_id attributes are unlikely to conflict; templates carry bausteinsicht_template_version. The draw.io version is pinned in the devcontainer. Open.

R-6

DSL import parsing errors — Structurizr DSL / LikeC4 parsers may fail on valid-but-unexpected syntax, losing data on import.

Medium

High

High

Comprehensive error messages + validation warnings; add roundtrip tests (import → export → import). Open. Burdens internal/importer.

R-5

LSP server crashes or hangs — editor integration depends on its availability.

Medium

Medium

Medium

Health checks, restart logic, timeout handling. Open. Burdens internal/lsp.

R-9

Headless draw.io dependency — PNG/SVG export drives the draw.io Electron app via xvfb + dbus; a fragile setup that fails silently in unusual environments.

Medium

Medium

Medium

Text exports (export-diagram/-sequence/-table) need no draw.io; the devcontainer pins the setup. Open. Burdens internal/export.

R-10

Auto-layout quality — the engine is a layered heuristic, not crossing-minimization; dense diagrams still need manual cleanup.

Medium

Low

Low

none layout mode + draw.io editing as escape hatch; see ADR-005. Open. Burdens internal/layout.

R-4

Large-model sync performance — O(n·m) element/view matching on every run.

Low

Medium

Low

Go keeps this acceptable below ~1000 elements; profile with a 500-element model. Open (v2).

R-7

Large-model export performance — exporting 1000+ elements to text/DSL could be slow.

Low

Medium

Low

Streaming export for large models; profile at 500 elements. Open (v2).

R-8

Search completeness — pattern matching might miss results due to escaping or scope filtering.

Low

Low

Low

Property-based tests for search patterns; edge cases (special chars, deep nesting). Open. Burdens internal/search.

R-11

Supply chain (SEC-014) — the Dockerfile downloads install scripts without checksum verification.

Low

Medium

Low

Deferred; see the security review. Affects the dev/CI image only, not the released binary.

R-1

Path traversal via --model / --template / --output — an agent with untrusted input could read/write outside the working directory.

Resolved

validatePathContainment rejects ../escaping paths (exit 2), SEC-001/SEC-016; documented in the trust model.

R-2

Sync-state file corruption — a corrupt .bausteinsicht-sync could make the next sync treat everything as new.

Resolved

The state file carries a SHA-256 checksum verified on load (internal/sync/state.go); it is also committed to git (recoverable).

11.2. Technical Debts

Each item names the building block it burdens (see Chapter 5).

  • D-1 — Auto-layout is heuristic (internal/layout, internal/sync): layered/grid placement, not edge-crossing minimization. Adequate for typical C4 diagrams; a force-directed engine remains a future option (ADR-005). (Replaces the former "no auto-layout" debt — auto-layout now ships.)

  • D-2 — REPL full-save loses JSONC comments (cmd/bausteinsicht repl, internal/model patch): pure additions are patched comment-preserving, but any modification/deletion falls back to a full rewrite that drops comments (with a visible warning). Tracked in #410.

  • D-3 — LSP editor support (internal/lsp): the server works but only the VS Code integration is complete; extend to Neovim/Sublime/Emacs.

  • D-4 — Import/export roundtrip is lossy (internal/importer, internal/exporter): Structurizr/LikeC4 import and Structurizr export may drop custom metadata on a full cycle; document lossy fields, plan full roundtrip for v2.

  • D-5 — Coverage gate friction (CI): the SonarCloud new-code-coverage gate (80%) blocks refactors touching untested legacy code while the baseline is ~70%; see #449.

11.3. Non-Risks

The following were evaluated and confirmed not to be threats (see ATAM Non-Risks):

  • XXE / XML-bomb — the draw.io XML parser does not expand external entities.

  • JSON deserialization — Go’s encoding/json is memory-safe.

  • Command injection from input — the tool does invoke external binaries (internal/export → draw.io, internal/stale & internal/changeloggit, internal/lsp re-exec), but they are resolved from PATH and their names/arguments are never derived from model or template content, so untrusted input cannot inject a command. Harden PATH in restricted environments.

  • Supply chain — the product binary uses no npm and only 4 direct Go modules (beevik/etree, fsnotify, cobra, pgregory.net/rapid), with module verification; the optional VS Code extension is a separate TypeScript/npm artifact, not part of the CLI.

  • Regression safety — 863 test functions (9 skipped), property-based tests (pgregory.net/rapid), and pre-commit hooks guard the build.

12. Glossary

Contents

The most important domain and technical terms that your stakeholders use when discussing the system.

You can also see the glossary as source for translations if you work in multi-language teams.

Motivation

You should clearly define your terms, so that all stakeholders

  • have an identical understanding of these terms

  • do not use synonyms and homonyms

Form

A table with columns <Term> and <Definition>.

Potentially more columns in case you need translations.

Further Information

See Glossary in the arc42 documentation.

The terms below form Bausteinsicht’s ubiquitous language — the same words are used in this documentation, the specification, and the source code.

12.1. Model concepts

Term Definition

Element

A node in the architecture model — a system, container, component, actor, datastore, and so on. Elements are nested arbitrarily deep and keyed by a dot-separated path that doubles as their unique ID (e.g. onlineshop.api.catalog).

Element kind

The type of an element (actor, system, container, component, …). Kinds are not hardcoded; each model defines its own set in the specification. A kind may be marked as a container (allowed to have children).

Relationship

A directed connection between two elements, with a from, a to, a label, and a kind (e.g. uses). Stored on the element and rendered as a connector.

View

A named filter over the model that becomes one draw.io page. A view lists what to include/exclude (wildcards allowed) and optionally a scope and layout. The same element can appear in many views; it exists once in the model.

Scope

The element a view drills into. A scoped view shows that element’s children inside its boundary and powers page-based drill-down navigation.

Dynamic view

A behavioral view: an ordered list of interaction steps between elements, rendered by export-sequence as a PlantUML/Mermaid sequence diagram. See ADR-008.

Specification

The model section that defines the vocabulary: which element kinds and relationship kinds exist, plus tags, patterns, and decision records.

Lifecycle status

An optional element field tracking its stage: proposed, design, implementation, deployed, deprecated, archived. Queryable via status.

Pattern

A reusable element/relationship template that add from-pattern instantiates into the model.

12.2. Synchronization

Term Definition

Forward sync

Applying model changes to the draw.io diagram (model → draw.io).

Reverse sync

Applying draw.io edits (titles, descriptions, technology, new shapes/connectors) back to the model (draw.io → model).

Model-wins

The conflict-resolution policy: when the same element changed on both sides since the last sync, the model value is kept and a warning is shown — never a silent overwrite.

Sync state

The checksummed JSON snapshot of the last synchronized state, stored in .bausteinsicht-sync, so the next sync can tell what changed on each side.

bausteinsicht_id

The attribute carried by every synced draw.io cell that anchors it to its model element — the link between the two file formats.

Endpoint lifting

When a relationship’s endpoint is not directly visible in a view, the connector is attached to the nearest visible ancestor element instead.

Boundary

A container shape in draw.io that visually encloses a scoped element’s children; it auto-expands to fit them.

Drill-down navigation

Page-based navigation between abstraction levels: one draw.io page per view, with sync-generated cross-page links and a back button. See ADR-009.

12.3. Tooling & styling

Term Definition

Template

A draw.io file whose shapes carry a bausteinsicht_template attribute naming the element kind they style. Sync clones the matching shape for each new element. Templates are versioned (bausteinsicht_template_version).

Overlay

A metric heatmap applied on top of a diagram (e.g. coloring elements by a metric), added/removed by the overlay command without altering the underlying model.

Badge

A small visual marker attached to an element in the diagram (e.g. a decision badge).

Snapshot

A versioned capture of the whole architecture model, stored under .bausteinsicht-snapshots/, semantically diffable via snapshot diff.

Stale element

An element flagged by the stale command as possibly forgotten — shown in no view, touched by no relationship, or unchanged for longer than a threshold (derived from git history).

Workspace

A multi-model grouping that lets several Bausteinsicht models be validated and related together.

REPL

The interactive shell (bausteinsicht repl) for guided, validated model editing; pure additions are patched into the JSONC preserving comments.