Skip to content

Plan — Manual de usuario + recorrido guiado ("Explicación")

Date: 2026-09-12 Status: Debatido y decidido con Carlos (2026-09-12) — listo para ejecutar

Qué se construye

Dos piezas que se complementan a propósito:

  1. Manual de usuario — contenido escrito, con un solo origen (Markdown) y dos salidas: dentro de la app filtrado por los permisos del usuario, y tres PDF imprimibles para capacitación.
  2. Recorrido guiado — el botón "Explicación": un tour in-app que señala los controles de cada pantalla y explica el flujo, corriendo sobre la UI real.

La división de trabajo entre los dos es deliberada: el manual lleva los conceptos y las reglas de negocio (por qué el pago no se bloquea, qué significa "pagada pero incompleta", por qué fondear una caja no descuenta el prefondeo del país); el tour lleva lo visual (dónde está cada botón y en qué orden se usa). Así el manual no depende de capturas para explicarse, y el tour nunca queda desactualizado porque corre sobre la pantalla real.

Punto de partida

  • La ruta ya existe: /documentacion/manual-usuario, sin meta.module a propósito (visible para cualquier autenticado), hoy apuntando a un placeholder "en construcción" (frontend/src/views/ManualUsuarioView.vue, 29 líneas). Ver doc/plans/2026-07-25-seccion-documentacion.md.
  • meStore ya expone modules: Record<string, ModulePermission> con canRead/canWrite/canDelete — el filtro por permisos no hay que construirlo.
  • El frontend no tiene ninguna dependencia de Markdown todavía.
  • El CI ya levanta Postgres 17 y corre php artisan migrate + php artisan test (.github/workflows/ci.yml), pero no levanta la app entera ni el emulador de Firebase.
  • No existe nada de tours/onboarding en el frontend.

Decisiones tomadas — no reabrir sin una razón nueva

#DecisiónPor qué
D1Tres recorridos filtrados por permisos efectivos, no por rol nominalLa matriz de permisos es editable por el Admin y un usuario puede tener roles distintos por país. Un manual "para Supervisor" le mentiría a un Supervisor con permisos recortados. Se filtra con meStore.canRead(modulo)
D2Camino híbrido: un origen Markdown, dos salidasAutoría cómoda y versionada con el código, pero filtrado real por permisos dentro de la app
D3Tres PDF, uno por rolMismo contenido y mismo filtro que la app; la entrada cambia: en la app son los permisos vivos, en el build es la matriz seedeada de cada rol
D4Capturas automatizadas en CI (Playwright)Nunca quedan viejas. Es la pieza de infraestructura del paquete, por eso va última
D5Tour seco — no siembra datosSeñala los controles que existen siempre (buscador, botones, menú) y describe con texto qué pasaría al usarlos. Funciona aunque el usuario no tenga ninguna transacción cargada
D6Tour a demanda + automático en el primer loginEl botón "?" siempre disponible; el automático necesita guardar estado por usuario en el backend

Estructura del contenido

Un archivo por módulo de permiso, con frontmatter — espejo exacto de lo que ya declara el router:

doc/manual/
  00-primeros-pasos.md        (sin modulo → siempre visible: login, sidebar, país/PDV activo)
  10-pago.md                  modulo: pago
  20-transacciones.md         modulo: transacciones
  30-caja.md                  modulo: caja
  31-caja-apertura-cierre.md  modulo: apertura_cierre_caja
  32-caja-fondeo.md           modulo: fondeo_caja
  40-prefondeo.md             modulo: prefondeo
  41-prefondeo-pais.md        modulo: prefondeo_pais
  50-dashboard.md             modulo: dashboard
  60-reportes.md              modulo: reportes
  70-tipo-cambio.md           modulo: tipo_cambio
  80-admin-usuarios.md        modulo: abm_usuarios
  81-admin-asignacion.md      modulo: abm_asignacion_roles
  82-admin-paises.md          modulo: abm_paises
  83-admin-estaciones.md      modulo: abm_estaciones
  84-admin-configuracion.md   modulo: abm_configuracion
  90-auditoria.md             modulo: auditoria

Frontmatter mínimo:

yaml
---
titulo: Caja
modulo: caja
orden: 30
---

Reglas del contenido:

  • El router declara meta: { module: 'caja' } y el manual declara modulo: caja. Misma clave, mismo filtro. Un archivo sin modulo es siempre visible — la misma convención que ya usa el router para rutas sin meta.module.
  • Cuando una pantalla mezcla permisos (Caja se opera con caja pero se fondea con fondeo_caja, que Backoffice no tiene), se resuelve partiendo el archivo, nunca con condicionales dentro del Markdown. Sin parser custom, sin lógica escondida en el contenido.
  • El contenido sale del Análisis Funcional que ya existe (doc/functional/), reescrito en lenguaje de usuario final: el análisis explica por qué se decidió algo, el manual explica qué tiene que hacer la persona.

