feat(config): modulo Configuraciones admin + permisos por rol

- Tablas ConfiguracionSistema (7 configs) + RolConfiguracion (6 roles)
- Endpoints: config/sistema GET/PATCH, config/roles GET/PATCH,
  config/usuarios GET/PATCH, config/reset-roles POST, config/acciones GET
- modulosDeRol() async con fallback a MATRIZ estatica
- auth/me devuelve acciones[] segun rol del usuario
- saludMonday.estaDisponible() lee modo_local_forzado de DB (cache 30s)
- Landing: vista Configuraciones con 4 tabs (Modo, Roles, Usuarios, Sistema)
- Mi-dia: boton Descartar se deshabilita si !descartar_lead
- 630 API tests + 24 landing tests + 20 mi-dia tests verdes

Seed: npm run seed:config
This commit is contained in:
2026-09-06 09:46:19 +00:00
parent 50e6eca7da
commit b2634f97ab
35 changed files with 2572 additions and 33 deletions

View File

@@ -7,7 +7,8 @@
* local) en lugar de pagar los reintentos por request; un cron sondea cada 60 s
* y al recuperarse dispara el sync worker.
*
* MODO_LOCAL_FORZADO=true fuerza modo local aunque Monday responda (pruebas).
* MODO_LOCAL_FORZADO=true (env var o DB) fuerza modo local aunque Monday
* responda (pruebas / toggle admin). La DB se cachea 30 s en configService.
*
* El ping se inyecta con `registrarPing()` (wiring en index.ts) para no
* importar monday.service aquí y evitar ciclos de imports.
@@ -45,9 +46,24 @@ export class SaludMondayService {
return this.mondayOk
}
/** true si los callers pueden hablar con Monday ahora mismo */
/**
* true si los callers pueden hablar con Monday ahora mismo.
* Lee modo_local_forzado de la DB (via cache 30 s en configService) y de
* process.env como fallback. Síncrono: la DB se precarga al iniciar y se
* invalida al cambiar configs.
*/
estaDisponible(): boolean {
return this.mondayOk && process.env.MODO_LOCAL_FORZADO !== 'true'
// Lazy import para no crear ciclos en tests (configService importa prisma)
let forzadoDb = false
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const cs = require('./config.service.js') as typeof import('./config.service.js')
forzadoDb = cs.obtenerConfigSync('modo_local_forzado') === 'true'
} catch {
// configService no disponible (tests aislados, DB no inicializada)
}
const forzadoEnv = process.env.MODO_LOCAL_FORZADO === 'true'
return this.mondayOk && !forzadoDb && !forzadoEnv
}
/**