Ir al contenido

El contexto de la plantilla

Cuando genera código, Restorm pasa todo su diseño a la plantilla bajo la forma de un objeto ctx. Sus modelos, sus enums, sus rutas y sobre todo sus intenciones (searchable, PII, cache, y todo el perfil operativo del modelo: volumetría, perfil de acceso, tráfico, frescura, sensibilidad, retención) están ahí — una plantilla los lee para decidir qué generar. No hace falta una variable para eso: la información que ya ha introducido en el diseño está directamente disponible.

La pestaña Code generation de una propiedad: sus flags y sus variables leídas por la plantilla

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

Las referencias se hacen por nombre (nunca por identificador interno): property.enum es el nombre del enum, property.references.model el nombre del modelo apuntado, model.inherits el nombre del padre. En un modelo, properties[] lista sus propiedades propias (para la declaración del tipo) y allProperties[] las propiedades propias + heredadas, aplanadas (para una instancia completa: datos de ejemplo, columnas SQL, cuerpo de petición).

Los flags booleanos solo están presentes en ctx cuando están activados. El motor renderiza en StrictUndefined: hay que, por tanto, probar la presencia de la clave, nunca su valor.

{# ✅ correcto — se prueba la presencia #}
{% if 'searchable' in p %}INDEX({{ p['name'] }}){% endif %}
{# ❌ incorrecto — lanza un error cuando el flag está ausente #}
{% if p.searchable %}…{% endif %}

Solo property.required (booleano) y route.auth (enumeración) están siempre presentes. Los demás flags booleanos son «presente = verdadero»; los campos con valor (volumetría, perfil operativo, cache…) llevan su valor cuando están rellenados, y están ausentes en caso contrario — misma regla de presencia.

En una propiedadEn un modeloEn una ruta
readOnly · writeOnly · nullabletimestamps · softDelete (booleanos)idempotent · deprecated (booleanos)
unique · searchable · immutable · piiPerfil operativo (valores): volumetry · accessPattern · traffic · freshness · sensitivity · retentioncacheSeconds (número) · pagination (objeto)

Los valores del perfil operativo de un modelo: 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).

Ejemplo: cachear los datos con fuerte demanda de lectura

Section titled “Ejemplo: cachear los datos con fuerte demanda de lectura”

Dos casos, según que la información exista ya en el diseño o no.

Si ha rellenado una duración de caché en una ruta, llega en route['cacheSeconds']; route['idempotent'] le dice que es segura para cachear (solo lectura):

{% 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) «Fuerte demanda de lectura» es un campo nativo del modelo

Section titled “b) «Fuerte demanda de lectura» es un campo nativo del modelo”

No hace falta variable: «fuerte demanda de lectura» es directamente el perfil de acceso del modelo. En los ajustes del modelo, grupo Perfil operativo, usted elige Lectura dominante — la plantilla lo lee en model['accessPattern']. Combínelo con model['freshness'] (tolerancia a la frescura) para decidir si hay que cachear, y por cuánto tiempo:

{% 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 }}); // caché activada ({{ ttl }}s)
{% endif %}
{% endfor %}

Note la prueba != 'strong': un modelo con lectura dominante pero en consistencia fuerte no debe cachearse. Ese es todo el interés de tener las dos intenciones lado a lado en el diseño.

Reserve las variables de generación para lo que el diseño no lleva ya (un ajuste propio de la plantilla): las intenciones de negocio — volumetría, perfil de acceso, tráfico, frescura, sensibilidad, retención — son campos nativos del modelo.

Este contexto está versionado (ctx['contextVersion']) y descrito exhaustivamente por un JSON-Schema entregado en el repositorio de la aplicación (docs/contributing/design-codegen-context.schema.json) — cópielo en su plantilla para que su CI valide el contexto de referencia. Un agente IA obtiene el mismo contrato al vuelo mediante la herramienta MCP get_design_template_contract.