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. 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 two test-only helper packages). The complete map is in the Package Map below; the core engine is decomposed further in the Level 2 sections.

5.1.2. Building Blocks (core)

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

Export

container

Go

Diagram export to PNG and SVG formats via draw.io CLI

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

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 three (model, drawio, sync) 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 and LikeC4 (import)

internal/importer/ (structurizr/, likec4/)

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) and internal/benchmarks 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

Diagram export to PNG and SVG 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. 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/                                       // test-only helpers
├── go.mod
└── go.sum

5.5.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.

6. Runtime View

6.1. Sync Command

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

runtime sync

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.

runtime watch

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

runtime init

6.4. LLM-Driven Modification

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

runtime llm

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

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

runtime import

The result is immediately syncable with bausteinsicht sync. The importer never touches draw.io — it only produces the model.

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.

runtime repl save

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.

runtime stale

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.

runtime recovery

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.

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. Error Handling

8.1.1. Strategy

Bausteinsicht uses Go’s explicit error handling pattern consistently. Errors propagate upward and are only formatted for the user at the CLI layer.

Layer Error Handling

internal/*

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

cmd/*

Catch errors, format them for the user (plain text or JSON depending on --format), and set the exit code.

8.1.2. Exit Codes

Code Meaning

0

Success

1

Validation error or sync conflict

2

File not found or I/O error

8.1.3. Structured Error Output

With --format json, errors are returned as:

{
  "error": "validation failed",
  "details": [
    { "path": "model.webshop.api", "message": "unknown kind: container2" }
  ]
}

This enables LLM agents to parse and react to errors programmatically.

8.2. Testing Strategy

8.2.1. Test Levels

Level Scope Approach

Unit tests

Individual functions (label parsing, ID resolution, XML element creation)

Table-driven tests using go test. Test files co-located with source (*_test.go).

Integration tests

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

Use test fixtures in testdata/ directories. Verify file output matches expected golden files.

End-to-end tests

Full CLI commands

Run the compiled binary with test input files. Verify output files and exit codes. Use testscript or shell-based test runner.

8.2.2. Test Fixtures

Each package has a testdata/ directory with representative input files:

internal/model/testdata/
├── valid-model.jsonc
├── invalid-missing-kind.jsonc
└── nested-elements.jsonc

internal/drawio/testdata/
├── simple-diagram.drawio
├── multi-page.drawio
└── with-containers.drawio

internal/sync/testdata/
├── scenario-new-element/
│   ├── before-model.jsonc
│   ├── before-drawio.drawio
│   ├── sync-state.json
│   ├── expected-model.jsonc
│   └── expected-drawio.drawio
└── scenario-conflict/
    └── ...

8.2.3. Golden File Testing

For sync scenarios, the test runs a sync cycle and compares the output against expected files. If the output changes intentionally, update the golden files with a flag:

go test ./internal/sync/ -update-golden

8.3. Logging and Output

8.3.1. User-Facing Output

Normal output goes to stdout in one of two formats:

  • text (default): Human-readable summaries

  • json (--format json): Machine-parseable output for LLM integration

Warnings and errors go to stderr.

8.3.2. Verbose Mode

With --verbose, additional details are printed to stderr:

[DEBUG] Loading model from architecture.jsonc
[DEBUG] Loading draw.io from architecture.drawio
[DEBUG] Loading sync state from .bausteinsicht-sync
[DEBUG] Detected 2 model changes, 1 drawio change, 0 conflicts
[DEBUG] Forward: creating element webshop.cache
[DEBUG] Forward: updating label on webshop.api
[DEBUG] Reverse: updating title of customer
[INFO]  Sync complete: 2 forward changes, 1 reverse change

8.3.3. No Logging Framework

Bausteinsicht uses Go’s standard log package for verbose output and fmt for normal output. No external logging framework is needed for a CLI tool.

8.4. Version Management

The binary version is set at build time via ldflags:

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

The --version flag prints:

bausteinsicht version 0.1.0

GoReleaser handles this automatically for tagged releases.

8.5. JSONC Handling

Standard Go encoding/json does not support comments. Bausteinsicht strips comments before parsing:

  1. Remove single-line comments (// …​)

  2. Remove trailing commas before } and ]

  3. Parse the cleaned JSON with encoding/json

  4. When writing back, format with json.MarshalIndent (comments are lost on write)

Note
Preserving user comments across sync cycles is a future enhancement. For v1, comments in the model file are stripped on write.

8.6. 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.

8.7. Configuration Discovery

Bausteinsicht uses convention over configuration:

  1. Look for *.jsonc in the current directory. Exactly one match is used as the model file; if several exist, the command aborts and requires --model (it never silently picks one, since the tool mutates and synchronizes files).

  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).

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

Category (ISO 25010) Quality Requirement

Usability / Learnability

The tool and its DSL must be easy to learn for developers and architects. No prior knowledge of C4, Structurizr, or LikeC4 should be required.

Usability / Operability (IDE Support)

Editing the architecture model must be supported by IDE features (autocompletion, validation, hover docs) without installing tool-specific plugins.

Compatibility / Interoperability (LLM Friendliness)

The model format and CLI must be designed so that LLM agents can reliably read, write, and manipulate architecture models.

Functional Suitability / Correctness (Sync Reliability)

Bidirectional synchronization must never silently lose data. New elements, changed descriptions, and relationships must be correctly propagated in both directions.

Portability / Installability

The tool must be distributable as a single binary without runtime dependencies. Installation must not require package managers, virtual environments, or runtimes.

Maintainability / Modifiability (Flexible Hierarchy)

The element hierarchy must not be hardcoded to a fixed number of levels. Users must be able to define their own element kinds and nesting depth.

10.2. Quality Scenarios

10.2.1. QS-1: Learnability

Context

A developer unfamiliar with Bausteinsicht wants to create an architecture model for a new project.

Stimulus

The developer reads the getting-started documentation and opens their IDE.

Acceptance Criteria

Within 30 minutes, the developer has created a valid architecture model with at least 3 elements, 2 relationships, and 1 draw.io view — using only the documentation and IDE autocompletion.

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

10.2.2. QS-2: IDE Support

Context

An architect edits a .jsonc architecture model file in VS Code, IntelliJ, or Neovim.

Stimulus

The architect types a new element definition.

Acceptance Criteria

The editor provides autocompletion for property names, validates values against allowed types, and shows hover documentation for each field — without any Bausteinsicht-specific plugin installed. Only the JSON Schema association is required.

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

10.2.3. QS-3: LLM Friendliness

Context

An LLM agent (e.g., Claude) is asked to add a new microservice to an existing architecture model.

Stimulus

The agent reads the current model file and uses CLI commands.

Acceptance Criteria

The agent successfully adds the element with title, description, technology, and relationships, then runs bausteinsicht sync — all without human intervention and without producing invalid JSON.

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

10.2.4. QS-4: Sync Reliability

Context

An architect modifies an element’s description in draw.io and adds a new element in the JSON model simultaneously.

Stimulus

bausteinsicht sync is executed.

Acceptance Criteria

The description change from draw.io is applied to the model. The new element from the model appears in the draw.io view. No data is silently lost. If a true conflict exists (same field changed in both), a warning is displayed.

10.2.5. QS-5: Installability

Context

A developer on macOS, Linux, or Windows wants to use Bausteinsicht.

Stimulus

The developer downloads the binary and runs bausteinsicht --version.

Acceptance Criteria

The tool runs immediately without installing Go, Python, Node.js, Java, or any other runtime. Total time from download to first successful command is under 1 minute.

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

10.2.6. QS-6: Flexible Hierarchy

Context

An architect models a system where a component contains sub-components, which in turn contain further sub-components (3+ nesting levels beyond the C4 standard).

Stimulus

The architect defines deeply nested elements in the JSON model.

Acceptance Criteria

The model validates successfully. draw.io views correctly render all nesting levels. There is no artificial limit on hierarchy depth.

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.