This post continues from the second part. That introduced bausteinsicht init, sync, and watch. Here the focus is on the heart of it: the JSONC data model with all fields and extension points.

The Basic Structure

An architecture.jsonc file has four required fields and several optional sections:

{
  "$schema": "./node_modules/.bausteinsicht/bausteinsicht.schema.json",
  "config": { ... },
  "specification": { ... },
  "model": { ... },
  "relationships": [ ... ],
  "views": { ... },

  "asIs":         { ... },
  "toBe":         { ... },
  "dynamicViews": [ ... ],
  "constraints":  [ ... ]
}

config

Global settings for diagram generation:

"config": {
  "author":   "Paul Fleischmann",
  "repo":     "https://github.com/my-org/my-repo",
  "metadata": true,
  "legend":   true
}

specification

The specification defines the language of the model — which element types and relationship kinds exist. It is the only section that needs to be set up once and then rarely changed.

specification.elements

"specification": {
  "elements": {
    "actor": {
      "notation":    "Actor",
      "description": "A user or external system",
      "container":   false
    },
    "system": {
      "notation":  "Software System",
      "container": true
    },
    "container": {
      "notation":  "Container",
      "container": true
    },
    "component": {
      "notation":  "Component",
      "container": true
    }
  }
}

The container flag controls whether an element may have children in the hierarchy. If the flag is missing (or is false), bausteinsicht validate rejects any model element of that type that has children.

specification.relationships

"specification": {
  "relationships": {
    "uses": {
      "notation": "uses",
      "dashed":   false
    },
    "reads": {
      "notation": "reads",
      "dashed":   true
    }
  }
}

specification.tags

Tags are defined under specification.tags and can optionally carry draw.io styling:

"specification": {
  "tags": [
    {
      "id":          "external",
      "description": "External system outside our control",
      "style": {
        "fillColor": "#f5f5f5",
        "fontColor": "#666666"
      }
    },
    {
      "id":          "legacy",
      "description": "Legacy system — no active further development"
    }
  ]
}

specification.patterns

Patterns are reusable topology templates — for example, a standard microservice pattern with frontend, API, and database:

"specification": {
  "patterns": {
    "microservice": {
      "description": "Standard pattern: API + Database",
      "elements": [
        { "id": "api", "kind": "container", "title": "{{name}} API",      "technology": "Go"          },
        { "id": "db",  "kind": "container", "title": "{{name}} Database", "technology": "PostgreSQL"  }
      ],
      "relationships": [
        { "id": "r1", "from": "api", "to": "db", "label": "reads/writes", "kind": "uses" }
      ]
    }
  }
}

specification.decisions

ADR references (Architecture Decision Records) can be managed directly in the specification:

"specification": {
  "decisions": [
    {
      "id":     "ADR-001",
      "title":  "PostgreSQL as the primary database",
      "status": "active",
      "date":   "2025-01-15",
      "file":   "docs/adr/001-postgresql.md"
    }
  ]
}

model

The model describes the concrete elements of the system. Each key is the element ID — it must be unique within its hierarchy level.

Element Fields

"model": {
  "onlineshop": {
    "kind":        "system",
    "title":       "Online Shop",
    "description": "The core of the system",
    "technology":  "Go, PostgreSQL",
    "tags":        ["external", "legacy"],
    "status":      "deployed",
    "decisions":   ["ADR-001"],
    "metadata": {
      "owner":   "Team Backend",
      "cost":    "€500/month"
    },
    "children": {
      "frontend": { ... },
      "api":      { ... }
    }
  }
}

Nested Hierarchy

Elements can be nested to any depth, as long as the respective kind has container: true:

"model": {
  "shop": {
    "kind": "system", "title": "Online Shop",
    "children": {
      "backend": {
        "kind": "container", "title": "Backend",
        "children": {
          "orderservice": { "kind": "component", "title": "Order Service" },
          "paymentservice": { "kind": "component", "title": "Payment Service" }
        }
      }
    }
  }
}

The element ID in relationships and views uses dot notation for the path: shop.backend.orderservice.

status Values

