Przejdź do głównej zawartości

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.

Zakładka Code generation właściwości: jej flagi i zmienne odczytywane przez szablon

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, vars

Referencje 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).

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ściNa modeluNa trasie
readOnly · writeOnly · nullabletimestamps · softDelete (logiczne)idempotent · deprecated (logiczne)
unique · searchable · immutable · piiProfil operacyjny (wartości): volumetry · accessPattern · traffic · freshness · sensitivity · retentioncacheSeconds (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.

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.

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.