Apéndice: Auditoría de contenido
Esta página registra el estado de la auditoría de contenido del manual. La iteración de contenido (SPEC 054) corrigió las páginas desactualizadas y documentó los módulos que no tenían manual. Aquí se distingue lo resuelto de lo que sigue pendiente.
Resuelto en esta iteración
Sección titulada «Resuelto en esta iteración»Páginas desactualizadas — corregidas
Sección titulada «Páginas desactualizadas — corregidas»Las siguientes páginas se corrigieron contra el comportamiento real del sistema y se les retiró el aviso “contenido en revisión”:
| Página | Corrección aplicada |
|---|---|
| Ventas / Procesamiento de Ventas | Atajos reales del POS (F1 Ayuda, F2 Buscar Productos, F8 Procesar Pago, F9 Caja Registradora, F12 Limpiar Carrito). Se eliminaron funciones no implementadas (ver abajo). |
| Facturación / Generación de CFDI · Proveedores PAC | Se documenta únicamente Finkok, el PAC realmente integrado. Se retiraron Facturama y Gosocket y la opción de “cambiar de PAC”. |
| Compras / Órdenes de Compra | Estados reales del ciclo: Borrador, Por Aprobar, Pendiente, Parcial, Recibida, Cancelada. |
| Inventarios / Administración de Productos | Niveles de precio reales: Costo, Precio General, Precio Mayoreo (opcional), Precio Especial (opcional) + IVA/IEPS. Se eliminó el “cálculo automático de margen” inexistente. |
Afirmaciones sin respaldo — reconciliadas
Sección titulada «Afirmaciones sin respaldo — reconciliadas»Las siguientes funciones se documentaban como disponibles y no están implementadas; se eliminaron del manual:
- Suspender / recuperar una venta en el Punto de Venta.
- Autorización de supervisor para descuentos por encima de un umbral.
- Panel de “Favoritos” en el Punto de Venta.
El filtro por categoría del Punto de Venta sí existe y se documenta como tal (no era una afirmación sin respaldo).
Módulos documentados
Sección titulada «Módulos documentados»Se redactó el manual (es-MX, derivado del código real) de los módulos que no tenían página, organizados por área en la navegación:
- Contabilidad y Fiscal: Contabilidad, Reportes SAT, Presupuestos, Consolidación, Nómina, Carta Porte, Activos Fijos.
- CRM y Cobranza: CRM, Cobranza.
- Punto de Venta y Lealtad: Promociones, Lealtad, Tarjetas de Regalo.
- Finanzas: Banca, Pronósticos (forecasting).
- Logística: Paquetería.
- Portales: Portal B2B, Portal de Proveedores, Portal del Empleado.
- Integraciones: Marketplace, WhatsApp, Webhooks y API, Notificaciones.
- Configuración: Monedas, Listas de Precio, Sucursales, OCR de Facturas, Preferencias, Asistente y Tours.
El contenido fiscal (contabilidad, nómina, reportes SAT, carta porte, presupuestos) fue revisado por una auditoría fiscal contra el cálculo real del sistema.
Pendiente
Sección titulada «Pendiente»Capturas de pantalla reales
Sección titulada «Capturas de pantalla reales»El manual referencia capturas con un marcador (/placeholder.svg). La infraestructura de
captura está lista y probada (apps/docs/scripts/): script Playwright con login único +
reutilización de sesión (evita el rate-limit de /auth/login) y manifiesto. Ver
apps/docs/scripts/SCREENSHOTS.md.
Capturas reales ya producidas (datos de prueba, sin PII): 51 pantallas sustituyen su marcador en las páginas correspondientes:
- Contabilidad (6 + formulario de nueva póliza): catálogo, pólizas, libro mayor, balanza, estados financieros, períodos.
- Nómina (1): panel principal.
- Ventas / POS (3): punto de venta, caja registradora, pagos.
- Facturación CFDI (1): listado de facturas.
- Inventarios (4): productos, panel, conteo, reportes de inventario.
- Clientes (1 + diálogo de nuevo cliente): listado de clientes.
- Compras (3): proveedores, órdenes de compra, cuentas por pagar.
- Reportes (1): panel de reportes.
- Seguridad (3 + diálogo de crear usuario): usuarios, roles, bitácora.
- Cobranza (1): bandeja principal (KPIs y deudores reales, poblada con datos sembrados).
- Módulos nuevos remediados (10): CRM (Leads + Pipeline kanban + Actividades), Carta Porte (flota), Banca, Lealtad, Forecasting, Listas de Precio, Marketplace (dashboard + configuración) y Presupuestos (ejercicios) — todas afloran datos sembrados reales tras corregir los mismatches GraphQL frontend↔backend (ver «Depuración realizada» más abajo).
Los módulos núcleo tienen datos seed ricos, por lo que sus capturas muestran pantallas reales pobladas.
Datos de prueba sembrados (módulos nuevos)
Sección titulada «Datos de prueba sembrados (módulos nuevos)»Se escribieron seeds transaccionales (idempotentes, tenant EKU9003173C9) para 9 módulos
nuevos: CRM, Cobranza, Carta Porte, Lealtad, Forecasting, Banca, Marketplace, Listas de
Precio, Presupuestos (apps/api-gateway/.../seed/development/seed-*.ts). Los datos quedan
en la base de datos de desarrollo (p. ej. Cobranza ya muestra 4 casos en gestión y 3 promesas).
Causa raíz confirmada (remediación GraphQL): las pantallas de listado de los módulos nuevos
(SPECs 048–052) no afloraban datos porque sus hooks GraphQL del frontend habían derivado del
esquema real del backend — argumentos/campos renombrados o eliminados, nombres de query
distintos y paginación incorrecta. Cada query inválida devuelve 400 GRAPHQL_VALIDATION_FAILED,
React Query reintenta indefinidamente y la pantalla queda en skeleton. No era falta de datos
ni un bug de auth del cliente.
Método aplicado por módulo: curl a /graphql con el JWT → leer el 400 → comparar contra el
tipo/resolver del backend → corregir el hook (alias de campo frontendName: backendName, nombre
de query, args de paginación) o el resolver (tenant-context) → verificar 200 → capturar.
Módulos remediados y capturados (datos sembrados reales):
- CRM (SPEC 048) —
useLeads/useOportunidadestenían 3 mismatches: argspage/pageSizequeQuery.leadsno acepta (pagina por cursor dentro defilters); selecciónpage/pageSizeen la conexión (devuelvetotal/nextCursor);createdAt/updatedAtque enLeadTypesoncreadoEn/actualizadoEn(alias GraphQL). Leads y Actividades capturados. Pipeline kanban: además, las queriespipelineBoardyoportunidadesfallaban con «Cannot return null for non-nullable fieldOportunidadClienteRefType.nombre» — los handlers seleccionan el campo PrismarazonSocialpero el tipo GraphQL exponenombre, que quedaba sin mapear (null). ComoapiClient.graphqllanza al vererrors, el kanban quedaba vacío (no era un bug de render). Corregido con un único@ResolveField('cliente')enOportunidadResolverque mapearazonSocial → nombre, cubriendo board + lista + detalle. Kanban capturado con datos reales. - Carta Porte (SPEC 024) — alias
configVehicularDesc: configVehicularDescripcionypermSCTDesc: permSCTDescripcion; además los resolversvehiculo/operadorno envolvían elqueryBusentenantContextStorage.run({ tenantId }), lanzando «Tenant context not found» (Apollo intercepta antes deTenantMiddleware). Corregido resolver + hook. Flota capturada. - Banca (SPEC 020) — fragmento de conexión bancaria realineado (
institutionId: bankInstitution,institutionName: bankName,balanceCurrent: currentBalance, etc.) y analytics (totalTransactionsThisMonth: totalTransactions…). Pantalla principal capturada. - Lealtad (SPEC 049) — alias
expiracionMeses: mesesExpiracion,umbralGasto: umbralGastoAcumulado,multiplicador: multiplicadorPuntos; ruta del manual corregida a/configuracion/lealtad. Programa capturado. - Forecasting (SPEC 043) — alias
sku: codigoen la sub-selección de producto. Panel capturado. - Listas de Precio (SPEC 050) — el hook llamaba una query inexistente
listasPrecioCliente; la real esportalB2BListasPrecioCliente(argsclienteId/grupoId/activa/limit/offset, devuelve{ items, total }, sinlineasen el tipo de lista — las líneas son la query aparteportalB2BLineasListaPrecio). Corregido nombre + shape.items;lineashecho opcional en el tipo. Listado capturado (2 listas: Distribuidor y Mayoreo). - Marketplace (SPEC 023) — divergencia más profunda:
marketplaceConfigymarketplaceDashboardexponen campos planos con nombres distintos (enabled,sellerId,totalOrdersToday,syncHealth,errorMappings…) y el frontend esperaba otros nombres + unsyncConfiganidado + algunas métricas que el backend no computa (ordersThisWeek,revenueToday,successRate). Resuelto con funciones adaptadoras en el hook (adaptMarketplaceConfig/adaptMarketplaceDashboard) que reshapean la respuesta real al contrato del componente: alias de campos, reconstrucción delsyncConfigdesde flags planos,successRatederivada deactiveMappings/totalMappings, y defaults honestos (0/null) para las métricas sin equivalente backend, documentadas en comentarios. Dashboard capturado con datos reales (3 órdenes/mes, $3,606, 50% de éxito) + página de configuración. - Presupuestos (SPEC 051) — la tabla de ejercicios era un stub de UI («módulo en
configuración»); el componente
EjerciciosPresupuestalesTablenunca se había implementado. Se construyó el componente (tabla con año/nombre/estado/líneas/total, badge de estado, formato de moneda, navegación al detalle) y se cableó a la página. Además había drift GraphQL: el hook llamabaejerciciosPresupuestales(la query real esejercicios), el resolver devolvía el wrapper{ items }del handler CQRS en vez de la lista (error «Expected Iterable»), y el hook pedíacreatedBy/aprobadoBy(inexistentes en el tipo). Corregidos los tres + componente. Listado capturado (ejercicio «Presupuesto Anual 2026», Aprobado, 6 líneas).
Sin pendientes mecánicos: todas las pantallas de listado de los módulos nuevos tratables por navegación directa ya afloran datos reales. Lo que resta son sub-pantallas que requieren interacción (formularios/diálogos), que el script de captura por navegación no cubre.
Barrido de pantallas principales (otros módulos): además de los 10 módulos nuevos, se
capturó la pantalla principal de activos-fijos, consolidación, monedas, sucursales,
preferencias, notificaciones, paquetería, vendor-portal, gift-cards, webhooks y WhatsApp.
Dos de ellas requirieron también corrección de drift GraphQL: gift-cards (page/pageSize →
skip/take, alias fechaVencimiento/creadoEn/compradorClienteId) y webhooks
(successCount → successRate, eliminación de failureCount/lastDeliveryStatus
inexistentes). Monedas y sucursales muestran estado vacío honesto (sin seed para ese tenant).
Promociones — listado (SPEC 049): resuelto. El PromocionesController sólo expone
POST/PUT, así que el GET /promociones del frontend daba 404 — pero el listado sí existe
en GraphQL (promociones(filtros, paginacion)). Se cambió el hook de REST a GraphQL (alias
creadoEn/actualizadoEn/limitePorCliente, paginación page/pageSize → limit/offset).
Listado capturado (3 promos: Buen Fin Temporada, Descuento 10% Porcentaje, 2x1).
Casos profundos restantes (exceden corrección de query):
- Portal B2B — configuración (SPEC 050): el tipo backend
PortalB2BConfigTypesólo expone campos escalares (habilitado,approvalThreshold,clienteCancelWindowMinutes…); el frontend espera sub-objetosbranding,notificaciones,emailsAdmin,monedasPermitidasque el backend no tiene (y el componente los usa sin guard, p. ej.config.emailsAdmin.length). Las tabs Apariencia/Notificaciones dependen de ellos. Requiere ampliar el tipo backend o refactor del componente, no aliases. - Empleado-portal — admin (SPEC 052): la pantalla de gestión de accesos lista empleados con su RFC; se omite la captura por la regla de no exponer RFC/CURP/NSS/salario.
- Nómina — Empleados: la tabla de empleados expone datos personales (RFC/salario); se conserva el marcador. El tab Resumen (agregados sin PII) sí es capturable.
Nota de entorno: la primera navegación a una ruta compila en frío con Webpack (>12 s en
8 GB de RAM); el script usa skeletonTimeout configurable por pantalla para esperar.
Sub-pantallas con interacción (cubo 2) — patrón probado
Sección titulada «Sub-pantallas con interacción (cubo 2) — patrón probado»El script de captura (apps/docs/scripts/capture-screenshots.mjs) sí captura flujos con
interacción mediante el campo actions de cada entrada del manifiesto. Acciones soportadas:
{click}, {fill:[sel,val]}, {select:[sel,val]}, {hover}, {press}, {waitFor}, {wait:ms}.
Patrones validados (capturas reales en el manual):
- Botón → diálogo:
actions: [{wait}, {click:'text=Nuevo Webhook'}, {waitFor:'[role="dialog"]'}, {wait}]. Ejemplos: emitir gift-card, agregar cuenta contable, crear sucursal, nuevo ejercicio presupuestal, nuevo webhook, nueva clave API. - Formulario en ruta
/nuevo: navegación directa (muchos “Nuevo X” son<Link>a una página, no diálogos). Ejemplos: nuevo vehículo, nuevo operador, nueva cotización, nueva promoción, nuevo grupo empresarial, alta de activo fijo, nueva ubicación. - Pestaña como ruta: varias “pestañas” son rutas independientes (
/integraciones/api-keys,/integraciones/catalogo-eventos,/contabilidad/centros-costo) → navegación directa.
Endurecimiento del harness (necesario por la fragilidad de RAM): el script ahora detecta el
redirect a /login (sesión expirada) y re-autentica automáticamente a mitad de lote, y
aborta la captura si tras el reintento sigue sin sesión (nunca guarda un PNG de login). El
límite de intentos de /auth/login es configurable vía AUTH_LOGIN_THROTTLE_LIMIT (default
estricto 5; relajar SOLO en dev/captura, nunca en producción).
Runbook para el resto del cubo 2 (corrida desatendida en entorno estable recomendada):
AUTH_LOGIN_THROTTLE_LIMIT=1000 pnpm dev:api+pnpm dev(admin-web).- Por cada marcador profundo: identificar ruta + secuencia
actions(botón→diálogo, fill, tab). - Añadir entrada al manifiesto con
skeletonTimeoutalto (30000) y capturar en lotes ≤6. - Colocar la captura en su marcador (o, si el caption no calza, insertar en la sección de prosa).
Pendientes reales que NO son captura mecánica: estados profundos multi-paso (secciones dentro de un formulario, confirmaciones post-submit), pantallas con PII (RFC/CURP/salario), y el config de Portal B2B (faltan campos en el backend). El disco se liberó de worktrees obsoletos que causaban fallos de compilación.
Funcionalidad existente en backend sin pantalla de usuario
Sección titulada «Funcionalidad existente en backend sin pantalla de usuario»Durante la redacción se detectaron funciones implementadas en el backend que no tienen pantalla en la aplicación y por tanto no se documentan como disponibles para el usuario (ejemplos): captura de incapacidades de nómina, administración de tablas fiscales por UI, recarga de tarjetas de regalo, edición de reglas de escalación de cobranza, y algunos detalles de exportación filtrada en CRM. Se documenta solo lo que el usuario puede operar desde la interfaz.
Módulos sin interfaz de usuario
Sección titulada «Módulos sin interfaz de usuario»Los dominios técnicos/transversales sin pantalla (p. ej. entities, shared, auditoria
interna) no requieren página de manual de usuario y se omiten intencionalmente.