StatusMeaningdraw.io Color

proposed

Planned, not yet started

Yellow

design

In design

Blue

implementation

Under development

Orange

deployed

In production

Green

deprecated

Outdated, being replaced

Red

archived

Decommissioned

Gray

relationships

Relationships are defined as a flat array at the top level, not inside elements. This allows relationships between elements at different hierarchy levels:

"relationships": [
  {
    "from":        "shop.backend.orderservice",
    "to":          "shop.backend.paymentservice",
    "label":       "confirms payment",
    "kind":        "uses",
    "description": "Synchronous REST call",
    "cardinality": "1:N",
    "dataFlow":    "sync",
    "decisions":   ["ADR-002"]
  }
]

views

Views define which elements appear in which diagram tab. Each key becomes a tab in architecture.drawio.

View Fields

"views": {
  "context": {
    "title":        "System Context",
    "description":  "Overview of all systems",
    "scope":        "shop",
    "include":      ["customer", "shop"],
    "exclude":      ["shop.backend.legacy"],
    "filter-tags":  ["external"],
    "exclude-tags": ["archived"],
    "layout":       "auto"
  }
}

include with wildcards:

"include": [
  "customer",
  "shop.*",
  "shop.**"
]

Optional Extensions

asIs / toBe

For as-is/to-be comparisons, the current and target architecture can be stored directly in the model:

"asIs": {
  "elements": {
    "legacy-monolith": { "kind": "system", "title": "Legacy Monolith" }
  },
  "relationships": [
    { "from": "customer", "to": "legacy-monolith", "label": "uses" }
  ]
},
"toBe": {
  "elements": {
    "shop": { "kind": "system", "title": "Online Shop (Microservices)" }
  },
  "relationships": [
    { "from": "customer", "to": "shop", "label": "uses" }
  ]
}

bausteinsicht diff visualizes the difference between asIs and toBe as an annotated diagram.

dynamicViews

Sequence diagrams describe the temporal flow of interactions:

"dynamicViews": [
  {
    "key":   "checkout",
    "title": "Checkout Flow",
    "steps": [
      { "index": 1, "from": "customer",     "to": "frontend",       "label": "clicks Buy",      "type": "sync"   },
      { "index": 2, "from": "frontend",     "to": "orderservice",   "label": "POST /orders",    "type": "sync"   },
      { "index": 3, "from": "orderservice", "to": "paymentservice", "label": "charge()",        "type": "sync"   },
      { "index": 4, "from": "paymentservice", "to": "orderservice", "label": "OK",              "type": "return" }
    ]
  }
]

type values: sync (solid arrow) | async (open arrow) | return (dashed back). bausteinsicht export sequence generates PlantUML or Mermaid from this.

constraints

Architecture rules are defined as machine-checkable constraints and evaluated with bausteinsicht lint:

"constraints": [
  {
    "id":          "NO-DIRECT-DB-ACCESS",
    "description": "Only services may access the database directly",
    "rule":        "no-relationship",
    "from-kind":   "component",
    "to-kind":     "database"
  },
  {
    "id":          "REQUIRE-DESCRIPTION",
    "description": "All systems must have a description",
    "rule":        "required-field",
    "element-kind": "system",
    "field":       "description"
  }
]

Available rule values: no-relationship, allowed-relationship, required-field, max-depth, technology-allowed.

JSON Schema for IDE Auto-Completion

Without a plugin, auto-completion works through the bundled JSON schema. Set the $schema entry in architecture.jsonc:

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

In VS Code (and any editor with JSON schema support), auto-completion for all fields appears immediately — without having to install an extension.

Example Model

The example for this part is stored as a runnable JSONC file at teil_3.jsonc and shows specification, model, views, and relationships with all optional fields.

This is what the result looks like in draw.io (bausteinsicht sync):

The draw.io file for this can be found here: teil_3.drawio

Generated PNG files via bausteinsicht export --image-format png:

backend
context

Generated PlantUML diagrams via bausteinsicht export-diagram:

Diagram
Diagram

What Comes Next

Official documentation: User Manual · Tutorial on doctoolchain.org