103 lines
14 KiB
Markdown
103 lines
14 KiB
Markdown
# 06 — Software, configuraciones y licencias
|
||
|
||
## Relaciones reales
|
||
|
||
**CONFIRMADO:** SoftwareInstallation vive en Companies, aunque la interfaz se abre desde un activo o puesto. ApplicationConfiguration también vive en Companies. Asset pertenece a Assets y WorkProfile a Companies. Las relaciones operativas conservan companyId obligatorio; Resource es un agregado separado. [softwareRead: sequelize-software-installation.repository.ts:27](../../../modules/companies/src/api/infrastructure/persistence/sequelize-software-installation.repository.ts#L27) [applicationRead: sequelize-application-configuration.repository.ts:34](../../../modules/companies/src/api/infrastructure/persistence/sequelize-application-configuration.repository.ts#L34).
|
||
|
||
```mermaid
|
||
erDiagram
|
||
COMPANY ||--o{ ASSET : posee
|
||
COMPANY ||--o{ RESOURCE : posee_hoy
|
||
COMPANY ||--o{ WORK_PROFILE : posee
|
||
ASSET ||--o{ SOFTWARE_INSTALLATION : documenta
|
||
RESOURCE ||--o{ SOFTWARE_INSTALLATION : software_resourceId
|
||
RESOURCE o|--o{ SOFTWARE_INSTALLATION : licencia_opcional
|
||
ASSET ||--o{ WORK_PROFILE : dispositivo
|
||
WORK_PROFILE ||--o{ APPLICATION_CONFIGURATION : configura
|
||
RESOURCE ||--o{ APPLICATION_CONFIGURATION : aplicacion_resourceId
|
||
SOFTWARE_INSTALLATION ||--|{ SOFTWARE_INSTALLATION_REVISION : historial
|
||
APPLICATION_CONFIGURATION ||--|{ APPLICATION_CONFIGURATION_REVISION : historial
|
||
```
|
||
|
||
No existe un FK de ApplicationConfiguration a «activo principal» del puesto: el perfil referencia un activo; el dashboard puede usar el ordenador de un puesto como contexto de presentación. No existe FK instalación–configuración ni obligación de crear una al dar de alta la otra. Un recurso puede aparecer en muchos equipos y perfiles. La misma pareja activo/recurso o perfil/recurso admite varios periodos cerrados, pero solo uno abierto mediante currentKey nullable unique. [softwareSQL: software-installation-migration.ts:6](../../../modules/companies/src/api/infrastructure/persistence/software-installation-migration.ts#L6) [applicationSQL: application-configuration-migration.ts:6](../../../modules/companies/src/api/infrastructure/persistence/application-configuration-migration.ts#L6).
|
||
|
||
## Contratos y persistencia
|
||
|
||
| Propiedad | SoftwareInstallation | ApplicationConfiguration |
|
||
| --- | --- | --- |
|
||
| Raíz | UUID, companyId, values, history | UUID, companyId, values, history |
|
||
| Destino fijo | assetId + resourceId | profileId + resourceId |
|
||
| Uso aceptado | application u os | application |
|
||
| Versión | string trim ≤100 o null | string trim ≤100 o null; solo delivery installed |
|
||
| Forma de uso | No delivery | installed o web |
|
||
| Licencia | licenseResourceId UUID o null | No campo de licencia |
|
||
| Estado | pending/configured/removal_pending/removed/never_configured | Mismo conjunto, evolución independiente |
|
||
| Notas | string trim ≤4000 o null | Igual |
|
||
| Historia | ID, actor, fecha, snapshot de valores | Igual; incluye delivery |
|
||
| Derivado | needsReview | needsReview |
|
||
|
||
Schemas fuente, sin interfaces DTO duplicadas: [softwareInput: software-installation-values.ts:5](../../../modules/companies/src/api/domain/software-installation-values.ts#L5) [softwareDTO: software-installations.ts:19](../../../modules/companies/src/common/software-installations.ts#L19) [applicationInput: application-configuration-values.ts:5](../../../modules/companies/src/api/domain/application-configuration-values.ts#L5) [applicationDTO: application-configurations.ts:20](../../../modules/companies/src/common/application-configurations.ts#L20). Persistencia: `software_installations`, `software_installation_revisions`, `application_configurations`, `application_configuration_revisions`; snapshots definen FK a assets/work_profiles/resources y licencia. Los hijos históricos conservan FKs a Resource, incluso cuando ya no está vigente en la raíz. [softwareFK: software-installation-snapshot.ts:7](../../../modules/companies/src/api/infrastructure/persistence/software-installation-snapshot.ts#L7) [applicationFK: configuration-snapshots.ts:57](../../../modules/companies/src/api/infrastructure/persistence/configuration-snapshots.ts#L57).
|
||
|
||
## Lectura y escritura backend
|
||
|
||
1. GET carga relaciones de compañía y revisiones, actores y contextos de activos/perfiles/personas/recursos. Comprueba referencias actuales; inconsistencias persistidas causan error, no omisión silenciosa.
|
||
2. POST valida schema en route, actor de sesión y UUID de compañía/id en UseCases. Mappers aplican políticas de pertenencia y elegibilidad; repositorio escribe raíz y solo revisiones nuevas bajo bloqueo de compañía.
|
||
3. Alta/reconfiguración pending/configured exige activo no retirado, recurso activo y tipo compatible; perfil/persona activos para configuración. Licencia nueva requiere activa y no caducada.
|
||
4. Edición mantiene la pareja; `sameTarget` rechaza cambiar producto o destino. Notas/retirada pueden seguir registrándose con referencias inactivas según reglas del mapper. Estados terminales se validan en dominio.
|
||
5. Igualdad semántica evita nueva revisión. `needsReview` se calcula al responder, no se almacena en Resource.
|
||
6. Eliminación de registro operativo elimina sus propias revisiones mediante acción explícita; eliminar Resource queda protegido por referencias actuales/históricas.
|
||
|
||
Evidencia: [profileInput: work-profile-values.ts:3](../../../modules/companies/src/api/domain/work-profile-values.ts#L3) [softwareMapper: software-installation-input.mapper.ts:15](../../../modules/companies/src/api/application/software-installation-input.mapper.ts#L15) [applicationMapper: application-configuration-input.mapper.ts:11](../../../modules/companies/src/api/application/application-configuration-input.mapper.ts#L11) [softwareResponse: software-installation-response.builder.ts:7](../../../modules/companies/src/api/application/software-installation-response.builder.ts#L7) [softwareRead: sequelize-software-installation.repository.ts:27](../../../modules/companies/src/api/infrastructure/persistence/sequelize-software-installation.repository.ts#L27) [applicationRead: sequelize-application-configuration.repository.ts:34](../../../modules/companies/src/api/infrastructure/persistence/sequelize-application-configuration.repository.ts#L34) [remove: remove-resource.ts:37](../../../modules/resources/src/api/infrastructure/persistence/remove-resource.ts#L37). Las reglas actuales no comprueban que una licencia concreta corresponda al producto seleccionado: no existe relación canónica licencia→aplicación que lo acredite.
|
||
|
||
## Flujo completo de selección actual
|
||
|
||
| Paso | Instalación | Configuración por perfil |
|
||
| --- | --- | --- |
|
||
| Apertura | SoftwareInstallationsPanel abre SoftwareInstallationEditorDialog | Página de configuraciones abre editor; perfil puede estar fijado |
|
||
| Carga | softwareApi + inventoryApi + catalogApi por compañía | profiles + inventoryApi + catalogApi; controlador del formulario |
|
||
| Candidatos | Recurso activo application/os o valor actual al editar | applicationOptions: plantillas builtin application o usage application; activo o seleccionado |
|
||
| Búsqueda | Opciones de SelectWithAction; la búsqueda del listado filtra instalaciones, no catálogo remoto | SelectWithAction con array local; no endpoint de búsqueda conjunta |
|
||
| Selección | resourceId; edición bloquea destino | resourceId y profileId; edición fija ambos |
|
||
| Alta rápida | SoftwareResourceCreateDialog con ResourceEditor initialKind os/application | ApplicationQuickEditor con ResourceEditor o editor de perfil |
|
||
| Validación | React Hook Form + Zod; backend política software | React Hook Form + Zod; backend política application |
|
||
| Guardado | softwareApi.save; invalida softwareKeys.company | applicationApi.save; invalida applicationKeys.company |
|
||
| Lectura posterior | Nombre por lookup en resources y enlace /companies/C/resources/ID | Nombre por lookup del inventario; ficha/historial |
|
||
| Historial | SoftwareHistoryDialog resuelve software y licencia por IDs | ApplicationHistoryDialog conserva versión, estado y delivery |
|
||
|
||
[softwareUI: software-installations-panel.tsx:26](../../../modules/companies/src/web/software-installations/list/ui/software-installations-panel.tsx#L26) [softwareForm: software-installation-form.tsx:19](../../../modules/companies/src/web/software-installations/shared/ui/software-installation-form.tsx#L19) [softwareQuick: software-resource-create-dialog.tsx:5](../../../modules/companies/src/web/software-installations/create/ui/software-resource-create-dialog.tsx#L5) [applicationForm: use-application-configuration-form-controller.ts:28](../../../modules/companies/src/web/application-configurations/shared/controllers/use-application-configuration-form-controller.ts#L28) [applicationOptions: application-configuration-form-values.ts:8](../../../modules/companies/src/web/application-configurations/shared/helpers/application-configuration-form-values.ts#L8) [applicationQuick: application-quick-editor.tsx:8](../../../modules/companies/src/web/application-configurations/create/ui/application-quick-editor.tsx#L8) [select: select-with-action.tsx:19](../../../packages/rdx-ui/src/components/select-with-action.tsx#L19).
|
||
|
||
**CONFIRMADO:** SelectWithAction compone Select de shadcn/Base UI y una acción adjunta; no hay input de búsqueda remota ni API asíncrona de candidatos en ese contrato. No afirmar que buscar Chrome ya esté implementado en este selector. Los listados operativos sí tienen filtros/búsqueda locales. El requerimiento de búsqueda conjunta necesitará adaptar la interacción, reutilizando primitivas existentes. La opción seleccionada debe seguir resolviéndose aunque no esté en la página de candidatos o haya quedado inactiva.
|
||
|
||
## Incorporar un Resource global
|
||
|
||
**DERIVABLE:** la FK por UUID simple puede apuntar al mismo global desde instalaciones/configuraciones de compañías distintas sin cambiar sus IDs. Deben cambiar la resolución pública de candidatos/referencias, políticas, mappers de Resource y nombres/enlaces frontend. No necesitan nullable en `software_installations.companyId` ni `application_configurations.companyId`, ni una columna scope en estos agregados. No duplicar producto por compañía.
|
||
|
||
Para conservar historia: no modificar revisiones antiguas ni recalcular sus versiones; los snapshots operativos contienen resourceId/version, no snapshot del nombre del producto. Renombrar Resource cambia el nombre resuelto en el historial operativo; su nombre anterior se consulta en historial de Resource. **PROPUESTO:** mantener esa semántica existente inicialmente; cualquier requisito de nombre de producto inmutable en cada revisión requeriría contrato adicional.
|
||
|
||
Inactivo global: mantener resolución por ID, bloquear nuevas asociaciones/reconfiguraciones que exijan activo, permitir notas y retirada, calcular revisión en cada compañía y excluirlo solo de candidatos nuevos. No retirar instalaciones, revocar acceso ni invalidar licencias automáticamente. El listado local de gestión no debe perder acceso a usados globales en ficha/historial.
|
||
|
||
## Licencias
|
||
|
||
**CONFIRMADO:** son Resource con `stockKey='template:software_license'` o `usage='license'`, no una entidad License agregada aparte. Seed incluye producto, edición, proveedor, modalidad, criterio, cantidad, referencia, caducidad, renovación, autorrenovación y descripción. La instalación referencia opcionalmente ese Resource; configuración de perfil no lo hace. [seed: resource-catalog-seed.ts:140](../../../modules/resources/src/api/domain/resource-catalog-seed.ts#L140) [usage: resource-inventory.service.ts:54](../../../modules/resources/src/api/application/resource-inventory.service.ts#L54) [softwareFK: software-installation-snapshot.ts:7](../../../modules/companies/src/api/infrastructure/persistence/software-installation-snapshot.ts#L7).
|
||
|
||
`softwareLicenseAvailable` comprueba active y expiresOn con fecha UTC inclusiva; expiresOn se resuelve por `field:expires`. No hay consumo de plazas, asignación a personas/cuentas ni asignación directa a la aplicación por FK. Cantidad y nombre de producto son datos documentales; no acreditan cobertura. No compartir licencia de A con B porque ambas usen Chrome global. Mantener licencia local y validarla por separado del resourceId global. [softwarePolicy: software-installation-policy.ts:5](../../../modules/companies/src/api/application/software-installation-policy.ts#L5) [service: resource-inventory.service.ts:7](../../../modules/resources/src/api/application/resource-inventory.service.ts#L7).
|
||
|
||
## Duplicados y adopción
|
||
|
||
| Estrategia | Evaluación |
|
||
| --- | --- |
|
||
| Coexistencia temporal global/local | Recomendación inicial: mismo nombre visible, IDs/origen distintos |
|
||
| Aviso de coincidencias normalizadas | Ayuda documental; no prueba identidad semántica ni licencia equivalente |
|
||
| Priorizar global en resultados | Posible orden por coincidencia y origen, decisión UX explícita; nunca reemplazar ID seleccionado |
|
||
| Relación local→canónico | Solo si aparece necesidad real de mapeo/adopción; entidad relacional y auditoría propia |
|
||
| Migrar referencias | Requiere comando específico: destinos son fijos, unicidad abierta puede colisionar; no sirve update ordinario |
|
||
| Reescribir historia o borrar locales | Rechazado como automatismo; preservar referencias históricas y FK |
|
||
|
||
No deducir identidad de mayúsculas, idioma, edición o nombre de fabricante. Una consolidación debe mostrar previamente referencias afectadas, conflictos de parejas abiertas, reversibilidad, responsables y resultado auditable. Véase R2.6 y decisiones D07/D08 en [10](10-plan-implementacion.md).
|
||
|
||
## Pruebas localizadas y ejecutadas
|
||
|
||
Dominio: Resource, SoftwareInstallation y ApplicationConfiguration; HTTP: resources.integration, software-installations.integration y applications.integration; web: resources.test.tsx, software.test.tsx y application.test.tsx. [unitResource: resource.test.ts:38](../../../modules/resources/src/api/domain/resource.test.ts#L38) [unitSoftware: software-installation.test.ts:52](../../../modules/companies/src/api/domain/software-installation.test.ts#L52) [unitApplication: application-configuration.test.ts:75](../../../modules/companies/src/api/domain/application-configuration.test.ts#L75) [integrationSoftware: software-installations.integration.ts:17](../../../apps/server/src/software-installations.integration.ts#L17) [integrationApplication: applications.integration.ts:18](../../../apps/server/src/applications.integration.ts#L18).
|
||
|
||
En esta auditoría pasaron el comando de test de Resources (11 archivos reportados por Node) y los dos archivos de dominio de software/aplicación. No se ejecutó HTTP/SQL, navegador ni datos masivos. Inspeccionar un test no equivale a ejecutarlo ni acredita soporte global, aún inexistente.
|