Data Models

Overview

Bausteinsicht works with three data formats that must be kept in sync:

Format Purpose Location

JSON Model (JSONC)

Single source of truth for the architecture

*.jsonc files in project directory

JSON Schema

Validation and IDE support for the model

Published schema file

draw.io XML (mxGraph)

Visual representation of architecture views

*.drawio files in project directory (uncompressed XML)

JSON Model Structure

The model consists of four top-level sections:

{
  "$schema": "https://raw.githubusercontent.com/docToolchain/Bausteinsicht/main/schema/bausteinsicht.schema.json",

  // Define available element and relationship kinds
  "specification": {
    "elements": {
      "actor": {
        "notation": "Actor",
        "description": "A person or external system that interacts with the system"
      },
      "system": {
        "notation": "Software System",
        "description": "A top-level software system",
        "container": true
      },
      "container": {
        "notation": "Container",
        "description": "A deployable unit within a system",
        "container": true
      },
      "component": {
        "notation": "Component",
        "description": "A logical grouping within a container",
        "container": true
      }
    },
    "relationships": {
      "uses": { "notation": "uses" },
      "async": { "notation": "async", "dashed": true }
    }
  },

  // The actual architecture elements and their hierarchy
  "model": {
    "customer": {
      "kind": "actor",
      "title": "Customer",
      "description": "End user of the webshop"
    },
    "webshop": {
      "kind": "system",
      "title": "Webshop",
      "description": "Online shopping platform",
      "children": {
        "api": {
          "kind": "container",
          "title": "REST API",
          "technology": "Spring Boot",
          "description": "Handles all HTTP requests",
          "children": {
            "auth": {
              "kind": "component",
              "title": "Auth Module",
              "technology": "Spring Security"
            }
          }
        },
        "db": {
          "kind": "container",
          "title": "Database",
          "technology": "PostgreSQL",
          "description": "Stores all persistent data"
        }
      }
    }
  },

  // Connections between elements
  "relationships": [
    {
      "from": "customer",
      "to": "webshop.api",
      "label": "uses",
      "kind": "uses",
      "description": "Sends HTTP requests"
    },
    {
      "from": "webshop.api",
      "to": "webshop.db",
      "label": "reads/writes",
      "kind": "uses"
    }
  ],

  // View definitions
  "views": {
    "context": {
      "title": "System Context",
      "include": ["customer", "webshop"],
      "description": "High-level system overview"
    },
    "containers": {
      "title": "Container View",
      "scope": "webshop",
      "include": ["customer", "webshop.*"],
      "description": "Webshop internals"
    }
  }
}

Element Properties

Property Type Required Description

kind

string

yes

Element kind as defined in specification

title

string

yes

Display name shown in diagrams

description

string

no

Detailed description (shown in tooltips)

technology

string

no

Technology/framework used

tags

string[]

no

Tags for filtering and styling

children

object

no

Nested child elements (only if kind has container: true)

metadata

object

no

Arbitrary key-value metadata

The key of each element in the model object (e.g., "customer", "api") serves as its unique ID. Nested elements are referenced using dot notation: "webshop.api.auth".

Relationship Properties

Property Type Required Description

from

string

yes

Source element ID (dot notation for nested)

to

string

yes

Target element ID (dot notation for nested)

label

string

no

Display label on the connector

kind

string

no

Relationship kind as defined in specification

description

string

no

Detailed description

View Properties

Property Type Required Description

title

string

yes

View title displayed as tab/page name

scope

string

no

Parent element whose children are shown

include

string[]

no

Element IDs to include (supports wildcard patterns, see [Wildcard Patterns])

exclude

string[]

no

Element IDs to exclude from the view (supports wildcard patterns, see [Wildcard Patterns])

description

string

no

View description

layout

string

no

Auto-layout mode for new pages: "layered" (default), "grid", or "none". Layered groups elements by kind tier; grid places alphabetically in a grid; none uses a horizontal row.

