// Matriz de módulos visibles por rol (definida con el cliente, sep-2026). // Es la fuente de verdad del ecosistema: GET /auth/me la expone como // `modulos` y las apps filtran su navegación con ella. export const MODULOS = [ 'mi-dia', 'alta-cliente', 'alta-afluencia', 'cotizador', 'mi-tablero', 'tablero-comercial', 'cobranza', 'contactos', 'chat', 'clientes-maestro', 'captura', 'soporte', ] as const export type Modulo = (typeof MODULOS)[number] export const ROLES = [ 'vendedor', 'administracion_venta', 'director_ventas', 'escrituracion', 'direccion_general', 'manager', 'admin', ] as const export type Rol = (typeof ROLES)[number] // 'captura' y 'soporte' son transversales: todos los roles los ven const MODULOS_VENDEDOR: readonly Modulo[] = [ 'mi-dia', 'alta-cliente', 'alta-afluencia', 'cotizador', 'mi-tablero', 'contactos', 'chat', 'clientes-maestro', 'captura', 'soporte', ] export const MATRIZ: Record = { vendedor: MODULOS_VENDEDOR, administracion_venta: [...MODULOS_VENDEDOR, 'cobranza'], director_ventas: [...MODULOS_VENDEDOR, 'cobranza', 'tablero-comercial'], escrituracion: [...MODULOS_VENDEDOR, 'cobranza'], direccion_general: ['mi-dia', 'tablero-comercial', 'cobranza', 'chat', 'clientes-maestro', 'captura', 'soporte'], // manager: mismos módulos que admin, sin poder crear usuarios ni editar permisos manager: MODULOS, admin: MODULOS, } // Roles que ya existen en la BD pero no en la matriz nueva: se homologan a // director_ventas (su equivalente funcional en la operación actual). const ROLES_LEGACY: Record = { coordinador: 'director_ventas', corporativo: 'director_ventas', } /** * Módulos visibles para un rol. Intenta leer de RolConfiguracion (DB) y * hace fallback a la MATRIZ estática si no existe registro. * * Roles legacy ('coordinador', 'corporativo') se tratan como director_ventas; * un rol desconocido cae a vendedor (fallback seguro: es el conjunto más chico * de módulos operativos). */ export async function modulosDeRol(rol: string): Promise { const clave = rol.trim().toLowerCase() const rolEfectivo: Rol = (ROLES as readonly string[]).includes(clave) ? (clave as Rol) : (ROLES_LEGACY[clave] ?? 'vendedor') try { // Importación dinámica para evitar circular dependency con services const { prisma } = await import('../services/prisma.js') const row = await prisma.rolConfiguracion.findUnique({ where: { rol: clave } }) if (row) { return JSON.parse(row.modulos) as Modulo[] } } catch { // Si la tabla aún no existe o hay error de conexión, fallback silencioso } return [...MATRIZ[rolEfectivo]] } /** ¿Es un rol válido de la matriz nueva? (para PATCH /usuarios/:id/rol) */ export function esRolValido(rol: string): boolean { return (ROLES as readonly string[]).includes(rol) }