- 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
85 lines
3.8 KiB
TypeScript
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
|