# Normalización de activos ## Objetivo 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: - un campo usa `fieldType` y `unit`; - una relación usa `inverseName` y `symmetric`; - una plantilla se compone mediante sus tablas relacionadas. 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. ## Migración La migración crea las tablas normalizadas, lee una única vez los datos JSON existentes, valida su estructura con los schemas de dominio y crea las filas correspondientes dentro de una transacción. Solo elimina las columnas JSON después de una transferencia íntegra. Cualquier dato que no cumpla el contrato detiene el arranque sin descartar el origen. ## 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. Se adaptan también las lecturas de dashboard y asistencia técnica. ## Ejecución y recuperación Las migraciones se ejecutan antes de exponer las rutas durante `createAssetModule`. Primero crean las estructuras necesarias y transfieren datos dentro de transacciones. La lectura desde el destino se compara con el origen antes de retirar sus columnas. Se valida el historial completo, además de los valores actuales. Un dato inválido detiene la transferencia y conserva las columnas originales. MariaDB confirma las operaciones DDL de forma independiente: la migración no promete rollback del esquema completo. Cada paso comprueba el estado existente y permite repetir un arranque, incluido el corte entre la retirada del JSON de las revisiones y la del activo. No se deben mantener escritores de versiones antiguas funcionando durante una actualización del esquema. Antes de aplicar cambios a la BD de desarrollo puede ejecutarse `bash scripts/backup-assets-normalization.sh`. La copia SQL completa se guarda fuera del repositorio en `/home/david/.local/state/metis-desk/backups`, con permisos restringidos. Contiene datos privados y no debe versionarse. ## Alcance Esta entrega normaliza catálogo de activos, inventario, especificaciones, revisiones y relaciones entre activos. No cambia la persistencia de recursos, puestos de trabajo, asistencia técnica, tickets ni los otros módulos que todavía tienen JSON. Su normalización requiere migraciones específicas posteriores; no se introduce JSON nuevo para guardar valores en el diseño de activos. ## Verificación `apps/server/src/asset-normalization.integration.ts`, incluido en `pnpm --filter @metis/server test`, reconstruye el formato anterior únicamente en `metis_desk_test` y comprueba transferencia, dato inválido sin descarte del origen, idempotencia, recuperación de DDL interrumpido y restricciones de valores. Cubre los cinco tipos, cero, falso, campos omitidos, secciones congeladas, marcas, identidades y revisiones existentes. La integración HTTP habitual verifica catálogo global/local, creación y edición, relaciones, puestos, asistencia y dashboards. ## Esquema de relaciones ```mermaid erDiagram asset_catalogs ||--o{ asset_definitions : contiene asset_definitions ||--o{ asset_field_choices : opciones asset_definitions ||--o{ asset_template_sections : secciones asset_definitions ||--o{ asset_template_fields : plantilla_y_campo asset_template_sections o|--o{ asset_template_fields : agrupa asset_definitions ||--o{ asset_availability : disponibilidad_por_compania asset_definitions ||--o{ assets : plantilla asset_brands o|--o{ assets : marca assets ||--o{ asset_specification_sections : captura assets ||--|{ asset_specification_fields : captura asset_specification_sections o|--o{ asset_specification_fields : agrupa asset_specification_fields ||--o{ asset_specification_field_choices : captura_opciones asset_specification_fields ||--o{ asset_characteristics : valor_actual assets ||--|{ asset_revisions : historial asset_revisions ||--o{ asset_revision_characteristics : valores_historicos asset_specification_fields ||--o{ asset_revision_characteristics : interpreta assets ||--o{ asset_relationships : origen_o_destino asset_definitions ||--o{ asset_relationships : tipo ``` La tabla `asset_template_fields` referencia `asset_definitions` dos veces: plantilla y campo. `asset_relationships` referencia `assets` dos veces: origen y destino. Las cardinalidades de valor por campo se interpretan dentro de cada activo o revisión; los campos opcionales pueden no tener fila. En desarrollo se comprobó la lectura de las tres compañías y la conservación de 52 definiciones, 5 activos, 6 revisiones y 1 relación. La copia previa de esta ejecución se guardó en `/home/david/.local/state/metis-desk/backups/pre-normalizacion-activos-20261010-113023.sql`.