- 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>
Ensures tipo_usuario, EsPortalCliente, and other new columns on core
models are created in Docker deployments that never run --migrate.
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>
La tabla prov_servidor_submodules (many2many) solo se creaba con --migrate.
Al agregar ProvServidor al AutoMigrate del arranque normal, GORM crea la
tabla join automáticamente en cada deploy sin necesidad de flags manuales.
También incluye Servidor (agent_token, agent_last_seen, metricas_json)
y ConxDb (host) que tampoco se migraban en el arranque normal.
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>
El Dockerfile no incluía el directorio agent/, por eso GET /agent/install.sh
y GET /agent/download/:filename devolvían 404 — los archivos no existían
en /app/agent/ dentro del contenedor.
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>
- Cross-compila usite-agent para linux/amd64, linux/arm64, linux/arm
Binarios en agent/dist/ (CGO_ENABLED=0, stripped ~6MB c/u)
- GET /agent/download/:filename sirve el binario correcto
con Content-Disposition attachment y validación anti path-traversal
- install.sh ya apunta a /agent/download/usite-agent-linux-ARCH
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>
go-redis/v9 requiere Go 1.24. El Dockerfile estaba usando 1.22,
causando fallo en build de Coolify: 'go: requires go >= 1.24'
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>
- Agrega splitPostgresStatements() que parsea SQL respetando dollar-quoting, strings y comentarios
- En ExecuteSQL, si es PostgreSQL y hay múltiples sentencias, cada una se ejecuta con su propio db.Exec()
- Evita el error: 'CREATE DATABASE cannot run inside a transaction block'
- Error ocurría porque PostgreSQL envuelve multi-statement en transacción implícita al usar simple query protocol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Detecta isPostgres desde tipo_db.nombre al cambiar conexión
- sqlHelpers: getter dinámico — chips distintos para PostgreSQL vs MySQL
PostgreSQL: pg_database, information_schema, pg_stat_activity, pg_indexes
MySQL: SHOW DATABASES/TABLES/USERS/PROCESSLIST/CREATE TABLE
- generateDbHelper: genera SQL correcto por dialecto
PostgreSQL: sin backticks, sin charset, sin @host, DO$$ para CREATE USER IF NOT EXISTS,
GRANT ALL ON DATABASE + SCHEMA + DEFAULT PRIVILEGES
MySQL: backticks, utf8mb4, 'user'@'host', FLUSH PRIVILEGES
- Badge PostgreSQL/MySQL en header del generador DBA
- Campo Host oculto en conexiones PostgreSQL
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Chips rápidos: SHOW DATABASES, SHOW TABLES, SHOW USERS, SHOW GRANTS,
SHOW PROCESSLIST, SHOW CREATE TABLE, DESCRIBE, info_schema engine/charset
- Generador DBA (collapsible): form con BD, usuario, host y contraseña
Operaciones: Setup completo | CREATE DATABASE | CREATE USER | GRANT ALL |
REVOKE | SHOW GRANTS | DROP USER | DROP DATABASE
- Setup completo genera las 3 sentencias en bloque con comentarios
- Visible só
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Añade botones 'Ver' y 'Editar' en cada card de plan
- Modal 'Ver Plan': todos los campos + tabla completa de tarifas por país
(nombre, descripción, características HTML, imagen, cantidad, estado,
plan_id_anual/mensual, PayPal IDs, timestamps, tarifas con pais_id/monto)
- Modal 'Editar Plan': formulario con todos los campos editables
(nombre, descripcion, caracteristicas HTML, cantidad, img, estado,
plan_id_anual/mensual, plan_anual/mensual_paypal)
+ tabla de tarifas en sólo lectura
- Backend: agrega VcardApiPlan (GET) y VcardApiPlanUpdate (PUT) como proxy
- Rutas: GET/PUT /app/vcard-api/planes/:id
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Corrección: p.activo → p.estado (activo no existe en la respuesta)
- Corrección: tarifas usan t.monto, no t.precio/t.moneda/t.periodo
- Mejora: precios únicos resumidos con helper uniqueMontos() (max 5)
- Añade: img del plan, cantidad de vcards permitidas, conteo de tarifas por país
- Añade: ID del plan al pie de cada card
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Tabla VCards: boton 'Ver' abre modal detalle con 3 tabs (Info, Redes, Apariencia)
- Modal Ver VCard: muestra todos los campos, colores con preview, redes configuradas
- Footer del modal: boton 'Ver VCard' abre https://vcard.u-site.app/{unico} en nueva pestaña
- Footer: boton 'Editar' abre modal de edicion desde el ver
- Edit VCard: campo animacion cambiado a select (Sin animacion, Fade, Slide, Zoom, Bounce, Flip)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Reemplaza drill-down inline de Usuarios por modal 'Ver' con tabs:
General, Perfil, VCards, Wallet, Pagos, Logs, MiniWebs
- Añade columna Rol en tabla de usuarios con badge coloreado
- Edit Usuario: rol_id ahora es <select> con nombres reales (administrador/cliente)
- Roles se acumulan automáticamente al cargar usuarios (sin endpoint dedicado)
- Carga lazy de Pagos, Logs, MiniWebs dentro del modal de detalle
- VCards en detalle incluye URL con enlace directo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Nuevo endpoint POST /app/vcard-api/login que llama a /api/login del sistema VCard externo
- Modal de configuración con campos email+password y botón 'Obtener Token'
- El token se auto-rellena en el campo Bearer Token al conectar exitosamente
- Se mantiene la opción de pegar el token manualmente como fallback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Nuevo modelo VcardApiConfig con helpers GetVcardApiConfig/UpsertVcardApiConfig
- Controlador con proxies GET y mutaciones POST/PUT hacia la API externa
- Vista Alpine.js con tabs (Usuarios/VCards/Planes/Pagos/Transacciones/Logs/MiniWebs)
- Seed idempotente en SeedIntegraciones() para registrar submódulo en sidebar
- AutoMigrate de VcardApiConfig en startup normal (main.go)
- Fix CreateUser: setea tipo_usuario='sistema' por defecto
- Fix AllUsersSistema: incluye usuarios con tipo_usuario vacío o NULL
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Implemented VCard API controller with methods to manage configuration (save, get).
- Added proxy functions to handle API requests for users, vcards, memberships, payments, transactions, logs, and miniwebs.
- Included error handling and response formatting for API interactions.
- Botón de ojo reemplazado por badge con etiqueta Visible/Oculto
- Toast de confirmación al cambiar visibilidad (3s, estilo app)
- Tooltip descriptivo con acción esperada
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>