[[Wildcard Patterns]] ==== Wildcard Patterns

The include and exclude arrays support the following patterns for matching elements:

Pattern Description

"id"

Exact match — includes only the element with the given ID

"*"

All top-level elements only (IDs without dots)

"**"

All elements at all levels (entire model)

"prefix.*"

Direct children of prefix (one level deep, e.g., "webshop.*" matches webshop.api and webshop.db but not webshop.api.auth)

"prefix.**"

All descendants of prefix (recursive, e.g., "webshop.**" matches webshop.api, webshop.db, and webshop.api.auth)

JSONC Comment Support

Model files use the JSONC (JSON with Comments) format. Both comment styles are supported:

  • // — single-line comments

  • /\* …​ */ — block comments (can span multiple lines)

draw.io XML Structure

Bausteinsicht generates and reads uncompressed draw.io XML (compressed="false") for Git-friendliness.

File Structure

<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="bausteinsicht" compressed="false">

  <!-- One <diagram> per view -->
  <diagram id="view-context" name="System Context">
    <mxGraphModel dx="1422" dy="794" grid="1" gridSize="10"
                  page="1" pageWidth="1169" pageHeight="827"
                  background="#ffffff">
      <root>
        <!-- Mandatory base cells (always present) -->
        <mxCell id="0" />
        <mxCell id="1" parent="0" />

        <!-- All diagram content goes here -->
      </root>
    </mxGraphModel>
  </diagram>

</mxfile>

Mandatory Base Cells

Every page requires exactly two base cells:

  • id="0" — root cell, no parent

  • id="1" parent="0" — default drawing layer, parent for all top-level content

These are never modified by Bausteinsicht.

Elements as <object> with Custom Properties

Every Bausteinsicht element is wrapped in an <object> element to carry custom metadata. The nested <mxCell> has no id — the <object> owns the ID. The parent <mxCell> uses container=1 so that child text sub-cells are grouped inside it.

<object label=""
        id="containers--webshop.api"
        bausteinsicht_id="webshop.api"
        bausteinsicht_kind="container"
        technology="Spring Boot"
        tooltip="Handles all HTTP requests">
  <mxCell style="rounded=1;whiteSpace=wrap;html=1;
                 fillColor=#438DD5;strokeColor=#3C7FC0;fontSize=13;container=1;"
          vertex="1"
          parent="1">
    <mxGeometry x="200" y="150" width="240" height="150" as="geometry" />
  </mxCell>
</object>

<!-- Text sub-cells: separate mxCell children for title, technology, description -->
<mxCell id="containers--webshop.api-title" value="REST API"
        style="text;html=1;fontSize=14;fontStyle=1;fontColor=#ffffff;fillColor=none;strokeColor=none;align=center;verticalAlign=middle;movable=0;resizable=0;deletable=0;editable=0;"
        vertex="1" parent="containers--webshop.api">
  <mxGeometry x="0" y="20" width="240" height="30" as="geometry" />
</mxCell>
<mxCell id="containers--webshop.api-tech" value="[Spring Boot]"
        style="text;html=1;fontSize=11;fontStyle=2;fontColor=#CCCCCC;fillColor=none;strokeColor=none;align=center;verticalAlign=middle;movable=0;resizable=0;deletable=0;editable=0;"
        vertex="1" parent="containers--webshop.api">
  <mxGeometry x="0" y="55" width="240" height="20" as="geometry" />
</mxCell>
<mxCell id="containers--webshop.api-desc" value="Handles all HTTP requests"
        style="text;html=1;fontSize=10;fontColor=#BBBBBB;fillColor=none;strokeColor=none;align=center;verticalAlign=middle;movable=0;resizable=0;deletable=0;editable=0;"
        vertex="1" parent="containers--webshop.api">
  <mxGeometry x="0" y="80" width="240" height="40" as="geometry" />
</mxCell>

Custom properties on <object>:

Property Purpose

label

