"Avisame cuando esta API devuelva stock en cero." La vigilancia apunta a una HERRAMIENTA ya configurada del agente y nunca a una URL libre: así hereda entero el blindaje de LlamarHerramientaWebhook —DNS resuelto en el connect, IPs internas rechazadas, sin redirects, respuesta acotada— sin reimplementar una línea de eso. Hay un test que falla si alguien le agrega un campo url. El ahorro que hace viable la feature: se hashea la respuesta y, si no cambió, no hay nada que evaluar y no se gasta un token. Preguntarle a la IA en cada chequeo serían 1440 consultas diarias por cliente para responder algo que ya sabíamos. El test verifica que el corte por hash esté ANTES de la evaluación. Y se avisa al ENTRAR en condición, no en cada chequeo que la siga cumpliendo: una alerta que llega cada media hora deja de leerse a la segunda. Es la lección que el monitor de sitios ya había aprendido con las transiciones de estado. Solo un SI explícito dispara el aviso. Un modelo que devuelve una explicación, un error o cualquier otra cosa se toma como que no: un aviso que no llega molesta menos que uno que despierta a alguien a las 3 AM sin motivo. Si el envío del aviso falla, no se marca como avisado — se reintenta al siguiente ciclo. Y tras diez fallos seguidos la vigilancia se apaga sola: una API que dejó de existir no puede consultarse para siempre ni seguir gastando el plan de quien la configuró. Máximo 5 por agente, mínimo 5 minutos de intervalo. Solo canal interno: cada vigilancia es una llamada saliente recurrente y consultas a la IA, o sea plan del dueño gastado por quien la pida. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
5.6 KiB
Go
101 lines
5.6 KiB
Go
package routes
|
|
|
|
import (
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/sujit-baniya/fiber-boilerplate/rest/controllers"
|
|
)
|
|
|
|
// RegistrarRutasUmind monta los mismos handlers de uMind bajo dos prefijos:
|
|
// /app/umind para el staff y /portal/umind para el cliente. Una sola
|
|
// implementación, dos historias de autenticación — duplicar los handlers sería
|
|
// duplicar también las chances de que uno se olvide un chequeo de alcance.
|
|
//
|
|
// scope decide QUÉ tenants ve el que llama (UmindScopeStaff/UmindScopePortal).
|
|
// escritura middleware extra para POST/PUT/DELETE (SoloAdmin del lado staff;
|
|
// nil del lado del cliente, que ya está acotado por su scope).
|
|
//
|
|
// El CRUD de tenants NO se registra acá a propósito: crear/borrar tenants y
|
|
// asignarles cliente y plan es del staff, el cliente solo administra lo que
|
|
// hay adentro.
|
|
func RegistrarRutasUmind(g fiber.Router, scope fiber.Handler, escritura fiber.Handler) {
|
|
// Concatena el scope con el middleware de escritura, si lo hay. El scope
|
|
// va SIEMPRE, también en las lecturas.
|
|
w := func(h ...fiber.Handler) []fiber.Handler {
|
|
out := []fiber.Handler{scope}
|
|
if escritura != nil {
|
|
out = append(out, escritura)
|
|
}
|
|
return append(out, h...)
|
|
}
|
|
r := func(h ...fiber.Handler) []fiber.Handler {
|
|
return append([]fiber.Handler{scope}, h...)
|
|
}
|
|
|
|
g.Get("/umind/tenants", r(controllers.GetUmindTenants)...)
|
|
g.Get("/umind/agentes", r(controllers.GetUmindAgentesHandler)...)
|
|
g.Post("/umind/agentes", w(controllers.CreateUmindAgenteHandler)...)
|
|
g.Put("/umind/agentes/:id", w(controllers.UpdateUmindAgenteHandler)...)
|
|
g.Post("/umind/agentes/:id/duplicar", w(controllers.DuplicarUmindAgenteHandler)...)
|
|
g.Delete("/umind/agentes/:id", w(controllers.DeleteUmindAgenteHandler)...)
|
|
|
|
g.Get("/umind/plantillas-rubro", r(controllers.GetPlantillasRubroHandler)...)
|
|
g.Get("/umind/documentos", r(controllers.GetUmindDocumentosHandler)...)
|
|
g.Post("/umind/documentos", w(controllers.CreateUmindDocumentoHandler)...)
|
|
g.Post("/umind/documentos/texto", w(controllers.CreateUmindTextoHandler)...)
|
|
g.Post("/umind/documentos/archivo", w(controllers.CreateUmindArchivoHandler)...)
|
|
g.Get("/umind/documentos/:id/fragmentos", r(controllers.GetFragmentosDocumentoHandler)...)
|
|
g.Put("/umind/documentos/:id", w(controllers.ActualizarUmindDocumentoHandler)...)
|
|
g.Post("/umind/documentos/:id/reprocesar", w(controllers.ReprocesarUmindDocumentoHandler)...)
|
|
g.Delete("/umind/documentos/:id", w(controllers.DeleteUmindDocumentoHandler)...)
|
|
|
|
g.Get("/umind/sesiones", r(controllers.GetUmindSesionesHandler)...)
|
|
g.Get("/umind/historial", r(controllers.GetUmindHistorialHandler)...)
|
|
|
|
g.Get("/umind/tools", r(controllers.GetUmindHerramientasHandler)...)
|
|
g.Post("/umind/tools", w(controllers.CreateUmindHerramientaHandler)...)
|
|
g.Put("/umind/tools/:id", w(controllers.UpdateUmindHerramientaHandler)...)
|
|
g.Delete("/umind/tools/:id", w(controllers.DeleteUmindHerramientaHandler)...)
|
|
|
|
g.Get("/umind/canales", r(controllers.GetUmindCanalesHandler)...)
|
|
g.Post("/umind/canales", w(controllers.CreateUmindCanalHandler)...)
|
|
g.Put("/umind/canales/:id", w(controllers.UpdateUmindCanalHandler)...)
|
|
g.Delete("/umind/canales/:id", w(controllers.DeleteUmindCanalHandler)...)
|
|
|
|
g.Post("/umind/chat", r(controllers.UmindChatPruebaHandler)...)
|
|
|
|
g.Get("/umind/conexiones", r(controllers.GetUmindConexionesHandler)...)
|
|
g.Get("/umind/conexiones/conectar", w(controllers.UmindConectarHandler)...)
|
|
g.Get("/umind/vigilancias", w(controllers.GetUmindVigilanciasHandler)...)
|
|
g.Delete("/umind/vigilancias/:id", w(controllers.DeleteUmindVigilanciaHandler)...)
|
|
g.Get("/umind/plantillas", w(controllers.GetUmindPlantillasHandler)...)
|
|
g.Post("/umind/plantillas", w(controllers.CreateUmindPlantillaHandler)...)
|
|
g.Post("/umind/plantillas/importar", w(controllers.ImportarUmindPlantillaHandler)...)
|
|
g.Delete("/umind/plantillas/:id", w(controllers.DeleteUmindPlantillaHandler)...)
|
|
g.Get("/umind/acciones", w(controllers.GetUmindAccionesHandler)...)
|
|
g.Post("/umind/acciones/:id/aprobar", w(controllers.AprobarUmindAccionHandler)...)
|
|
g.Post("/umind/acciones/:id/rechazar", w(controllers.RechazarUmindAccionHandler)...)
|
|
g.Get("/umind/archivos", w(controllers.GetUmindArchivosHandler)...)
|
|
g.Post("/umind/archivos", w(controllers.CreateUmindArchivoRepoHandler)...)
|
|
g.Get("/umind/archivos/:id/descargar", w(controllers.DownloadUmindArchivoHandler)...)
|
|
g.Post("/umind/archivos/:id/conocimiento", w(controllers.UsarArchivoComoConocimientoHandler)...)
|
|
g.Delete("/umind/archivos/:id", w(controllers.DeleteUmindArchivoHandler)...)
|
|
g.Get("/umind/avisos", w(controllers.GetUmindAvisosHandler)...)
|
|
g.Delete("/umind/avisos/:id", w(controllers.DeleteUmindAvisoHandler)...)
|
|
g.Post("/umind/conexiones/imap", w(controllers.CrearConexionImapHandler)...)
|
|
g.Post("/umind/conexiones/:id/probar", w(controllers.ProbarConexionImapAgenteHandler)...)
|
|
g.Delete("/umind/conexiones/:id", w(controllers.DeleteUmindConexionHandler)...)
|
|
|
|
g.Get("/umind/eventos", r(controllers.GetUmindEventosHandler)...)
|
|
g.Get("/umind/uso", r(controllers.GetUmindUsoHandler)...)
|
|
g.Get("/umind/ai-configs", r(controllers.GetUmindAiConfigsHandler)...)
|
|
|
|
// La cuenta de IA propia del cliente: la carga él, queda atada a su espacio
|
|
// y nadie más la ve. Las configs globales del staff no se tocan desde acá.
|
|
g.Get("/umind/ai-propia", r(controllers.ListarAiConfigsPropiasHandler)...)
|
|
g.Post("/umind/ai-propia", w(controllers.CrearAiConfigPropiaHandler)...)
|
|
g.Put("/umind/ai-propia/:id", w(controllers.ActualizarAiConfigPropiaHandler)...)
|
|
g.Delete("/umind/ai-propia/:id", w(controllers.BorrarAiConfigPropiaHandler)...)
|
|
g.Post("/umind/ai-propia/:id/probar", w(controllers.ProbarAiConfigPropiaHandler)...)
|
|
g.Get("/umind/reporte.xlsx", r(controllers.GetUmindReporteHandler)...)
|
|
}
|