Model JSON contract
editor.model (and the value you persist, send to a server, or hand to another
tool) is a plain JSON object. This page documents that wire format as a
stable, versioned contract so integrators — Artemis, BESSER, grading
scripts — can store and validate diagrams with confidence.
The schema
Apollon publishes a JSON Schema generated from the source UMLModel type and
shipped in the package:
import schema from "@tumaet/apollon/schema" with { type: "json" }
It is also resolvable by URL for use with $ref, editor tooling, or CI
validators:
https://unpkg.com/@tumaet/apollon/schema/uml-model-4.schema.json
Validate a model with any JSON Schema validator, e.g. ajv:
import Ajv from "ajv"
import schema from "@tumaet/apollon/schema" with { type: "json" }
const validate = new Ajv({ strict: false }).compile(schema)
if (!validate(model)) console.error(validate.errors)
Shape
A v4 model is:
type UMLModel = {
version: `4.${number}.${number}` // wire-format version, currently "4.2.0"
id: string
title: string
type: UMLDiagramType // "ClassDiagram" | "BPMN" | … (13 values)
nodes: ApollonNode[] // diagram elements
edges: ApollonEdge[] // relationships
assessments: { [elementId: string]: Assessment }
interactive?: {
elements: { [id: string]: boolean }
relationships: { [id: string]: boolean }
}
}
The schema is strict about the envelope — unknown top-level, node, or edge
fields are rejected, as are a missing version, an unknown diagram type, or a
malformed nodes/edges array.
Element data is an open envelope
Each node and edge carries a data object whose shape depends on its type
(a class node's name / attributes / methods, a BPMN task's taskType, an
edge's multiplicities, colors, …). The schema intentionally leaves data open
(additionalProperties) rather than under-describing it; a full discriminated
union of all ~50 node types is planned follow-up work. For the concrete per-type
fields today, read lib/types/nodes/NodeProps.ts and lib/edges/EdgeProps.ts
in the source.
One cross-cutting data field worth knowing: every node — and every class
attribute/method — may carry an optional tags: string[] of host-defined
grouping labels. See Element tags & group coloring for their
normalization rules and the addressing API.
Versioning policy
version tracks the wire-format major line (4.x) — not the npm package
version. The current canonical model version is 4.2.0. importDiagram
accepts every supported v2, v3, and v4 payload, migrates it in place where
necessary, and returns the current v4 representation.
The 4.2 minor adds optional, interior-only waypoints to straight connections.
When loading a 4.0 or 4.1 model, Apollon discards data.points only on those
straight edge families: older releases used that field for inert full-route
geometry, which must not become visible user-authored bends. Orthogonal edge
waypoints and all other model data are preserved. Models from 4.2 and later keep
their straight-edge waypoints unchanged.
| Change | Bump | What you do |
|---|---|---|
| Breaking shape change | MAJOR | new top-level version + importDiagram converter |
| New optional field | MINOR | nothing — additive |
| No shape change | PATCH | nothing |
The schema describes canonical v4 — the output of importDiagram(). Older
v2 / v3 payloads are not covered: normalise them first.
import { importDiagram } from "@tumaet/apollon"
editor.model = importDiagram(maybeV2OrV3Json) // → guaranteed v4
Server code that only needs to normalize model JSON can use the DOM-free entry:
import { importDiagram } from "@tumaet/apollon/model"
export const normalizeDiagram = (data: unknown) => importDiagram(data)
The v2 / v3 detectors and converters live behind @tumaet/apollon/internals
and are not part of the stability guarantee — only importDiagram is.
This is the diagram data contract. It is unrelated to the standalone webapp's diagram version history feature, which is about storing snapshots over time.
See also: Export and Headless rendering.