From c82831702e02a9332ab8d276596562913aae59d9 Mon Sep 17 00:00:00 2001
From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com>
Date: Mon, 25 May 2026 15:14:04 -0500
Subject: [PATCH] up
---
migrations/migrate.go | 2 +
pkg/models/coolify_config.go | 54 ++
resources/views/coolify.html | 1186 ++++++++++++++++++++++++
rest/controllers/coolify_controller.go | 313 +++++++
rest/controllers/seed_controller.go | 1 +
rest/routes/user.go | 50 +
6 files changed, 1606 insertions(+)
create mode 100644 pkg/models/coolify_config.go
create mode 100644 resources/views/coolify.html
create mode 100644 rest/controllers/coolify_controller.go
diff --git a/migrations/migrate.go b/migrations/migrate.go
index 84bcf5f..3574acd 100755
--- a/migrations/migrate.go
+++ b/migrations/migrate.go
@@ -93,6 +93,8 @@ func Migrate() {
&models.PartnerComunicado{},
// Integración VCard API Admin (Laravel)
&models.VcardApiConfig{},
+ // Integración Coolify
+ &models.CoolifyConfig{},
); err != nil {
log.Fatalf("Error during main migration: %v", err)
}
diff --git a/pkg/models/coolify_config.go b/pkg/models/coolify_config.go
new file mode 100644
index 0000000..da584e4
--- /dev/null
+++ b/pkg/models/coolify_config.go
@@ -0,0 +1,54 @@
+package models
+
+import (
+ "github.com/sujit-baniya/fiber-boilerplate/app"
+ "gorm.io/gorm"
+)
+
+// CoolifyConfig almacena las credenciales para la API REST de Coolify.
+// Coolify expone su API en {base_url}/api/v1 con Bearer token.
+type CoolifyConfig struct {
+ gorm.Model
+ Nombre string `json:"nombre" gorm:"column:nombre;not null"`
+ BaseURL string `json:"base_url" gorm:"column:base_url;type:text;not null"`
+ ApiToken string `json:"api_token" gorm:"column:api_token;type:text;not null"`
+ Activo bool `json:"activo" gorm:"column:activo;default:true"`
+}
+
+func (CoolifyConfig) TableName() string { return "coolify_configs" }
+
+func GetCoolifyConfig() (*CoolifyConfig, error) {
+ var cfg CoolifyConfig
+ if err := app.Http.Database.DB.First(&cfg).Error; err != nil {
+ return nil, err
+ }
+ return &cfg, nil
+}
+
+func UpsertCoolifyConfig(nombre, baseURL, apiToken string, activo bool) (*CoolifyConfig, error) {
+ var cfg CoolifyConfig
+ err := app.Http.Database.DB.First(&cfg).Error
+ if err != nil {
+ // No existe → crear
+ cfg = CoolifyConfig{
+ Nombre: nombre,
+ BaseURL: baseURL,
+ ApiToken: apiToken,
+ Activo: activo,
+ }
+ if createErr := app.Http.Database.DB.Create(&cfg).Error; createErr != nil {
+ return nil, createErr
+ }
+ return &cfg, nil
+ }
+ cfg.Nombre = nombre
+ cfg.BaseURL = baseURL
+ if apiToken != "" {
+ cfg.ApiToken = apiToken
+ }
+ cfg.Activo = activo
+ if err := app.Http.Database.DB.Save(&cfg).Error; err != nil {
+ return nil, err
+ }
+ return &cfg, nil
+}
diff --git a/resources/views/coolify.html b/resources/views/coolify.html
new file mode 100644
index 0000000..6e4c915
--- /dev/null
+++ b/resources/views/coolify.html
@@ -0,0 +1,1186 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Coolify
+
Gestión completa de aplicaciones, servicios, bases de datos, servidores y despliegues a través de la API de Coolify.
+
+
+
+
+
+
+ Configurar API
+
+
+
+
+
+ Sin configuración activa. Haz clic en "Configurar API" para ingresar la URL base y el token de tu instancia de Coolify.
+ El token lo generas en Coolify → Keys & Tokens → API tokens .
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Buscar
+
+
+
+
+
+
+
+
Sin aplicaciones. Haz clic en "Actualizar".
+
+
+
+
+
+
+
+
+
+
+
+
+ Build:
+
+
+
+
+
+
+ Start
+
+
+
+ Stop
+
+
+
+ Restart
+
+
+
+ Deploy
+
+
+
+ Logs
+
+
+
+ Envs
+
+
+
+ Historial
+
+
+
+
+
+
+
+
+
+
+
+
+
Sin servidores. Haz clic en "Actualizar".
+
+
+
+
+
+
Deshabilitado
+
Activo
+
+
+
IP:
+
Puerto SSH:
+
Usuario:
+
Proxy:
+
+
+ Build Server
+ CF Tunnel
+ Jump Server
+ Swarm Manager
+
+
+
+ Validar conexión
+
+
+ Recursos
+
+
+ Dominios
+
+
+
+
+
+
+
+
+
+
+
Sin servicios. Haz clic en "Actualizar".
+
+
+
+
+
+
+ Start
+ Stop
+ Restart
+ Envs
+
+
+
+
+
+
+
+
+
+
Sin bases de datos. Haz clic en "Actualizar".
+
+
+
+
+
+
+ Start
+ Stop
+ Restart
+
+
+
+
+
+
+
+
+
+
Sin proyectos. Haz clic en "Actualizar".
+
+
+
+
+
+
+
+
+
+
+
+ Ver entornos
+
+
+
+
+
+
+
+
+
+
Sin despliegues. Haz clic en "Actualizar".
+
+
+
+
+ Aplicación
+ Status
+ Commit
+ Iniciado
+ Logs
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ver
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID:
+ Equipo personal
+
+
+
+
Sin miembros cargados.
+
+
Miembros del equipo
+
+
+
+
+ Nombre
+ Email
+ Rol
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Configurar Coolify API
+
Ingresa la URL base de tu instancia y el token de API.
+
+
+
+ Nombre (referencia)
+
+
+
+
URL Base *
+
+
Ej: http://10.0.0.1:8000 o https://app.coolify.io
+
+
+
API Token *
+
+
Genera el token en Coolify → Keys & Tokens → API tokens . Deja en blanco para no cambiar el token guardado.
+
+
+
+ Integración activa
+
+
+
+
+
+
+
+ Probar conexión
+
+
+ Cancelar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Actualizar
+
+ ×
+
+
+
+ Cargando logs...
+ Sin logs disponibles.
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
Cargando variables...
+
Sin variables de entorno.
+
+
+
+
+ Preview
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
Cargando...
+
Sin despliegues registrados.
+
+
+
+ UUID
+ Status
+ Commit
+ Fecha
+ Logs
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ver
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Log de despliegue
+ ×
+
+
+ Sin log disponible.
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
Cargando recursos...
+
Sin recursos.
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
Cargando dominios...
+
Sin dominios.
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
Cargando entornos...
+
Sin entornos.
+
+
+
+
+
+
+
+
+
+
diff --git a/rest/controllers/coolify_controller.go b/rest/controllers/coolify_controller.go
new file mode 100644
index 0000000..bfec79b
--- /dev/null
+++ b/rest/controllers/coolify_controller.go
@@ -0,0 +1,313 @@
+package controllers
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/gofiber/fiber/v2"
+ "github.com/sujit-baniya/fiber-boilerplate/pkg/models"
+)
+
+// ─── helpers internos ────────────────────────────────────────────────────────
+
+// coolifyDo ejecuta una petición a la API de Coolify y devuelve el body crudo.
+func coolifyDo(method, endpoint string, reqBody io.Reader, contentType string, cfg *models.CoolifyConfig) ([]byte, int, error) {
+ base := strings.TrimRight(cfg.BaseURL, "/")
+ url := fmt.Sprintf("%s/api/v1%s", base, endpoint)
+
+ client := &http.Client{Timeout: 30 * time.Second}
+ req, err := http.NewRequest(method, url, reqBody)
+ if err != nil {
+ return nil, 0, err
+ }
+ req.Header.Set("Authorization", "Bearer "+cfg.ApiToken)
+ req.Header.Set("Accept", "application/json")
+ if contentType != "" {
+ req.Header.Set("Content-Type", contentType)
+ }
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, 0, err
+ }
+ defer resp.Body.Close()
+ body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024*1024))
+ return body, resp.StatusCode, nil
+}
+
+// coolifyProxy resuelve config, aplica qs de la request y responde al frontend.
+func coolifyProxy(c *fiber.Ctx, method, endpoint string) error {
+ cfg, err := models.GetCoolifyConfig()
+ if err != nil {
+ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Configura primero la integración Coolify"})
+ }
+ if !cfg.Activo {
+ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "La integración Coolify está inactiva"})
+ }
+
+ ep := endpoint
+ if qs := string(c.Request().URI().QueryString()); qs != "" {
+ ep = endpoint + "?" + qs
+ }
+
+ var bodyReader io.Reader
+ ct := ""
+ if raw := c.Body(); len(raw) > 0 {
+ bodyReader = strings.NewReader(string(raw))
+ ct = c.Get("Content-Type", "application/json")
+ }
+
+ body, status, err := coolifyDo(method, ep, bodyReader, ct, cfg)
+ if err != nil {
+ return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
+ }
+
+ var result json.RawMessage
+ if err := json.Unmarshal(body, &result); err != nil {
+ result = json.RawMessage(fmt.Sprintf(`{"raw":%q}`, string(body)))
+ }
+ c.Status(status)
+ return c.JSON(result)
+}
+
+// ─── Página principal ─────────────────────────────────────────────────────────
+
+func CoolifyIndex(c *fiber.Ctx) error {
+ cfg, _ := models.GetCoolifyConfig()
+ return c.Render("coolify", fiber.Map{
+ "user": c.Locals("user").(map[string]interface{}),
+ "modules": c.Locals("userModules"),
+ "config": cfg,
+ }, "layouts/main")
+}
+
+// ─── Configuración ────────────────────────────────────────────────────────────
+
+func CoolifyGetConfig(c *fiber.Ctx) error {
+ cfg, err := models.GetCoolifyConfig()
+ if err != nil {
+ return c.JSON(fiber.Map{"config": nil})
+ }
+ masked := "••••••••"
+ if cfg.ApiToken == "" {
+ masked = ""
+ }
+ return c.JSON(fiber.Map{"config": fiber.Map{
+ "ID": cfg.ID,
+ "nombre": cfg.Nombre,
+ "base_url": cfg.BaseURL,
+ "api_token": masked,
+ "activo": cfg.Activo,
+ }})
+}
+
+func CoolifySaveConfig(c *fiber.Ctx) error {
+ type Req struct {
+ Nombre string `json:"nombre"`
+ BaseURL string `json:"base_url"`
+ ApiToken string `json:"api_token"`
+ Activo bool `json:"activo"`
+ }
+ var req Req
+ if err := c.BodyParser(&req); err != nil {
+ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"})
+ }
+ req.BaseURL = strings.TrimRight(strings.TrimSpace(req.BaseURL), "/")
+ if req.BaseURL == "" {
+ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "base_url es requerido"})
+ }
+ cfg, err := models.UpsertCoolifyConfig(req.Nombre, req.BaseURL, req.ApiToken, req.Activo)
+ if err != nil {
+ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
+ }
+ return c.JSON(fiber.Map{"ok": true, "config": cfg})
+}
+
+// CoolifyTestConnection verifica conectividad con /health (no requiere auth).
+func CoolifyTestConnection(c *fiber.Ctx) error {
+ cfg, err := models.GetCoolifyConfig()
+ if err != nil {
+ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Sin config"})
+ }
+ base := strings.TrimRight(cfg.BaseURL, "/")
+ client := &http.Client{Timeout: 10 * time.Second}
+ resp, err := client.Get(base + "/api/health")
+ if err != nil {
+ return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"error": err.Error()})
+ }
+ defer resp.Body.Close()
+ body, _ := io.ReadAll(io.LimitReader(resp.Body, 64*1024))
+ var result json.RawMessage
+ if jsonErr := json.Unmarshal(body, &result); jsonErr != nil {
+ result = json.RawMessage(fmt.Sprintf(`{"raw":%q}`, string(body)))
+ }
+ c.Status(resp.StatusCode)
+ return c.JSON(result)
+}
+
+// ─── Applications ─────────────────────────────────────────────────────────────
+
+func CoolifyListApplications(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications")
+}
+
+func CoolifyGetApplication(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid"))
+}
+
+func CoolifyApplicationLogs(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid")+"/logs")
+}
+
+func CoolifyApplicationEnvs(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid")+"/envs")
+}
+
+func CoolifyApplicationEnvCreate(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodPost, "/applications/"+c.Params("uuid")+"/envs")
+}
+
+func CoolifyApplicationEnvUpdateBulk(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodPatch, "/applications/"+c.Params("uuid")+"/envs")
+}
+
+func CoolifyApplicationEnvDelete(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodDelete, "/applications/"+c.Params("uuid")+"/envs/"+c.Params("env_id"))
+}
+
+func CoolifyApplicationStart(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid")+"/start")
+}
+
+func CoolifyApplicationStop(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid")+"/stop")
+}
+
+func CoolifyApplicationRestart(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid")+"/restart")
+}
+
+func CoolifyApplicationDeployments(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/applications/"+c.Params("uuid")+"/deployments")
+}
+
+func CoolifyApplicationDeploy(c *fiber.Ctx) error {
+ // POST /api/v1/deploy?uuid={uuid}&force=false
+ return coolifyProxy(c, http.MethodPost, "/deploy")
+}
+
+// ─── Servers ──────────────────────────────────────────────────────────────────
+
+func CoolifyListServers(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/servers")
+}
+
+func CoolifyGetServer(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/servers/"+c.Params("uuid"))
+}
+
+func CoolifyServerResources(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/servers/"+c.Params("uuid")+"/resources")
+}
+
+func CoolifyServerDomains(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/servers/"+c.Params("uuid")+"/domains")
+}
+
+func CoolifyServerValidate(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/servers/"+c.Params("uuid")+"/validate")
+}
+
+// ─── Services ─────────────────────────────────────────────────────────────────
+
+func CoolifyListServices(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/services")
+}
+
+func CoolifyGetService(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/services/"+c.Params("uuid"))
+}
+
+func CoolifyServiceStart(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/services/"+c.Params("uuid")+"/start")
+}
+
+func CoolifyServiceStop(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/services/"+c.Params("uuid")+"/stop")
+}
+
+func CoolifyServiceRestart(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/services/"+c.Params("uuid")+"/restart")
+}
+
+func CoolifyServiceEnvs(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/services/"+c.Params("uuid")+"/envs")
+}
+
+func CoolifyServiceEnvUpdateBulk(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodPatch, "/services/"+c.Params("uuid")+"/envs")
+}
+
+// ─── Databases ────────────────────────────────────────────────────────────────
+
+func CoolifyListDatabases(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/databases")
+}
+
+func CoolifyGetDatabase(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/databases/"+c.Params("uuid"))
+}
+
+func CoolifyDatabaseStart(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/databases/"+c.Params("uuid")+"/start")
+}
+
+func CoolifyDatabaseStop(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/databases/"+c.Params("uuid")+"/stop")
+}
+
+func CoolifyDatabaseRestart(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/databases/"+c.Params("uuid")+"/restart")
+}
+
+// ─── Projects ─────────────────────────────────────────────────────────────────
+
+func CoolifyListProjects(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/projects")
+}
+
+func CoolifyGetProject(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/projects/"+c.Params("uuid"))
+}
+
+func CoolifyProjectEnvironments(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/projects/"+c.Params("uuid")+"/environments")
+}
+
+// ─── Deployments ──────────────────────────────────────────────────────────────
+
+func CoolifyListDeployments(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/deployments")
+}
+
+func CoolifyGetDeployment(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/deployments/"+c.Params("uuid"))
+}
+
+// ─── Teams ────────────────────────────────────────────────────────────────────
+
+func CoolifyListTeams(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/teams")
+}
+
+func CoolifyCurrentTeam(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/teams/current")
+}
+
+func CoolifyTeamMembers(c *fiber.Ctx) error {
+ return coolifyProxy(c, http.MethodGet, "/teams/current/members")
+}
diff --git a/rest/controllers/seed_controller.go b/rest/controllers/seed_controller.go
index 22182d6..82f4287 100644
--- a/rest/controllers/seed_controller.go
+++ b/rest/controllers/seed_controller.go
@@ -15,6 +15,7 @@ func RunSeed(c *fiber.Ctx) error {
if err := seedModulo("Integraciones", "Conexión con servicios externos: Hostinger, Cloudflare y más", []seedEntry{
{"Hostinger", "Panel de VPS, dominios, hosting y DNS de Hostinger", "/app/hostinger"},
{"Cloudflare", "Gestión de zonas, DNS, SSL y firewall en Cloudflare", "/app/cloudflare"},
+ {"Coolify", "Gestión de aplicaciones, servicios, bases de datos y deployments con Coolify", "/app/coolify"},
{"Pasarelas de Pago", "Configuración de Bold, dLocal y otras pasarelas", "/app/pasarelas-pago"},
}); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
diff --git a/rest/routes/user.go b/rest/routes/user.go
index 2464fb4..99955be 100755
--- a/rest/routes/user.go
+++ b/rest/routes/user.go
@@ -163,6 +163,56 @@ func UserRoutes(app fiber.Router) {
protected.Get("/cloudflare/zones/:zone_id/ssl", controllers.GetCloudflareSSL)
protected.Get("/cloudflare/zones/:zone_id/firewall", controllers.GetCloudflareFirewall)
+ // ─── Coolify API ──────────────────────────────────────────────────
+ protected.Get("/coolify", middlewares.MenuMiddleware, controllers.CoolifyIndex)
+ protected.Get("/coolify/config", controllers.CoolifyGetConfig)
+ protected.Post("/coolify/config", controllers.CoolifySaveConfig)
+ protected.Get("/coolify/health", controllers.CoolifyTestConnection)
+ // Applications
+ protected.Get("/coolify/apps", controllers.CoolifyListApplications)
+ protected.Get("/coolify/apps/:uuid", controllers.CoolifyGetApplication)
+ protected.Get("/coolify/apps/:uuid/logs", controllers.CoolifyApplicationLogs)
+ protected.Get("/coolify/apps/:uuid/envs", controllers.CoolifyApplicationEnvs)
+ protected.Post("/coolify/apps/:uuid/envs", controllers.CoolifyApplicationEnvCreate)
+ protected.Patch("/coolify/apps/:uuid/envs", controllers.CoolifyApplicationEnvUpdateBulk)
+ protected.Delete("/coolify/apps/:uuid/envs/:env_id", controllers.CoolifyApplicationEnvDelete)
+ protected.Get("/coolify/apps/:uuid/start", controllers.CoolifyApplicationStart)
+ protected.Get("/coolify/apps/:uuid/stop", controllers.CoolifyApplicationStop)
+ protected.Get("/coolify/apps/:uuid/restart", controllers.CoolifyApplicationRestart)
+ protected.Get("/coolify/apps/:uuid/deployments", controllers.CoolifyApplicationDeployments)
+ protected.Post("/coolify/apps/:uuid/deploy", controllers.CoolifyApplicationDeploy)
+ // Servers
+ protected.Get("/coolify/servers", controllers.CoolifyListServers)
+ protected.Get("/coolify/servers/:uuid", controllers.CoolifyGetServer)
+ protected.Get("/coolify/servers/:uuid/resources", controllers.CoolifyServerResources)
+ protected.Get("/coolify/servers/:uuid/domains", controllers.CoolifyServerDomains)
+ protected.Get("/coolify/servers/:uuid/validate", controllers.CoolifyServerValidate)
+ // Services
+ protected.Get("/coolify/services", controllers.CoolifyListServices)
+ protected.Get("/coolify/services/:uuid", controllers.CoolifyGetService)
+ protected.Get("/coolify/services/:uuid/start", controllers.CoolifyServiceStart)
+ protected.Get("/coolify/services/:uuid/stop", controllers.CoolifyServiceStop)
+ protected.Get("/coolify/services/:uuid/restart", controllers.CoolifyServiceRestart)
+ protected.Get("/coolify/services/:uuid/envs", controllers.CoolifyServiceEnvs)
+ protected.Patch("/coolify/services/:uuid/envs", controllers.CoolifyServiceEnvUpdateBulk)
+ // Databases
+ protected.Get("/coolify/databases", controllers.CoolifyListDatabases)
+ protected.Get("/coolify/databases/:uuid", controllers.CoolifyGetDatabase)
+ protected.Get("/coolify/databases/:uuid/start", controllers.CoolifyDatabaseStart)
+ protected.Get("/coolify/databases/:uuid/stop", controllers.CoolifyDatabaseStop)
+ protected.Get("/coolify/databases/:uuid/restart", controllers.CoolifyDatabaseRestart)
+ // Projects
+ protected.Get("/coolify/projects", controllers.CoolifyListProjects)
+ protected.Get("/coolify/projects/:uuid", controllers.CoolifyGetProject)
+ protected.Get("/coolify/projects/:uuid/environments", controllers.CoolifyProjectEnvironments)
+ // Deployments
+ protected.Get("/coolify/deployments", controllers.CoolifyListDeployments)
+ protected.Get("/coolify/deployments/:uuid", controllers.CoolifyGetDeployment)
+ // Team
+ protected.Get("/coolify/team", controllers.CoolifyCurrentTeam)
+ protected.Get("/coolify/team/members", controllers.CoolifyTeamMembers)
+ protected.Get("/coolify/teams", controllers.CoolifyListTeams)
+
// ─── Pasarelas de Pago ────────────────────────────────────────────
protected.Get("/pasarelas-pago", middlewares.MenuMiddleware, controllers.PasarelasPage)
// Bold