metis-desk/docs/normalizacion-de-la-persistencia.md
2026-10-10 16:40:51 +02:00

16 KiB

Normalización de la persistencia

Se mantiene Sequelize 6 y MariaDB. El criterio del proyecto es almacenar datos de negocio en columnas y relaciones, sin documentos JSON. Los objetos values del dominio y el JSON del contrato HTTP no implican columnas JSON.

Estado de la normalización

La auditoría y normalización de la persistencia actual están completadas. Activos, recursos, configuraciones, tickets e intervenciones se completan con cuentas y accesos, correo, accesos remotos, procesos y sesiones HTTP. No se mantienen documentos JSON en la base de desarrollo; los contratos HTTP continúan usando JSON como transporte.

Ámbito Persistencia actual
Compañías, personas, departamentos, sedes, usuarios y marcas Columnas y relaciones existentes
Catálogo e inventario de activos Definiciones, campos tipados, especificaciones y revisiones normalizados previamente
Catálogo e inventario de recursos Definiciones, opciones, secciones, especificaciones congeladas, valores tipados e integración en columnas/tablas
Puestos de trabajo Nombre, estado y referencias en columnas; activos exclusivos/compartidos por puesto y revisión en tablas
Asistencia técnica de activos Destino, VPN, preferencia, estado y notas en columnas actuales e históricas
Perfiles de usuario Nombre, estado, notas y referencias en columnas actuales e históricas
Teletrabajo Estado, periodo, notas y persona en columnas actuales e históricas
Aplicaciones, certificados, impresoras y carpetas del perfil Valores escalares y referencias en columnas actuales e históricas
Cuentas y accesos Subtipos en tablas actuales e históricas; permisos de necesidades en asociaciones ordenadas
Correo Buzones, usos y configuraciones en columnas actuales e históricas; variantes legadas conservadas
Accesos remotos Origen, destinos con claves foráneas independientes, VPN y estado en columnas actuales e históricas
Procesos y plantillas de procesos Columnas escalares y tablas de instrucciones/tareas actuales e históricas
Tickets e intervenciones Columnas actuales e históricas; afectados, pasos, procedimientos congelados y plantillas en tablas relacionadas
Sesiones HTTP Almacén Sequelize propio: autenticación, CSRF y opciones de cookie en columnas; sin documento serializado

Las columnas data de fotos y logotipos son datos binarios; no son documentos JSON de negocio.

Recursos

Las tablas existentes resource_definitions, resource_template_fields, resources y resource_revisions mantienen sus identidades. Se añaden:

  • resource_field_choices: opciones ordenadas de cada campo.
  • resource_template_sections: secciones ordenadas, identificadas por (templateId, id); copiar una plantilla puede conservar los identificadores internos de sus secciones.
  • resource_specification_sections, resource_specification_fields y resource_specification_field_choices: definición congelada al crear el recurso.
  • resource_characteristics y resource_revision_characteristics: valores actuales e históricos con columnas independientes de texto, número, booleano y fecha.

La ausencia de una característica se representa mediante ausencia de fila. Una cadena vacía, 0 y false siguen siendo valores y se conservan. Las fechas se leen como fechas ISO. La especificación congelada no se reemplaza por el estado actual del catálogo.

Los vínculos de integración con buzones y accesos se conservan en columnas con claves foráneas. Eliminar una referencia externa no debe eliminar en cascada el recurso ni sus revisiones. Las proyecciones de compatibilidad de correo/accesos conservan las integraciones y sus identidades; sus lectores y escritores también utilizan columnas y tablas normalizadas.

Puestos, perfiles y configuraciones

workstation_members conserva la composición actual del puesto, con tipo exclusive o shared y posición. workstation_revision_members conserva la composición de cada revisión. workstation_assets sigue siendo la proyección técnica que protege referencias históricas y reserva activos exclusivos de puestos vigentes; no es otra asignación de negocio.

Los perfiles y configuraciones mantienen sus reglas de unicidad, transiciones y cierre. El cambio de persistencia no modifica rutas, formularios, DTO, contadores, permisos, identidad ni comportamiento funcional. Las referencias de las revisiones se conservan mediante claves foráneas.

Tickets, intervenciones y plantillas

Los seis registros principales (tickets, ticket_revisions, interventions, intervention_revisions, intervention_templates, intervention_template_revisions) ya no almacenan values en JSON. Asunto, descripción, estados, prioridad, canal, modalidad, fechas, minutos, diagnóstico, trabajo realizado, resolución, nombre y estado de la plantilla tienen columnas tradicionales según la entidad. plannedDate es una fecha SQL; los instantes ISO conservan su representación exacta en columnas de texto para no perder precisión del historial.

Se añaden diez tablas:

Información Actual Histórica
Afectados de tickets ticket_targets ticket_revision_targets
Afectados de intervenciones intervention_targets intervention_revision_targets
Ejecución de pasos intervention_steps intervention_revision_steps
Pasos de plantillas intervention_template_steps intervention_template_revision_steps
Procedimiento congelado intervention_procedures Procedencia inmutable de la intervención
Pasos originales del procedimiento intervention_procedure_steps Copia independiente del catálogo

