Der Kontext des Templates
Wenn Sie Code generieren, übergibt Restorm Ihr gesamtes Design an das
Template in Form eines ctx-Objekts. Ihre Modelle, Ihre Enums, Ihre Routen
und vor allem ihre Absichten (searchable, PII, cache und das gesamte
operative Profil des Modells: Volumen, Zugriffsprofil, Traffic, Aktualität,
Sensibilität, Aufbewahrung) sind da — ein Template liest sie, um zu entscheiden,
was zu generieren ist. Dafür braucht es keine Variable: die Informationen, die
Sie bereits im Design erfasst haben, sind direkt verfügbar.

Die Form von ctx
Section titled “Die Form von ctx”ctx├─ design # name, version, description, basePath, defaultAuth, vars├─ enums[] # name, description, values[]├─ models[] # name, description, inherits, identifier, timestamps, softDelete,│ # volumetry, accessPattern, traffic, freshness, sensitivity,│ # retention, properties[], allProperties[], examples[], vars└─ groups[] # name, basePath, versionPrefix, headers[], routes[] └─ routes[] # method, path, fullPath, params[], body, responses[], # auth, pagination, cacheSeconds, idempotent, deprecated, varsDie Referenzen erfolgen über den Namen (niemals über einen internen
Bezeichner): property.enum ist der Name des Enums, property.references.model
der Name des angezielten Modells, model.inherits der Name des übergeordneten
Modells. Auf einem Modell listet properties[] seine eigenen Eigenschaften
(für die Deklaration des Typs) und allProperties[] die eigenen + geerbten,
abgeflachten Eigenschaften (für eine vollständige Instanz: Beispieldaten,
SQL-Spalten, Anfrage-Body).
Ein Flag lesen: die goldene Regel
Section titled “Ein Flag lesen: die goldene Regel”Die booleschen Flags sind in ctx nur dann vorhanden, wenn sie aktiviert
sind. Die Engine rendert in StrictUndefined: man muss also die Präsenz
des Schlüssels testen, niemals seinen Wert.
{# ✅ correct — on teste la présence #}{% if 'searchable' in p %}INDEX({{ p['name'] }}){% endif %}
{# ❌ faux — lève une erreur quand le flag est absent #}{% if p.searchable %}…{% endif %}Nur property.required (boolesch) und route.auth (Enumeration) sind immer
vorhanden. Die anderen booleschen Flags sind „vorhanden = wahr”; die Felder mit
Wert (Volumen, operatives Profil, cache…) tragen ihren Wert, wenn sie
ausgefüllt sind, und fehlen andernfalls — dieselbe Präsenzregel.
| Auf einer Eigenschaft | Auf einem Modell | Auf einer Route |
|---|---|---|
readOnly · writeOnly · nullable | timestamps · softDelete (boolesch) | idempotent · deprecated (boolesch) |
unique · searchable · immutable · pii | Operatives Profil (Werte): volumetry · accessPattern · traffic · freshness · sensitivity · retention | cacheSeconds (Zahl) · pagination (Objekt) |
Die Werte des operativen Profils eines Modells: accessPattern
(readHeavy / writeHeavy / balanced / appendOnly), traffic
(low / medium / high), freshness (strong / shortCache / longCache),
sensitivity (public / internal / confidential / pii), retention
(permanent / archivable / ephemeral), volumetry (hundreds /
tenThousands / millions).
Beispiel: Daten mit hoher Lesenachfrage cachen
Section titled “Beispiel: Daten mit hoher Lesenachfrage cachen”Zwei Fälle, je nachdem, ob die Information bereits im Design existiert oder nicht.
a) Das Design trägt die Info bereits
Section titled “a) Das Design trägt die Info bereits”Wenn Sie eine Cache-Dauer auf einer Route ausgefüllt haben, kommt sie in
route['cacheSeconds'] an; route['idempotent'] sagt Ihnen, dass sie sicher zu
cachen ist (schreibgeschützt):
{% for group in ctx['groups'] %}{% for route in group['routes'] %}{% if 'cacheSeconds' in route and 'idempotent' in route %}// {{ route['method'] }} {{ route['fullPath'] }}app.use("{{ route['fullPath'] }}", cache({{ route['cacheSeconds'] }}));{% endif %}{% endfor %}{% endfor %}b) „Hohe Lesenachfrage” ist ein natives Feld des Modells
Section titled “b) „Hohe Lesenachfrage” ist ein natives Feld des Modells”Keine Variable nötig: „hohe Lesenachfrage” ist direkt das Zugriffsprofil des
Modells. In den Einstellungen des Modells, Gruppe Operatives Profil, wählen
Sie Lesedominant — das Template liest es in model['accessPattern'].
Kombinieren Sie es mit model['freshness'] (Toleranz gegenüber der Aktualität),
um zu entscheiden, ob und für wie lange gecacht werden soll:
{% for model in ctx['models'] %}{% if model['accessPattern'] == 'readHeavy' and model['freshness'] != 'strong' %}{% set ttl = 3600 if model['freshness'] == 'longCache' else 60 %}registerCache("{{ model['name'] }}", {{ ttl }}); // cache activé ({{ ttl }}s){% endif %}{% endfor %}Beachten Sie den Test != 'strong': ein lesedominantes Modell, aber mit
starker Konsistenz, darf nicht gecacht werden. Das ist genau der Sinn davon,
die beiden Absichten im Design nebeneinander zu haben.
Reservieren Sie die Generierungsvariablen für das, was das Design nicht bereits trägt (eine template-eigene Einstellung): die fachlichen Absichten — Volumen, Zugriffsprofil, Traffic, Aktualität, Sensibilität, Aufbewahrung — sind native Felder des Modells.
Der vollständige Vertrag
Section titled “Der vollständige Vertrag”Dieser Kontext ist versioniert (ctx['contextVersion']) und wird vollständig
durch ein JSON-Schema beschrieben, das im Repository der Anwendung geliefert wird
(docs/contributing/design-codegen-context.schema.json) — kopieren Sie es in Ihr
Template, damit dessen CI den Referenzkontext validiert. Ein KI-Agent erhält
denselben Vertrag im laufenden Betrieb über das MCP-Tool
get_design_template_contract.