Ir al contenido

Frontend

Documentación del proyecto web/: el panel de administración que usa la oficina.

  • Stack y estructura de carpetas — y la razón de esa estructura.
  • Sistema de diseño — componentes, tokens, criterios de composición.
  • Manejo de estado y datos — cómo se consume la API y dónde vive el estado.
  • Rutas y permisos en UI — qué ve cada rol. La UI oculta; la API prohíbe. Las dos capas, siempre.

Al 21-sep-2026:

  • M0 — Auth + RBAC: ✅ (20-ago-2026)
  • M1 — Productos: ✅ (22-ago-2026)
  • M2 — Stock: ✅ (22-ago-2026)
  • M3 — Insumos, M4 — Producción, M5 — Clientes, M6 — Ventas, M7 — Retornables: ✅
  • M9 — Proveedores, M11 — Contador, M12 — Alertas: ✅
  • M13 — Auditoría: ✅ (transversal desde M0)
  • M14 — Clientes ubicables: ✅ (10-sep-2026)
  • M15 — Seguimientos: ✅ (21-sep-2026)
  • Fase de diseño: ✅ aplicada (22-ago-2026) — marca real, vidrio y agua, semáforo de estados, vacíos diferenciados, errores sin jerga, voz de usted, accesibilidad medida (anillo de foco y objetivos táctiles).
  • M10 — Precios: ✅ absorbido por M1 y M6
  • M8 — Rutas y seller mobile: ⏸ POST-MVP (diferido)

1258 tests en web/, verificados contra api/ real.

Repositorio: aquazaku-web.

Ruta Quién entra Qué hace
/login cualquiera Ingreso. Distingue credenciales inválidas de cuenta desactivada y de límite de intentos
/forgot-password cualquiera Pide el correo de recuperación
/reset-password?token=… con token Destino del link del correo
/change-password con sesión Primer ingreso forzado (spec §7.2)
/ con sesión Dashboard
/modulos/productos los cuatro roles Catálogo en lectura: código, litros y precios
/modulos/productos/gestion admin Alta, precios y activación
/modulos/stock los cuatro roles Total, vendible y vencido por producto
/modulos/stock/[productoId] los cuatro roles Lotes en orden FIFO; formularios según permiso
/modulos/insumos admin, pos, contador Tapas, sellos y bolsas contra su mínimo configurable
/modulos/produccion admin, pos, contador Cierre diario, tanques y reconciliación
/modulos/clientes los cuatro roles Padrón, alta y direcciones
/modulos/clientes/[id] los cuatro roles Ficha con saldo, teléfonos, direcciones y ventas
/modulos/seguimientos los cuatro roles Clientes atrasados con días, teléfonos y WhatsApp (RN-CLI-18)
/modulos/ventas los cuatro roles Ventas, recortadas por alcance (RN-ACC-03)
/modulos/retornables los cuatro roles Botellones y bases, con entrega híbrida y daño
/modulos/retornables/bases/[id] los cuatro roles Historia de una base por id_sticker
/modulos/proveedores admin, pos, contador Padrón y compras
/modulos/reportes admin, contador Extracto, cartera por edad y resúmenes mensuales
/modulos/reportes/exportar admin, contador Descarga CSV / PDF a elección
/modulos/usuarios admin Alta, roles y estado
/modulos/usuarios/[id] admin Ficha y edición
/modulos/auditoria admin Bitácora con filtros encadenados
/modulos/alertas admin Umbrales configurables (RN-STK-11, RN-INS-03)

Todo lo que requiere sesión vive bajo el route group (app), que no agrega segmento a la URL. El guard está en su layout: una pantalla nueva nace protegida sin que su autor tenga que acordarse de nada.

src/
├── app/
│ ├── (auth)/ ← sin sesión: login, recuperación, cambio
│ └── (app)/ ← con sesión: guard + shell + módulos
│ ├── layout.tsx ← sesión, primer ingreso y sidebar
│ └── error.tsx ← distingue 403 de 5xx
├── components/
└── lib/
├── api-server.ts ← el ÚNICO lugar donde se llama fetch()
├── api-types.ts ← las formas que devuelve api/
└── modules.ts ← qué módulos ve cada rol

Ninguna alcanza sola; ver Patrón BFF:

  1. Skill del proyecto — atrapa al asistente antes de que escriba el anti-patrón.
  2. apiServerFetch() — reenvía cookies, propaga x-request-id, declara el Origin y nunca cachea datos de sesión.
  3. Regla de ESLint — prohíbe fetch() directo, localStorage y sessionStorage. Corre en CI: si no corriera, la capa no existiría.

apiServerFetch lanza ApiError con el status. El boundary de (app) lee el digest —lo único que sobrevive a producción, porque Next borra message y stack— y distingue:

  • 401 → el layout manda a /login.
  • 403 → pantalla de “no tenés acceso”, no un redirect silencioso.
  • 5xx → aviso genérico con el código para pasarle a soporte.

Está en el stack y en M1+ se gana el lugar: las tablas de ventas y stock van a ordenar y filtrar del lado del cliente. Las de M0 no hacen ninguna de las dos cosas —los filtros los resuelve api/ y la paginación es por cursor—, así que usarlo solo mandaría la librería al browser para renderizar celdas estáticas.