18 KiB
10 — Plan incremental posterior
Plan PROPUESTO, no ejecutado. Dependencias: R2.0 → R2.1 → R2.2 → R2.3 → R2.4/R2.5 → R2.6. Se puede preparar código de autorización/lectura antes de DDL, pero no activar ni crear productos globales hasta completar lectores y controles. El plan preserva los módulos, la identidad Resource y relaciones operativas separadas.
R2.0 — Cerrar contratos y pruebas de aceptación
- Objetivo: aprobar D01–D10 de 09, fijar invariantes, visibilidad y límites del catálogo. Resolver si todos los operadores continúan accediendo al espacio de soporte o se requiere ACL nueva por compañía.
- Áreas: documentación, schemas propuestos en Resources common, puertos públicos y composition roots de Identity/Resources/Companies/servidor.
- Dependencias/migraciones: ninguna migración para especificación y tests de políticas puras; ACL persistente requeriría diseño/migración aparte si se aprueba.
- Pruebas: matriz C/otra compañía/global; permisos globales; propósito application/software/license/operativo; inválidos e inactivos; pruebas de contrato antes de cambios.
- Riesgos: aprobar implícitamente permiso global o asumir adopción como licencia.
- Aceptación: cada decisión con responsable; endpoints/DTO y política de historial acordados, sin recursos ni datos globales creados.
R2.1 — Persistencia y ámbito
- Objetivo: ampliar Resource sin cambiar UUID ni compañías de datos legacy; mantener tablas normalizadas.
- Áreas: ResourceProps/ResourceValues según responsabilidad, mapper y InventoryRow, resource.model, resource-inventory-relational, resource-revision-specifications, prepare-resource-template-updates, remove-resource, ResourceDashboardReader; revisar directory/network/support constraints.
- Dependencias: D01/D02 y ensayo de esquema efectivo. Si A, introducir scope en raíz y esquema discriminado; si B, mismo alcance salvo columna/CHECK de par.
- Migraciones: scope + backfill company y companyId nullable; CHECK y constraints/índices necesarios, conservando FK company. Nada de NULL en relaciones operativas; no JSON ni reasignación de IDs.
- Pruebas: migración repetida e interrumpida por paso, filas legacy, combinaciones inválidas, FK operativa local, lectura de globales y revisión histórica, propagación de plantilla sobre globales/locales y campos retirados, rollback antes de activación.
- Riesgos: DDL con commit implícito, FK dependiente de índice/columna, lectores legacy, locks y recuentos con NULL.
- Aceptación: esquema ensayado en metis_desk_test; todos los datos anteriores siguen company con mismos IDs/revisiones; ninguna ruta permite crear global aún. Inventario SQL de constraints resultante documentado.
R2.2 — Autorización, contratos y resolución
- Objetivo: establecer visibilidad por propósito y restricción de escritura global antes de publicar catálogo.
- Áreas: Identity servicio/guard público, rutas Resource y catálogo de definiciones que afecte productos, Resources common/services, ResourceInventoryService o servicio nuevo con consumidor real, runtime, builders y API web.
- Dependencias: R2.0/R2.1; preservar contrato genérico list local. Definir serialización de validación/asociación con servicio público sin exportar ORM/repositorio.
- Migraciones: ninguna adicional si administrador inicial soporta permiso acordado; una ACL nueva no debe improvisarse como columna ajena a Resources.
- Pruebas: usuario normal rechaza alta/edición/status/delete global; revocación de sesión; por ID/lote no revela B desde C; global con plantilla/campo local se rechaza; integración operativa global se rechaza; global inactivo se resuelve pero no se ofrece; no IDOR en actualización/borrado/importadores futuros.
- Riesgos: solo ocultar botones, autorizar fuera del servicio o ampliar listado para todos, separar transacciones sin contrato de concurrencia.
- Aceptación: políticas probadas vía HTTP además de tests puros; error 403 correcto, sin nombres/SQL/stacks en denegaciones; clientes nuevos y legacy compatibles según contrato aprobado.
R2.3 — Catálogo global de aplicaciones
- Objetivo: crear/consultar/editar/desactivar Resource global con plantilla Aplicación y atributos de producto existentes.
- Áreas: Resources web por entidad/operación, global-catalog-content/shell de Companies, i18n es/en, rutas/servicios Resources, ResourceDetail y cache keys.
- Dependencias: permisos y resolución completos R2.2, prueba de nombre/duplicados globales, políticas de campos/historial.
- Migraciones: ninguna adicional usando name/provider/url/description/active. Categoría u otros metadatos requieren decisión explícita y no son prerequisite de primer catálogo.
- Pruebas: CRUD permitido/denegado, inmutabilidad de plantilla/ámbito, nombre concurrente, desactivación idempotente, borrado usado actual/histórico, búsqueda/orden/paginación/retorno; vista producto sin usos ajenos.
- Riesgos: confundir ResourceCatalog de plantillas con catálogo de productos; historial global con notas privadas; invalidación entre compañías.
- Aceptación: catálogo separado funcionalmente de plantillas, permisos de servidor, componentes existentes reutilizados, cero copias automáticas por compañía; pruebas visuales y evidencias según 08.
R2.4 — Selectores e instalaciones
- Objetivo: buscar globales y locales en una consulta y guardar instalación de compañía con application global.
- Áreas: servicio de candidatos/resolución Resources, software policies/mappers/repository, SoftwareInstallationsPanel/Form/History y editor rápido; fichas de activo/puesto/entorno y nombres/enlaces; SequelizeProcessRepository/ProcessReviewReader deben resolver los productos globales usados por configuraciones locales sin ampliar destinos de remoto.
- Dependencias: R2.2/R2.3. Antes de activar, lectura por referencia debe funcionar en todos los sitios, no solo el formulario.
- Migraciones: ninguna de instalaciones si se conservan resourceId y licencia local; no backfill de producto ni versión. Índices de candidatos solo si ensayo demuestra necesidad.
- Pruebas: C crea con global; rechaza local B aunque manipule ID; OS/soporte/licencia global rechazados; licencia local B rechazada; historial/licencia/estado/versiones independientes; inactive conserva notas/retirada; concurrencia deactivate/create; selección con búsqueda/página y homónimos; nuevo producto no asigna licencia.
- Riesgos: caché por compañía incompleta, consulta de historial para todo candidato, transacción anidada o lock order inverso, global convertido en target remoto.
- Aceptación: buscar Chrome encuentra global y local sin scope previo, guardar conserva ID global; activo/relación/licencia siguen locales; backend valida al guardar; el lector genérico de remoto/certificados sigue local.
R2.5 — Configuraciones por perfil
- Objetivo: reutilizar candidatos application y resolución, preservando perfil/instalación independientes.
- Áreas: application policies/mappers/repository, applicationOptions/form controller/form/quick editor, listados/historial, puesto y entorno.
- Dependencias: R2.2/R2.3 y contrato/composición compartida de selector R2.4. Puede desarrollarse tras R2.2 en paralelo de código, activación solo con catálogo y resolución listos; esta auditoría no delegó trabajo.
- Migraciones: ninguna de application_configurations; resourceId actual ya representa UUID del producto.
- Pruebas: application global en perfiles de C y B con distintas versiones/estado; perfil/activo/persona ajenos rechazados; web sin versión; destino fijo; parejas abiertas únicas; inactivo global, retirada, notas y nombres históricos; no instalación creada automáticamente.
- Riesgos: copiar filtro de software y admitir OS, descartar inactivos, perder contexto de perfil fijo o foco de modal padre.
- Aceptación: ambos flujos usan la misma política application; sus datos/versiones/historias siguen separados y no se propagan cambios operativos entre compañías.
R2.6 — Duplicados y adopción
- Objetivo: convivencia documentada y detección no destructiva de coincidencias; consolidación solo si se aprueba contrato separado.
- Áreas: Resources, políticas de identidad/destino de software/application, comandos de migración y auditoría, vistas de coincidencias.
- Dependencias: D07/D08, catálogo estable y pruebas de volumen. No es requisito para usar un catálogo nuevo sin migrar recursos previos.
- Migraciones: ninguna para coexistir/avisar por lectura. Asociación de adopción o equivalencias requeriría tabla normalizada con identidad y reglas propias, solo tras requisito. Reasignar referencias requiere estrategia de historia/colisiones aprobada, sin reutilizar update ordinario.
- Pruebas: productos homónimos diferentes, ediciones/fabricantes, colisiones de parejas abiertas, operación repetida sin duplicados, interrupción, rollback y preservación de UUID/historial/FKs.
- Riesgos: fusión por nombre, pérdida de trazabilidad, eliminación de local con referencias históricas.
- Aceptación: nunca borrado/fusión automático; resultado previsualizado y verificable, responsables y procedimiento de reversión. Sin consolidación aprobada, entrega final es coexistencia con origen explícito.
Registro de riesgos
Probabilidad no cuantificada: no hay telemetría ni ensayo global. La prioridad se basa en impacto y en precondiciones observables, no en porcentaje estimado. Cada riesgo incluye escenario y prueba pendiente.
| ID / severidad | Evidencia y escenario | Impacto | Mitigación / prueba |
|---|---|---|---|
| A01 Alto | authenticate único en catálogo global; operador normal lo edita catalogRoutes: resource-catalog.routes.ts:65 | Alteración masiva de definiciones/productos | Guard global R2.2; HTTP normal/admin y authVersion revocado |
| A02 Crítico condicionado | Sesión no aplica ACL por compañía auth: require-authenticated.ts:6 relationshipAuth: relationship-read-access.ts:7; despliegue presume aislamiento por operador | Lectura/escritura de otra compañía cambiando path | Acordar modelo compartido o ACL R2.0; pruebas de permisos reales, no solo IDs de referencia |
| A03 Crítico | Ampliar list para todo consumidor; remoteReferences acepta cualquier recurso remotePolicy: remote-connection-policy.ts:6 | Producto convertido en destino operativo o exposición no prevista | Servicio por propósito; pruebas negativas remoto/certificado/SMB/support y licencia ajena |
| A04 Alto | ResourceSchema/mapper exigen UUID compañía dto: inventory.ts:35 mapper: resource-persistence.mapper.ts:24 | Fallo de lectura general con NULL o campos strict nuevos | Contratos coordinados, gates de despliegue y tests cliente legacy/nuevo |
| A05 Alto | FKs compuestas/DDL directorySQL: directory-domain-migration.ts:5 supportSQL: support-migration.ts:86 | Migración bloqueada o integridad debilitada | Ensayo DDL paso a paso, reconstrucción de constraints y no NULL en hijos |
| A06 Alto | remove descubre FKs actuales/históricas remove: remove-resource.ts:37 | Borrado global usado causa pérdida o errores operativos | Mantener protección/locks y probar referencia solo histórica y carrera de alta/borrado |
| A07 Alto | Propagación enumera compañías propagation: prepare-resource-template-updates.ts:15 | NULL omitido/fallo al editar plantilla; cambios masivos parciales | Rama global, misma transacción, casos con campos nuevos/retirados |
| A08 Medio | Nombre no identifica producto; destino operativo fijo softwareMapper: software-installation-input.mapper.ts:15 applicationMapper: application-configuration-input.mapper.ts:11 | Duplicados y consolidación inválida | Convivencia, origen, comando explícito; pruebas de colisiones e idempotencia |
| A09 Medio | readInventory carga valores, especificación y toda historia read: resource-inventory-relational.ts:195 | Selectores pesados; memoria/latencia a volumen | Proyección paginada mínima, medir volumen/EXPLAIN R2.4 |
| A10 Medio | Lecturas seriales de servicios y filtros por cada recurso/revisión softwareRead: sequelize-software-installation.repository.ts:27 applicationRead: sequelize-application-configuration.repository.ts:34 | Cascadas y CPU repetida; posible N+1 al añadir getById por fila | Resolver lotes, no llamada por fila; prueba de número de consultas y tamaño de payload; N+1 global no medido hoy |
| A11 Alto | Cache keys solo locales e invalidación dirigida actual inventoryAPI: inventory-api.ts:11 invalidation: resource-related-query-keys.ts:4 | Estado/nombre/needsReview obsoletos en otras compañías o navegadores | Claves por propósito, invalidación global dirigida + refetch; prueba dos compañías y sesiones |
| A12 Alto | Lectura de recursos usa otra transacción softwareRead: sequelize-software-installation.repository.ts:27 service: resource-inventory.service.ts:7 | Validación active no atómica frente a desactivar | Unidad de consistencia/orden de locks; prueba concurrente desactivar/asociar |
| A13 Medio | Dashboard count y filas con inner join companies dashboard: resource-dashboard-reader.ts:15 | Total incluye globales mientras filas los omiten | Métrica explícita local/global; prueba global + locales con paginación |
| A14 Alto | Historial Resource incluye notas y actorName resourceDetail: resource-detail.tsx:11 dto: inventory.ts:35 | Exposición de notas internas u operadores, usos de otros clientes | Proyección de lectura mínima y prueba de ausencia de datos de B |
| A15 Alto | usage y plantilla fijos, estructura propagable definitionEntity: resource-definition.entity.ts:35 update: resource.aggregate.ts:100 | Cambio de clasificación/ámbito invalida datos usados | Mantener inmutabilidad, allowlist y pruebas de plantilla/campos locales en global |
| A16 Medio | Composición por servicios y SQL transversal en asistencia module: module.ts:39 supportRead: sequelize-support.repository.ts:21 | Frontera modular rota o globales filtrados accidentalmente en consumidores | Puertos públicos explícitos; pruebas de contratos/registro de relaciones y smoke de módulos |
| A17 Alto | companyId NULL en unique no asegura duplicado global; validación actual de nombres en memoria save: resource.use-cases.ts:64 | Altas globales duplicadas concurrentes o índice demasiado restrictivo | Definir semántica nombre/contexto y lock de catálogo; test concurrente; índice solo tras decisión |
| A18 Medio | Historial operativo guarda resourceId, no nombre de producto softwareDTO: software-installations.ts:19 applicationDTO: application-configurations.ts:20 | Cambio de nombre se ve retroactivamente; fusión confunde historia | Conservar historia de Resource; decisión explícita de snapshots y test de renombrado |
No se corrigen estos puntos en esta fase. Un riesgo condicionado no se presenta como vulnerabilidad explotada ni como resultado de pentest.
Validación y salida por fase
Reutilizar pruebas existentes de dominio/HTTP/UI y añadir comportamiento nuevo con global/local ajeno, inválidos, límites, inactivos, idempotencia y concurrencia. HTTP/SQL solo contra metis_desk_test desechable, sin semillas ni limpieza de bases reales. Pruebas visuales e integración de listados con 15 compañías y principal con al menos 50 personas/activos/recursos, más perfiles/puestos coherentes; unidades pequeñas como complemento.
Cambios transversales futuros: pnpm typecheck, pnpm lint, pnpm test, pnpm check, pnpm build, además de Playwright y ensayo de migración. Registrar fallos reales sin ocultarlos. En esta auditoría documental solo se ejecutaron las pruebas dirigidas y comprobaciones documentales descritas en 12.
Partes sin esquema: análisis/contratos, guard con privilegio existente aprobado, proyección de candidatos locales, UI de procedencia, resolución por lotes, invalidaciones y coexistencia/avisos. Ninguna habilita persistir un Resource global válido sobre el esquema actual NOT NULL.