Files
FRASA-CAS/api-gateway/src/config/index.ts
Consult AS Technology aa27e89c75 feat: mis cobranzas, recordatorios de pago y agente IA con acciones
- PlanPago.vendedorId + filtro ?mios=1; toggle Mis planes/Todos en /pay
- Motor de recordatorios: próximos a vencer (3d) y vencidos (re-cada 7d),
  canal Monday Actividad + stub WhatsApp listo para WA CRM, log persistente,
  cron diario 9:30, run manual con dry-run, historial en /api/cobranza/recordatorios
- Agente IA: memoria por usuario (conversaciones aisladas) y tool calling:
  cotizar_unidad (motor real por desarrollo) y buscar_unidad (inventario Monday)
- Tests: api 261, cobranza 75, agente-ia 13
2026-08-28 08:07:12 +00:00

85 lines
3.8 KiB
TypeScript

import path from 'node:path'
import dotenv from 'dotenv'
// Carga .env local si existe y luego el .env raíz del ecosistema (no pisa vars ya definidas)
dotenv.config({ path: [path.resolve(process.cwd(), '.env'), path.resolve(process.cwd(), '..', '.env')] })
function env(name: string, fallback?: string): string {
const v = process.env[name] ?? fallback
if (v === undefined) throw new Error(`Falta la variable de entorno ${name}`)
return v
}
export const config = {
port: Number(env('PORT', '3000')),
nodeEnv: env('NODE_ENV', 'development'),
databaseUrl: env('DATABASE_URL', 'file:./dev.db'),
uploadsDir: path.resolve(process.cwd(), env('UPLOADS_DIR', './uploads')),
monday: {
apiKey: env('MONDAY_API_KEY'),
apiUrl: env('MONDAY_API_URL', 'https://api.monday.com/v2'),
apiVersion: '2024-10',
workspace: env('MONDAY_WORKSPACE', ''),
boards: {
contactos: env('MONDAY_BOARD_CONTACTOS'),
desarrollos: env('MONDAY_BOARD_DESARROLLOS'),
unidades: env('MONDAY_BOARD_UNIDADES'),
leads: env('MONDAY_BOARD_LEADS'),
oportunidades: env('MONDAY_BOARD_OPORTUNIDADES'),
apartado: env('MONDAY_BOARD_APARTADO'),
ventas: env('MONDAY_BOARD_VENTAS'),
// Tableros creados por scripts/setup-crm.ts; '' = aún no configurado
motivos: env('MONDAY_BOARD_MOTIVOS', ''),
actividades: env('MONDAY_BOARD_ACTIVIDADES', ''),
},
},
automatizaciones: {
// 'false' desactiva los crons (útil en tests/CI); los endpoints admin siguen vivos
enabled: env('MONDAY_AUTOMATIONS_ENABLED', 'true') !== 'false',
// 'false' desactiva la creación de actividades en Monday (default true; false en tests)
actividadesEnabled: env('ACTIVIDADES_ENABLED', 'true') !== 'false',
// IDs de usuario Monday separados por coma; vacío = auto-detectar usuarios no-guest del workspace
rrUserIds: env('MONDAY_RR_USER_IDS', ''),
inactividadDias: Number(env('INACTIVIDAD_DIAS', '10')),
// Horas que un lead asignado puede seguir en NUEVO/Intento de contacto antes de escalar
escaladoHoras: Number(env('LEAD_ESCALADO_HORAS', '48')),
// User ID de Monday del coordinador que recibe los escalados; vacío = al vendedor asignado
coordinadorUserId: Number(env('MONDAY_COORDINADOR_USER_ID', '0')),
pollCron: env('POLL_CRON', '*/5 * * * *'),
recordatorioCron: env('RECORDATORIO_CRON', '0 9 * * *'),
},
recordatoriosCobranza: {
// Escaneo diario de pagos por vencer / vencidos (motor de recordatorios)
cron: env('RECORDATORIOS_CRON', '30 9 * * *'),
// Días de anticipación para el recordatorio "próximo a vencer"
diasAntes: Number(env('RECORDATORIO_DIAS_ANTES', '3')),
// Cada cuántos días se re-recuerda un pago que sigue vencido
revolverDias: Number(env('RECORDATORIO_REVOLVER_DIAS', '7')),
},
ai: {
// Proveedor NAN (OpenAI-compatible): chat + embeddings
apiKey: env('NAN_API_KEY'),
baseUrl: env('NAN_BASE_URL', 'https://api.nan.builders/v1'),
chatModel: env('NAN_CHAT_MODEL', 'qwen3.6'),
embedModel: env('NAN_EMBED_MODEL', 'qwen3-embedding'),
// Umbral mínimo de similitud coseno para recuperar contexto (0-1)
minScore: Number(env('AI_MIN_SCORE', '0.3')),
},
auth: {
jwtSecret: env('JWT_SECRET'),
// Cadena aceptada por jsonwebtoken (p. ej. '7d')
jwtExpiresIn: env('JWT_EXPIRES_IN', '7d'),
// 'false' desactiva la exigencia de token en /api (tests, arranque temprano)
enabled: env('AUTH_ENABLED', 'true') !== 'false',
// Password del usuario admin sembrado (seed-usuarios.ts)
adminPassword: env('ADMIN_PASSWORD', 'Frasa2026'),
},
ligaRemota: {
// Expiración del token de la liga pública de firma/documentos (cadena
// aceptada por jsonwebtoken, p. ej. '72h')
expiresIn: env('LIGA_REMOTA_EXP', '72h'),
},
} as const
export type AppConfig = typeof config