La persistencia de activos no utiliza JSON para definiciones, características ni historial. La flexibilidad del catálogo se representa mediante relaciones, no mediante columnas creadas dinámicamente.
## Catálogo
`asset_definitions` contiene los atributos comunes de una definición: identidad, catálogo, compañía opcional, origen, tipo (`field`, `template` o `relation`), nombre, descripción y estado. Sus atributos específicos se almacenan en columnas tipadas:
Las opciones de un campo de lista se guardan en `asset_field_choices`. Las secciones de una plantilla se guardan en `asset_template_sections`. `asset_template_fields` une plantilla y campo, e incluye obligatoriedad, posición y sección opcional.
## Inventario
`assets` guarda las propiedades estables: compañía, plantilla, sede, marca, nombre, estado y notas. Las características variables se almacenan en `asset_characteristics`, una fila por activo y campo, con columnas tipadas para texto, número, fecha o booleano.
Una instantánea de la plantilla se conserva mediante `asset_specification_sections`, `asset_specification_fields` y `asset_specification_field_choices`. De este modo, editar posteriormente el catálogo no altera la interpretación de un activo existente.
`asset_revisions` conserva las propiedades estables de cada revisión. Sus características se guardan en `asset_revision_characteristics`, vinculadas a la instantánea del activo.
## Relaciones entre activos
`asset_relationships` guarda sus extremos, tipo, nombre e inverso capturados, simetría, notas y auditoría en columnas. Se conservan sus UUID, clave de relación activa, autor y fechas de creación y retirada. Los nombres capturados no cambian cuando se renombra el tipo en el catálogo.
## Integridad y contratos
Las FK compuestas impiden asignar una sección de otra plantilla, usar un campo que no esté en la instantánea del activo o asociar una característica histórica a una revisión de otro activo. Los CHECK limitan los tipos de definición, estados y valores tipados: exactamente una columna de valor debe estar informada y corresponder al tipo declarado. La fecha se almacena como DATE; la lectura la convierte explícitamente a ISO sin depender de la zona horaria del proceso.
`sectionsDefined` y `brandDefined` conservan la distinción del contrato entre una propiedad ausente, una lista vacía y una marca nula en datos históricos. Una marca no nula siempre implica `brandDefined=1`.
El catálogo global, los particulares de compañía, disponibilidad, secciones, orden y campos obligatorios mantienen su comportamiento. Dominio, DTO y HTTP continúan utilizando objetos `values` y `specification`; estos objetos se ensamblan desde las tablas normalizadas y no se almacenan como JSON. Los lectores de dashboard y asistencia técnica utilizan las mismas columnas.
`createAssetModule` prepara explícitamente tablas, índices, restricciones y catálogos antes de exponer las rutas. Las inicializaciones son idempotentes y no modifican los valores ni el historial de los activos.
La creación del esquema usa columnas con su nulabilidad definitiva y tablas dependientes para opciones, secciones, especificaciones y valores. Los repositorios reconstruyen y validan el agregado completo, incluidas sus revisiones.
Para una copia de seguridad de desarrollo puede utilizarse `bash scripts/backup-database.sh`. El SQL se guarda fuera del repositorio en `/home/david/.local/state/metis-desk/backups`, con permisos restringidos.