Add visual UI/UX audit report for Metis Desk application

This commit is contained in:
David Arranz 2026-10-21 17:56:12 +02:00
parent 9b3363198c
commit e6f9fb6309
3 changed files with 645 additions and 0 deletions

View File

@ -84,6 +84,8 @@ Las fuentes normativas se consultan, no se duplican:
## Frontend
Antes de realizar tareas de frontend o UI/UX, consultar [DESIGN.md](DESIGN.md), referencia del sistema visual. Los patrones especializados siguen siendo normativos en su ámbito; comprobar las APIs de los componentes y los tokens reales antes de implementarlos. Las mejoras pendientes documentadas no se consideran implementadas. Validar los cambios visuales relevantes en navegador cuando sea viable, siguiendo el procedimiento de Playwright MCP.
Todo código web nuevo de módulos, entidades y operaciones debe seguir [la estructura web por entidades y operaciones](docs/estructura-web-por-entidades-y-operaciones.md): `modules/<module>/src/web/<entity>/<operation>/`, con ámbitos `shared` según sus consumidores e índices únicamente donde haya contenido exportable para otras unidades. Esta guía es la fuente normativa de la organización interna del frontend; no cambia las capas del servidor ni la implementación vendor.
React, TanStack Query, Tailwind y shadcn/ui (Base UI, estilo Vega). Los componentes propios compartidos viven en @repo/rdx-ui y reutilizan las primitivas vendor de @repo/shadcn-ui. TanStack Table y React Hook Form ya tienen consumidores; seguir los patrones existentes.

279
DESIGN.md Normal file
View File