Empty string ("") for elements using sub-cells. Legacy elements may still have an HTML label (backward compatible).

id

Cell ID — page-scoped for file-wide uniqueness: <viewID>--<elementID> (e.g., context—​customer). When an element appears on multiple view pages, each instance has a distinct cell ID.

bausteinsicht_id

The canonical element ID from the model (e.g., customer). Used for reverse sync identification. Unlike id, this value is the same across all pages where the element appears.

bausteinsicht_kind

Element kind (actor, system, container, component)

technology

Technology string from the model

tooltip

Element description — shown on hover in draw.io

link

Drill-down navigation link (see Navigation section)

Text Sub-Cells (Grouped Labels)

Each element’s display text is decomposed into independent child <mxCell> elements, giving full control over font size, color, weight, and vertical positioning. The parent element has label="" and container=1.

Three child cell types exist, identified by their ID suffix:

Sub-Cell ID Suffix Style

Title

-title

Bold, larger font (14px), element’s font color

Technology

-tech

Italic, smaller font (11px), [bracketed], lighter color

Description

-desc

Smallest font (10px), lighter color

Child cells use movable=0;resizable=0;deletable=0;editable=0; to prevent accidental manipulation in draw.io.

Technology and description sub-cells are only created when the corresponding field is non-empty. Actor elements have only a title sub-cell.

HTML Labels (Backward Compatible)

Legacy draw.io files may still use HTML-formatted label attributes instead of sub-cells. Bausteinsicht reads both formats: it checks for child text sub-cells first, and falls back to parsing the HTML label if none are found.

The legacy label format has up to three lines:

  1. Title — bold (<b>Title</b>)

  2. Technology — grey, wrapped in square brackets, italic

  3. Description — lighter grey, smaller font

Entity escaping rules for HTML labels:

Character Escaped

<

<

>

>

"

"

&

&

Containers (Nested Elements)

Systems and containers that hold children use the swimlane style. Child elements set parent to the container’s ID. Child coordinates are relative to the container’s top-left corner (below the header).

<!-- Container (system boundary) -->
<object label="Webshop" id="webshop"
        bausteinsicht_id="webshop"
        bausteinsicht_kind="system">
  <mxCell style="swimlane;startSize=30;fillColor=#f5f5f5;
                 strokeColor=#666666;fontColor=#333333;
                 whiteSpace=wrap;html=1;rounded=1;container=1;"
          vertex="1" parent="1">
    <mxGeometry x="100" y="100" width="500" height="300" as="geometry" />
  </mxCell>
</object>

<!-- Child element — parent references the container -->
<object label=""
        id="containers--webshop.api"
        bausteinsicht_id="webshop.api"
        bausteinsicht_kind="container"
        technology="Spring Boot">
  <mxCell style="rounded=1;whiteSpace=wrap;html=1;
                 fillColor=#438DD5;strokeColor=#3C7FC0;container=1;"
          vertex="1"
          parent="webshop">
    <mxGeometry x="30" y="60" width="240" height="150" as="geometry" />
  </mxCell>
