- Asociar entornos locales con activos y conservar su trazabilidad. - Registrar la cuenta de acceso del mapeo con historial de cambios. - Calcular cobertura documental específica sin alterar la cobertura general. - Añadir migraciones, validaciones, endpoints protegidos, pruebas y documentación.
18 KiB
Recursos compartidos SMB — pasos 3.1 y 3.2
Identidad y alcance
Una carpeta SMB es un Resource existente especializado, con el mismo UUID. Se reutilizan
template:shared_folder, field:unc, field:server y field:description. El nombre visible
es independiente de la UNC. La capacidad del recurso es network:smb-share y solo se
expone cuando existe una proyección válida; la clasificación de plantilla por stockKey
identifica el tipo esperado, no convierte un recurso antiguo en SMB.
No se incorporan publicadores, relaciones Asset–Resource, cuentas nuevas, resolutores de relaciones ni modificaciones de WorkProfile o FolderMapping. Los accesos reutilizan el modelo de permisos, necesidades y concesiones existente.
Dirección y normalización
field:unc es la única entrada editable. La presentación conserva mayúsculas, Unicode
y un separador final introducido por el usuario, después del trim exterior ya utilizado
por Resource. La clave de comparación elimina un único separador final y pliega solo
ASCII A–Z. No aplica NFC/NFKC, eliminación de tildes ni case folding Unicode.
Se admiten hosts NetBIOS, DNS e IPv4 como nombres documentales, comparticiones administrativas como C$, Unicode y espacios interiores en nombres de carpetas. No se resuelve DNS ni se identifica el publicador por el host o la IP.
Se rechazan rutas locales, URL, host/compartición vacíos, separadores repetidos,
segmentos . y .., caracteres de control, Unicode mal formado, nombres de segmento
con espacios exteriores o punto final, caracteres estructuralmente incompatibles,
UNC extendidas de dispositivo y direcciones con más de 255 unidades UTF-16.
IPv6 con dos puntos, URI SMB y hosts terminados en punto quedan fuera de v1.
La comparación conservadora considera equivalentes \\NAS\Docs y \\nas\docs, pero
no equipara \\nas\Docs con \\files.empresa.local\Docs, ni formas Unicode distintas.
Las variantes Unicode no ASCII pueden permanecer distintas aunque un servidor concreto
las trate como equivalentes: no inventamos una política de cotejo universal.
Raíz y subcarpetas
Se permiten rutas profundas por compatibilidad con el modelo UNC existente de Companies.
El contrato distingue host, shareName y relativePath; una ruta relativa vacía indica
la raíz de la compartición. Se recomienda registrar la raíz cuando se inventaría una
compartición y utilizar rutas más profundas en FolderMapping, pero no se invalidan
registros por contener subcarpetas. La unicidad corresponde a la dirección completa;
una raíz y una subcarpeta son direcciones distintas.
Persistencia e integridad
La migración idempotente migrateNetworkShares crea resource_network_shares, sin
rellenar registros anteriores. Se ejecuta después de las migraciones de Resources y
Dominios, cuyos índices compuestos de raíz y plantilla reutiliza.
resourceId CHAR(36) BINARY PRIMARY KEY
companyId CHAR(36) BINARY NOT NULL
templateId CHAR(36) BINARY NOT NULL
templateKey VARCHAR(100) NOT NULL -- fijo: template:shared_folder
protocol VARCHAR(10) NOT NULL -- fijo: smb
normalizedAddress VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL
activeAddress VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL
UNIQUE (companyId, activeAddress)
UNIQUE (resourceId, companyId)
FOREIGN KEY (resourceId, companyId, templateId)
REFERENCES resources(id, companyId, templateId)
FOREIGN KEY (templateId, templateKey)
REFERENCES resource_definitions(id, stockKey)
CHECK restringe protocolo, plantilla, dirección no vacía y coincidencia binaria entre
clave activa y normalizada cuando no es null. El código mantiene activeAddress igual a
la dirección canónica para activos y null para inactivos. MariaDB garantiza la unicidad
de las claves activas, incluso bajo concurrencia; no se depende de un SELECT previo.
El cotejo binario conserva diferencias Unicode y acentos.
La proyección no es otra entidad principal ni otro editor. No duplica dirección de presentación, host o shareName: se obtienen del campo UNC validado de Resource.
Transacciones, historial y ciclo de vida
El guardado existente valida nuevas carpetas y carpetas ya especializadas. Dentro de
una transacción escribe Resource, revisiones y proyección SMB. Un conflicto de índice se
traduce a SMB_ADDRESS_EXISTS y provoca rollback de todas esas escrituras, también de
la proyección access si existía. Una UNC inválida produce INVALID_SMB_ADDRESS.
Cambiar UNC o nombre conserva UUID y revisiones. Un guardado idéntico no añade revisión. Modificar solo notas/nombre/presentación no actualiza innecesariamente la proyección si la dirección canónica y el estado no cambian.
Desactivar conserva Resource, proyección e historial y libera la clave activa. Reactivar vuelve a adquirirla; un conflicto mantiene el recurso inactivo sin una revisión parcial. Las direcciones inactivas se pueden reutilizar.
Eliminar utiliza las protecciones anteriores y comprueba también referencias a la
proyección SMB. Si existen referencias actuales o históricas externas, devuelve
RESOURCE_IN_USE. Sin referencias, elimina los datos propios, incluida la proyección,
en la transacción existente. No conserva un historial separado tras un borrado físico
explícito: se mantiene la semántica anterior de Resource.
Catálogo
Renombrar plantilla/campos, cambiar etiquetas, iconos, secciones u orden no elimina la
capacidad. template:shared_folder debe conservar el campo de serie field:unc; quitarlo
produce SMB_FIELD_REQUIRED. El mecanismo anterior ya impide cambiar el tipo del campo.
No se modifica automáticamente la obligatoriedad del catálogo: el validador especializado
exige UNC para altas SMB aunque la característica siga figurando como opcional.
Deshabilitar disponibilidad por compañía impide altas nuevas, sin desespecializar los registros existentes. No existe una operación ordinaria de borrado físico de plantillas; las FK protegen la plantilla de los recursos especializados. La sincronización de especificaciones conserva las características y añade revisiones mediante el mecanismo existente; no altera la dirección ni la proyección por cambios de presentación.
Registros anteriores y diagnóstico
Los registros previos no se convierten automáticamente, incluso si su UNC es válida, al reiniciar, editar, activar/desactivar o sincronizar la plantilla. La distinción se basa en la presencia de la proyección persistida, no en fechas aproximadas.
GET /api/resources/:companyId/network-share-diagnostics, con la autenticación existente,
no acepta parámetros adicionales y devuelve solo identificadores y clasificación:
classification:shared-foldercierta por stockKey, olegacy-candidateheurística.addressStatus:valid,invalidomissing.duplicate: dirección canónica compartida por candidatos activos de esa compañía.managed: ya tiene proyección SMB.requiresConversion: todavía no tiene esa proyección.
La heurística para template:access busca una referencia o característica con prefijo
UNC. No usa nombres visibles, no declara capacidad y puede necesitar revisión humana.
No descubre carpetas escondidas en cualquier texto libre ni interpreta nombres de tipos
de acceso. El diagnóstico informa duplicados también entre candidatos, pero la restricción
SQL solo se aplica a recursos especializados; resolver legados queda fuera de 3.1 y 3.2.
El diagnóstico usa el inventario autorizado ya existente, no escribe ni incluye notas, credenciales o características completas. No modifica plantilla, integración ni historial, y no fusiona, elimina o sustituye recursos.
Contratos públicos y siguientes fases
ResourceDTO incluye networkShare opcional con capacidad, protocolo, dirección principal,
clave canónica, host, nombre compartido y ruta relativa. Es solo respuesta, no entrada.
@metis/resources/services exporta INetworkShareReader y NetworkShareReference.
resources.services.networkShares(transaction).find(companyId, resourceId) devuelve
Maybe de la referencia mínima con UUID, compañía y estado; comprueba la especialización
y la dirección persistida y bloquea la lectura para los futuros comandos de publicación.
El consumidor debe autenticar y autorizar el comando antes de usar el lector interno.
No expone repositorios ni introduce dependencias de Resources hacia Assets o Companies.
La integración access sigue teniendo contexto fijo. Una carpeta histórica sin integración
no puede incorporarla mediante edición ordinaria. Las nuevas carpetas reciben integración
automática según el paso 3.2 descrito más abajo; no se incorpora conversión histórica ni
se crean cuentas o una segunda ficha editable.
field:server sigue siendo documental y no se resuelve contra Assets.
Una modificación de UNC en un recurso integrado actualiza su proyección access mediante
el flujo existente. No reescribe UNC, letra ni historial de FolderMapping; una ruta vieja
sigue siendo detectable por las reglas de disponibilidad anteriores. permissionsCovered
no cambia y continúa siendo cobertura documental, no comprobación real de permisos.
Validación
- Resources: normalizador, equivalencias/no equivalencias, catálogo y diagnóstico.
- MariaDB: alta, edición, rollback, estados, concurrencia, FK, unicidad, lector, borrado, legado, access, dominios, recursos ordinarios, FolderMapping y contrato HTTP autenticado.
- Integración dedicada:
pnpm --filter @metis/server test:network-shares. - La prueba exige NODE_ENV=test y DB_NAME=metis_desk_test antes de conectar; limpia solo UUID de fixture y tablas auxiliares de referencias creadas por esa ejecución.
Las incidencias previas de dos textos de Companies y TS2375 en el calendario vendor permanecen fuera del alcance. Los resultados de validación de esta entrega se informan al finalizar, sin atribuir a esta fase pruebas que no se hayan ejecutado.
Resultados del paso 3.1
- Suite completa de Resources: 78/78.
- Integración combinada Dominios 2.1–2.4 y SMB 3.1: 27/27 casos nativos, solo metis_desk_test. Incluye 11 subcasos SMB y su contenedor.
- Typecheck de Resources, Assets, Companies, servidor y web: correcto.
- Biome y ESLint de los archivos afectados: correctos; build del servidor y
git diff --check: correctos. - Suite completa Companies: 171/173; se reproducen únicamente los dos fallos previos de texto en companies-page.test.tsx. No se modifican esas pruebas.
- Typecheck directo de vendor: reproduce TS2375 en calendar.tsx:165. No se modifica packages/shadcn-ui ni se oculta el error.
Comandos utilizados (PNPM requiere desactivar su verificación automática de dependencias antes de ejecutar en este entorno):
pnpm --config.verify-deps-before-run=false --filter @metis/resources --filter @metis/assets --filter @metis/companies --filter @metis/server --filter @metis/web typecheck
pnpm --config.verify-deps-before-run=false --filter @metis/server build
pnpm --config.verify-deps-before-run=false --filter @metis/server test:network-shares
Las suites completas de Resources y Companies se ejecutaron con todos los archivos de
sus scripts existentes, añadiendo --test-isolation=none para obtener los casos nativos.
La integración combinada se ejecutó con ese mismo flag y --test-concurrency=1 sobre
los cinco archivos directory-domains, asset-directory-memberships, typed-relationships,
windows-domains-ui y network-shares. Biome y ESLint se limitaron a los archivos afectados.
Paso 3.2 — integración automática con AccessWorkspace
Esta sección actualiza el comportamiento de las nuevas altas descrito para 3.1. El paso 3.2 no incorpora conversión, adopción ni migración de recursos anteriores. Cualquier adopción histórica requerirá un encargo independiente.
Alta y contexto
El servidor establece integration.kind=access, referencia field:unc y fija
systemId=null y environmentId=null. No deduce autenticación del host UNC, dominio
ni publicador. Un cliente que suministra buzón, otro campo/tipo o un contexto incompatible
recibe SMB_ACCESS_INCOMPATIBLE; omitir integración activa la configuración automática.
El tipo configurable de AccessWorkspace se obtiene por el UUID ya utilizado por otra carpeta de esa plantilla en la compañía. Así, renombrar el tipo no cambia las referencias. Para la primera carpeta, Companies reutiliza un tipo visible llamado «Carpeta compartida SMB» o crea ese tipo local usando el agregado y su auditoría habituales. Esta etiqueta solo selecciona un valor por defecto de catálogo: la capacidad SMB sigue dependiendo de stockKey y de la especialización, nunca del nombre. No se crean permisos, cuentas ni grupos. Un tipo existente inactivo no se reactiva silenciosamente.
No se añade una migración de esquema ni una clasificación paralela. El tipo se conserva por sus referencias UUID existentes; después de eliminar todas las carpetas, una primera alta vuelve a aplicar la selección de catálogo descrita.
Puerto transaccional y ownership
IResourceAccessWriter, exportado por @metis/resources/services, dispone de:
ensureSmbType: prepara el tipo de acceso para una nueva carpeta dentro de la transacción.project: recibe valores e identidades de Resource y sus revisiones, sin exponer su repositorio ni acceder al agregado de Companies desde Resources.
Companies implementa el puerto con ResourceAccessWriter, reutiliza writeAccessRow y
conserva el UUID de Resource y los UUID, actor, fecha y orden de sus revisiones. La
composición inyecta companies.resourceAccess(transaction) en Resources siguiendo
el patrón de DirectoryContextWriter. Resources no importa Companies: no aparece un ciclo.
La escritura de proyecciones access se ha trasladado de resource-compatibility a su módulo
propietario. Se conservan las consultas de referencias y las protecciones de eliminación
existentes, sin refactorizar globalmente AccessWorkspace.
Flujo atómico
- Bloquear catálogo de Resources, catálogo de accesos y compañía en el orden compartido.
- Solo para una nueva carpeta, preparar el tipo configurable dentro de la transacción.
- Validar datos y establecer integración en el servidor.
- Escribir Resource y sus revisiones.
- Escribir la proyección SMB y comprobar unicidad.
- Proyectar valores y revisiones en AccessWorkspace.
- Confirmar; cualquier fallo revierte también el tipo creado y ambas proyecciones.
ACCESS_PROJECTION_UNAVAILABLE indica que no se puede preparar el acceso; no se guarda
una nueva carpeta a medias si falta el participante de Companies. Las composiciones
que escriban recursos con integración access deben inyectar ese participante.
Renombrar, editar características/UNC y activar/desactivar reutiliza la misma proyección. No se cierran necesidades, concesiones ni configuraciones al desactivar. Las referencias actuales o históricas de acceso siguen impidiendo el borrado físico de Resource.
Interfaz y utilización
El formulario existente muestra ayuda traducida sobre acceso automático, configurado o
histórico. No ofrece selectores incompatibles de sistema, entorno o tipo para SMB.
El navegador sigue editando únicamente Resource; los endpoints antiguos de escritura
AccessItem(resource) continúan rechazados por RESOURCE_MOVED.
Cuentas y accesos permite crear permisos configurables, necesidades y concesiones para la carpeta, con las reglas existentes. Una misma carpeta puede recibir una concesión a un grupo AD y otra a una cuenta local NAS. La cobertura es documental: no autentica, comprueba ACL ni demuestra permisos efectivos SMB/NTFS.
WorkProfile y FolderMapping conservan su implementación, referencias, UNC registrada, letra de unidad, historial y cálculo de cobertura. El cambio de dirección del recurso no reescribe mapeos anteriores: sigue siendo detectable como desactualización.
Históricos y límites
El alta automática se decide por una operación nueva, no por la presencia de una UNC ni por una fecha. Leer, reiniciar, editar o activar una carpeta antigua sin integración no añade AccessItem ni cambia su contexto. También se conservan carpetas especializadas en 3.1 sin integración, y recursos anteriores bajo template:access.
No hay publicadores (3.3), identidades locales vinculadas a activos ni cambios de FolderMapping (3.4), pantallas de administración de carpetas (3.5), LDAP, credenciales, grupos anidados ni permisos efectivos. No se amplía el diagnóstico histórico.
Prueba dedicada: pnpm --filter @metis/server test:smb-access, exclusivamente contra
metis_desk_test. Comprueba integración, rechazos, sincronización, tipo renombrado, concesiones
AD/NAS, cobertura, borrado, rollback tras escribir accesos y ausencia de adopción histórica.
Verificación del paso 3.2
- Resources completo: 80/80, incluidos contrato automático, rechazo de contexto y ayuda es/en.
- MariaDB: 35/35 en la ejecución combinada de Dominios 2.1–2.4, SMB 3.1 y SMB Access 3.2. Solo metis_desk_test; incluye concesiones directas y por grupo, cobertura, rollback real después de escribir proyecciones, contexto renombrado y registros anteriores sin adopción.
- Typechecks de Resources, Assets, Companies, servidor y web: correctos.
- Biome, ESLint de los archivos afectados, build del servidor y git diff --check: correctos.
- Grafo de los 13 paquetes del workspace: sin ciclos.
- Companies completo: 171/173; permanecen las dos expectativas previas de texto en companies-page.test.tsx. Las pruebas de accesos incluidas en esa suite pasan.
- Se reproduce TS2375 en packages/shadcn-ui/src/components/calendar.tsx:165; vendor intacto.
La integración combinada usa NODE_ENV=test, DB_NAME=metis_desk_test, --test-isolation=none y --test-concurrency=1. Las comprobaciones completas de paquetes mantienen todos los archivos de sus scripts y añaden --test-isolation=none para obtener los casos del runner nativo. Este paso no añade migraciones, conversiones históricas ni pruebas de interacción en navegador; el cambio mínimo del formulario se verifica mediante SSR.
Publicador documental (paso 3.3)
La relación especializada, sus comandos e historial, las restricciones SQL y las consultas tipadas se describen en publicación de recursos compartidos SMB. Assets es su propietario y consume el lector SMB público de Resources; esta relación no modifica la integración de accesos descrita en este documento.