@ -0,0 +1,279 @@
# Metis Desk — Sistema de diseño v1
Referencia del sistema visual para desarrollo frontend. Fecha: 21 de octubre de 2026.
Formaliza la identidad y los patrones existentes; no introduce un rediseño.
**Cómo consultarlo:** elegir el patrón de pantalla, consultar su documentación especializada y comprobar las APIs y tokens enlazados antes de implementar. **Vigente** identifica una decisión ya establecida; **implementado** describe una capacidad del código; **pendiente** identifica deuda o una decisión todavía no validada. Documentar un hallazgo no lo resuelve.
## 1. Propósito e identidad
Metis Desk organiza la información informática de compañías atendidas por un espacio de soporte: activos, personas, puestos, perfiles, recursos y sus relaciones. Las tareas prioritarias son localizar, consultar, comparar, relacionar y mantener esa información. Las personas de una compañía no equivalen a los usuarios internos de la aplicación.
El carácter visual actual combina superficies claras, tipografía Inter, acciones primarias rojas, navegación global verde oscuro con acento turquesa y componentes Base UI/Vega. Conservar esta identidad; priorizar densidad legible frente a decoración o grandes bloques vacíos.
Principios vigentes, derivados de [AGENTS.md](AGENTS.md) y de los patrones del proyecto:
- **Productividad:** dar prioridad a datos y acciones operativas; presentar ayuda e información secundaria con menor jerarquía.
- **Consistencia:** resolver casos equivalentes con los mismos componentes, conservando restricciones de cada entidad.
- **Jerarquía:** distinguir identidad, datos principales, características técnicas, relaciones, historial y acciones.
- **Accesibilidad:** semántica, teclado, foco y estados comprensibles; verificar las combinaciones visuales efectivas.
- **Capacidad del contenedor:** distribuir según el espacio disponible para la tarea, también con navegaciones y paneles simultáneos.
- **Evolución incremental:** extender soluciones existentes con consumidores reales; justificar excepciones.
## 2. Fuentes normativas, precedencia y capas
La precedencia de instrucciones es la de AGENTS: petición actual del usuario, AGENTS más cercano, AGENTS raíz y convenciones aplicables. Dentro del sistema visual:
| Fuente | Responsabilidad |
| --- | --- |
| [AGENTS.md](AGENTS.md) | Restricciones, arquitectura, disciplina, seguridad y validación del trabajo |
| Este DESIGN.md | Mapa de decisiones visuales, componentes, fundamentos y deuda conocida |
| [Listados](docs/patron-de-listados-de-entidades.md) y [diálogos](docs/patron-de-dialogos.md) | Fuentes normativas especializadas; prevalecen sobre un resumen general de este documento en su ámbito |
| [Componentes](docs/componentes-de-interfaz.md), [rutas](docs/rutas-del-cliente.md) y [estructura web](docs/estructura-web-por-entidades-y-operaciones.md) | Contratos de composición, navegación y organización |
| Tokens y componentes implementados | Valores efectivos y APIs reales; su existencia no convierte una desviación en pauta correcta |
| [Auditoría visual](docs/auditoria-ui-ux-visual.md) | Evidencias, escenarios comprobados y limitaciones; no prescribe por sí sola un nuevo diseño |
| Skills instaladas | Criterios complementarios, subordinados a las decisiones específicas de Metis |
Ante una contradicción, comprobar normativa especializada, consumidor y evidencia; identificar qué está obsoleto y corregir documentación dentro del alcance autorizado. No copiar una inconsistencia del código ni presentar una propuesta como implementada. Por ejemplo, el patrón exige altura estable aunque ciertos asistentes todavía no la aplican.
### Responsabilidades de implementación
| Capa | Qué contiene y cómo se consume |
| --- | --- |
| `packages/shadcn-ui` → `@repo/shadcn-ui` | Primitivas vendor, Base UI, estilo `base-vega`. **No modificar su implementación ni configuración**, salvo instrucción explícita del usuario. Consultar su API pública. |
| `packages/rdx-ui` → `@repo/rdx-ui` | Componentes propios genéricos, hooks y catálogo visual. Imports por componente, sin un barrel universal. No conocen DTO, endpoints, consultas ni reglas de negocio de Metis. |
| `modules/*/src/web` | Composición por entidad/operación; datos, permisos, reglas, traducciones y callbacks del dominio consumidor. |
| `apps/web` | Entrada de aplicación, coordinación de navegación y estilos globales. El shell concreto está compuesto actualmente desde `modules/companies`; no se traslada de capa por este documento. |
Preferir `children` y props semánticas explícitas. No construir un componente universal con numerosas combinaciones booleanas ni extraer componentes sin responsabilidad o reutilización real. Mantener APIs accesibles y documentadas. Fuentes de contexto: [configuración de la app](apps/web/components.json), [vendor](packages/shadcn-ui/components.json), [exports propios](packages/rdx-ui/package.json).
## 3. Fundamentos visuales implementados
### Color
El tema se importa desde `@repo/shadcn-ui/globals.css`. Las variables semánticas y sus utilidades Tailwind se definen en [globals.css del vendor](packages/shadcn-ui/src/styles/globals.css); las extensiones propias viven en [global.css de la aplicación](apps/web/src/global.css). Usar `bg-background`, `text-foreground`, `border-border`, etc., en lugar de repetir colores por pantalla. Los siguientes valores son **implementación actual**, no una nueva paleta ni una garantía de contraste:
| Token CSS | Claro | Oscuro |
| --- | --- | --- |
| `--background` | `oklch(0.9911 0 0)` | `oklch(0.1645 0.0086 274.3354)` |
| `--foreground` | `oklch(0.1763 0.0140 258.3572)` | `oklch(0.9911 0 0)` |
| `--card`, `--popover` | `oklch(1.0000 0 0)` | `oklch(0.2145 0.0184 270.4182)` |
| `--card-foreground`, `--popover-foreground` | Igual a foreground | Igual a foreground |
| `--primary`, `--ring` | `oklch(0.5882 0.2309 28.2936)` | `oklch(0.6453 0.2404 27.3106)` |
| `--primary-foreground` | `oklch(1.0000 0 0)` | `oklch(1.0000 0 0)` |
| `--secondary` | `oklch(0.3303 0.0753 267.1046)` | `oklch(0.2604 0.0471 267.4902)` |
| `--secondary-foreground` | `oklch(1.0000 0 0)` | `oklch(1.0000 0 0)` |
| `--muted` | `oklch(0.9674 0.0013 286.3752)` | `oklch(0.2739 0.0055 286.0326)` |
| `--muted-foreground` | `oklch(0.5517 0.0138 285.9385)` | `oklch(0.7118 0.0129 286.0665)` |
| `--accent` | `oklch(0.8342 0.0950 7.8239)` | `oklch(0.6986 0.1954 14.1660)` |
| `--accent-foreground` | `oklch(0.3155 0.1064 18.1157)` | `oklch(1.0000 0 0)` |
| `--destructive` | `oklch(0.3999 0.1641 29.2339)` | `oklch(0.3958 0.1331 25.7230)` |
| `--destructive-foreground` | `oklch(1.0000 0 0)` | `oklch(1.0000 0 0)` |
| `--border`, `--input` | `oklch(0.9197 0.0040 286.3202)` | `oklch(0.2739 0.0055 286.0326)` |
`--chart-1` a `--chart-5` y `--sidebar-*` están definidos en la misma fuente; no equivalen a estados de negocio. La navegación global utiliza los tokens propios `shell-*`, no los anchos genéricos de sidebar del vendor:
| Token propio, fuente `apps/web/src/global.css` | Valor y función |
| --- | --- |
| `--color-shell-sidebar` | `#0e282c`, fondo de navegación |
| `--color-shell-sidebar-top` / `-bottom` | `#0c252a` / `#102c30`, gradación del fondo |
| `--color-shell-sidebar-foreground` / `-muted` | `#f4f7f7` / `rgb(255 255 255 / 82%)`, texto |
| `--color-shell-accent` | `#00d2c1`, identidad del shell |
| `--color-shell-active-start` / `-end` | `rgb(0 188 177 / 40%)` / `rgb(0 128 130 / 45%)`, selección global |
| `--color-shell-header` / `-exterior` | `#fff` / `#000`, superficies propias |
| `--color-shell-content` | `var(--color-background)` |
| `--color-shell-navy` / `-muted-navy` | `#0c2850` / `#607895`, detalles del shell |
| `--color-shell-border` / `-search-icon` | `#d1d9e2` / `#1d3e6e` |
No existen aquí tokens globales propios `success` o `warning`. Los componentes actuales aportan sus representaciones; no inventar una API de tokens ni extender colores fijos a nuevas pantallas. La semántica de éxito y algunos colores fijos requieren revisión según la auditoría. El modo oscuro tiene tokens, pero no fue validado visualmente en esa auditoría.
### Tipografía y escala
Fuentes locales variables WOFF2, pesos 100–900, `font-display: swap`; [global.css](apps/web/src/global.css) sobrescribe las familias del vendor tanto en `:root` como en `.dark`:
| Utilidad | Familia y uso vigente |
| --- | --- |
| `font-sans` | Inter: interfaz general |
| `font-mono` | Geist Mono: código, identificadores y valores técnicos cuando corresponda |
| `font-serif` | Roboto Serif: contenido editorial puntual, no títulos generales de gestión |
No fijar ejes variables manualmente ni cargar fuentes remotas nuevas. El peso lo controlan las utilidades `font-*`. La escala efectiva combina Tailwind 4, overrides vendor y recetas propias; valores en px equivalentes con raíz de 16 px:
| Papel / fuente | Receta implementada |
| --- | --- |
| Texto general, controles y datos | `text-sm` = 0,875 rem; **`text-base` también se redefine a 0,875 rem** en `@theme` vendor. No asumir que base significa 16 px. |
| Ayudas y metadatos | `text-xs` = 0,75 rem; `FieldHelp` y `DetailField` conservan sus recetas |
| Cabecera de listado / identidad de activo | `text-2xl font-semibold` = 1,5 rem / 600, en `EntityListHeader` y `AssetDetailPage` |
| Título de modal | `text-lg font-bold` = 1,125 rem / 700, en `FormDialog` |
| Grupo de formulario | `text-xs font-semibold uppercase tracking-wide text-muted-foreground`, en `FormSectionTitle`; standalone añade `mb-4`, inline no |
| Encabezados HTML sin receta propia | Vendor h1–h6: 38/30/24/20/16/14 px, pesos 700/700/600/600/600/600; no reemplazan las recetas anteriores |
| Tracking base | `--tracking-normal: -0.02em`, vendor; conservar las variantes implementadas |
El nivel semántico de un encabezado no se elige por su tamaño. Reutilizar las recetas de [EntityListHeader](packages/rdx-ui/src/components/entity-list.tsx), [FormSectionTitle](packages/rdx-ui/src/components/form-section-title.tsx), [DetailField](packages/rdx-ui/src/components/detail-field.tsx) y [FieldHelp](packages/rdx-ui/src/components/field-help.tsx).
### Espacio, forma y elevación
- **Unidad:** `--spacing: 4px` en el tema vendor. En recetas existentes, gap-2/3/4/5/6 son 8/12/16/20/24 px. No convertir esta lista en un conjunto cerrado nuevo: copiar la receta del componente equivalente.
- **Contenido:** `CompanyDetail` usa p-4 y shell:p-6, 16/24 px; `FormDialog`, px-6 y py-5 en cabecera; `FormBody` conserva margen para el anillo de foco. Las separaciones específicas de grupos están en el patrón de diálogos.
- **Controles vendor:** [Button](packages/shadcn-ui/src/components/button.tsx) default h-9 = 36 px, sm 32 px, xs 24 px, lg 40 px; tamaños icon correspondientes. [Input](packages/shadcn-ui/src/components/input.tsx) h-9 = 36 px. No redimensionarlos independientemente por pantalla.
- **Radios vendor:** `--radius: 0.5rem`; sm/md/lg/xl/2xl/3xl/4xl derivan −4/−2/0/+4/+8/+12/+16 px: 4/6/8/12/16/20/24 px con raíz 16. `rounded-full` y los límites de variantes pequeñas conservan su función.
- **Radios propios:** `--radius-shell-control: 8px`, `--radius-shell-popover: 10px`, `--radius-shell: 20px`, `--radius-panel: 12px`; fuente global de la app.
- **Bordes:** usar `border-border`, `border-input` y opacidades de la receta. El diálogo efectivo añade `1px solid color-mix(in oklch, var(--foreground) 1%, var(--border))` en CSS de la app.
- **Sombras:** input/outline consumen `shadow-xs`; claro: `0px 4px 10px -2px hsl(0 0% 0% / 0.05)`, fuente vendor. La escala completa claro/oscuro vive allí. Shell popover: `0 3px 12px rgb(12 40 80 / 8%)`. La última regla global de diálogo aplica `0 24px 60px rgb(12 40 80 / 24%), 0 8px 18px rgb(12 40 80 / 14%), 0 0 0 1px rgb(12 40 80 / 8%)`; sustituye una regla anterior, no representa dos variantes intencionadas.
### Iconos y estados interactivos
Usar el [catálogo semántico propio](packages/rdx-ui/src/lib/icons.ts), basado en Tabler: Activos `BoxIcon`, Recursos `LayersIcon`, Personas `PersonIcon`, Puestos `MonitorIcon`, Perfiles `WorkProfileIcon`. Icono de entidad coherente en navegación, título y alta; título de listado 24 px, icono de Button 16 px por defecto. Decorativos con `aria-hidden`; acciones solo icono con nombre traducido y tooltip.
`apps/web/components.json` declara Tabler; el vendor conserva Lucide en su configuración e iconos internos. No migrar vendor ni importar bibliotecas de iconos directamente desde módulos.
Button ofrece default/outline/secondary/ghost/destructive/link. Conservar sus hover, expanded, disabled y focus-visible; disabled reduce opacidad y bloquea interacción. Input conserva ring de foco y estado inválido. `.app-link` usa primario, subrayado en hover y outline de 2 px con offset de 3 px en foco. Las combinaciones de selección deben comprobarse: V02 sigue abierto. No se añaden tokens ni variantes nuevas en esta versión documental.
## 4. Layout y navegación
Implementación representativa: [CompaniesWorkspace](modules/companies/src/web/workspace/view/ui/companies-workspace.tsx), [WorkspaceSidebar](modules/companies/src/web/workspace/view/ui/workspace-sidebar.tsx), [WorkspaceHeader](modules/companies/src/web/workspace/view/ui/workspace-header.tsx), [CompanyDetail](modules/companies/src/web/companies/detail/ui/company-detail.tsx).
| Medida / condición actual | Fuente |
| --- | --- |
| Sidebar global 228 px; contraída 72 px; inset 20 px | Tokens `--spacing-shell-*`, global.css app |
| Cabecera 88 px; búsqueda 41 px; navegación 48 px; avatar 35 px | Misma familia de tokens |
| Navegación de compañía 240 px en shell; contenido flexible | Grid de CompanyDetail |
| `shell: 768px`, `inventory: 1100px`, `dashboard: 1200px` | `--breakpoint-*`, global.css app |
| Panel de inventario `clamp(320px,24vw,400px)` con gap-6 | [AssetInventoryPage](modules/assets/src/web/assets/list/ui/inventory-page.tsx) |
| Detalle compacto hasta 1099 px | [useCompactDetail](packages/rdx-ui/src/hooks/use-compact-detail.ts) |
Estos son umbrales existentes, **no mínimos operativos validados para layouts futuros**. En móvil el shell se apila y la navegación de compañía precede al contenido; V01 demuestra pérdida importante de espacio útil. Queda pendiente diseñar y validar su compactación y la decisión tabla/panel por contenedor. No se fijan aquí nuevos breakpoints, drawers o anchos mínimos.
Usar [BrowserLink y rutas existentes](docs/rutas-del-cliente.md) para destinos reales; botones para acciones, selección local y modales. Conservar acceso directo, recarga, Atrás/Adelante, clic modificado y sección activa accesible. No inventar rutas de edición o fichas para entidades que no las tienen. Si el esquema narrativo de rutas queda desactualizado, contrastarlo con `workspace/shared/helpers/workspace-routes.ts`; no cambiar el modelo de negocio para adaptar una URL.
## 5. Patrones de listados
Fuente normativa: [patrón de listados](docs/patron-de-listados-de-entidades.md). Receta de partida: `EntityListHeader` + `EntityTable`, con acciones de fila y formularios en componentes independientes.
1. Cabecera: icono, título y subtítulo; alta a la derecha, adaptable al espacio.
2. Banda de búsqueda y filtros propios, con limpieza sin cambiar el ámbito de compañía/perfil.
3. Contador de resultados, Columnas y ordenación.
4. Tabla semántica; valores ausentes «—»; acciones fijadas a la derecha. Acción principal mediante icono, tooltip y nombre; secundarias en menú de tres puntos, sin duplicar la principal.
5. Rango repetido y paginación; filtros/tamaño ajustan página válida. No confundir cero resultados filtrados con falta de registros.
[EntityTable](packages/rdx-ui/src/components/entity-list.tsx) compone bandas, estados, contenido y controles; [useEntityTable](packages/rdx-ui/src/hooks/use-entity-table.ts) gestiona TanStack Table, orden, visibilidad y paginación **locales**. Nombre comienza ascendente salvo criterio explícito; comparación por idioma, sin tildes/mayúsculas y con cifras numéricas. Esto no describe el comportamiento de búsqueda: V07 sigue pendiente.
Columnas de inventario persisten con clave propia en localStorage; otros consumidores deben habilitar una clave explícita. Identificación y acciones no se ocultan. El selector extenso necesita revisión, V08. La búsqueda y ciertos filtros de rutas se conservan según su contrato; la restauración completa de orden/página no está implementada de forma general, V05. Cancelar un modal debe mantener contexto del listado.
Familias por plantilla usan `ScrollableTabsList`; `min-w-0` y scroll horizontal quedan dentro del listado. `onRowClick` solo selecciona desde zonas no interactivas, conservando enlaces, menús y controles internos. No añadir selección múltiple sin operación consumidora.
Para consultas **paginadas en servidor**, seguir [RemoteOptionPicker](packages/rdx-ui/src/components/remote-option-picker.tsx), `RemoteOptionList` y `CursorPagination`: el consumidor aporta página, búsqueda, estado y callbacks. No volver a paginar ni ordenar una página como si fuera el conjunto completo. No imponer paginación remota universal ni virtualización sin medir volumen y coste de los listados actuales.
## 6. Fichas de entidades
Referencia de composición: [AssetDetailPage](modules/assets/src/web/assets/detail/ui/asset-detail-page.tsx) y [WorkstationDetailPage](modules/companies/src/web/workstations/detail/ui/workstation-detail-page.tsx). La identidad incluye nombre, icono y metadatos relevantes; después, datos principales, características técnicas y relaciones. Conservar el ámbito y el retorno al listado.
- Reutilizar `DetailPanel`, `DetailSection`, `DetailField` y `TimeLine` desde rdx-ui cuando su contrato encaje. `DetailField` compone dt/dd; su consumidor mantiene dl y semántica adecuada.
- Información reúne datos y relaciones pertinentes; Historial presenta hechos registrados y sus fechas. No crear una pestaña por cada relación si el patrón existente los reúne en Información; no inventar historial donde no exista.
- Las relaciones con destino existente son navegables; los enlaces y acciones describen su destino real. Los componentes genéricos no resuelven reglas de pertenencia ni consultas.
- Edición explícita; acciones secundarias/destructivas agrupadas y con sus restricciones. Conservar las confirmaciones del dominio.
- El panel lateral es consulta contextual; la ficha completa y el diálogo compacto conservan su función. En el panel de activos, Accordion permite varias secciones abiertas (`multiple` de Base UI).
- No ocultar información o acciones útiles al resumir un grupo vacío. **Pendiente V10:** revisar la acumulación de grupos vacíos, títulos repetidos y explicaciones administrativas antes de decidir qué se pliega inicialmente.
## 7. Formularios, diálogos y asistentes
Fuente normativa: [patrón de diálogos](docs/patron-de-dialogos.md). Cada interacción modal con responsabilidad propia vive en su fichero; el padre aporta apertura, datos y callbacks. Reutilizar `FormDialog`, `FormBody`, `FormActions`, `FormStepActions`, `FormLabel`, `FormSection`, `FormSectionTitle`, `FieldHelp`, `FormHelp` y selectores existentes antes de crear estructuras equivalentes.
| Capacidad implementada | Uso y adopción pendiente |
| --- | --- |
| FormDialog small/medium/large | Desde sm: máximos 36 rem/48 rem; large 90vw con máximo 1200 px. Margen y altura máxima respecto a ventana. Consultar su [implementación](packages/rdx-ui/src/components/form-dialog.tsx). |
| `layout="stable"` | Para contenido variable, pasos, filtros y selecciones: altura `calc(100dvh - 2rem)`; desde sm, `min(85dvh,900px)`. Puestos/perfiles lo utilizan; activos/recursos todavía incumplen esta pauta, V03. |
| `layout="picker"` | Selector de altura estable; búsqueda inicial en input `data-quick-search`; tabla `layout="fill"`, selección primera y compacta, confirmación/cancelación de borrador. |
| `layout="content"` | Diálogos breves de contenido estable; es el default técnico, no la elección normativa para asistentes variables. |
| FormBody | Scroll interno, `min-h-0`, margen de foco; `contentLayout="fill"` distribuye alto restante y permite que EmptyState crezca por toda la cadena flex. |
| FormHelp | Hermano de FormBody antes de acciones, junto al pie; scroll propio y límite actual del 40 %. Su densidad en ventana corta requiere diseño adicional, V04. ContextHelp dentro del cuerpo no garantiza ese anclaje. |
| FormProgress | Paso actual, completados y anuncio con foco; falta ajustar etiquetas estrechas, V04. No simular navegación clicable si los pasos no la ofrecen. |
Etiquetas con `htmlFor`, obligatoriedad según contrato y un único indicador de `FormLabel`; campos optativos sin sufijo. Títulos de grupo uniformes; título y contador en fila usan `layout="inline"` e `items-center`. Secciones adaptadas a su contenedor; detalles de columnas, reordenación accesible y numeración pertenecen al patrón especializado.
Una fuente de verdad por campo; React Hook Form y schemas Zod según patrones existentes. Errores junto al campo o como error global según su origen, con asociación accesible para mensajes propios; no cerrar ni limpiar antes de confirmar guardado. La ayuda no rellena campos automáticamente; propuestas de nombre o selecciones únicas solo donde el contrato específico ya lo establece.
Conservar cabecera y acciones visibles, scroll del cuerpo y valores al retroceder. Guardar al final del asistente; impedir envíos duplicados. Cancelar/Escape/cierre descartan el borrador según la operación y restituyen foco al disparador; **V06** evidencia un consumidor que no lo cumple. No añadir manualmente primitivas de modalidad que Base UI ya resuelve.
En diálogos anidados, mantener borrador padre y foco de retorno; cancelar selección no modifica el padre. Un alta rápida guardada puede persistir aunque después se cancele el formulario principal: respetar su contrato, no tratarla como una selección provisional. No añadir niveles de anidación sin revisar los consumidores existentes.
## 8. Estados y comunicación
| Situación | Convención vigente / limitación conocida |
| --- | --- |
| Carga inicial | Mensaje de estado sin fingir vacío; reservar estructura cuando la integración lo permita. Activos aún desmonta controles, V12. |
| Actualización en segundo plano | TanStack Query gestiona estado remoto; conservar datos y controles disponibles. No duplicar la caché en estado local. |
| Sin registros / sin resultados | Distinguir primer registro de filtros sin coincidencias. Mantener CTA de alta o limpieza cuando proceda; EmptyState para incorporación de elementos en pasos. |
| Éxito | Confirmar solo tras respuesta satisfactoria. No equiparar color primario con éxito: FormFeedback mantiene una inconsistencia señalada en la auditoría, sin estado de éxito visual validado. |
| Error | Mensaje recuperable, contexto del campo/formulario/consulta y reintento pertinente; sin SQL, stacks ni secretos. |
| Advertencia / información | Usar componentes y textos existentes adecuados a la finalidad; explicación secundaria con ayuda contextual. No inventar un token global a partir de una apariencia aislada. |
| Selección | Estado visual y semántico además de color; en pickers distinguir borrador/confirmación. Revisar pareja de colores, V02. |
| Acción deshabilitada | `disabled` o contrato accesible de la primitiva, estado visible y restricciones conservadas; no ofrecer acciones que la operación no permite. |
| Valor ausente | En toda celda de listado/sublistado/PickerList, exclusivamente «—»; conservar 0 y false con su representación correcta. |
| Estado de negocio | Texto real como Inactivo o Sin puesto activo no equivale automáticamente a ausencia. «Sin asignar» puede ser placeholder de un selector; en una celda que solo carece de sede corresponde «—». V11 requiere revisar renderizadores. |
Textos de interfaz es/en mediante i18n; código e identificadores en inglés, documentación en castellano. Etiquetas breves para columnas/acciones, explicación en ayuda contextual. V09 señala una traducción explicativa reutilizada como cabecera; no debe convertirse en patrón. No deducir permisos ni estado de una entidad solo por color.
## 9. Accesibilidad verificable
Aplicar las obligaciones de AGENTS y de los patrones; comprobar comportamiento en navegador, además de JSX:
- Elementos semánticos, jerarquía de encabezados, nombres accesibles y asociación etiqueta/control. Iconos decorativos ocultos al lector; acciones de icono identificables.
- Teclado sin operaciones exclusivas de ratón/arrastre, orden DOM coherente, Tab/Shift+Tab, Enter/Espacio y Escape según la primitiva. No bloquear controles internos de filas.
- Foco visible sin recortes; inicial pertinente, contenido inválido accesible y retorno al origen al cerrar. PickerList busca por defecto. Verificar cada consumidor, no presumir cobertura general por usar Dialog.
- Validación HTML nativa conserva su semántica; su ausencia de `aria-invalid` no prueba un defecto. Para errores propios, asociar mensajes y estado al control, abrir grupos inválidos y diferenciar error global.
- Medir colores computados de texto/fondo efectivo y estados. Referencia [WCAG 2.2, 1.4.3](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html): 4,5:1 texto normal, 3:1 texto grande según su definición. V02: enlace de activo sobre selección ≈2,68:1, pendiente de corrección. Blanco sobre el botón primario medido ≈4,65:1; no extender el fallo a todos sus usos.
- Comprobar zoom 200/400 %, acceso a contenido/acciones, contraste de estados y respeto a movimiento reducido; conservar las variantes `motion-reduce` existentes. Estas comprobaciones, lector de pantalla y modo oscuro no se validaron completamente en la auditoría.
No declarar cumplimiento WCAG global a partir de tokens, snapshots, capturas o una muestra de contraste.
## 10. Responsive y densidad operativa
Vigente: distribución por contenedor para grupos de formulario, orden DOM conservado, acciones accesibles, nombres que puedan partirse y tabla desplazable dentro de su área. Los umbrales concretos de componentes como `TemplateMetadataSection` están en el patrón de diálogos; no son breakpoints globales nuevos.
- Escritorio amplio: mostrar datos comparables y paneles cuando quepan; evitar márgenes ornamentales y tarjetas sin función.
- Portátil/tablet: evaluar el ancho restante después de las navegaciones y el panel. Los 768/1100 px actuales no garantizan espacio operativo, V01.
- Móvil: contenido y acciones alcanzables sin desbordamiento global horizontal; la tabla puede tener scroll propio. La navegación compacta de compañía sigue por diseñar, sin imponer aquí una solución.
- Ventanas bajas: altura dinámica, cuerpo desplazable y pie visible; no reducir campos para hacerlos caber. El presupuesto de ayuda y la versión compacta de progreso siguen pendientes, V04.
- Formularios y tablas extensas: usar grupos/pestañas/componentes existentes; truncar solo con acceso al valor completo cuando sea necesario. La búsqueda del selector de columnas, V08, y el resumen de ficha, V10, requieren implementación o diseño adicional.
Ninguna propuesta de nuevo ancho, breakpoint, colapso inicial o token se considera decisión vigente por aparecer en la auditoría.
## 11. Verificación, calidad y deuda trazada
Procedimiento: [Playwright MCP](docs/playwright-mcp.md), [preparador sintético autenticado](scripts/visual-audit.py) y [auditoría visual](docs/auditoria-ui-ux-visual.md).
1. Identificar consumidores equivalentes, patrón, cambio esperado y datos necesarios. Consultar las skills instaladas pertinentes: frontend-design, shadcn, vercel-composition-patterns y vercel-react-best-practices; sus recomendaciones no autorizan modificar vendor ni regenerar el proyecto.
2. Reutilizar sesión/entorno sintético activo; si se prepara uno, seguir el procedimiento aislado y retirarlo al terminar. No usar bases reales, fixtures destructivas o guardar formularios sin autorización correspondiente.
3. Para cambios visuales relevantes, comparar antes/después en navegador cuando sea viable. Revisar carga/error/vacío, contenido largo, teclado, foco y contraste, con resoluciones representativas de la matriz: 1920×1080, 1440×900, 1366×768, 1024×768, 768×1024, 390×844 y 320×640; priorizar problemas y evitar capturas redundantes.
4. Esperar carga y transiciones antes de medir. Abrir los PNG: captura, snapshot, geometría y prueba funcional son evidencias distintas. Las capturas en `.artifacts/playwright/`, excluidas de Git, **no son evidencia portable por sí solas**: acompañar el informe con escenarios, medidas y un mecanismo explícito de entrega de imágenes sin secretos.
5. Ejecutar pruebas de comportamiento y comprobaciones apropiadas al alcance según AGENTS; cambios transversales de código requieren typecheck, lint, test, check y build. Para documentación, enlaces, tokens y diff bastan; informar lo ejecutado y lo pendiente, sin afirmar validaciones no realizadas.
Todos los hallazgos siguientes están **pendientes**; las mediciones detalladas y pasos viven en la auditoría:
| ID | Tipo y alcance | Próxima decisión o comprobación |
| --- | --- | --- |
| V01 | Diseño de layout/navegación + implementación | Diseñar por capacidad real; validar móvil, tablet y tabla/panel antes de fijar nuevos umbrales |
| V02 | Combinación de tokens/estados y consumidor | Corregir contraste de selección; medir pares efectivos y hover |
| V03 | Adopción de patrón existente | Aplicar estabilidad a asistentes de activos/recursos; probar pasos cortos/largos |
| V04 | Diseño de ayuda/progreso compacto + componentes | Acordar presupuesto de altura sin perder ayuda junto al pie; verificar 320×640 |
| V05 | Estado/navegación de implementación | Definir restauración completa por vista; orden reproducido, página de activos pendiente por datos |
| V06 | Integración de foco del diálogo | Reproducir y corregir retorno con Escape/Cancelar y distintos disparadores |
| V07 | Contrato de búsqueda y consumidores | Acordar normalización por idioma y probar tildes/ñ; no confundir con ordenación |
| V08 | Evolución del selector de columnas | Diseñar búsqueda/agrupación con API genérica; conservar preferencias |
| V09 | Etiquetas/i18n de listados | Separar cabecera breve de motivo explicativo y revisar casos equivalentes |
| V10 | Jerarquía de ficha | Diseñar resumen de vacíos y grupos sin ocultar relaciones/acciones; validar fixture poblada |
| V11 | Renderizadores y semántica de ausencia | Aplicar pauta de «—» distinguiendo estado de negocio |
| V12 | Carga inicial de implementación | Reservar estructura y mensajes precisos; probar recuperación y actualización |
La auditoría usó una compañía y un portátil. Faltan relaciones pobladas, fichas de otras entidades, todos los pasos de puesto/perfil, guardados positivos, rendimiento con volumen y comprobación de accesibilidad ampliada. Los riesgos detectados solo por código conservan esa categoría; no implican fallo visual demostrado.
## 12. Gobernanza y mantenimiento
- Antes de añadir componente, buscar equivalentes en rdx-ui y módulos. Extraer por responsabilidad/repetición real y documentar consumidores, props, accesibilidad y estados en [componentes de interfaz](docs/componentes-de-interfaz.md). Fuente: disciplina y frontend de AGENTS.
- Modificar un patrón en su documento especializado, revisar consumidores equivalentes y actualizar este mapa si cambia una decisión transversal. Documentar una excepción con motivo, alcance y verificación; no convertir una desviación accidental en variante.
- Añadir tokens solo ante una necesidad real no cubierta: nombre semántico, fuente, usos, pares/estados y contraste verificado. Las extensiones propias se implementan fuera de vendor. Esta v1 no crea tokens propuestos ni una escala paralela.
- Mantener APIs coherentes y revisar consumidores al cambiarlas; no introducir compatibilidad hipotética, flags universales o duplicación de estado remoto. Fuente: contratos de AGENTS y composición de componentes.
- Incorporar hallazgos con su estado, reproducción y evidencia. Marcar resuelto únicamente después de implementar y verificar; actualizar auditoría/trazabilidad sin borrar las limitaciones históricas.
Fuentes de esta versión: normas y código enlazados, las cuatro skills indicadas y la auditoría del 21 de octubre de 2026. Se volvieron a inspeccionar sus capturas conservadas de Activos en escritorio y Nuevo puesto a 320 px como referencia documental. No se inició otra aplicación ni se repitieron las pruebas de navegación para redactar esta v1.

