| Salud | NIT | Versión | Plataforma | Licencia | Outbox | Err 24h | Último reporte | Vendedor |
|---|
| Estado | NIT | Meses | Sedes | Valor | Origen | Creada | Pagada | Transacción | Nota |
|---|
| NIT | Razón social | Contacto | Ciudad | Teléfono | Dirección | Instalaciones | Críticas | Licencia mín. | Vendedor(es) | Último reporte |
|---|
| Tipo | NIT | Vendedor | Motivo | Emitida | Notificada |
|---|
| Estado | Comando | Huella | Detalle | Creado | Completado |
|---|
El servidor firma el comando con la clave ECDSA del proveedor y lo entrega a cada instalación en su próximo check-in. Los clientes validan la firma antes de aplicar; el valor aplicado persiste aunque el comando venza.
Valores publicados actualmente
| Clave | Descripción | Valor | Comando vence |
|---|
Relay central de correo
Los POS de la flota envían sus correos (backups, alertas) a través de este servidor. La contraseña SMTP vive SOLO aquí: rotarla es cambiarla una vez, sin tocar ninguna instalación. Base: variables de entorno SMTP_*; lo guardado aquí las reemplaza (data/smtp-config.json).
💡 Con Gmail use una contraseña de aplicación (myaccount.google.com → Seguridad → Verificación en dos pasos → Contraseñas de aplicaciones), no la contraseña normal de la cuenta.
Adopción de versiones en la flota
| Plataforma | Versión | Instalaciones | Estado |
|---|
Historial de releases
| Versión | Plataforma | URL | Obligatoria | Notas | Publicado |
|---|
| NIT | Precio sede/mes | Desde | Hasta | Nota |
|---|
| Fecha | IP | Método | Ruta | Resultado |
|---|
| Archivo | Tamaño | Creado |
|---|
📚 Documentación técnica
Guías y runbooks del sistema. Audiencia: implementador / soporte / administrador técnico.
Cargando catálogo…
📖 Guía de operación del panel de flota
Referencia rápida de cada sección y de los procesos habituales del proveedor. Todo el panel requiere la llave de administrador (variable de entorno ADMIN_API_KEY del servidor), que se ingresa arriba y se guarda en este navegador.
🗺️ ¿Cómo funciona todo? — Mapa general del sistema
Reportan estado (check-in)
y reciben órdenes.
periódico
Licencias, comandos, config,
releases, relay de correo.
+ llave admin
y administra la flota
desde el navegador.
La regla de oro (modelo pull): el servidor NUNCA se conecta a las instalaciones. Cada instalación «llama a casa» periódicamente (check-in) y en esa misma respuesta recibe: comandos pendientes, configuración publicada y noticias de releases. Por eso todo cambio tarda hasta el próximo check-in de cada equipo en aplicarse.
🚀 Primeros pasos y puesta en marcha del servidor
El servidor se configura exclusivamente con variables de entorno (nunca hay secretos en archivos):
ADMIN_API_KEY— llave para entrar a este panel y a los endpoints administrativos.LICENSE_PRIVATE_KEY— clave privada ECDSA del proveedor; firma códigos de activación y comandos de configuración. Sin ella no se puede activar licencias ni publicar configuración.WOMPI_PRIVATE_KEYyWOMPI_EVENTS_SECRET— integración de pagos Wompi.SMTP_HOST/SMTP_USER/SMTP_PASSWORD— relay central de correo de la flota. Rotar la contraseña = cambiar la variable y reiniciar; la flota no se toca.LICENSE_DATA_PATH,FLEET_DATA_PATH— rutas de los archivos de datos (por defectodata/junto al ejecutable).DEVICE_TOKEN_SECRET— activa el token por instalación del relay de correo (anti-suplantación). Vea la sección «🔐 Seguridad».REQUIRE_HTTPS=true— rechaza todo tráfico sin HTTPS (respetaX-Forwarded-Protodel reverse proxy).BACKUP_OFFSITE_PATH— segunda copia de cada backup en otro destino (regla 3-2-1).NEW_INSTALLS_PER_DAY_ALERT— umbral de alerta por crecimiento anómalo del inventario (por defecto 50/día).
Puesta en marcha desde cero
- Genere el par de claves del proveedor:
licensetool keys→ guardalicense-private.key(secreta, solo el servidor) ylicense-public.key(se embebe en la app). - Defina las variables de entorno del servidor (
ADMIN_API_KEY,LICENSE_PRIVATE_KEY, SMTP, Wompi). - Inicie el servidor (consola, servicio o Docker) y abra
/adminen el navegador. - Ingrese la llave de administrador y pulse Conectar.
- Espere el primer check-in de las instalaciones: aparecerán solas en el tab Instalaciones.
data/: contiene activaciones, instalaciones, precios, vendedores y configuración publicada.🔐 Seguridad — token por instalación del relay de correo
El relay de correo puede exigir un token secreto por instalación (header X-Device-Token). El servidor lo deriva con HMAC-SHA256 de un secreto que solo el servidor conoce: una huella inventada jamás podrá producir un token válido, lo que elimina por completo la suplantación y el uso del relay como spam.
¿Cómo se distribuye el token a la flota?
Pasos para activarlo
- Genere un secreto fuerte (64 caracteres hex). En PowerShell:
[Convert]::ToHexString([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))— o en Linux:openssl rand -hex 32. - Configúrelo como variable de entorno
DEVICE_TOKEN_SECRETy reinicie el servidor. Nunca lo guarde en archivos ni en el repositorio. - Espere ~24 horas (un ciclo de check-in): cada POS con licencia pagada recibe y guarda su token automáticamente.
- Listo: el relay ya exige el token. Las huellas falsas reciben 401 aunque hagan check-in.
Preguntas frecuentes
| Situación | Qué pasa |
|---|---|
Sin DEVICE_TOKEN_SECRET | El relay funciona como antes (huella conocida + límites). El token es opcional. |
| Cambio el secreto | Todos los tokens quedan inválidos; la flota recibe el nuevo en su siguiente check-in (~24 h). Útil si sospecha una filtración. |
| Instalación sin pago | Nunca recibe token: no puede usar el relay aunque haga check-in. |
| POS reinstalado | Misma huella + pago previo ⇒ recibe su token de nuevo en el primer check-in. |
🛰️ Instalaciones — monitoreo de la flota
Muestra cada instalación que ha hecho check-in (la app reporta su estado periódicamente de forma automática). Columnas clave:
- Salud: Ok normal, Advertencia requiere atención pronto, Crítico requiere acción inmediata (licencia vencida, muchos errores, sin reportar).
- Licencia: estado y días restantes.
- Outbox: correos/sincronizaciones pendientes en el equipo (número alto sostenido = problema de conectividad del cliente).
- Err 24h: errores registrados en las últimas 24 horas.
Procesos habituales: asignar vendedor a una instalación (campo editable en la fila), verificar geo-discrepancias (⚠️ indica que la ciudad declarada no coincide con la IP — posible copia de la instalación), y enviar comandos remotos desde la fila.
¿Qué hago según la salud?
| Veo | Significa | Acción recomendada |
|---|---|---|
| Ok | Todo normal | Nada 😊 |
| Advertencia | Licencia por vencer u outbox creciendo | Contacte al cliente para renovar / revise su internet |
| Crítico | Licencia vencida, muchos errores o sin reportar | Llame al cliente; envíe Ping para confirmar conectividad |
| ⚠️ geo | Ciudad declarada ≠ ciudad por IP | Posible copia: verifique con el cliente y marque como verificado si es legítimo |
🔑 Licencias — ciclo de vida de las activaciones
Historial completo de todas las activaciones de licencia: pagadas por Wompi, generadas manualmente y revocadas. Desde aquí se administra el ciclo de vida completo sin salir del panel.
- Ver código (🔑): recupera el código de activación firmado de una licencia pagada, para reenviarlo al cliente si lo perdió.
- Activación manual (➕): genera un código firmado sin pasar por la pasarela de pago. Úsela solo cuando el pago fue verificado por otro medio (transferencia, efectivo). Requiere NIT, huella del equipo (la muestra la app del cliente) y meses. Queda auditada con origen "Manual".
- Revocar (⛔): invalida una licencia pagada en el servidor (p. ej. contracargo o fraude). Pide un motivo y queda registrada en Auditoría. Es idempotente: revocar dos veces no genera error.
Estados de una activación
| Estado | Significa |
|---|---|
| Pendiente | El cliente generó el link de pago pero aún no paga. |
| Pagada | Pago confirmado; el código de activación ya fue emitido. |
| Rechazada | El pago fue declinado o anulado en la pasarela. |
| Revocada | Un administrador invalidó la licencia manualmente. |
👥 Clientes — visión por NIT
Agrupa las instalaciones por cliente (NIT) con sus datos de contacto reportados por la propia app. Útil para saber cuántos equipos tiene cada cliente, cuáles están críticos y cuándo reportaron por última vez. Es solo lectura: los datos se corrigen en la app del cliente.
💰 Comisiones y 🧑💼 Vendedores
Comisiones
Liquida comisiones por rango de fechas: elija Desde/Hasta, la tasa % y pulse Liquidar. El cálculo usa los pagos registrados y el vendedor asignado a cada instalación.
Vendedores
Alta y edición de vendedores (nombre, teléfono, email, activo). El nombre del vendedor es el que se asigna a las instalaciones en el tab Instalaciones. Las tarjetas muestran el desempeño de los últimos meses seleccionados.
💵 Precios — precio base, especiales y ajuste masivo
- Precio base: valor por sede/mes que pagan todos los clientes sin precio especial. Cambiarlo aplica a pagos futuros; no requiere tocar la app.
- Precio especial: por NIT, con vigencia opcional (desde/hasta) y nota. Tiene prioridad sobre el base.
- Ajuste masivo: aumenta por % o fija precio a: solo base, solo negociados, ambos, o una lista de NITs. Use la nota para dejar rastro (ej.: «ajuste anual 2026»).
precio especial?
Proceso de aumento anual
- En «Ajuste masivo» elija el alcance: Base + negociados (lo usual para aumento general).
- Tipo: Aumento % y escriba el porcentaje (ej.
8). - Escriba una nota de rastro: «ajuste anual 2026».
- Pulse 📈 Aplicar ajuste masivo y confirme.
- Revise la tabla resultante de precios especiales.
🚨 Alertas — vigilancia automática
El servidor evalúa la flota periódicamente y genera alertas (licencias por vencer, equipos sin reportar, errores altos). Si configuró un webhook, también las notifica allí. Esta vista es el historial; no requiere acción sobre el panel, sino sobre el cliente afectado.
📟 Comandos — acciones remotas sobre una instalación
Permite encolar comandos que la instalación ejecuta en su próximo check-in (modelo pull; no hay conexión directa al equipo). Comandos soportados:
Ping— verificar que el equipo responde y ver su latencia de check-in.ForzarBackup— el equipo genera un backup inmediato.ActualizarEstado— fuerza un reporte de estado completo.
Proceso:
en la fila del equipo
⚙️ Configuración — cambios masivos a toda la flota
Publica valores que TODAS las instalaciones aplican en su próximo check-in, sin redistribuir la app. El servidor firma cada comando con la clave ECDSA del proveedor y cada cliente valida la firma antes de aplicar.
Claves disponibles:
server_url— URL de este servidor (para migraciones de dominio/host).enforcement— enforcement de licencia (1activo /0desactivado).support_phone— teléfono/WhatsApp de soporte mostrado en la app.support_email— correo de soporte mostrado en la app.website— sitio web oficial mostrado en la app.
Ejemplo: cambiar el teléfono de soporte en toda la flota
- Elija la clave
support_phoneen el selector. - Escriba el nuevo número (ej.
313 000 0000). - Defina la vigencia del comando en días (tiempo en que las instalaciones pueden recogerlo; el valor aplicado persiste aunque venza).
- Pulse 📡 Publicar a la flota y confirme.
- Cada instalación lo aplica en su siguiente check-in — verifíquelo en la tabla de valores publicados.
Cómo viaja el cambio (seguridad)
o vencido
server_url: si publica una URL errónea, la flota dejará de hacer check-in y no podrá corregirla por este medio. Verifique dos veces antes de publicar.🚀 Releases — actualizaciones de la app
Proceso para publicar una actualización:
- Compile y firme el instalador de la nueva versión y súbalo a un hosting con HTTPS.
- Calcule el SHA-256 del archivo (recomendado: el cliente verifica integridad):
Get-FileHash .\pos-1.4.0.msix -Algorithm SHA256 - En este tab llene: versión (ej.
1.4.0), plataforma (WinUI/Android/iOS/MacCatalyst), URL de descarga, SHA-256 y notas. - Marque Obligatoria solo para correcciones críticas o de seguridad; la app insistirá al usuario hasta actualizar.
- Pulse 🚀 Publicar. Cada instalación se entera en su próximo check-in.
- Vigile la tabla Adopción los días siguientes hasta que la mayoría esté en la nueva versión.
La tabla Adopción muestra cuántas instalaciones ya están en cada versión — úsela para saber cuándo puede retirar soporte de versiones viejas.
🔐 Auditoría — quién hizo qué
Registra cada acceso administrativo (fecha, IP, método, ruta, resultado). 10 intentos fallidos en 15 minutos bloquean la IP temporalmente. Use los filtros de fecha y «solo fallidos» para investigar accesos sospechosos, y la purga para retirar registros antiguos.
💾 Backups — protección de los datos del servidor
Los datos del servidor (inventario de la flota, activaciones, comisiones, auditoría) son irremplazables. El servidor los respalda solo, pero la seguridad total depende de que usted saque copias fuera del servidor.
Qué hace el servidor automáticamente
- Cada 6 horas (configurable con
BACKUP_INTERVAL_HOURS) crea un ZIP con todos los archivos de datos. - Cada archivo lleva su huella SHA-256 en un manifiesto; el ZIP se verifica antes de darse por bueno. Un backup corrupto nunca se guarda.
- Conserva los 30 más recientes (configurable con
BACKUP_RETAIN_COUNT) y purga los demás.
Su rutina como operador — regla 3-2-1
3 copias de los datos · en 2 medios distintos · 1 fuera del servidor.
- Entre a este tab (Backups) al menos una vez por semana.
- Pulse ⬇️ Descargar el más reciente y guarde el ZIP en su computador.
- Suba esa copia a un almacenamiento externo (Google Drive, OneDrive, S3…). Puede automatizarlo con un cron:
curl -H "X-Admin-Key: SU_LLAVE" https://su-servidor/api/backups/ultimo -o backup.zip - Si usa Docker, monte
/app/backupsen un disco distinto al de/app/data.
Cómo restaurar (ensáyelo al menos una vez)
- Detenga el servidor.
- Descomprima el ZIP del backup dentro del directorio de datos (
/app/data), reemplazando los archivos. - Arranque el servidor: la flota se re-sincroniza sola con los check-ins diarios.
⚠️ Un backup que nunca se ha probado a restaurar no es un backup: es una esperanza.
🩹 Qué hacer si un archivo de datos se corrompe
El servidor nunca se cae por un archivo dañado: al arrancar, si un JSON de datos no se puede leer, lo renombra a *.corrupt-<fecha> (cuarentena, sin borrarlo) y arranca con ese store vacío. El tab Backups muestra la alerta «⚠ Atención» con el archivo afectado.
Procedimiento de recuperación
- Identifique el archivo: en el tab Backups verá el nombre en cuarentena (ej.
instalaciones.json.corrupt-1760000000). - Detenga el servidor.
- Restaure desde el último backup: descomprima el ZIP más reciente y copie el archivo afectado (ej.
instalaciones.json) al directorio de datos. - Arranque el servidor y verifique en el tab Backups que aparezca «✓ Servidor sano» (elimine manualmente el
.corrupt-*cuando ya no lo necesite).
¿Qué pierdo según el archivo afectado?
| Archivo | Si arranca vacío (sin restaurar) |
|---|---|
instalaciones.json | Se repobla solo con los check-ins diarios de la flota (se pierden notas/vendedor asignado). |
activaciones.json | ⚠ CRÍTICO: historial de pagos y códigos emitidos. Restaure siempre del backup. |
precios.json | Vuelve al precio base de la variable de entorno; se pierden los especiales por NIT. |
config-broadcast.json | Se deja de difundir, pero las instalaciones conservan lo ya aplicado. Re-publique. |
comandos.json / alertas.json / auditoria.json | Solo historial; sin impacto operativo. |
vendedores.json / releases.json | Re-cree los registros o restaure del backup. |
🧯 Solución de problemas del servidor — diagnóstico rápido
Primer paso siempre: abra el tab Backups (consulta /api/salud) y lea los problemas detectados. Luego:
| Síntoma | Causa probable | Solución |
|---|---|---|
| El panel dice «Llave de administrador inválida» | Llave mal escrita o IP bloqueada por 10 fallos en 15 min | Verifique ADMIN_API_KEY; espere 15 minutos si hubo bloqueo. |
| La flota no reporta (todo «Crítico» por última conexión) | Servidor caído, URL cambiada o certificado vencido | Pruebe /api/salud desde fuera; revise DNS/HTTPS; si cambió la URL, publique server_url ANTES de apagar la vieja. |
| No se emiten licencias tras el pago | Falta LICENSE_PRIVATE_KEY o webhook Wompi mal configurado | /api/salud lo indica; verifique el secreto de eventos de Wompi. |
| «El último backup tiene más de N horas» | Worker de backups fallando (disco lleno o sin permisos) | Revise logs del servidor; libere espacio; verifique permisos de /app/backups. |
| «El directorio de datos NO es escribible» | Permisos del volumen o disco lleno | ⚠ Urgente: los cambios se pierden al reiniciar. Corrija permisos/espacio de /app/data. |
| Datos desaparecieron tras redeploy de Docker | Volumen no montado: los datos vivían dentro del contenedor | Monte /app/data y /app/backups como volúmenes; restaure del backup externo. |
Si nada de esto aplica, revise los logs del proceso (Docker: docker logs <contenedor>) — el servidor registra cada backup, alerta y fallo con detalle.
🔑 Licencias — activación y renovación de clientes
El flujo normal es automático: el cliente paga desde la app (Wompi) y el servidor emite el código de activación firmado.
Flujo automático (el habitual)
Flujo manual de respaldo (pago por otro medio o sin internet)
- El cliente le comparte su huella (la muestra la app en la pantalla de licencia) o la solicitud completa (
LIC-REQ|v1|...). - Genere el código con LicenseTool:
licensetool code <nit> <huella> <meses>(ej.:licensetool code 900123456-7 AB3D-K9M2 3) olicensetool code "<solicitud>". - Envíe el código al cliente; lo ingresa en la app y queda activado.
🆘 Problemas frecuentes — diagnóstico rápido
| Síntoma | Causa probable | Solución |
|---|---|---|
| «Llave de administrador inválida» | La llave no coincide con ADMIN_API_KEY | Verifique la llave; tras varios fallos su IP queda bloqueada unos minutos |
| Una instalación no aparece | Aún no hace su primer check-in | Verifique internet del cliente y la URL del servidor configurada en la app |
| Configuración publicada pero un equipo no la aplica | El equipo no hace check-in o el comando venció | Revise «último reporte» en Instalaciones; republique con más días de vigencia |
| El relay de correo devuelve error | Variables SMTP faltantes o credencial vencida | Corrija las variables y reinicie el servicio |
| No se puede publicar configuración (503) | Falta LICENSE_PRIVATE_KEY | Defina la variable en el servidor y reinicie |
| Comando lleva días «pendiente» | El equipo está apagado o sin internet | Contacte al cliente; verifique salud en Instalaciones |
Árbol de decisión: «un cliente reporta un problema»
Instalaciones?
URL del servidor en la app
Ping oActualizarEstadopara confirmar diagnósticopida ZIP de diagnóstico