Entregas

E1 — El manual dentro de la app

  • Escribir los archivos de doc/manual/ (contenido real, no esqueleto).
  • Reemplazar el placeholder de ManualUsuarioView.vue: trae los .md con import.meta.glob('../../doc/manual/*.md', { query: '?raw', eager: true }), parsea el frontmatter, filtra por meStore.canRead(modulo) y renderiza.
  • Agregar el renderer de Markdown como dependencia del frontend. La ruta ya es lazy, así que el parser solo se descarga cuando alguien abre el manual — no entra en el bundle del resto.
  • Índice lateral con las secciones visibles para ese usuario, y deep-link por sección (/documentacion/manual-usuario#caja) para poder enlazar desde cada pantalla.
  • Terminado cuando: un Backoffice ve solo sus secciones, un Supervisor las suyas y un Admin todas, sin tocar código al cambiar un permiso desde el ABM.

E2 — Los tres PDF (sin capturas todavía)

  • Script de build que toma los mismos .md, los filtra con la matriz seedeada de cada rol (RoleSeeder::MATRIX) y arma un PDF por rol.
  • Cada PDF imprime en la portada la fecha de generación y con qué matriz se generó — es un artefacto estático y va a quedar viejo si alguien edita permisos después.
  • Botón "Descargar PDF" en la pantalla del manual, que baja el PDF del rol que corresponde.
  • Terminado cuando: los tres PDF se generan desde un comando y el contenido coincide con lo que cada rol ve en la app.

E3 — El recorrido guiado

  • Runner de tours con pasos declarativos, un archivo por flujo (frontend/src/tours/pago.ts, caja.ts, prefondeo.ts, ...), declarados con la misma clave de módulo que el manual.
  • Anclaje con atributos data-tour="buscar-mtcn" explícitos en los elementos. Nunca selectores de clases de Tailwind — el primer refactor de UI los rompería en silencio.
  • Soporte para tours que cruzan pantallas (el flujo de pago va /pago → buscar → pagar → datos → documentos): el runner tiene que poder navegar de ruta y retomar el recorrido.
  • Pasos que apuntan a un control que el usuario no tiene por permiso: se saltean.
  • Botón "?" en cada pantalla que ofrece las dos cosas, leer el manual y ver el recorrido, filtradas por el mismo permiso.
  • Disparo automático la primera vez: columna nueva por usuario en el backend (tipo onboarding_completed_at) y una forma de reiniciarlo desde el perfil.
  • Terminado cuando: los recorridos de Pago, Caja y Prefondeo corren de punta a punta sin datos cargados, y ninguno ejecuta una acción real.

E4 — Capturas automatizadas en CI (la pieza de infra)

  • Seeder de datos de demostración: país, PDV, un usuario por rol, transacciones en ACCEPTED / PAID / CANCELLED, una caja abierta con movimientos.
  • Job de CI que levanta backend + frontend + emulador de Firebase (el login es contra Firebase; start-dev.sh ya lo levanta en dev, hay que replicarlo en el pipeline).
  • Playwright entra con cada rol, navega las pantallas y guarda las capturas.
  • El build del PDF las inyecta en las secciones que corresponden.
  • Terminado cuando: un cambio de UI que rompa una pantalla se refleja en la captura del siguiente build, sin que nadie saque una foto a mano.

Riesgos y cosas a tener presente

  • El tour explica, nunca ejecuta. No debe disparar el botón de pagar ni ninguna acción que mueva plata o toque documentos. En un sistema con dinero real y PII de población vulnerable, un tour que "hace click para mostrarte" no es aceptable.
  • E4 es lo más caro y lo más frágil — es un entorno completo corriendo en CI, no solo Playwright. Por eso va última: E1-E3 entregan el manual y el recorrido completos sin depender de ella. Si E4 se demora, el paquete igual sirve.
  • El seeder de E4 habilita el "tour con datos" si alguna vez se quiere revisar D5. Es el mismo trabajo hecho una sola vez.
  • El manual se desactualiza solo si no se lo mantiene. Conviene sumar al checklist de PR: si el cambio toca una pantalla, revisar si toca su archivo del manual.
  • doc/ y frontend/ son directorios hermanos: el import.meta.glob del frontend cruza al directorio de al lado. Hay que verificar server.fs.allow en dev.

Preguntas abiertas (menores, no bloquean arrancar)

  1. Tono e idioma — el análisis funcional está en rioplatense. Para Guatemala probablemente convenga español neutro en el manual y el tour. A confirmar con el cliente.
  2. Quién escribe el contenido — propuesta: borrador derivado del Análisis Funcional existente, revisado por Carlos antes de publicarlo.
  3. Dónde vive el PDF — propuesta: se descarga desde la propia pantalla del manual, no se publica como archivo suelto (sigue el mismo criterio de acceso que el resto del sistema).

Documentación viva — se actualiza junto con el código, no es un anexo aparte.