El objeto Alpine.js tenía un } sin coma al final de openAppDeployments,
causando un error de sintaxis JS que impedía la inicialización del componente
y hacía que la página /app/coolify apareciera completamente en blanco.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- CoolifyApplicationStart/Stop/Restart cambian GET → POST (Coolify API requiere POST)
- Nuevo endpoint público POST /webhooks/coolify para recibir notificaciones
de deployment/restart desde Coolify Settings → Notifications → Webhook
- UI: muestra URL del webhook en modal de config para fácil copia
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- rest/controllers/coolify_controller.go: proxy completo hacia API Coolify
- resources/views/coolify.html: interfaz Alpine.js con tabs apps/servers/services/dbs/projects/deployments/team
- rest/routes/user.go: registra todas las rutas /app/coolify/*
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add coolify_config.go model (missing from worktree branch)
- Add CoolifyConfig to normal-startup AutoMigrate → creates table on next start
- Fix miniwebs tab: m.activo is not in API response; fallback to
vcard.estado (true/false) to show real status instead of always Inactiva
- Improve miniwebs row: show url, user name, vcard status badge
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Botón '🚫 + VCards' abre modal de confirmación
- Modal carga y lista las VCards activas del usuario
- Al confirmar: inactiva cada VCard (PUT estado:false) y desactiva el usuario
- Muestra resumen del resultado antes de cerrar
- Botón 'Ordenar por vencimiento' con colores en filas (rojo/amarillo/verde)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Declara users:[] y roles:[] en el estado inicial de Alpine para que
x-for funcione reactivamente desde el primer render
- Agrega totalPages:0 al estado inicial
- Añade comprobación response.ok antes de parsear JSON
- Usa || [] y || 0 para evitar TypeError si el backend retorna error
- Reemplaza data.Users.length con this.users.length (siempre array)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Alpine v3 NO puede rastrear accesos dinámicos pingCargando[cx.ID]
dentro de x-for porque no sabe qué key observar por item.
Solución: estado de ping embebido en cada objeto cx:
- abrirModal inyecta _pingCargando:false y _pingResultado:null en cada cx
- hacerPing muta cx._pingCargando / cx._pingResultado directamente
- template usa cx._pingCargando y cx._pingResultado (proxy reactivo del x-for)
Esto garantiza que el spinner, el botón deshabilitado y el resultado
del ping se actualicen correctamente para cada card.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Problema raíz:
1. El ping TCP usaba Servidor.IpServidor → fallaba si la BD solo escucha
en localhost del servidor remoto (comportamiento normal en producción)
2. La reactividad Alpine v3.13 no detectaba keys nuevas en objeto vacío {}
dentro de x-for loops, spinner nunca aparecía
Cambios:
- pkg/models/conx_db.go: nuevo campo Host (vacío = usa Servidor.IpServidor)
+ método HostEfectivo() como fuente única de verdad para host
- pkg/services/query_runner_service.go: todos los puntos (openDynamicDB,
openDynamicDBWithName, redisConnect, mongoURI) usan c.HostEfectivo()
- rest/controllers/servidor_controller.go: PingConexion reescrito —
primero prueba conexión real a la BD (no solo TCP), si falla prueba TCP,
devuelve host+puerto testeado y mensajes de error descriptivos
- servidor_dashboard.html: hacerPing usa spread-replace para forzar
reactividad + $nextTick, resultado muestra host:puerto testeado y
mensaje de error completo en múltiples líneas
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Backend:
- Servidor model: AgentToken, AgentLastSeen, MetricasJson nuevos campos
- AgentHeartbeat: endpoint público POST /agent/heartbeat (auth por token)
- GenerateAgentToken: endpoint protegido POST /app/servidor/:id/agent-token
- Ruta pública /agent/install.sh sirve el script de instalación
Agente Go (agent/):
- agent/main.go: binario independiente con gopsutil
- Recolecta RAM, CPU, Disco, Uptime, OS, Load average
- Lee agent.yml o flags --api-url / --token
- Envía POST a /agent/heartbeat cada N segundos
- Instala como servicio systemd via install.sh
- agent/go.mod: módulo independiente (usite-agent)
- agent/agent.yml.sample: configuración de ejemplo
- agent/install.sh: instalador en 1 curl para Linux (systemd)
Frontend servidor_dashboard.html:
- Cards: badge ● En línea / ● Fuera / ○ Sin agente
- Barras de progreso live: RAM%, CPU%, Disco%
- Valores: GB usado/total, núcleos, uptime, OS real
- Tiempo desde último reporte
- Botón 'Agente' en cada card → modal de configuración
- Modal agente: estado, token con copy, comando curl 1 línea,
instalación manual/avanzada con collapse, métricas actuales
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Cambia spread+reassign por mutación directa (this.pingCargando[id] = true)
para garantizar reactividad correcta en Alpine.js 3.x
- Usa (cx.ID || cx.id) en toda la plantilla para compatibilidad con
ambos formatos de serialización JSON de GORM
- Agrega type="button" y @click.stop en el botón de verificar
- Maneja respuestas HTTP no-OK con mensaje de error explícito
- Muestra mensaje de error real del catch en la UI
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Mueve el resultado del ping directamente bajo los datos de la BD
- Muestra mensaje de error cuando falla la conexión (usa campo error del backend)
- Spinner y texto 'Probando...' durante la espera
- Resultado verde/rojo inline con ✓/✗ y tiempo/mensaje de error
- Etiqueta del botón cambia a 'Verificar' (más descriptivo que 'Ping')
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ProvServidor model: add Integraciones []Submodules (many2many:prov_servidor_submodules)
- GetAllProvServidor: preload Integraciones
- SetProvServidorIntegraciones: new model func to replace associations
- New endpoint PUT /app/provservidor/:id/integraciones
- GetSubmodules: support ?limit= query param
- prov_servidor.html: show integrations as badges in table, view modal,
and edit modal with checkboxes to select one or more existing submodules
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- GetServidor: query conx_count per server with GROUP BY and attach to response
- servidor_dashboard.html: use conx_count from API (fallback to _conexiones.length)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Routes are registered under /app (web group), not /api/app.
The requests were hitting the JWT-protected API group causing 'Invalid Attempt' error.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Added console.log statements to track data loading
- Better error messages with emojis and details
- Shows count of servidores, proveedores, tipos loaded
- Helps diagnose if data is not loading
This will help identify if:
- API endpoint is working
- Data is being returned
- Frontend is processing it correctly
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Created servidor_dashboard.html with beautiful visual dashboard
- Shows all servers in grid cards with basic info
- Click button opens detailed modal with:
- Server full information (IP, CPU, RAM, Storage, OS, Expiration)
- All connected databases in a clean diagram layout
- Database connection status (active/inactive)
- Connection details (Host, Port, User, Type)
- Ping button to test connection with response time
- View Connection button to open query-runner
- Backend updates:
- Added ServidorDashboard() controller to render the dashboard view
- Added GetServidorDashboard() API endpoint to fetch server + connections
- Added PingConexion() endpoint to test database connections (TCP + DB test)
- Color-coded status badges and database type indicators
- Responsive design for mobile and desktop
- Routes:
- GET /app/servidor-dashboard (render view)
- GET /api/app/servidor-dashboard/:id (get server details API)
- GET /api/app/conx-ping/:id (ping connection endpoint)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Backend:
- Agrega github.com/redis/go-redis/v9 como dependencia
- isRedisDriver() detecta 'redis' y 'valkey' en nombre del tipo de BD
- redisConnect(): abre cliente Redis con auth, host, port, db index
- redisTestConnection(): PING para probar conexión
- redisListDatabases(): lee CONFIG GET databases → devuelve db0..dbN
- redisListKeys(): SCAN iterativo, hasta 200 keys del db seleccionado
- redisExecuteCommand(): parsea comandos línea a línea, multi-comando
devuelve tabla command/result/error; comando único devuelve QueryResult
tipado (string, int64, []any para KEYS/SMEMBERS/LRANGE, HGETALL como
field/value table)
- redisParseArgs(): tokenizador respetando comillas simples y dobles
- Todos los comandos se guardan en query_history
Frontend:
- isRedis: false estado y reset en onConxChange()
- Detecta redis/valkey en tipo_db.nombre
- Editor cambia label 'Redis CLI', placeholder con ejemplos Redis
- Sidebar: 'Keys' en lugar de 'Tablas' para Redis
- insertTable(): TYPE + TTL + GET para inspeccionar una key de Redis
- Panel de chips rojos: KEYS *, DBSIZE, INFO, CONFIG GET, CLIENT LIST, SLOWLOG
- Generador Redis: select de 24 comandos + formulario contextual
(key, value, ttl, field según el comando elegido)
- generateRedisCmd(): genera el comando en el editor
- Badge MySQL no aparece cuando es Redis
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>