Kontekst szablonu
Gdy Pan/Pani generuje kod, Restorm przekazuje cały Pana/Pani projekt do szablonu w
postaci obiektu ctx. Pana/Pani modele, enumy, trasy, a przede wszystkim ich
intencje (searchable, PII, cache oraz cały profil operacyjny modelu:
wolumetria, profil dostępu, ruch, świeżość, wrażliwość, retencja) są tam —
szablon odczytuje je, aby zdecydować, co wygenerować. Nie potrzeba do tego
zmiennej: informacje, które już wprowadzono w projekcie, są bezpośrednio
dostępne.

Kształt ctx
Section titled “Kształt 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, varsReferencje odbywają się po nazwie (nigdy po wewnętrznym identyfikatorze):
property.enum to nazwa enuma, property.references.model nazwa docelowego
modelu, model.inherits nazwa rodzica. Na modelu properties[] wylicza jego
własne właściwości (do deklaracji typu), a allProperties[] właściwości
własne + odziedziczone, spłaszczone (dla kompletnej instancji: dane
przykładowe, kolumny SQL, treść żądania).
Odczyt flagi: złota zasada
Section titled “Odczyt flagi: złota zasada”Flagi logiczne są obecne w ctx tylko wtedy, gdy są włączone. Silnik
renderuje w trybie StrictUndefined: należy więc testować obecność
klucza, nigdy jego wartość.
{# ✅ poprawnie — testujemy obecność #}{% if 'searchable' in p %}INDEX({{ p['name'] }}){% endif %}
{# ❌ błędnie — zgłasza błąd, gdy flaga jest nieobecna #}{% if p.searchable %}…{% endif %}Tylko property.required (logiczna) i route.auth (enumeracja) są zawsze
obecne. Pozostałe flagi logiczne są „obecne = prawda”; pola o wartości
(wolumetria, profil operacyjny, cache…) niosą swoją wartość, gdy są uzupełnione,
i są nieobecne w przeciwnym razie — ta sama zasada obecności.
| Na właściwości | Na modelu | Na trasie |
|---|---|---|
readOnly · writeOnly · nullable | timestamps · softDelete (logiczne) | idempotent · deprecated (logiczne) |
unique · searchable · immutable · pii | Profil operacyjny (wartości): volumetry · accessPattern · traffic · freshness · sensitivity · retention | cacheSeconds (liczba) · pagination (obiekt) |
Wartości profilu operacyjnego modelu: 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).
Przykład: buforowanie danych o dużym zapotrzebowaniu na odczyt
Section titled “Przykład: buforowanie danych o dużym zapotrzebowaniu na odczyt”Dwa przypadki, w zależności od tego, czy informacja już istnieje w projekcie, czy nie.
a) Projekt już zawiera tę informację
Section titled “a) Projekt już zawiera tę informację”Jeśli uzupełniono czas buforowania na trasie, przychodzi on w
route['cacheSeconds']; route['idempotent'] mówi Panu/Pani, że jest ona bezpieczna
do buforowania (tylko do odczytu):
{% 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) „Duże zapotrzebowanie na odczyt” to natywne pole modelu
Section titled “b) „Duże zapotrzebowanie na odczyt” to natywne pole modelu”Nie potrzeba zmiennej: „duże zapotrzebowanie na odczyt” to bezpośrednio
profil dostępu modelu. W ustawieniach modelu, grupa Profil operacyjny,
wybiera Pan/Pani Dominacja odczytu — szablon odczytuje to w model['accessPattern'].
Proszę połączyć to z model['freshness'] (tolerancja świeżości), aby zdecydować, czy
buforować i na jak długo:
{% 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 włączony ({{ ttl }}s){% endif %}{% endfor %}Proszę zwrócić uwagę na test != 'strong': model z dominacją odczytu, ale z silną
spójnością nie powinien być buforowany. To właśnie cała wartość posiadania
obu intencji obok siebie w projekcie.
Proszę zarezerwować zmienne generowania do tego, czego projekt jeszcze nie zawiera (ustawienie specyficzne dla szablonu): intencje biznesowe — wolumetria, profil dostępu, ruch, świeżość, wrażliwość, retencja — są natywnymi polami modelu.
Pełny kontrakt
Section titled “Pełny kontrakt”Ten kontekst jest wersjonowany (ctx['contextVersion']) i wyczerpująco opisany
przez JSON-Schema dostarczony w repozytorium aplikacji
(docs/contributing/design-codegen-context.schema.json) — proszę skopiować go do swojego
szablonu, aby jego CI walidowało kontekst referencyjny. Agent AI otrzymuje ten
sam kontrakt w locie za pośrednictwem narzędzia MCP get_design_template_contract.