Un afectado tiene exactamente una referencia: persona, puesto, activo o recurso, con clave foránea real para cada tipo. Las asociaciones se identifican por propietario y posición; los pasos mantienen su UUID y un orden único dentro de cada propietario. Las claves foráneas restringen eliminar destinos referenciados, mientras que las filas dependientes pertenecen a su ticket, revisión, plantilla o procedimiento y se eliminan en cascada con su propietario.

El procedimiento conserva plantilla, revisión concreta, nombre, descripción, estado original y pasos. La base comprueba que la revisión pertenece a esa plantilla. No se sustituye esa copia por el catálogo vigente. Una intervención sencilla puede no tener procedimiento, pasos, técnico o ticket, según las reglas existentes.

Los repositorios reconstruyen los mismos Value Objects y agregados. Se mantienen las rutas, DTO, UUID, autores, fechas, contadores, reintentos idempotentes, revisión esperada, conflictos concurrentes y reglas para cerrar o reabrir. Los lectores del dashboard consultan las columnas normalizadas tanto del estado actual como de las revisiones.

Migraciones

Las migraciones se ejecutan explícitamente al inicializar los módulos; no se utiliza sync({ alter: true }).

  1. Se añaden columnas y tablas de destino sin borrar el origen.
  2. Se valida el documento anterior mediante el esquema de dominio, incluidas las referencias ya persistidas.
  3. La transferencia de valores se realiza en una transacción.
  4. Se reconstruye el destino y se compara con el origen antes de retirar las columnas antiguas.
  5. Se eliminan las columnas JSON transferidas y se refuerzan las restricciones.

El DDL de MariaDB no es transaccional. Una interrupción puede dejar columnas de preparación, pero el origen se conserva hasta verificar la transferencia. Las migraciones de tickets, intervenciones y plantillas permiten reconstruir conjuntamente registros legados y normalizados si el DDL se interrumpe entre columnas. La migración de recursos admite también el corte en el que las revisiones ya se transfirieron y el recurso aún conserva sus columnas de origen. Repetir las migraciones no añade revisiones ni duplica datos.

Las pruebas de integración utilizan exclusivamente metis_desk_test. Comprueban origen inválido, conservación de UUID/historial/orden/valores, referencias incompatibles, idempotencia, arranque vacío y mantenimiento del comportamiento HTTP. Las fixtures SQL que antes escribían JSON se adaptan a las tablas nuevas.

Cuentas y accesos

Se conservan las raíces access_workspaces, access_items y access_revisions, y las proyecciones access_references y access_person_references. La raíz identifica compañía/ámbito y tipo; las revisiones mantienen UUID, secuencia, autor e instante. Cada tipo tiene una tabla de valores y otra de valores históricos:

Tipo Actual Histórica
Sistema access_system_values access_system_revision_values
Tipo de recurso access_resource_type_values access_resource_type_revision_values
Permiso access_permission_values access_permission_revision_values
Plantilla de grupo access_template_values access_template_revision_values
Entorno access_environment_values access_environment_revision_values
Cuenta access_account_values access_account_revision_values
Titular/usuario de cuenta access_account_person_values access_account_person_revision_values
Grupo access_group_values access_group_revision_values
Pertenencia a grupo access_membership_values access_membership_revision_values
Proyección de recurso access_resource_values access_resource_revision_values
Permiso concedido access_grant_values access_grant_revision_values
Necesidad access_need_values access_need_revision_values
Cobertura access_coverage_values access_coverage_revision_values

ownerId es clave primaria y foránea a la raíz o revisión correspondiente. Las referencias entre elementos y personas tienen claves foráneas. access_need_permissions y access_need_revision_permissions conservan permisos y orden; no permiten duplicar un permiso dentro de la misma necesidad. Las vistas access_current_values y access_historical_values unen columnas de los subtipos para lecturas comunes, sin generar JSON SQL.

El catálogo global y los ámbitos de compañía mantienen sus reglas. Se conservan titularidad histórica, cuentas compartidas, caducidad opcional, grupos, permisos, coberturas, bloqueos de concurrencia y proyecciones de referencias.

Correo y accesos remotos

mailboxes, mailbox_uses, mail_configurations y sus revisiones almacenan dirección, tipo/contexto, cuenta vinculada, personas autorizadas, periodo, perfil, protocolo, estado y notas en columnas. snapshotKind diferencia configuraciones históricas anteriores (persona/cuenta/activo) de las actuales (perfil/buzón). No se inventa un perfil para transformar el historial anterior. Las restricciones SQL exigen las referencias apropiadas a cada variante.

remote_connections y remote_connection_revisions mantienen persona, tipo de origen, activo corporativo cuando corresponde, sede/red, método, VPN, estado y notas. El destino se separa en targetAssetId y targetResourceId, con claves foráneas reales. Las restricciones SQL impiden destinos incompatibles, un origen personal con activo corporativo y acceso al propio equipo como destino.

Los repositorios, lectores de dashboard/procesos y proyecciones de recursos reconstruyen los mismos contratos anteriores. Se mantienen las configuraciones múltiples por persona, la adopción de configuraciones legadas y todo el historial.