View File

@ -0,0 +1,364 @@
# Auditoría UI/UX visual de Metis Desk
Fecha: 21 de octubre de 2026. Referencia del repositorio: `9b33631`.
Auditoría diagnóstica sobre Chromium headless mediante Playwright MCP. No se han modificado componentes, estilos, código de negocio, dependencias ni `packages/shadcn-ui`. Este documento no constituye una certificación de accesibilidad.
## 1. Resumen ejecutivo
La aplicación tiene una base visual reconocible y bastante consistente: navegación por compañía, cabeceras con iconos, tablas con acciones explícitas, formularios modales, secciones plegables y ficha de activo con Información e Historial. Conviene corregir sus puntos débiles extendiendo los componentes existentes de `@repo/rdx-ui`, sin incorporar otro sistema de diseño.
Las prioridades observadas son:
1. Recuperar espacio útil en móvil y tablet: la navegación precede al contenido con una altura excesiva en móvil; en 768 px las dos barras laterales dejan unos 251 px para trabajar.
2. Corregir el contraste del enlace del activo sobre la fila seleccionada: aproximadamente **2,68:1**.
3. Estabilizar los asistentes de activos y recursos: su ventana cambia de altura entre pasos, aunque el patrón documentado exige estabilidad.
4. Reducir el espacio que consumen la ayuda y el progreso en modales pequeños, conservando la ayuda junto al pie.
5. Conservar la ordenación al volver de una ficha y devolver el foco al disparador al cerrar el alta de activo mediante Escape.
También se confirman dificultades menores de búsqueda sin tildes, selección entre muchas columnas y textos demasiado largos en cabeceras de revisión.
La cobertura funcional está limitada por los datos disponibles: una compañía y un portátil, sin personas, sedes, puestos, perfiles ni recursos registrados. Se han inspeccionado esas pantallas vacías y sus formularios disponibles; **no se han validado sus fichas pobladas, relaciones reales ni guardados satisfactorios**.
## 2. Alcance, preparación y método
### Entorno realmente utilizado
- Se comprobó que no existía una sesión desechable activa. El usuario autorizó expresamente una única ejecución de `python3 scripts/visual-audit.py`.
- Se reutilizó la sesión privada producida por esa ejecución durante toda la auditoría. No se crearon otros entornos de aplicación ni usuarios adicionales a los del preparador.
- La preparación verificó el formulario real de acceso, la identidad de usuario ordinario, el rechazo de administración de usuarios, el listado, la ficha, un diálogo cancelado y la reutilización de sesión desde otro contenedor MCP.
- Compañía: «Auditoría visual — Datos sintéticos». Activo: `AUDIT-PORT-01`, plantilla Portátil, operativo, sin sede ni puesto.
- Playwright MCP Docker fijado en `.codex/config.toml`: distribución `v0.0.83`, digest `sha256:690763cbb437ee7233f538a953bb5390bf03791eb5c965b471e59d17a6132fcb`.
- Se utilizó el cliente stdio del comprobador existente para invocar las herramientas reales de MCP. En esta sesión de agente no estaban expuestas directamente como herramientas de navegador. No se atribuye esta prueba a una carga nueva de herramientas en la extensión o Desktop de Codex.
- Servicios de desarrollo y base aislados, con puertos efímeros; no se accedió a datos de compañías reales. Las rutas de este documento omiten el origen temporal.
Las capturas son de viewport, en píxeles CSS. Se combinaron navegación, snapshots accesibles, geometría DOM, teclado, estado de controles y revisión de PNG abiertos explícitamente. Las comprobaciones de red se describen como simulaciones y no como fallos espontáneos del servidor.
### Fuentes y skills consultadas
Se consultaron `AGENTS.md`, [patrón de diálogos](patron-de-dialogos.md), [patrón de listados](patron-de-listados-de-entidades.md), [componentes de interfaz](componentes-de-interfaz.md), [rutas del cliente](rutas-del-cliente.md) y [procedimiento Playwright](playwright-mcp.md). No se localizó un `DESIGN.md` del proyecto.
| Skill leída | Ruta | Aplicación en esta auditoría |
| --- | --- | --- |
| frontend-design | `.agents/skills/frontend-design/SKILL.md` | Jerarquía, tipografía, espacio, claridad de acciones, densidad y revisión mediante capturas. Sus recomendaciones estéticas se subordinan al producto empresarial existente. |
| shadcn | `.agents/skills/shadcn/SKILL.md` | Composición, controles semánticos, títulos de modales, validación, tokens y diferencias Base UI/Radix. Se consultaron las referencias de formularios y Base UI. |
| vercel-composition-patterns | `.agents/skills/vercel-composition-patterns/SKILL.md` | Recomendaciones de reutilización por responsabilidad y composición; referencia sobre proliferación de props booleanas. |
| vercel-react-best-practices | `.agents/skills/vercel-react-best-practices/SKILL.md` | Separación entre estado derivado y persistente, consultas y riesgos de volumen; referencia sobre estado derivado sin efectos. No se trasladan recomendaciones de Next.js a Vite automáticamente. |
`ui-ux-pro-max` y `web-design-guidelines` no estaban disponibles. No se instalaron skills ni bibliotecas. La pauta genérica de evitar mayúsculas no sustituye el `FormSectionTitle` normativo; tampoco se propone sustituir los wrappers propios por otro catálogo de componentes.
### Revisiones anteriores
Se contrastaron los hallazgos recuperables del contexto de las auditorías anteriores. **No se localizaron los dos informes UI/UX originales como archivos versionados**; los documentos de auditoría existentes en `docs` tratan infraestructura, UniFi, cliente o auditoría centralizada. La comparación de la sección 6 no pretende reconstruir contenidos ausentes ni garantizar trazabilidad exhaustiva contra esos dos originales.
## 3. Matriz de pantallas y resoluciones
Leyenda: **M** = navegación y medición del layout mediante MCP; **C** = además se conserva captura. Una C no significa ausencia de problemas. Se priorizaron imágenes de escritorio, anchuras estrechas y escenarios con incidencias. Las imágenes citadas en los hallazgos se abrieron para su inspección.
| Pantalla | 1920×1080 | 1440×900 | 1366×768 | 1024×768 | 768×1024 | 390×844 | 320×640 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Dashboard | M | C | M | C | M | C | C |
| Compañías | M | C | M | C | M | C | C |
| Resumen de compañía | M | C | M | C | M | C | C |
| Listado de activos | C | C | C | C | C | C | C |
| Ficha de activo, Información | M | C | M | C | M | C | C |
| Personas, vacío | M | C | M | C | M | C | C |
| Puestos, vacío | M | C | M | C | M | C | C |
| Recursos, vacío | M | C | M | C | M | C | C |
| Catálogo global de activos | M | C | M | C | M | C | C |
Son **63 combinaciones de pantalla y tamaño** en la matriz principal. La segunda pasada esperó a las fuentes y a las animaciones finitas tras redimensionar, para evitar interpretar geometría transitoria como un defecto.
Cobertura adicional:
| Área | Comprobación ejecutada | Límite |
| --- | --- | --- |
| Panel lateral de activo | Apertura por celda, escritorio 1920/1440/1366/1100; paso a diálogo compacto en 1024; apertura móvil en 390 | Un único activo, sin interfaces o conexiones registradas |
| Alta de activo | Pasos 1–3, plantilla Portátil; capturas de cada paso en 1440 | Sin guardado positivo |
| Alta de recurso | Pasos 1–3, plantilla Aplicación; capturas de cada paso en 1440 | Sin recurso creado |
| Alta de puesto | Paso 1 en escritorio y móvil; medición estable en 1440/1366/1024/768/390/320 | Sin sedes: no se avanzó a pasos 2–4 |
| Alta de perfil | Paso 1 y selector de puestos, búsqueda enfocada, Tab/Shift+Tab/Escape | Sin puestos: no se avanzó a pasos 2–4 |
| Nueva compañía, persona y activo; editar activo | Apertura y cancelación; capturas en 1440/1366/390/320 | No todos los campos o condiciones posibles |
| Editor de plantilla de activo | Portátil global: apertura, títulos, contadores y filas; apertura nueva en 320 | No se guardó ni probó reordenación persistida |
| Catálogo de recursos | Listado de compañía con nueve plantillas en 1440 | No se abrió su editor de plantilla en esta auditoría |
| Infraestructura, sedes, departamentos | Pantallas vacías en 1440 | Sin fichas pobladas |
| Cuentas y accesos | Pantalla inicial Cuentas en 1440 | No se recorrieron todas las subpestañas ni sus formularios |
| Carpetas, aplicaciones, impresoras, certificados, correo | Listados de configuración vacíos en 1440 | Sin permisos, cuentas, publicaciones ni perfiles relacionados |
| Accesos remotos, teletrabajo, procesos | Listados vacíos en 1440 | Sin recorridos de detalle o ejecución |
| Administración de usuarios | Ruta `/settings/users`: acceso denegado al usuario ordinario | No se auditó su interfaz administrativa |
No se auditó cada ruta existente ni cada combinación de campos. Las resoluciones son viewports de Chromium de escritorio: no equivalen a dispositivos táctiles reales, Safari, teclado virtual o pruebas de orientación en hardware.
## 4. Evaluación visual y funcional
### Lo que funciona en los escenarios ejecutados
- Las cabeceras de entidades mantienen icono, título y acción reconocibles; las tablas conservan bandas de búsqueda, controles, resultados y paginación.
- Activos distingue «sin resultados para estos criterios» del listado poblado. Los demás listados muestran mensajes de ausencia de registros sin inventar datos.
- El nombre del activo abre su ficha y esta ofrece Información e Historial. Se abrió el historial y se vio el evento real de creación sintética.
- Las pestañas de plantilla se desplazan dentro de su franja; no se observó ensanchamiento global del documento en la matriz principal. La tabla puede ser más ancha que su contenedor y desplazarse horizontalmente: eso se distingue del desbordamiento de toda la página.
- El panel de activo permite varias secciones abiertas a la vez. A anchuras compactas aparece un diálogo en lugar del panel lateral.
- Cancelar la edición conserva búsqueda y plantilla. Tanto Atrás del navegador como «Volver a activos» recuperaron la búsqueda probada.
- La selección de columnas se guarda en `asset-inventory-columns`. Tras marcar Notas y recargar, la cabecera Notas seguía presente; se comprobó el contenido, sin confundirlo con la flecha de ordenación.
- El catálogo de activos pasó de las filas 1–10 a 11–12 de doce plantillas mediante Página 2.
- El selector de puestos abrió la búsqueda como foco inicial; Shift+Tab/Tab permanecieron en el selector y Escape devolvió el foco a «Seleccionar puesto» del formulario padre.
- La validación de Nombre vacío en persona y edición de activo impidió la petición de escritura. Se vio el aviso nativo de Chromium y el foco en el control. El navegador muestra ese mensaje nativo en inglés: no se presenta como traducción del sistema i18n de Metis.
- El alta de puesto conservó una altura exterior de 765 px en 1440×900 y aproximadamente 653 px en 1366×768, adaptándose a la ventana. No se pudieron contrastar cambios de paso por falta de sede.
- El editor de plantilla abierto directamente en 320×640 mantuvo un modal de 288×608 px, cuerpo desplazable y acciones visibles. Título Campos y contador aparecieron alineados en escritorio.
### Jerarquía, tipografía y densidad
La tipografía y la separación entre cabecera, grupos y campos resultan legibles en escritorio. El sistema usa Inter, tokens semánticos y un catálogo propio de iconos; no necesita otra familia visual para resolver las incidencias observadas.
La densidad operativa empeora por tres factores concretos: navegación que consume ancho o altura antes de los datos, columnas con frases explicativas completas y ayudas extensas siempre visibles. En el dashboard, la lista de situaciones reserva altura también para contadores cero; es una oportunidad de compactación, no un error funcional demostrado.
En el portátil, los ejemplos de Marca y Modelo enumeran fabricantes y modelos de tipos muy distintos. En el paso 2 ocupan más espacio que sus controles. Conviene ofrecer ejemplos adecuados a la plantilla y desplegar el detalle secundario, manteniendo visibles finalidad y formato esperado.
### Accesibilidad: comprobaciones y límites
Se revisaron controles etiquetados, snapshots accesibles, estado de ordenación, foco inicial, navegación parcial por teclado, cierre y contraste de una muestra. El aviso nativo de campo requerido utiliza la semántica de validación HTML; la ausencia de `aria-invalid` en ese caso, por sí sola, no demuestra inaccesibilidad.
En la muestra medida, blanco sobre el botón primario dio aproximadamente **4,65:1**. El mismo primario sobre el fondo de selección dio **2,68:1**: no alcanza el umbral de 4,5:1 para texto normal de [WCAG 2.2, contraste mínimo](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html). Se tomaron colores computados, convertidos a sRGB mediante canvas y luminancia relativa; no se dedujeron colores de píxeles suavizados de la captura. Esta comprobación puntual no valida el resto de tokens ni el cumplimiento global de WCAG.
No se ejecutaron lector de pantalla, auditoría automatizada completa de accesibilidad, zoom del navegador al 200/400 %, contraste de todos los estados, alto contraste del sistema, modo oscuro o reducción de movimiento completa.
## 5. Hallazgos priorizados
Gravedad alta: perjudica de forma importante la lectura o el trabajo en la situación indicada. Media: genera pérdida de contexto, esfuerzo recurrente o inconsistencia de interacción. Baja: detalle de presentación o mantenimiento. No se han demostrado pérdida de datos ni bloqueos generales en escritorio.
### V01 — El layout reserva demasiado espacio a la navegación
**Alta · Confirmado visualmente y funcionalmente.** Pantallas de compañía, especialmente Activos.
- **Resoluciones:** 390×844 y 320×640; también 768×1024. El panel agrava el espacio reducido desde 1100 px.
- **Reproducción:** abrir Activos con navegación expandida. En móvil, recorrer la navegación hasta alcanzar el listado; en 768 px observar las dos barras laterales. En escritorio abrir el panel pulsando una celda no interactiva de la fila.
- **Resultado:** con layout asentado, el `main` comienza aproximadamente en y=1430 en 390 y en y=1496 en 320. En 768 quedan unos 251 px de contenido. Con panel abierto en 1100, la tabla dispone de unos 237 px: gran parte de sus columnas queda fuera de la vista simultánea.
- **Evidencia:** [móvil inicial](../.artifacts/playwright/ui-audit/assets-390.png), [contenido tras desplazamiento](../.artifacts/playwright/ui-audit/assets-scrolled-390.png), [tablet](../.artifacts/playwright/ui-audit/assets-scrolled-768.png), [panel a 1366](../.artifacts/playwright/ui-audit/asset-panel-1366.png). Mediciones en `results-responsive.json` y `results-panels.json`.
- **Responsables:** `CompanyDetail`, shell de navegación, `AssetInventoryPage`, `useCompactDetail`; umbrales `shell` e `inventory` de `apps/web/src/global.css`.
- **Recomendación:** acordar una navegación compacta de compañía en móvil, manteniendo contexto y sección activa; permitir contraer o superponer la secundaria en tablet. Decidir la convivencia tabla/panel por ancho real disponible, no solo por viewport. Conservar el desplazamiento de tabla y las acciones ancladas.
### V02 — El enlace pierde contraste en la fila seleccionada
**Alta · Confirmado visualmente y mediante medición.** Inventario de activos con panel abierto.
- **Resoluciones:** observado en escritorio, incluidas 1440×900 y 1366×768; medición en 1440.
- **Reproducción:** pulsar Plantilla u otra celda no interactiva de `AUDIT-PORT-01`, dejando seleccionada la fila.
- **Resultado:** enlace `rgb(230,25,25)` sobre fila `rgb(255,175,189)`, aproximadamente 2,68:1. El enlace es texto de 14 px, no texto grande.
- **Evidencia:** [fila seleccionada](../.artifacts/playwright/ui-audit/asset-panel-1366.png), colores en `results-verify.json`.
- **Responsables:** `selectedRowClass` y enlace de nombre de `inventory-page.tsx`, tokens primario/acento.
- **Recomendación:** definir el par de colores para contenido interactivo seleccionado; comprobar también hover y acciones fijadas. No corregirlo cambiando solo el rojo global, cuyo botón blanco supera el umbral medido.
### V03 — Los asistentes de activos y recursos cambian de altura
**Media · Confirmado visualmente y funcionalmente.** Alta de activo y alta de recurso.
- **Resolución reproducida entre pasos:** 1440×900.
- **Reproducción:** Nuevo activo → Portátil → Siguiente → Siguiente. Repetir Nuevo recurso → Aplicación → Siguiente → Siguiente. Cancelar.
- **Resultado:** activo pasa de unos 615 px a 868 px; recurso de 615 a 797 y 777 px. Se desplazan cabecera y pie. La estabilidad de puestos no se ha trasladado a estos asistentes.
- **Evidencia:** [activo paso 1](../.artifacts/playwright/ui-audit/asset-wizard-step1-1440.png), [activo paso 2](../.artifacts/playwright/ui-audit/asset-wizard-step2-1440.png), [recurso paso 2](../.artifacts/playwright/ui-audit/resource-wizard-step2-1440.png); `results-deep.json`.
- **Responsables:** `AssetEditorDialog`, `ResourceEditorDialog`, sus formularios y `FormDialog`. El primero omite `layout`, cuyo valor por defecto es `content`.
- **Recomendación:** aplicar `layout="stable"` en ambos asistentes y mantener cuerpo desplazable. Reutilizar `FormHelp` junto al pie donde corresponda, conservando campos y reglas de cada entidad.
### V04 — La ayuda fija y el progreso reducen demasiado el cuerpo en móvil
**Media · Confirmado visualmente.** Nuevo puesto y nuevo perfil.
- **Resoluciones:** especialmente 320×640; en 390×844 ya se necesita desplazamiento adicional.
- **Reproducción:** abrir Nuevo puesto o Nuevo perfil sin completar el primer paso.
- **Resultado:** en 320 la ventana ocupa 608 px, pero el cuerpo de puesto dispone de unos 197 px. La ayuda ocupa una franja separada hasta el pie. Sede queda debajo del primer encuadre del cuerpo. Las etiquetas «Ordenador principal» y «Resumen» del progreso llegan a juntarse.
- **Evidencia:** [puesto 320](../.artifacts/playwright/ui-audit/workstation-stable-320.png), [perfil 320](../.artifacts/playwright/ui-audit/profile-dialog-320.png), `results-responsive.json`.
- **Responsables:** `FormHelp`, `ContextHelp`, progreso y composición de los formularios de puesto/perfil.
- **Recomendación:** conservar la ayuda alineada al pie, con resumen breve y ampliación accesible; ajustar su presupuesto de altura en ventanas cortas. Simplificar el indicador de pasos en anchos mínimos sin perder paso actual y total. Mantener scroll y acceso por teclado a toda la ayuda.
### V05 — La ordenación se pierde al volver de la ficha
**Media · Confirmado funcionalmente.** Activos, 1440×900.
- **Reproducción:** buscar AUDIT, seleccionar Portátil, ordenar Nombre descendente, abrir el enlace del activo y volver con Atrás.
- **Resultado:** búsqueda y plantilla permanecen en URL; `aria-sort` pasa de `descending` a `ascending`.
- **Evidencia:** `beforeNavigation` y `afterNavigation` en [results-flows.json](../.artifacts/playwright/ui-audit/results-flows.json), [vuelta al listado](../.artifacts/playwright/ui-audit/context-return-1440.png).
- **Responsables:** estado local de `useEntityTable` y montaje de la lista al navegar entre listado y ficha.
- **Recomendación:** definir un contrato de contexto de listado —búsqueda, filtros, orden y página— y restaurarlo al volver. Usar URL o estado de navegación por vista según el patrón acordado; no guardar datos remotos duplicados. La pérdida de página en activos queda pendiente: solo existe una fila.
### V06 — Escape puede dejar el foco en el documento
**Media · Confirmado funcionalmente.** Alta de activo, 1440×900.
- **Reproducción:** enfocar Nuevo activo, abrir con Enter y cerrar con Escape; esperar al cierre y al retorno de foco.
- **Resultado:** tras esperar hasta tres segundos el foco seguía en `BODY`, sin indicación visible, en lugar del botón Nuevo activo. No ocurre en el selector anidado de puestos probado.
- **Evidencia:** [foco tras cierre](../.artifacts/playwright/ui-audit/keyboard-closed-settled-1440.png), `focusAfterClosed` en `results-verify.json`.
- **Responsables:** integración de `AssetEditorDialog`/`FormDialog` con el disparador externo y su desmontaje.
- **Recomendación:** establecer y comprobar la restitución de foco en el wrapper propio y sus consumidores; cubrir Escape y Cancelar, disparador de cabecera y acciones de fila. No modificar la implementación vendor.
### V07 — Búsqueda sensible a tildes
**Media · Confirmado funcionalmente.** Activos, 1440×900.
- **Reproducción:** escribir `portatil`; sustituir por `portátil`.
- **Resultado:** cero y un resultado respectivamente, aunque ambos buscan la misma plantilla. La ordenación sin tildes no implica que la búsqueda también las ignore.
- **Evidencia:** [consulta sin tilde](../.artifacts/playwright/ui-audit/search-unaccented-1440.png), resultados de ambas consultas en `results-flows.json`.
- **Responsable:** filtrado de `AssetList`, que aplica minúsculas e `includes` sin normalización de diacríticos.
- **Recomendación:** unificar comparación de búsqueda en los consumidores equivalentes, definiendo expresamente el tratamiento de ñ y otros caracteres del idioma. Añadir pruebas sobre comportamiento, no solo sobre el helper.
### V08 — Elegir entre 75 columnas requiere recorrer una lista plana
**Media · Confirmado visualmente y funcionalmente.** Activos → Columnas, 1440×900 y móvil.
- **Reproducción:** abrir Columnas con los catálogos de serie cargados.
- **Resultado:** 75 casillas, sin búsqueda ni agrupación visible. La personalización persiste correctamente, pero localizar un campo técnico resulta costoso.
- **Evidencia:** [selector de columnas](../.artifacts/playwright/ui-audit/columns-1440.png), `columnsCount` en `results-panels.json`.
- **Responsables:** `EntityTableColumnsDialog` y la descripción de columnas dinámicas de activos.
- **Recomendación:** extender el selector existente con búsqueda y grupos semánticos, manteniendo identificación/acciones protegidas y compatibilidad con las preferencias locales. El componente genérico recibe etiquetas y grupos, sin conocer plantillas ni DTO.
### V09 — Las cabeceras de revisión contienen explicaciones completas
**Media · Confirmado visualmente.** Perfiles y configuraciones relacionadas, 1440×900.
- **Reproducción:** abrir Perfiles de usuario, Aplicaciones del perfil, Impresoras del perfil, Certificados o Correo.
- **Resultado:** se usa una frase como «Revisar: la persona, el dispositivo…» como título de columna. Se recorta y ocupa un ancho desproporcionado, incluso con la tabla vacía.
- **Evidencia:** [perfiles](../.artifacts/playwright/ui-audit/section-work-profiles-1440.png), [aplicaciones](../.artifacts/playwright/ui-audit/section-application-configurations-1440.png).
- **Responsables:** definiciones de columnas y claves i18n; en perfiles, `profiles.review` sirve tanto de etiqueta como de explicación.
- **Recomendación:** cabecera breve «Revisión» y explicación accesible contextual; mantener el motivo específico en la celda cuando existan datos. No ocultar estados de negocio ni depender únicamente de un icono.
### V10 — La ficha acumula secciones vacías y mensajes administrativos
**Media · Confirmado visualmente.** Información del portátil sintético, escritorio y móvil.
- **Reproducción:** abrir el activo y recorrer Información sin características ni relaciones pobladas.
- **Resultado:** dos grupos llamados Identificación y una ficha de varios miles de píxeles con muchos guiones y bloques sin relaciones; la advertencia sobre evolución de plantillas precede a los datos en todas las consultas. Se tarda en alcanzar dominios, publicaciones y perfiles.
- **Evidencia:** [primer encuadre de ficha](../.artifacts/playwright/ui-audit/asset-detail-1440.png), [relaciones](../.artifacts/playwright/ui-audit/asset-relations-1440.png), [diálogo compacto](../.artifacts/playwright/ui-audit/compact-asset-panel-390.png).
- **Responsables:** composición de `AssetDetail`, secciones de características y bloques de relaciones/publicaciones.
- **Recomendación:** diferenciar datos generales de la sección Identificación de la plantilla; priorizar datos con valor y resumir grupos vacíos plegables, sin eliminar información. Dar menor presencia a la explicación administrativa de sincronización. Conservar accesibles altas y estados vacíos útiles.
### V11 — Ausencias representadas de manera distinta en tablas de ficha
**Baja · Confirmado visualmente.** Ficha y panel de activo.
- **Resoluciones:** 1440×900 y 390×844.
- **Reproducción:** consultar Ubicación y asignación de un activo sin sede.
- **Resultado:** el listado muestra «—»; la tabla de detalle muestra «Sin asignar». En el mismo bloque aparece «Sin puesto activo», cuyo significado debe distinguirse de una mera celda vacía.
- **Evidencia:** [detalle compacto](../.artifacts/playwright/ui-audit/compact-asset-panel-390.png).
- **Responsables:** renderizadores de detalle y panel; patrón de celdas sin valor.
- **Recomendación:** usar «—» para ausencia real en tablas y conservar textos que expresen estados de negocio. Revisar la semántica antes de sustituir indiscriminadamente mensajes.
### V12 — La carga inicial sustituye todo el listado
**Media · Confirmado funcionalmente con demora de red simulada.** Activos, 1440×900.
- **Reproducción:** retener la petición GET del inventario en el navegador y recargar; liberar el bloqueo y recargar para recuperar el listado.
- **Resultado:** desaparecen búsqueda, filtros, tabla y paginación; se conserva cabecera, alta deshabilitada y «Cargando catálogo…». Tras retirar la interceptación vuelve el activo. No se ha medido latencia real ni se extrapola a una recarga en segundo plano.
- **Evidencia:** [carga inicial](../.artifacts/playwright/ui-audit/assets-loading-1440.png), `results-network.json`.
- **Responsables:** condiciones de render de `AssetInventoryPage` y consultas requeridas por el listado.
- **Recomendación:** reservar estructura y espacio con los componentes de carga existentes; diferenciar inventario y catálogo en el mensaje. Conservar los datos actuales durante actualizaciones cuando ya están disponibles.
## 6. Contraste con las auditorías anteriores
| Hallazgo previo recuperable | Estado en esta auditoría | Contraste, impacto y propuesta |
| --- | --- | --- |
| Panel decidido por viewport, sin considerar ambas barras | Confirmado visualmente | V01. Tabla de unos 237 px a 1100 con panel. Resolver por contenedor y prioridades de navegación. |
| Estado de orden/paginación local al listado | Confirmado funcionalmente para orden; página pendiente | V05. Se conserva q/plantilla y se reinicia orden. No hay página 2 de activos para probarla. |
| Búsqueda solo en minúsculas, sensible a tildes | Confirmado funcionalmente | V07: `portatil`=0, `portátil`=1. |
| Selector de columnas plano y extenso | Confirmado visualmente | V08: 75 opciones; persistencia sí funciona. |
| Controles ausentes durante carga inicial | Confirmado funcionalmente mediante simulación | V12. No se considera un resultado de rendimiento real. |
| Errores de campos no asociados uniformemente en acceso | Detectado únicamente mediante código para CredentialForm | El formulario de credenciales mantiene error general. No se reprodujo un login fallido en esta auditoría autenticada. Los campos requeridos probados sí activan validación nativa; no se infiere un incumplimiento de ese hecho. |
| Consultas completas y filtrado/paginación en cliente; contadores cargan colecciones | Detectado únicamente mediante código; impacto pendiente | `useEntityTable` y controlador de compañía mantienen estos patrones. Una compañía y un activo no permiten medir degradación. Evaluar con fixture grande autorizada antes de cambiar contratos o introducir virtualización. |
| Éxito en color primario y colores fijos en componentes | Detectado únicamente mediante código para éxito/vacío; contraste de selección confirmado | `FormFeedback` usa primario para éxito y `EmptyState` contiene un rojo fijo. No hubo éxito de guardado probado. V02 sí aporta medición de una combinación visible defectuosa. |
| Reglas CSS duplicadas de dialog-content | Detectado únicamente mediante código | Dos reglas consecutivas en global.css; no se atribuye un defecto visual sin reproducción. Consolidación futura acotada, sin editar vendor. |
| Desbordamiento global de página en móvil | No reproducido en la matriz principal | Tablas anchas desplazan dentro de su contenedor; el problema demostrado es espacio útil y navegación, V01. |
| Foco inicial del PickerList | No reproducido como problema en el selector probado | Búsqueda de puesto enfocada y retorno al padre correctos. No equivale a validar todos los pickers. |
| Altura estable de todos los asistentes | Descartado como propiedad general | Puesto estable en el paso disponible; activos/recursos variables, V03. |
| Alineación de Campos y contador en editor de secciones | No reproducido en editor de activo | Alineados a 1440. Editor de recurso no abierto: pendiente específico. |
Los problemas nuevos con evidencia propia incluyen V02, V04, V06, V09 y la composición extensa de ficha. Para los hallazgos solo de código no se inventa una resolución afectada ni una captura de un fallo no visto.
## 7. Problemas transversales del sistema visual
- **Los umbrales no expresan capacidad del contenedor.** El shell, la compañía y el panel deciden su distribución por separado. El resultado es coherente técnicamente, pero deja poco espacio para la tarea.
- **Las variantes comunes no se usan de forma uniforme.** `FormDialog` ya ofrece estabilidad; `FormHelp` ya permite ayuda fuera del cuerpo. Su adopción es desigual.
- **Un token aislado no garantiza contraste en todas sus combinaciones.** El primario funciona sobre blanco y falla sobre selección. Es necesario definir parejas por estado.
- **La cantidad de texto no está jerarquizada por utilidad.** Se mezclan etiquetas, avisos, explicaciones y ejemplos extensos en lugares de lectura rápida.
- **El contexto de navegación está incompleto.** Parte vive en URL, parte en estado local que se pierde al desmontar la vista.
- **Los vacíos son correctos, pero poco orientativos en algunos casos.** Hay CTA de cabecera, aunque «No hay resultados» en Recursos no explica si falta registrar el primer recurso. No se propone convertir todos los vacíos en grandes tarjetas decorativas.
- **La presentación compacta no debe ocultar la tarea.** Ayuda, progreso y dos niveles de navegación compiten con controles y resultados.
## 8. Componentes compartidos que conviene revisar
| Componente o ámbito | Mejora propuesta | Criterio de aceptación |
| --- | --- | --- |
| Shell y CompanyDetail | Navegación adaptable por espacio y jerarquía | Llegar al contenido sin recorrer toda la navegación en móvil; tabla útil en tablet |
| Inventory layout / useCompactDetail | Panel según ancho de trabajo real | Tabla y panel simultáneos solo cuando ambos conservan espacio operativo |
| FormDialog | Adopción uniforme de stable y restitución de foco | Misma altura al cambiar paso; Escape y Cancelar devuelven al disparador |
| FormHelp / ContextHelp | Resumen y expansión adaptados a ventana corta | Ayuda pegada al pie, accesible, sin desplazar fuera del primer encuadre todos los campos |
| FormProgress / progreso de creación | Variante compacta | Sin solapamiento de etiquetas a 320 px |
| EntityTableColumnsDialog | Buscar y agrupar opciones | Encontrar un campo sin recorrer decenas de casillas |
| useEntityTable + navegación de entidades | Contexto persistido por vista | Volver conserva filtro, orden y página válida |
| EntityTable / enlaces de fila | Contraste de selección y títulos breves | Texto de datos legible y acciones ancladas en cada estado |
| FieldHelp / catálogo de ejemplos | Ejemplos ajustados al tipo | No enumerar modelos irrelevantes como ayuda permanente |
| AssetDetail / DetailSection | Datos prioritarios y vacíos resumidos | Identificar características y relaciones sin recorrer bloques vacíos extensos |
Son extensiones de componentes con consumidores reales. Los componentes genéricos reciben datos, textos y acciones; no deben conocer endpoints, Sequelize ni DTO concretos. Mantener `TimeLine`, `AssetSummaryCard`, `EmptyState`, `CountBadge` y las tarjetas de selección existentes donde correspondan, sin duplicar sus estructuras.
## 9. Plan incremental recomendado
1. **Correcciones pequeñas verificables:** contraste seleccionado, foco al cerrar, estabilidad de activos/recursos y cabeceras breves. Validar cada escenario de V02/V03/V06/V09 antes y después.
2. **Espacio de trabajo:** acordar comportamiento de navegación en 320/390/768/1024 y panel por contenedor. Verificar teclado, sección activa, acceso a todas las opciones y ausencia de scroll global horizontal.
3. **Formularios cortos:** ajustar ayuda y progreso en ventanas bajas; conservar ubicación junto al pie, contenido completo y scroll. Revisar todos los consumidores equivalentes.
4. **Productividad de listados:** búsqueda sin tildes, selector de columnas con búsqueda y contrato completo de retorno. Comprobar que preferencias existentes siguen siendo válidas.
5. **Fichas y relaciones:** jerarquizar bloques y datos vacíos con una fixture sintética representativa autorizada: sede, persona, puesto, perfil, impresora compartida, interfaces, dominio y publicación SMB. No utilizar compañías reales como banco de pruebas.
6. **Validación ampliada:** conjuntos grandes para rendimiento; lector de pantalla, zoom, idiomas, modo oscuro y dispositivos reales. Solo decidir paginación remota/virtualización después de medir el problema con volúmenes representativos.
No se han implementado estas recomendaciones. Los cambios futuros deben respetar las comprobaciones apropiadas de `AGENTS.md` y el veto de modificación de `packages/shadcn-ui`.
## 10. Implicaciones para DESIGN.md
No se ha generado el archivo definitivo. Su contenido debería consolidar decisiones del producto y enlazar las fuentes normativas existentes, sin duplicarlas:
1. **Propósito:** herramienta de soporte empresarial; prioridad a localizar, comparar y relacionar información.
2. **Fuentes y precedencia:** AGENTS, patrones de listados/diálogos, biblioteca propia sobre Base UI/Vega.
3. **Fundamentos:** Inter para interfaz, papel específico de Mono/Serif, escala tipográfica existente, espaciado, bordes y elevación actuales.
4. **Color por función y estado:** acción primaria, selección, éxito, aviso y error; tabla de parejas de contraste verificadas y pendientes. Registrar V02 como deuda, sin declarar todos los tokens accesibles.
5. **Layout por capacidad:** mínimos operativos del contenido, jerarquía de navegación global/compañía y convivencia tabla/panel. Documentar el comportamiento por contenedor acordado tras V01.
6. **Densidad:** filas, etiquetas breves, información secundaria, truncamiento con acceso al valor completo y grupos vacíos.
7. **Contratos de interacción:** enlaces frente a acciones, contexto de retorno, foco, cierre, cancelación y estados de consulta.
8. **Formularios y asistentes:** referenciar el patrón normativo, explicar adopción de stable/FormHelp y variante compacta de progreso.
9. **Fichas y relaciones:** jerarquía de resumen, información, bloques relacionados e historial; independencia de componentes genéricos.
10. **Verificación y deuda:** matriz de tamaños, evidencias, contraste, teclado, datos necesarios y excepciones justificadas.
Evitar convertirlo en una plantilla genérica de landing pages o imponer cambios de marca para resolver problemas de layout. La biblioteca propia y las primitivas existentes bastan para el plan propuesto.
## 11. Evidencias, consola y limitaciones
### Ubicación y trazabilidad
Las evidencias se guardan en [`.artifacts/playwright/ui-audit/`](../.artifacts/playwright/ui-audit/), excluido de Git. Se verificaron las cabeceras y dimensiones de los PNG. El índice distingue las capturas previas de acceso sin autenticar y una imagen descartada por representar una transición de tamaño; no sustentan los hallazgos de esta auditoría. Este informe se entrega para versionar; los PNG y JSON permanecen locales y deben compartirse expresamente si otro equipo necesita reproducir la inspección.
- `results-matrix.json`: matriz principal y mediciones.
- `results-flows.json`: búsquedas, ordenación y cancelación.
- `results-panels.json`: panel, diálogos compactos y columnas.
- `results-dialogs.json`: primera pasada de aperturas; algunas medidas inmediatas tras resize son transitorias y no fundamentan defectos geométricos.
- `results-deep.json`: pasos, selector anidado, validación y error de red simulado.
- `results-responsive.json`: geometría asentada de móvil y modales, historial y paginación.
- `results-sections.json`: configuraciones y relaciones disponibles.
- `results-final-checks.json` y `results-verify.json`: validación, permisos, comprobaciones adicionales y rectificaciones de medidas iniciales.
- `results-network.json`: demora artificial y recuperación.
- `results-a11y.json`: muestra de colores, teclado y acordeones.
- `results-mobile-template.json`: apertura nueva del editor en 320.
- Snapshots `.txt` y capturas `.png` con pantalla y ancho en el nombre; `evidence-index.json` contiene dimensiones y SHA-256 de las capturas.
Las comprobaciones posteriores prevalecen sobre las observaciones transitorias: el primer test de persistencia buscaba una cabecera exactamente igual a «Notas», ignorando su flecha; la verificación de cabeceras y almacenamiento confirmó persistencia. Una imagen tomada durante el cambio de ancho del editor parecía recortada; la apertura móvil nueva mostró geometría correcta y no se registra como defecto.
### Red, consola y ausencia de escrituras
- Se observó un **404 de `/favicon.ico`** en una de las sesiones MCP. Es un recurso accesorio, sin bloqueo de los flujos probados.
- En el recorrido profundo se bloquearon preventivamente todas las escrituras del navegador. El asistente de activo propuso un nombre y llegó a intentar un POST de alta; se abortó antes de llegar al servidor. La interfaz mostró «No se pudo completar la operación». Esa evidencia se conserva en `asset-wizard-invalid-1440.png`, pero **su nombre no debe interpretarse como una validación de campos**: documenta un error de red provocado. La validación real de Nombre vacío se ejecutó después en edición, sin petición de escritura.
- El `net::ERR_FAILED` de ese recorrido corresponde al aborto controlado anterior, no a un fallo espontáneo de la aplicación.
- La demora GET del inventario fue otra interceptación local del navegador; al retirarla y recargar se recuperó el listado.
- No se observaron excepciones JavaScript de aplicación en los registros conservados de los escenarios completados. Esto no demuestra ausencia de errores en rutas no recorridas.
- Hubo fallos del guion de inspección por selectores ambiguos y por esperar el shell en una pantalla de acceso denegado. Se corrigieron los recorridos; no se contabilizan como incidencias de Metis.
- No se guardaron formularios ni se ejecutaron bajas, desactivaciones, eliminaciones o mutaciones de negocio durante la auditoría. Solo el preparador creó su conjunto sintético autorizado. Los cambios de columnas afectaron a preferencias del navegador aislado.
### Pendientes reales
No se validaron guardados satisfactorios, estados de éxito, conflictos concurrentes, errores de servidor representativos, datos extensos, historial con múltiples modificaciones, relaciones pobladas, administración de usuarios, fichas de persona/puesto/perfil/recurso ni todos los pickers. Tampoco se validaron todos los pasos de puesto/perfil, por ausencia de sedes y puestos. Para cerrarlos hace falta una fixture ampliada y autorizada; no basta con revisar su JSX.
No se ejecutaron `pnpm typecheck`, `lint`, `test`, `check` o `build`: no se ha cambiado código ejecutable. Se ejecutaron el preparador autenticado, los recorridos MCP descritos, comprobaciones de capturas y enlaces locales del informe y revisión del diff. Al finalizar se cerró el preparador: retiró su entorno temporal y se comprobó la eliminación de `session.json` y `database.env`. Las capturas se conservan sin la sesión privada.