feat(umind): el cliente administra sus agentes desde el portal
Acá es donde uMind deja de ser una herramienta interna: el cliente entra a /portal/studio con su sesión de portal y gestiona lo suyo. - UmindScopePortal/UmindScopeStaff es el ÚNICO punto donde se decide el alcance. El del cliente sale de GetClienteIDsForPortalUser, el mismo que ya autoriza el resto del portal. nil = staff sin restricción, slice vacío = no ve nada; una ruta sin scope también cae en "no ve nada" para que olvidarse el middleware falle visible y no abra todo. - Un solo set de handlers montado bajo /app/umind y /portal/umind (RegistrarRutasUmind). Duplicarlos sería duplicar las chances de olvidar un chequeo. - Guarda de acceso en TODOS los handlers, incluidos los sub-recursos que llegan por :id (documento, tool, canal, conexión): hay que cargarlos para saber de quién son, si no un cliente podría borrar el canal de otro adivinando el id. Responden 404, no 403: un 403 confirmaría que el recurso existe. - Cierra un bug preexistente: las lecturas GET /app/umind/* no tenían SoloAdmin ni pasaban por MenuMiddleware, así que cualquier usuario de staff podía leer los tenants de todos los clientes. - Límite de agentes por plan (409 con mensaje claro). Un tenant sin plan no tiene límite: cortarles de golpe sería peor que dejarlos como estaban. - /umind/ai-configs reemplaza con alcance a /app/api/ai-config/select, que devolvía TODAS las configs del sistema. - El SPA deduce por la URL si es staff o cliente (base del router, prefijo de API y URL de login) y oculta lo que es solo de staff. - Test de aislamiento entre clientes: 7 casos, incluido que un scope vacío no se confunda con staff. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
08265510ea
commit
5b78f6677c
@@ -0,0 +1,66 @@
|
||||
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.Delete("/umind/agentes/:id", w(controllers.DeleteUmindAgenteHandler)...)
|
||||
|
||||
g.Get("/umind/documentos", r(controllers.GetUmindDocumentosHandler)...)
|
||||
g.Post("/umind/documentos", w(controllers.CreateUmindDocumentoHandler)...)
|
||||
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.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)...)
|
||||
}
|
||||
Reference in New Issue
Block a user