Skip to content

Authoring Models in a Source Repo

This page describes the producer side of the pipeline: an engineering team that authors architecture models as code and runs the Linked.Archi converters to emit RDF on every push. It is distilled from the example-architecture-project template.

If you want the whole picture first, read the Pipeline Overview.


Role

A source repo owns models in one or more notations and is responsible for converting them to RDF (TriG). The converted .trig file is the only interface contract with the rest of the world — it is published as a CI artifact and later pulled by the central aggregation graph.

Conversion happens once, here, in the source repo. The aggregation repo never runs a converter.


Repository layout

.
├── models/
│   ├── bpmn/                      BPMN 2.0 process files
│   │   ├── diagram-index.yaml     Index: model IDs + publish status
│   │   └── order-fulfillment.bpmn
│   ├── plantuml/                  PlantUML diagrams
│   │   ├── diagram-index.yaml
│   │   ├── inventory-domain.puml
│   │   └── checkout-sequence.puml
│   ├── backstage/                 Backstage catalog entities
│   │   ├── catalog-index.yaml
│   │   └── catalog-info.yaml
│   ├── structurizr/               Structurizr workspace (C4)
│   │   └── workspace.json
│   └── archimate/                 ArchiMate Exchange XML
│       └── enterprise-model.xml
├── config/
│   └── type-mapping-*.yml         Optional domain-ontology overrides
├── out/                           Generated RDF (gitignored)
├── convert-*.sh                   Per-notation convert scripts
├── convert-all.sh                 Converts everything
├── .gitlab-ci.yml                 convert → validate → publish
└── README.md

out/ is gitignored

In a fresh checkout out/ is empty. RDF only appears after ./convert-all.sh runs locally, or after a CI run.


Quick start

# Convert all models locally (requires Docker)
./convert-all.sh

# Or run individual converters
./convert-bpmn.sh
./convert-plantuml.sh
./convert-backstage.sh
./convert-structurizr.sh

Each script wraps the converter Docker image. For example, the BPMN conversion runs:

docker run --rm -v "$PWD:/work" -w /work linkedarchi-converters \
  bpmn2linkedarchi convert models/bpmn/*.bpmn \
  --diagrams-index models/bpmn/diagram-index.yaml \
  --base-iri "$BASE_IRI" --format TRIG -o out/bpmn.trig

See Docker & CI and the per-notation pages under Converters for the exact CLI of each tool.


Configuration

Base IRI

All scripts share a base IRI used to mint stable resource IRIs. Override it via the environment:

export BASE_IRI="https://archi.example.com/graph/"
./convert-all.sh

Type mapping (optional)

Override default notation types with a domain ontology by passing --type-mapping. See Type Mapping and Ontology Alignment.

bpmn2linkedarchi convert models/bpmn/*.bpmn \
  --type-mapping config/type-mapping-bpmn-lite.yml \
  --base-iri "$BASE_IRI" --format TRIG -o out/bpmn.trig

Diagram index files

Each notation directory carries a diagram-index.yaml that controls which files are processed, assigns stable model IDs (used in IRIs, independent of filename), and records each diagram's lifecycle state, which is published as adms:status and can be withheld from a build with --exclude-states:

diagrams:
  - id: order-fulfillment
    file: order-fulfillment.bpmn
    status: publish
    title: "Order Fulfillment Process"
    author: "Platform Team"

See Diagram Index Files for the full schema.

Model IDs and versioning

The id (from diagram-index.yaml, or --model-id for Structurizr) is what makes a model's IRIs stable and deterministic — IRIs are minted from it, never from the filename. Keep an id fixed across edits so re-conversions produce clean diffs in the graph rather than duplicate resources.

This matters for versioning. The graph repo overwrites each source in place, so git history is your version trail (see Versioning & overwrites). If you ever need two versions of the same model to coexist in the graph (e.g. during a migration), they must have distinct IDs — convert them with different id / --model-id values (e.g. order-v1, order-v2). Two models sharing an id mint identical graph IRIs, and the second would shadow the first when merged. This is the producer half of the side-by-side versioning contract.


Output format

By default the scripts and CI publish both formats — controlled by the FORMATS variable (default TRIG TURTLE):

  • out/*.trig — TriG, named-graph aware. Each model yields semantic / model / views / provenance named graphs, with semantic split one graph per input file where a model is built from several:

    <https://archi.example.com/graph/bpmn/order-fulfillment/graph/semantic> {
        <.../element/UserTask_1> a bpmn:UserTask, arch:Element ;
            bpmn:name "Validate Order" .
    }
    
  • out/*.ttl — Turtle, the flat union of those triples (no named graphs).

Publish just one by setting the variable, e.g. FORMATS=TRIG ./convert-all.sh or the FORMATS CI variable. See the format tradeoff in Aggregating into a Graph for when to prefer each — TriG preserves provenance separation and merges cleanly; Turtle is simpler and more portable.


CI pipeline

The source repo's .gitlab-ci.yml runs on every push:

  1. convert — runs the converters, produces out/*.trig, stored as an artifact (expire_in: never recommended on main)
  2. validate — Tier 1 structural SHACL validation on the output
  3. publish — optional; the artifact is what the aggregation repo pulls

The convert job runs once; its artifact is reused for the MR check and by the aggregation repo. See Validation Tiers for what Tier 1 checks.


Adapting the template

  1. Replace the sample models in models/ with your own
  2. Update each diagram-index.yaml with your model IDs
  3. Set BASE_IRI to your organization's graph root
  4. Point .gitlab-ci.yml at your registry (and triplestore, if publishing directly)
  5. Optionally add config/type-mapping-*.yml for domain ontology alignment
  6. Register the repo in the aggregation graph's sources-index.yaml