</object>
<!-- Sub-cells for the child element (parent = child's cell ID) -->
<mxCell id="containers--webshop.api-title" value="REST API"
        style="text;html=1;fontSize=14;fontStyle=1;..." vertex="1"
        parent="containers--webshop.api">
  <mxGeometry x="0" y="20" width="240" height="30" as="geometry" />
</mxCell>

Connectors (Relationships)

Connectors use edge="1" and reference source/target by their page-scoped cell IDs. Connectors always use parent="1" (the layer), even when connecting shapes inside containers.

<mxCell id="rel-containers--customer-containers--webshop.api-0"
        value="uses"
        style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;
               endArrow=block;endFill=1;strokeColor=#666666;"
        edge="1"
        source="containers--customer"
        target="containers--webshop.api"
        parent="1">
  <mxGeometry relative="1" as="geometry" />
</mxCell>

Connection point strategy:

By omitting exitX/exitY/entryX/entryY style properties, draw.io auto-routes connectors from the nearest perimeter point. This ensures connectors look correct when elements are moved by the user.

Connector ID convention: rel-<scopedSource>-<scopedTarget>-<index> where scoped IDs use the <viewID>--<elementID> format and <index> is a zero-based integer for disambiguation when multiple relationships exist between the same pair (e.g., rel-containers—​customer-containers—​webshop.api-0).

Cross-Page Navigation (Drill-Down)

Elements link to detail views using the link attribute on <object>:

<!-- System element with link to container view -->
<object label="Webshop" id="webshop"
        bausteinsicht_id="webshop"
        bausteinsicht_kind="system"
        link="data:page/id,view-containers">
  <mxCell style="..." vertex="1" parent="1">
    <mxGeometry ... />
  </mxCell>
</object>

Link format: data:page/id,<diagram-id> where <diagram-id> matches the id attribute of the target <diagram> element.

Back-navigation buttons are generated in detail views:

<object label="&amp;larr; System Context" id="nav-back-context"
        link="data:page/id,view-context">
  <mxCell style="rounded=1;fillColor=#f8cecc;strokeColor=#b85450;html=1;fontSize=10;"
          vertex="1" parent="1">
    <mxGeometry x="20" y="20" width="140" height="30" as="geometry" />
  </mxCell>
</object>

Multi-Page Structure

Each view is a separate <diagram> element. The id attribute uses the format view-<viewKey> (e.g., view-context for a view with key "context"). The name attribute is the view title displayed as the tab label.

<mxfile host="bausteinsicht" compressed="false">
  <diagram id="view-context" name="System Context">
    <mxGraphModel ...>...</mxGraphModel>
  </diagram>
  <diagram id="view-containers" name="Container View">
    <mxGraphModel ...>...</mxGraphModel>
  </diagram>
</mxfile>

Base cells (id="0" and id="1") exist on every page with the same IDs — this is standard draw.io convention. Element cell IDs are page-scoped using <viewID>--<elementID> to ensure file-wide uniqueness (e.g., context—​customer and containers—​customer for the same element on different pages). The bausteinsicht_id attribute always holds the canonical element ID.

Go Struct Mappings

// Top-level model file
type BausteinsichtModel struct {
    Schema        string                  `json:"$schema,omitempty"`
    Specification Specification           `json:"specification"`
    Model         map[string]Element      `json:"model"`
    Relationships []Relationship          `json:"relationships"`
    Views         map[string]View         `json:"views"`
}

// Specification defines available element and relationship kinds
type Specification struct {
    Elements      map[string]ElementKind      `json:"elements"`
    Relationships map[string]RelationshipKind `json:"relationships,omitempty"`
}

type ElementKind struct {
    Notation    string `json:"notation"`
    Description string `json:"description,omitempty"`
    Container   bool   `json:"container,omitempty"`
}

type RelationshipKind struct {
    Notation string `json:"notation"`
    Dashed   bool   `json:"dashed,omitempty"`
}

// Element represents an architecture building block
type Element struct {
    Kind        string              `json:"kind"`
    Title       string              `json:"title"`
    Description string              `json:"description,omitempty"`
    Technology  string              `json:"technology,omitempty"`
    Tags        []string            `json:"tags,omitempty"`
    Children    map[string]Element  `json:"children,omitempty"`
    Metadata    map[string]string   `json:"metadata,omitempty"`
}

// Relationship connects two elements
type Relationship struct {
    From        string `json:"from"`
    To          string `json:"to"`
    Label       string `json:"label,omitempty"`
    Kind        string `json:"kind,omitempty"`
    Description string `json:"description,omitempty"`
}

// View defines which elements appear in a diagram
type View struct {
    Title       string   `json:"title"`
    Scope       string   `json:"scope,omitempty"`
    Include     []string `json:"include,omitempty"`
    Exclude     []string `json:"exclude,omitempty"`
    Description string   `json:"description,omitempty"`
}