Procesos

process_templates y process_template_revisions tienen columnas de nombre, tipo, estado y notas. Sus pasos ordenados se guardan en process_template_instructions y process_template_revision_instructions.

person_processes y person_process_revisions tienen persona, plantilla, nombre congelado de plantilla, nombre del proceso, tipo, estado y notas. person_process_tasks y person_process_revision_tasks conservan UUID de tarea, orden, título, estado, notas y referencia de revisión (tipo, UUID, etiqueta y procedencia).

La referencia de una tarea es información congelada para revisar una situación, no una asignación viva. No lleva FK al elemento revisado: debe conservarse aunque ese elemento se retire o elimine. Sí existen claves foráneas entre procesos, personas, plantillas, revisiones y sus tablas dependientes. Las instrucciones originales y tareas históricas no se reemplazan por una plantilla modificada.

Sesiones

http_sessions conserva sid, expiración y fechas de creación/actualización; añade columnas de usuario, versión de autenticación, token CSRF y opciones de cookie. La columna data desaparece. El almacén propio SequelizeSessionStore sustituye connect-session-sequelize, que se retira de las dependencias.

Se conservan duración original y expiración de la cookie, opciones booleanas, autenticación y protección CSRF. touch renueva la cookie sin sobrescribir autenticación o CSRF de otra petición. Las sesiones vencidas no se recuperan y se purgan al guardar sesiones; la expiración tiene índice. No se necesita temporizador de fondo. La migración rechaza atributos de sesión desconocidos en lugar de descartarlos.

Auditoría final

La auditoría de information_schema en desarrollo no encuentra tipos JSON, restricciones JSON_VALID ni columnas values, specification, characteristics, procedure u otros documentos serializados. Las columnas instructions de intervenciones son texto de instrucciones de un paso; data en fotos/logotipos es binario.

El código de producción no declara DataTypes.JSON. Los lectores JSON restantes corresponden a migraciones del origen anterior; las escrituras JSON de pruebas reconstruyen ese origen exclusivamente en metis_desk_test. El uso de JSON en HTTP, traducciones, logs y fixtures no es persistencia de documentos de negocio.

Verificación de la revisión anterior

  • Suite completa: 277 pruebas superadas; espaciado: 3 pruebas superadas.
  • Typecheck de servidor, activos, compañías y recursos: correcto.
  • Build: correcto; mantiene el aviso de tamaño de bundles del frontend.
  • Biome y ESLint sobre los ficheros modificados en esta revisión: correctos.
  • Arranque y migraciones sobre una base de pruebas vacía: correctos.
  • Inicialización de desarrollo: comprobada después de guardar una copia SQL externa al repositorio en /home/david/backups/metis-desk/.

El typecheck global sigue encontrando el problema anterior de locale en packages/shadcn-ui/src/components/calendar.tsx. El lint/check global conserva errores de otros ficheros (principalmente código de fotos y formato pendiente). No se modifica código vendor ni cambios de interfaz ajenos a esta normalización.

Verificación de tickets e intervenciones

  • Suite completa: 277 pruebas superadas, incluida la integración HTTP/MariaDB y la transferencia del formato legado; 3 pruebas de espaciado superadas.
  • Typecheck de servidor y compañías, build, Biome y ESLint de todos los ficheros modificados: correctos.
  • La prueba de integración reconstruye el origen JSON exclusivamente en metis_desk_test, rechaza documentos y referencias incoherentes, conserva las instantáneas y contadores, comprueba restricciones de destinos y repite la migración después de simular un corte entre raíz y revisiones. También se ha ejercitado el arranque desde una base de pruebas vacía.
  • Base de desarrollo migrada e inicialización verificada. Auditoría del esquema: desaparecen las columnas values/procedure de los seis registros principales y existen las diez tablas relacionadas. Copia previa: /home/david/backups/metis-desk/20261010-133639-tickets-intervenciones.sql.
  • Los chequeos globales mantienen el error previo de locale en el calendario de shadcn/ui y errores de lint/formato en otros ficheros. No se modifica el código vendor ni cambios de interfaz realizados simultáneamente.

Verificación de cuentas, correo, accesos remotos, procesos y sesiones

  • Suite completa: 277 pruebas superadas; 3 pruebas de espaciado superadas.
  • Typecheck de servidor, identidad, compañías y recursos: correcto. Build: correcto.
  • Biome y ESLint sobre todos los ficheros modificados: correctos, sin avisos.
  • Integración HTTP/MariaDB desde una base de pruebas vacía: correcta. Se verifica transferencia del origen legado, rechazo de datos inválidos, conservación de valores actuales e históricos, UUID, orden, duración de cookies, CSRF, restricciones SQL e idempotencia, incluido un corte entre raíz e historial.
  • Base de desarrollo migrada, inicialización verificada y auditoría de esquema sin columnas JSON ni documentos serializados. Copia previa: /home/david/backups/metis-desk/20261010-140951-normalizacion-restante.sql.
  • El typecheck global mantiene el error previo de locale en el calendario vendor; lint/check global mantienen problemas de código y formato ajenos a estos cambios. No se modifica código vendor.