complete i18n migration to /[locale]/ with EN+ES content

Full rewrite of the docs site under app/[locale]/ with next-intl
in localePrefix:"always" mode. Every page now exists at both
/en/<path> and /es/<path>; the root / shows a meta-refresh + JS
redirect to /<defaultLocale>/ so GitHub Pages serves something
on the apex URL.

Highlights:
- 107 doc pages migrated to file-per-page JSON namespaces under
  messages/en/ and messages/es/. Spanish content is fully
  translated (no copy-of-English placeholders).
- New documentation for the Active Suppressions section in the
  Settings tab and the per-event Dismiss dropdown in the Health
  Monitor modal.
- New screenshots: dismiss-duration-dropdown.png and an updated
  health-suppression-settings.png.
- Pagefind integrated for client-side search; index is built on
  every CI deploy (not committed).
- RSS feeds: per-locale at /<locale>/rss.xml plus root /rss.xml
  for backward compat.
- Removed the dead app/[locale]/guides/[slug]/ route — every
  guide now has its own static page and no markdown source
  remains.
- Fixed orphan link /guides/nvidia -> /guides/nvidia-manual in
  docs/hardware/nvidia-host.
- Removed obsolete components (footer2, calendar, drawer).

Verified locally with `npm ci && npm run build`: 2804 files in
out/, 231 pages indexed by pagefind, root redirect intact, both
locale roots and the new Active Suppressions docs render OK.
This commit is contained in:
MacRimi
2026-05-31 12:41:10 +02:00
parent 875910b4d7
commit 5ca3463bf6
649 changed files with 83958 additions and 11096 deletions
@@ -0,0 +1,396 @@
{
"meta": {
"title": "Autenticación del panel de Proxmox — 2FA, API Tokens, perfil de usuario, reverse proxy | ProxMenux Monitor",
"description": "Acceder y asegurar ProxMenux Monitor: flujo de proteger-tu-panel en el primer arranque, autenticación con contraseña con nombre visible + avatar, página de perfil, alta de TOTP 2FA, API tokens de larga duración para scripts, configuración HTTPS, snippets de reverse proxy para Nginx, Caddy y Traefik, el log de auditoría y el jail Fail2Ban opcional.",
"ogTitle": "Autenticación del panel de Proxmox — 2FA, API Tokens, reverse proxy",
"ogDescription": "Asegura ProxMenux Monitor con contraseña + TOTP 2FA, API tokens de larga duración, HTTPS, snippets de reverse proxy y un jail Fail2Ban opcional.",
"twitterTitle": "Autenticación del panel de Proxmox | ProxMenux Monitor",
"twitterDescription": "Contraseña + TOTP 2FA, API tokens, HTTPS, snippets de Nginx/Caddy/Traefik y log de auditoría."
},
"header": {
"title": "Acceso y autenticación",
"description": "Cómo llegar al panel, el flujo de seguridad de primer arranque y cada capa que puede situarse entre un atacante y el host: contraseña + TOTP, sesiones JWT, API tokens de larga duración, HTTPS, reverse proxies, Secure Gateway y el jail Fail2Ban opcional.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "La autenticación es opt-in",
"body": "En el primer arranque el panel muestra un único diálogo — <em>\"¿Proteger tu panel?\"</em> — con dos botones: <strong>Sí, configurar contraseña</strong> y <strong>No, continuar sin protección</strong>. Decir que no deja todos los endpoints de la API abiertos en el puerto TCP 8008 — aceptable en una LAN de laboratorio aislada, peligroso en cualquier otro escenario. La autenticación de dos factores (2FA) <strong>no</strong> forma parte de esta elección inicial; se configura más tarde desde <strong>la pestaña Security</strong> una vez que hay una contraseña."
},
"reaching": {
"heading": "Cómo llegar al panel",
"intro": "ProxMenux Monitor escucha en <code>0.0.0.0:8008</code>. Hay tres formas habituales de llegar a él:",
"outro": "El acceso directo coincide con lo que la unidad systemd trae por defecto. Las secciones de reverse proxy y Secure Gateway a continuación cubren las otras dos. El Monitor respeta <code>X-Forwarded-For</code>, <code>X-Forwarded-Proto</code> y <code>X-Forwarded-Host</code> para que las URLs y CORS funcionen detrás de cualquiera de ellos sin configuración manual."
},
"firstLaunch": {
"heading": "Flujo de primer arranque",
"intro": "La primera vez que abres el panel, el frontend llama a <code>GET /api/auth/status</code>. Si la configuración de auth nunca se ha escrito (<code>configured: false</code>), aparece un único diálogo titulado <em>\"¿Proteger tu panel?\"</em> con dos opciones:",
"imageAlt": "Diálogo de primer arranque '¿Proteger tu panel?' con dos botones: Sí configurar contraseña, No continuar sin protección",
"imageCaption": "El selector de autenticación del primer arranque. Dos botones — protección con contraseña o saltar. Se vuelve a mostrar tras una instalación recién hecha o tras \"Desactivar autenticación\" desde Settings.",
"headerButton": "Botón",
"headerWhat": "Qué pasa",
"headerApi": "Llamada a la API",
"rows": [
{
"button": "Sí, configurar contraseña",
"what": "Abre un formulario con el usuario + contraseña obligatorios y un <em>nombre visible</em> + <em>imagen de avatar</em> opcionales. Los guarda en <code>auth.json</code> con <code>enabled: true</code>. Devuelve un JWT así que quedas logueado inmediatamente. El formulario se documenta en detalle más abajo.",
"api": "POST /api/auth/setup"
},
{
"button": "No, continuar sin protección",
"what": "Marca <code>declined: true</code> en <code>auth.json</code>. Todos los endpoints de la API son accesibles públicamente hasta que cambies de idea desde Settings.",
"api": "POST /api/auth/skip"
}
],
"twofaCalloutTitle": "El 2FA se configura después, no aquí",
"twofaCalloutBody": "El diálogo de primer arranque solo cubre la decisión de la contraseña. La <strong>autenticación de dos factores (TOTP)</strong> se configura después desde <strong>la pestaña Security</strong> una vez logueado con una contraseña. El walkthrough completo de TOTP está más abajo en esta página.",
"createTitle": "Crear el primer usuario",
"createIntro": "Pulsar <em>Sí, configurar contraseña</em> abre un único formulario que crea la cuenta y, opcionalmente, siembra el perfil del usuario de una sola vez para que el avatar aparezca en la cabecera nada más guardar. Los campos son:",
"headerField": "Campo",
"headerRequired": "Requerido",
"headerNotes": "Notas",
"fieldRows": [
{
"field": "Username",
"required": "Sí",
"notes": "El identificador de login. No se puede cambiar después desde la UI; editarlo requiere tocar <code>auth.json</code> directamente."
},
{
"field": "Contraseña",
"required": "Sí",
"notes": "Mínimo 10 caracteres, con al menos 3 de las 4 categorías (minúscula, mayúscula, dígito, símbolo). Una lista corta de contraseñas obvias (<code>password</code>, <code>12345678</code>, <code>proxmenux</code>…) se rechaza directamente. Las mismas reglas se aplican en el lado del servidor, así que una llamada curl no puede saltarse la comprobación del frontend."
},
{
"field": "Nombre visible",
"required": "No",
"notes": "Etiqueta amistosa que se muestra en el dropdown de la cabecera y en la página de perfil. Cae al username cuando está vacío. Se puede cambiar después desde <strong>Avatar → Ver perfil</strong>."
},
{
"field": "Imagen de avatar",
"required": "No",
"notes": "PNG, JPEG, WebP o GIF de hasta 2 MB. Renderizado como un círculo en la cabecera y en la página de perfil. Cuando está vacío, la cabecera muestra la primera letra del nombre visible (o del username) sobre un círculo coloreado. Se puede subir, reemplazar o eliminar después desde la página de perfil."
}
],
"createImageAlt": "Formulario de creación de usuario con campos obligatorios Username + Contraseña y la sección opcional Nombre visible + subida de Avatar",
"createImageCaption": "El formulario de creación de usuario del primer arranque. El nombre visible y el avatar son opcionales — dejarlos vacíos crea la cuenta y cae a un círculo con una sola letra en la cabecera.",
"saveCalloutTitle": "Un único guardado, tres llamadas a la API por dentro",
"saveCalloutBody": "El formulario envía primero <code>POST /api/auth/setup</code> (username + contraseña). Si tiene éxito usa el JWT recién emitido para hacer a continuación <code>PUT /api/auth/profile</code> (nombre visible) y <code>POST /api/auth/profile/avatar</code> (bytes del avatar) si esos campos se rellenaron. Los fallos en las llamadas de perfil no son fatales — la cuenta ya está creada y puedes terminar el perfil después desde la página dedicada.",
"avatarTitle": "Menú del avatar y página de perfil",
"avatarBody1": "Una vez configurada la autenticación, aparece un círculo de avatar en la parte superior derecha de cada página del panel junto al toggle de tema. Pulsarlo abre un pequeño dropdown con accesos directos a la página de perfil y a la pestaña Security, además de una acción <strong>Sign out</strong> — cerrar la sesión se puede hacer desde aquí o desde la pestaña Security, lo que esté más cerca de donde te encuentres.",
"avatarBody2": "La página de perfil en sí es una pequeña tarjeta con una vista previa del avatar, el username (solo lectura) y el nombre visible con un botón de edición en línea. Las subidas, reemplazos y eliminaciones de avatar son atómicas — el avatar de la cabecera se refresca automáticamente cuando cualquiera tiene éxito, así que no hay necesidad de recargar la página. El mismo conjunto de endpoints documentado en la siguiente sección lo usan tanto el formulario de creación de usuario como la página de perfil.",
"profileImageAlt": "Página de perfil con círculo de vista previa del avatar, botones Subir / Reemplazar / Eliminar, username de solo lectura y campo de nombre visible editable",
"profileImageCaption": "La página de perfil dedicada. El username es solo lectura; el nombre visible y el avatar se pueden editar desde aquí sin tocar la pestaña Security.",
"headerEndpoint": "Endpoint",
"headerEpWhat": "Qué hace",
"endpointRows": [
{
"endpoint": "GET /api/auth/profile",
"what": "Devuelve el username actual, el nombre visible y si hay un avatar configurado (<code>has_avatar</code>, <code>avatar_mtime</code>)."
},
{
"endpoint": "PUT /api/auth/profile",
"what": "Actualiza el nombre visible. Body: <code>'{' \"display_name\": \"...\" '}'</code>."
},
{
"endpoint": "GET /api/auth/profile/avatar",
"what": "Devuelve los bytes del avatar (PNG / JPEG / WebP / GIF) con el content type adecuado. Requiere la cabecera Bearer — el frontend lo descarga como blob y lo convierte en una URL de objeto local para renderizar."
},
{
"endpoint": "POST /api/auth/profile/avatar",
"what": "Sube un avatar nuevo (máx 2 MB). El content type debe coincidir con el archivo. El avatar antiguo se reemplaza atómicamente."
},
{
"endpoint": "DELETE /api/auth/profile/avatar",
"what": "Elimina el avatar. La cabecera cae al placeholder de inicial-sobre-círculo-coloreado."
}
],
"reversibleTitle": "Continuar sin protección es reversible — pero solo desde el host",
"reversibleBody": "Una vez que pulsas <em>No, continuar sin protección</em>, el diálogo de bienvenida ya no vuelve a aparecer. Puedes reactivar la autenticación desde <strong>la pestaña Security</strong> dentro del panel, o editando <code>/root/.config/proxmenux-monitor/auth.json</code> y quitando el flag <code>declined</code>, luego reiniciando el servicio."
},
"password": {
"heading": "Autenticación con contraseña",
"intro": "Tras Setup, cada llamada a la API (excepto los pocos endpoints públicos listados abajo) requiere un JWT en <code>Authorization: Bearer &lt;token&gt;</code>:",
"items": [
"<strong>Token de sesión (login):</strong> expiración de 24 horas. Emitido por <code>POST /api/auth/login</code>.",
"<strong>API token (integraciones):</strong> expiración de 365 días. Emitido por <code>POST /api/auth/generate-api-token</code>. Documentado por separado en la siguiente sección."
],
"loginImageAlt": "Pantalla de login mostrada tras configurar la autenticación — campos de usuario y contraseña",
"loginImageCaption": "Una vez configurada la autenticación, cada visita al panel empieza aquí. Con 2FA activado, la pantalla pide el código de 6 dígitos en un segundo paso tras aceptar la contraseña.",
"loginFlowTitle": "Flujo de login",
"twofaIntro": "Con 2FA activado, la misma llamada devuelve primero <code>requires_totp: true</code>. Reemite con el código de 6 dígitos:",
"publicTitle": "Endpoints públicos (sin token)",
"publicIntro": "Estos son los únicos endpoints que funcionan sin autenticación, incluso cuando auth está activado:",
"publicItems": [
"<code>/api/auth/login</code>, <code>/api/auth/status</code>, <code>/api/auth/setup</code> — el propio flujo de auth, por necesidad.",
"<code>/api/system-info</code> — snapshot ligero del sistema (hostname, uptime, <code>health.status</code>). El endpoint adecuado para probes externos (Uptime Kuma, health checks de balanceador, páginas de estado)."
],
"cryptoTitle": "Criptografía y almacenamiento",
"cryptoIntro": "ProxMenux Monitor es código abierto — nada de esto es secreto. Documentar el stack aquí de forma explícita es una decisión deliberada: los operadores que guardan credenciales en su host merecen saber cómo se protegen esas credenciales antes de decidir confiar en ellas. Los algoritmos de abajo son los mismos que usa el código en <code>scripts/auth_manager.py</code>; esta sección es un contrato, no una promesa de marketing.",
"headerAsset": "Activo",
"headerAlgo": "Algoritmo",
"headerWhere": "Dónde vive",
"cryptoRows": [
{
"asset": "Contraseña",
"algorithm": "PBKDF2-HMAC-SHA256 con un salt aleatorio por contraseña y un alto número de iteraciones (línea base OWASP 2023+). Guardada como <code>pbkdf2_sha256$&lt;iters&gt;$&lt;salt&gt;$&lt;hash&gt;</code>.",
"where": "<code>auth.json</code> → <code>password_hash</code>"
},
{
"asset": "JWT de sesión / API",
"algorithm": "HS256 firmado con un secret por instalación generado en el primer arranque (<code>secrets.token_urlsafe</code>, ≥48 bytes). Los tokens llevan claims <code>iss=proxmenux-monitor</code> + <code>aud=api</code>; la firma se valida contra el secret actual en cada petición.",
"where": "Secret: <code>auth.json</code> → <code>jwt_secret</code>. El JWT en sí: solo en el cliente."
},
{
"asset": "Metadatos de API token",
"algorithm": "SHA-256 del JWT guardado junto con una huella <code>signed_with</code> del <code>jwt_secret</code> usado para emitirlo — usado para mostrar el token en la UI y para detectar tokens cuyo secret de firma se ha rotado.",
"where": "<code>auth.json</code> → <code>api_tokens[]</code>"
},
{
"asset": "Secret TOTP de 2FA",
"algorithm": "TOTP estándar (RFC 6238) codificado en base32. Los códigos de backup se pregeneran, son de un solo uso, hasheados con el mismo esquema PBKDF2 que la contraseña.",
"where": "<code>auth.json</code> → <code>totp_secret</code> + <code>backup_codes[]</code>"
},
{
"asset": "Revocaciones",
"algorithm": "Cuando un token o sesión se revoca, su SHA-256 se añade a una deny-list comprobada en cada verificación (en memoria caché ~30 s para evitar lecturas de disco en la ruta caliente).",
"where": "<code>auth.json</code> → <code>revoked_tokens[]</code>"
}
],
"authJsonTitle": "auth.json — qué contiene y cómo se protege",
"authJsonBody": "Todo lo que ProxMenux Monitor necesita para autenticarte vive en un único archivo: <code>/root/.config/proxmenux-monitor/auth.json</code>, modo <code>0600</code>, propietario <code>root</code>. El archivo guarda <em>hashes</em> (PBKDF2) y <em>material de firma</em> (<code>jwt_secret</code>, <code>totp_secret</code>) — nunca una contraseña en texto plano. Trátalo como cualquier otro secreto de solo-root: si haces backup o replicas el host, cifra el destino y nunca lo subas a control de versiones.",
"rotateTitle": "Rotar jwt_secret invalida todos los JWTs existentes",
"rotateBody": "Si <code>auth.json</code> se regenera (borrado manual, reinstalación, restauración desde un backup con un secret distinto) el <code>jwt_secret</code> cambia y cada JWT previamente emitido — tanto sesiones interactivas como API tokens de larga duración — falla la verificación con \"Invalid or expired token\". La UI marca los API tokens afectados con un badge <strong>Invalid — regenerate</strong> para que el operador sepa que tiene que revocarlos y volver a emitirlos; Home Assistant / scripts / cualquier cliente externo necesita un token fresco después de eso.",
"recoverTitle": "Recuperar una contraseña perdida",
"recoverIntro": "No hay un flujo online de \"olvidé mi contraseña\" — por diseño, ya que el panel corre en el propio host del operador y el camino de recuperación es acceso shell a ese host. ProxMenux trae un reset guiado dentro del menú de configuración para que no tengas que editar a mano <code>auth.json</code>:",
"survivesTitle": "Qué sobrevive al reset",
"survivesBody": "Solo el login interactivo se borra. El <code>jwt_secret</code> y los <code>api_tokens</code> registrados se preservan — así que Home Assistant y cualquier otro script que use un API token de larga duración siguen funcionando sin reconfiguración. Si quieres una pizarra totalmente limpia (también rotar el secret JWT), borra <code>auth.json</code> manualmente y reinicia el servicio. El siguiente arranque genera un secret fresco y todos los tokens viejos se vuelven inválidos.",
"physicalTitle": "Prerrequisito de acceso físico",
"physicalBody": "Esta ruta de reset necesita <strong>shell root en el host</strong>. Esa es el ancla de confianza de todo el esquema de autenticación: cualquiera que pueda ejecutar <code>menu</code> como root ya puede hacer cualquier cosa en la máquina, así que darle reset de contraseña no es un aumento de privilegios. El corolario: si dejas que un usuario no confiable llegue a la shell de Proxmox, el login del Monitor no protegerá nada que ese usuario no pueda ya destruir por otros medios."
},
"twofa": {
"heading": "Autenticación de dos factores (TOTP)",
"intro": "El 2FA añade un segundo factor encima de tu contraseña: un código de 6 dígitos que rota cada 30 segundos, generado en un móvil o gestor de contraseñas que controlas. Aunque alguien obtenga la contraseña, sigue sin poder entrar sin el código de tu dispositivo. ProxMenux Monitor implementa el protocolo estándar <strong>TOTP</strong> (RFC 6238), así que cualquier app autenticadora funciona.",
"pickTitle": "Elige una app autenticadora",
"pickIntro": "Si ya usas una para Google / GitHub / tu banco, esa funcionará — salta al walkthrough de setup. Si no, aquí tienes un repaso de opciones habituales. Todas son gratis; las diferencias son sobre todo en qué plataformas corren y cómo (o si) hacen backup de tus secrets.",
"headerApp": "App",
"headerPlatforms": "Plataformas",
"headerAppNotes": "Notas",
"apps": [
{
"name": "Google Authenticator",
"href": "https://safety.google/authentication/",
"platforms": "iOS, Android",
"notes": "El predeterminado para muchos usuarios. Backup opcional a la cuenta de Google."
},
{
"name": "Microsoft Authenticator",
"href": "https://www.microsoft.com/en-us/security/mobile-authenticator-app",
"platforms": "iOS, Android",
"notes": "Backup a la cuenta Microsoft. También maneja notificaciones push de MS si las usas en el trabajo."
},
{
"name": "Authy",
"href": "https://authy.com/",
"platforms": "iOS, Android, escritorio",
"notes": "Sync cifrado multi-dispositivo (la app de escritorio se está retirando — comprueba el estado más reciente)."
},
{
"name": "Apple Passwords",
"href": "https://support.apple.com/guide/passwords/welcome/mac",
"platforms": "iOS, iPadOS, macOS, visionOS, Windows (vía iCloud)",
"notes": "Integrada en los SO de Apple; app Passwords independiente desde iOS 18 / macOS Sequoia. Guarda el TOTP junto a la contraseña y sincroniza entre dispositivos vía iCloud Keychain."
},
{
"name": "Bitwarden",
"href": "https://bitwarden.com/",
"platforms": "iOS, Android, escritorio, navegador",
"notes": "Código abierto. El TOTP vive junto a la contraseña que protege (cómodo si también usas BW para contraseñas; rompe el \"dispositivo separado\" si no)."
},
{
"name": "1Password",
"href": "https://1password.com/",
"platforms": "iOS, Android, escritorio, navegador",
"notes": "Misma idea que Bitwarden — TOTP integrado con la bóveda de contraseñas. Por suscripción."
},
{
"name": "Aegis Authenticator",
"href": "https://getaegis.app/",
"platforms": "Android",
"notes": "Código abierto. Archivo de backup cifrado en dispositivo que tú controlas. Sin nube, sin cuenta requerida."
},
{
"name": "Raivo OTP",
"href": "https://raivo-otp.com/",
"platforms": "iOS, macOS",
"notes": "Código abierto. Sync opcional a iCloud. La contraparte del ecosistema Apple a Aegis."
},
{
"name": "Ente Auth",
"href": "https://ente.io/auth/",
"platforms": "iOS, Android, escritorio, web",
"notes": "Código abierto. Sync en la nube cifrado de extremo a extremo entre dispositivos."
},
{
"name": "2FAS",
"href": "https://2fas.com/",
"platforms": "iOS, Android, extensión de navegador",
"notes": "Código abierto. Backup en la nube cifrado opcional; la extensión de navegador puede autocompletar códigos."
},
{
"name": "FreeOTP+",
"href": "https://github.com/helloworld1/FreeOTPPlus",
"platforms": "Android, iOS",
"notes": "Código abierto (impulsado por Red Hat). Mínimo — sin nube, sin cuenta."
}
],
"backupTitle": "Para qué importa realmente el \"backup\"",
"backupBody": "Si pierdes el dispositivo que tiene el autenticador, las únicas formas de volver a entrar son (1) un código de backup guardado cuando activaste el 2FA, o (2) un backup de la bóveda del autenticador. Las apps con sync en la nube (Google Auth, Microsoft Auth, Authy, Apple Passwords, Ente, 2FAS, Bitwarden, 1Password) pueden restaurar en un dispositivo nuevo. Las apps sin nube (Aegis, Raivo, FreeOTP+) necesitan un archivo de exportación cifrado que hayas copiado a un sitio seguro. Cualquier enfoque funciona — el caso malo es \"sin backup en absoluto\".",
"setupTitle": "Configuración paso a paso desde el panel",
"setupImageAlt": "Pantalla de configuración de 2FA con código QR y códigos de backup",
"setupImageCaption": "El diálogo de configuración de 2FA — código QR, secret en Base32 (para entrada manual) y los diez códigos de backup de un solo uso. Los códigos solo se muestran aquí; si cierras el diálogo sin copiarlos, se pierden.",
"setupSteps": [
"<strong>Instala la app autenticadora en tu móvil</strong> (o abre tu gestor de contraseñas). Una de las apps de la tabla de arriba. Solo necesitas hacerlo una vez — la misma app guardará códigos para cada servicio que protejas.",
"<strong>Loguéate en el panel</strong> con tu usuario y contraseña.",
"<strong>Abre la pestaña Security</strong> en la barra lateral del panel, luego pulsa <strong>Enable 2FA</strong>. Se abre un diálogo con un código QR, una cadena larga en formato Base32 y diez códigos cortos etiquetados como \"códigos de backup\".",
"<strong>Añade la entrada a la app autenticadora:</strong>",
"<strong>Guarda los códigos de backup.</strong> Copia los diez códigos a un sitio seguro — un gestor de contraseñas, una nota cifrada, una copia impresa en un cajón. Trátalos como llaves de repuesto: cada uno funciona exactamente una vez y te deja entrar si tu móvil se pierde o rompe.",
"<strong>Confirma escribiendo el código actual de 6 dígitos</strong> de la app en el campo \"Código de verificación\" del diálogo de setup y envía. Los códigos se refrescan cada 30 segundos, así que si caduca mientras escribes, simplemente introduce el siguiente.",
"<strong>Hecho.</strong> El 2FA está ahora activo. La próxima vez que te logues, el panel pide primero la contraseña; una vez aceptada pide el código actual de 6 dígitos."
],
"setupStep4Sub": [
"<em>Camino fácil:</em> en la app, pulsa <em>Añadir cuenta</em> → <em>Escanear código QR</em>, apunta la cámara al QR en la pantalla. La app nombra la entrada automáticamente (algo como <code>ProxMenux Monitor (tu-usuario)</code>) y empieza a mostrar un código de 6 dígitos que se refresca cada 30 segundos.",
"<em>Plan B manual</em> (cuando escanear no es posible — p. ej. configurando en el mismo móvil con el que abriste el panel): pulsa <em>Añadir cuenta</em> → <em>Introducir clave de setup</em>. Escribe cualquier nombre (p. ej. <em>Proxmox Monitor</em>), pega la cadena Base32 del diálogo, deja <em>Tipo</em> como <em>Basado en tiempo</em>, guarda."
],
"testTitle": "Prueba antes de hacer logout",
"testBody": "Una vez que pulses Guardar, haz logout y vuelve a entrar <em>inmediatamente</em>, mientras el diálogo de setup esté todavía fresco en tu memoria. Si el código se rechaza (la causa más común es el desfase de reloj entre servidor y móvil), aún puedes arreglarlo desde la sesión abierta. Hacer logout sin probar primero significa un viaje de ida sin retorno — en ese punto solo un código de backup o editar <code>auth.json</code> en el host te deja volver a entrar.",
"lostTitle": "Autenticador perdido",
"lostIntro": "Tres salidas de emergencia, en orden de cuán disruptivas son:",
"lostItems": [
"<strong>Usa un código de backup.</strong> En la pantalla de login, en el campo TOTP, escribe uno de los diez códigos que guardaste durante el setup. Cada uno funciona una vez y luego se consume; los códigos restantes siguen funcionando. Una vez dentro, regenera el 2FA desde Settings para conseguir diez nuevos.",
"<strong>Restaura el autenticador desde la nube / backup.</strong> Si tu app tiene sync en la nube (Google, Microsoft, Authy, Apple Passwords vía iCloud Keychain, Ente, 2FAS) instálala en un dispositivo nuevo, loguéate y las entradas reaparecen. Si tu app usa un archivo de exportación cifrado (Aegis, Raivo, FreeOTP+), instala la app en el dispositivo nuevo e importa el archivo.",
"<strong>Desactiva el 2FA desde la shell del host.</strong> Cuando las opciones anteriores no están disponibles, edita <code>/root/.config/proxmenux-monitor/auth.json</code> en el host Proxmox (necesitas SSH root o acceso por consola), pon <code>totp_enabled</code> a <code>false</code>, guarda y reinicia el servicio:"
],
"lostShellOutro": "Puedes loguearte con usuario + contraseña solo, luego reactivar el 2FA desde Settings.",
"disableTitle": "Desactivar el 2FA",
"disableBody": "Desde el panel, abre la pestaña <strong>Security</strong> y pulsa <strong>Disable 2FA</strong>. El endpoint <code>POST /api/auth/totp/disable</code> requiere la contraseña actual como confirmación, luego elimina el secret TOTP y limpia los códigos de backup. Recuerda también quitar la entrada en la app autenticadora — la app no sabe que el lado del servidor ha desaparecido, así que la entrada muerta se quedaría ahí para siempre si no.",
"rejectedTitle": "El código de 6 dígitos se rechaza siempre",
"rejectedIntro": "El TOTP está basado en tiempo — el reloj del servidor y el del móvil deben coincidir dentro de unos ~30 s. Dos comprobaciones:",
"rejectedItems": [
"<strong>Móvil:</strong> Ajustes → Fecha y hora → sync automático / de red ACTIVADO.",
"<strong>Host Proxmox:</strong> <code>timedatectl status</code> — \"System clock synchronized: yes\" debería aparecer. Si no, <code>timedatectl set-ntp true</code> y espera un minuto."
],
"rejectedOutro": "Una vez que ambos relojes coinciden, el código se acepta dentro de la siguiente ventana de 30 segundos."
},
"apiTokens": {
"heading": "API tokens (larga duración)",
"intro": "Las sesiones de navegador caducan tras 24 horas. Para integraciones desatendidas (widgets de Homepage, sensores de Home Assistant, scrapers de Grafana, probes de Uptime Kuma…) generas un <strong>API token</strong> aparte que vive 365 días. El token es un JWT firmado con el mismo secret que el token de sesión, pero su claim <code>token_name</code> facilita rastrearlo y revocarlo individualmente.",
"imageAlt": "Panel de API tokens mostrando la lista de tokens con nombre, prefijo, fecha de creación y caducidad",
"imageCaption": "La lista de API tokens bajo Settings — nombre, prefijo (se muestran los últimos 4 caracteres para identificación), fechas de creación y caducidad, acción de revocar.",
"generateTitle": "Generar un token",
"generateIntro": "Desde el panel:",
"generateSteps": [
"Navega a la sección <strong>pestaña Security → API Access Tokens</strong>.",
"Escribe un nombre descriptivo (<em>p. ej. \"Home Assistant\"</em>).",
"Vuelve a introducir tu contraseña. Si el 2FA está activado, también el código actual de 6 dígitos.",
"Pulsa <strong>Generate Token</strong>. El token aparece <strong>una vez</strong> — cópialo inmediatamente."
],
"generateCli": "Desde la línea de comandos:",
"useTitle": "Usar un token",
"revokeTitle": "Revocar un token",
"revokeBody": "Desde el panel de arriba: cada fila tiene una acción <strong>Revoke</strong> que añade el hash del token a <code>revoked_tokens</code> en <code>auth.json</code>. Los tokens revocados fallan la validación inmediatamente en la siguiente petición.",
"cheatTitle": "Chuleta de seguridad de tokens",
"cheatItems": [
"Guarda los tokens en el almacén de secrets nativo de tu integración — Homepage <code>secrets.yaml</code>, Home Assistant <code>!secret</code>, variables de entorno, etc. Nunca los subas a git.",
"Un token por integración, nombrado por el consumidor. Revoca individualmente al retirar una integración.",
"Rota cada 6-12 meses. La expiración es un límite duro, no una recomendación."
],
"outro": "Las mejores prácticas completas de almacenamiento y recetas de integración viven en <apiLink>API Reference → Token Management</apiLink> e <intLink>Integrations</intLink>."
},
"https": {
"heading": "HTTPS",
"intro": "Dos rutas hacia TLS:",
"items": [
"<strong>Reverse proxy (recomendado).</strong> Termina TLS en Nginx / Caddy / Traefik y reenvía HTTP en el puerto 8008 al proceso Flask. Snippets más abajo.",
"<strong>HTTPS directo en el AppImage.</strong> Configura un certificado vía <code>POST /api/ssl/configure</code> (UI: <strong>Settings → SSL</strong>). Cuando SSL está configurado el proceso cambia del servidor dev de Flask a <code>gevent.pywsgi</code> con el handler gevent-websocket para que el terminal WebSocket también funcione sobre WSS. Los archivos del cert viven donde tú los pongas; las rutas se guardan en la configuración SSL."
],
"calloutTitle": "Limitaciones del HTTPS directo",
"calloutBody": "La ruta gevent empaquetada es adecuada para certificados autofirmados o solo-LAN. Para Let's Encrypt / ACME y renovación automática, pon un reverse proxy real delante — Caddy autorrenueva y Traefik / Nginx tienen patrones bien conocidos. El Monitor no implementa ACME por sí mismo."
},
"gateway": {
"heading": "Secure Gateway (Tailscale)",
"intro": "Los reverse proxies son la respuesta clásica a \"llegar al panel desde fuera\" pero requieren un dominio público, certificado y un puerto abierto en el borde. <strong>Secure Gateway</strong> es la alternativa cero-puertos que viene dentro del propio Monitor — una app desplegable preconstruida que levanta un LXC Alpine ejecutando <a>Tailscale</a> como subnet router. Una vez unido a tu tailnet, cada dispositivo en él puede llegar al Monitor en la propia IP LAN del host — desde un portátil de vacaciones, un móvil con 5G u otro nodo — sin exponer TCP 8008 a internet.",
"calloutTitle": "Por qué esto es cómodo",
"calloutBody": "La URL se mantiene igual que en la LAN — <code>http://&lt;ip-lan-proxmox&gt;:8008</code> funciona donde Tailscale funcione. Sin certificados, sin DNS, sin port forwarding. El propio Monitor ve la petición viniendo de una IP de tailnet (típicamente <code>100.x.y.z</code>), así que el log de auth y el hook de Fail2Ban siguen funcionando como en la LAN.",
"deployBody": "El flujo de despliegue es una sola pantalla — elige el storage LXC del host, pega un auth-key de Tailscale (generado en <a>login.tailscale.com/admin/settings/keys</a>), elige qué subnets anunciar, pulsa Deploy. El LXC tarda ~30 segundos en arrancar y se registra en el tailnet automáticamente.",
"outro": "El despliegue paso a paso, la configuración de subnet-routes, las ACLs de Tailscale y el modo Exit Node se documentan por separado en <link>Dashboard → Security → Secure Gateway</link> — ahí vive el wizard de despliegue en la UI del panel. Esta página solo cubre el patrón de acceso."
},
"proxy": {
"heading": "Snippets de reverse proxy",
"intro": "La distribución más simple es un <strong>nombre de host dedicado</strong> para el Monitor (p. ej. <code>monitor.example.com</code>) apuntando al puerto 8008 del host Proxmox. Los snippets de abajo usan ese patrón. Los montajes en sub-path (<code>example.com/proxmenux-monitor/</code>) son posibles pero requieren reescritura extra y no son el valor por defecto — mira el callout al final.",
"nginxTitle": "Nginx",
"caddyTitle": "Caddy",
"traefikTitle": "Traefik (labels — Docker / Kubernetes)",
"subPathTitle": "Avanzado: montajes en sub-path bajo un dominio existente",
"subPathBody": "Si no quieres un nombre de host dedicado, puedes montar el Monitor bajo un path de un dominio existente — por ejemplo <code>example.com/proxmenux-monitor/</code>. El build de Next.js usa rutas relativas para los assets así que los archivos estáticos resuelven, pero el proxy debe <strong>quitar el prefijo</strong> antes de reenviar para que el Monitor reciba URLs <code>/api/*</code> sin más. En Nginx eso es un <code>location /proxmenux-monitor/ &rbrace; proxy_pass http://127.0.0.1:8008/; &lbrace;</code> (la barra final en <code>proxy_pass</code> hace el strip). En Caddy, usa <code>handle_path /proxmenux-monitor/*</code>. Un nombre de host dedicado es más simple."
},
"audit": {
"heading": "Log de auditoría",
"intro": "Cada evento de autenticación (éxito y fallo) se añade a <code>/var/log/proxmenux-auth.log</code> en formato de una sola línea, estilo syslog:",
"outro": "Sigue la cola con el método habitual: <code>tail -F /var/log/proxmenux-auth.log</code>. El archivo se rota con <code>logrotate</code> si se añade un drop-in de configuración; el Monitor no lo rota por sí mismo."
},
"fail2ban": {
"heading": "Opcional: jail Fail2Ban",
"calloutTitle": "Fail2Ban no viene incluido con el Monitor",
"calloutBody": "Fail2Ban <strong>no</strong> lo instala ProxMenux Monitor por sí mismo. Instálalo vía <link>Seguridad → Fail2Ban</link> en el menú de ProxMenux (o con el paquete estándar de Debian). Sin él, el Monitor sigue escribiendo el log de auditoría de arriba — simplemente no banea automáticamente a los repetidores.",
"intro": "Cuando Fail2Ban está instalado, la integración de ProxMenux trae un jail <code>[proxmenux]</code> que:",
"items": [
"Lee <code>/var/log/proxmenux-auth.log</code>.",
"Hace match con el patrón <code>authentication failure; rhost=&lt;ip&gt;</code> con un filtro dedicado.",
"Banea la IP infractora a nivel del firewall del kernel por defecto.",
"Se consulta desde el hook <code>before_request</code> de Flask cada 30 s — así que incluso cuando el firewall no puede bloquear (porque la conexión viene del reverse proxy), la aplicación devuelve HTTP 403 a las IPs baneadas según lo que Fail2Ban sabe."
],
"outro": "La configuración, el ajuste del tiempo de ban y los procedimientos de desbaneo están en <link>Seguridad → Fail2Ban</link>."
},
"troubleshoot": {
"heading": "Solución de problemas",
"noScreenTitle": "La pantalla de primer arranque nunca aparece",
"noScreenBody": "O bien auth ya está configurado (<code>configured: true</code>) o bien alguien ya eligió Skip. Para empezar desde cero:",
"noScreenOutro": "Esto borra el estado de auth — también cualquier secret TOTP y API tokens. Haz backup de <code>auth.json</code> primero si tienes tokens que quieres conservar.",
"tokenTitle": "HTTP 401 en cada petición desde un API token que funcionaba",
"tokenBody": "El token caducó (límite de 365 días) o entró en la lista <code>revoked_tokens</code>. Genera uno nuevo en Settings y actualiza la integración. Para comprobar:",
"tokenOutro": "Los tokens caducados o revocados devuelven <code>'{'\"error\":\"Invalid or expired token\"'}'</code>.",
"no2faTitle": "No puedo loguearme tras activar el 2FA, sin autenticador a mano",
"no2faBody": "Usa un código de backup en el campo TOTP. Si ya no quedan, edita <code>/root/.config/proxmenux-monitor/auth.json</code> desde una shell del host, pon <code>totp_enabled</code> a <code>false</code>, reinicia el servicio.",
"wsTitle": "El reverse proxy funciona pero la pestaña del terminal se desconecta cada minuto",
"wsBody": "Timeout de idle de WebSocket en el proxy. Sube el read timeout (Nginx: <code>proxy_read_timeout 86400s</code>; Traefik: <code>idleTimeout</code> en el entry-point o middleware) y confirma que <code>proxy_set_header Upgrade $http_upgrade</code> y <code>Connection \"upgrade\"</code> están presentes."
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "API Reference → Token Management",
"href": "/docs/monitor/api",
"tail": " — ciclo de vida completo de API tokens (generar / listar / revocar), mejores prácticas de seguridad, patrones de almacenamiento de secrets."
},
{
"label": "Integrations",
"href": "/docs/monitor/integrations",
"tail": " — Homepage, Home Assistant, Grafana / Prometheus, Uptime Kuma, cURL genérico."
},
{
"label": "Dashboard → Security → Secure Gateway",
"href": "/docs/monitor/dashboard/security",
"tail": " — despliega el LXC gateway Tailscale paso a paso (subnet routes, ACLs, modo Exit Node)."
},
{
"label": "Seguridad → Fail2Ban",
"href": "/docs/security/fail2ban",
"tail": " — cómo instalar y configurar el jail opcional."
},
{
"label": "Settings → ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — arranca / para el servicio systemd desde la TUI de ProxMenux."
}
]
}
}
@@ -0,0 +1,342 @@
{
"meta": {
"title": "Asistente de IA de Proxmox — OpenAI, Claude, Gemini, Groq, Ollama | ProxMenux Monitor",
"description": "El Asistente de IA opcional de ProxMenux Monitor reescribe los cuerpos de las notificaciones de Proxmox VE en lenguaje natural. Seis proveedores soportados: OpenAI, Anthropic Claude, Google Gemini, Groq, OpenRouter y Ollama local. Doce idiomas, tres niveles de detalle por canal, modo de prompt personalizado con una biblioteca comunitaria y una capa de enriquecimiento de contexto que añade uptime, recurrencia y datos SMART a los eventos de disco.",
"ogTitle": "Asistente de IA de Proxmox — OpenAI, Claude, Gemini, Groq, Ollama",
"ogDescription": "Reescribe las notificaciones de Proxmox VE en lenguaje natural con OpenAI, Anthropic Claude, Google Gemini, Groq, OpenRouter u Ollama local.",
"twitterTitle": "Asistente de IA de Proxmox | ProxMenux Monitor",
"twitterDescription": "Reescribe las notificaciones de Proxmox VE en lenguaje natural con OpenAI, Anthropic, Gemini, Groq, OpenRouter u Ollama local."
},
"header": {
"title": "Asistente de IA",
"description": "El reescritor opt-in que pasa cada notificación saliente por un LLM antes del fan-out — convirtiendo templates estructuradas en mensajes en lenguaje natural, con niveles de detalle por canal, doce idiomas, un modo de prompt personalizado con una biblioteca comunitaria pública y una capa de enriquecimiento de contexto que añade uptime, recurrencia, datos SMART y coincidencias con errores conocidos al prompt.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Desactivado por defecto, un solo interruptor para activarlo",
"body": "La reescritura con IA es opt-in. Hasta que pulses el toggle maestro dentro de <em>Settings → Notifications → Advanced: AI Enhancement</em>, cada evento se despacha con el cuerpo templated original. Cuando el toggle está activado y una llamada al proveedor falla o caduca, el dispatcher cae silenciosamente al cuerpo templated — tus notificaciones nunca se bloquean por el LLM."
},
"howItWorks": {
"heading": "Cómo funciona",
"intro": "Cada evento que despacha el Monitor pasa por la misma pipeline. El reescritor de IA es una etapa opcional que se sitúa entre el cuerpo templated y el envío del canal. De principio a fin, un solo evento camina por cuatro pasos:",
"steps": [
"<strong>Evento + template.</strong> Un evento llega desde uno de los seis colectores y se renderiza en un cuerpo estructurado de texto plano por <code>notification_templates.py</code>. Este es el cuerpo que el canal enviaría si la reescritura con IA estuviese desactivada.",
"<strong>Enriquecimiento de contexto.</strong> El dispatcher inspecciona el evento y añade condicionalmente las señales extra relevantes — uptime del sistema (solo para fallos críticos del sistema), frecuencia del evento, datos SMART (solo para eventos de disco), coincidencias con la base de datos de errores conocidos y líneas de log del journal.",
"<strong>Constructor de prompt.</strong> El system prompt se ensambla a partir del template más los ajustes por canal: idioma destino, nivel de detalle, reglas de emoji de <em>Rich messages</em> y el addon de AI Suggestions si está activado. En modo de prompt personalizado, tu prompt reemplaza el system prompt por completo. El user message se construye a partir del cuerpo templated más los bloques de contexto enriquecidos.",
"<strong>Llamada al proveedor.</strong> El proveedor configurado (Groq, OpenAI, Anthropic, Gemini, Ollama u OpenRouter) devuelve un título y cuerpo reescritos. El dispatcher parsea la respuesta, reemplaza el título y cuerpo originales para ese canal y lo entrega al adaptador del canal para su entrega."
],
"notesIntro": "Tres detalles que merece la pena retener antes de leer el resto de la página:",
"notes": [
"<strong>La IA no produce eventos.</strong> Cada evento nace de una señal real (escaneo del Monitor de salud, línea del journal, webhook de PVE, etc.) y se renderiza en un cuerpo templated antes de que la IA siquiera lo vea. La IA es una traductora y reformateadora, no una observadora.",
"<strong>La IA corre por canal.</strong> Telegram y Discord pueden usar una reescritura breve mientras que Email obtiene un reporte detallado — mismo evento, distinta forma, todo de una sola llamada al proveedor por canal.",
"<strong>El fallo es silencioso.</strong> Si el proveedor da un 5xx, caduca, devuelve salida malformada o rechaza la petición, el dispatcher loguea el error y cae al cuerpo templated original para ese canal. Nunca pierdes una notificación porque el LLM haya tenido un mal día."
]
},
"enabling": {
"heading": "Activar el panel",
"intro": "La configuración de IA vive al final del panel de Notifications dentro de la pestaña Settings, como un bloque colapsable <em>Advanced: AI Enhancement</em>. Pulsa la cabecera para expandirlo:",
"collapsedAlt": "Cabecera colapsada de Advanced AI Enhancement con indicador de chevron",
"collapsedCaption": "Colapsado por defecto — un clic expande el panel.",
"panelAlt": "Panel expandido de AI Enhancement mostrando el toggle maestro AI-Enhanced Messages, Provider Google Gemini, API Key enmascarada, Model gemini-2.5-flash, Prompt Mode Default, Language English, Detail Level por canal para Telegram Discord Gotify Email, toggle AI Suggestions y botón Test Connection",
"panelCaption": "El panel completo de AI Enhancement — cada control documentado en esta página corresponde a uno de los campos de arriba.",
"outro": "De arriba abajo, el panel expone: el toggle maestro <em>AI-Enhanced Messages</em>, el selector de proveedor con un modal de información a su lado, el input de API key (o URL de Ollama para modo local), el dropdown de modelo (cargado desde el proveedor tras introducir la key), el modo de prompt (<em>Default</em> / <em>Custom</em>), el idioma de salida, el nivel de detalle por canal, el opt-in de <em>AI Suggestions</em> y un botón <em>Test Connection</em> que envía un mensaje de prueba al proveedor para validar las credenciales."
},
"context": {
"heading": "Qué contexto recibe la IA",
"intro": "Antes de construir el prompt, el dispatcher recorre una rutina de enriquecimiento de contexto que decide qué señales extra son relevantes para el evento en cuestión. El objetivo es dar al LLM información suficiente para producir un mensaje útil, sin inundarlo (ni tu cartera) con ruido que no aplica. Cinco bloques de contexto pueden añadirse al user message:",
"headerBlock": "Bloque",
"headerWhen": "Cuándo se inyecta",
"headerWhat": "Qué transporta",
"rows": [
{
"block": "Uptime del sistema",
"when": "Solo para fallos críticos a nivel de sistema: <code>crash</code>, <code>panic</code>, <code>oom</code>, <code>kernel</code>, <code>split_brain</code>, <code>quorum_lost</code>, <code>node_offline</code>, <code>node_fail</code>, <code>system_fail</code>, <code>boot_fail</code>. Se omite para errores de disco, advertencias y operaciones rutinarias para mantener el prompt ajustado.",
"what": "Una línea tipo <code>System uptime: 14 days (stable system)</code>. Permite al LLM distinguir problemas de arranque de fallos de larga duración."
},
{
"block": "Frecuencia del evento",
"when": "Siempre, cuando el Monitor ha visto la misma fingerprint antes.",
"what": "Contador de ocurrencias, timestamp first-seen, etiqueta opcional de patrón (recurrente / one-off / spike). El LLM lo usa para formular \"problema recurrente\" vs \"primera vez visto\"."
},
{
"block": "Datos SMART",
"when": "Solo para eventos relacionados con disco (el tipo de evento contiene <code>disk</code>, <code>smart</code>, <code>storage</code>, <code>io_error</code>, o el cuerpo menciona <code>/dev/sd</code>, <code>ata</code>, <code>i/o error</code>).",
"what": "Salida de <code>smartctl</code> para el dispositivo afectado — salud global (PASSED / FAILED) más los atributos relevantes para el modo de fallo."
},
{
"block": "DB de errores conocidos",
"when": "Cuando el cuerpo o el contexto del journal coincide con un patrón de error específico de Proxmox que viene con el Monitor.",
"what": "Un bloque <code>KNOWN PROXMOX ERROR DETECTED</code> con la causa detectada y una solución concreta. El prompt instruye al LLM a traducir esto literalmente — sin parafrasear la solución recomendada."
},
{
"block": "Logs del journal",
"when": "Siempre que el colector que originó el evento capturó líneas del journal (sobre todo el journal watcher y el task watcher).",
"what": "Extractos crudos de <code>journalctl</code>. El prompt le dice al LLM que extraiga IDs, timestamps y pistas de root-cause, y que ignore entradas no relacionadas."
}
],
"afterBlocks": "Una vez unidos estos bloques, el user message enviado al LLM tiene esta forma:",
"calloutTitle": "Sin telemetría más allá del propio evento",
"calloutBody": "El Monitor solo envía lo que tiene a mano para el evento actual — sin telemetría a nivel de sistema, sin series históricas de métricas, sin volcados de inventario. Los cinco bloques de arriba son el techo de lo que sale del host en una sola reescritura con IA."
},
"tokens": {
"heading": "Tokens — qué son y cómo se consumen",
"intro1": "Cada proveedor comercial cobra por <em>token</em>, así que merece la pena entender qué es un token antes de elegir un plan. Un token son aproximadamente cuatro caracteres de texto en inglés o unas tres cuartas partes de una palabra. La frase <em>\"Backup completed on storage local-bak\"</em> son unos ocho tokens. Un extracto corto de journal de diez líneas puede ser 200-400 tokens según la densidad técnica.",
"intro2": "Se facturan dos cosas en cada llamada:",
"items": [
"<strong>Tokens de entrada</strong> — el system prompt más el user message (severidad, título, cuerpo, contexto enriquecido). Para ProxMenux el system prompt solo es del orden de 1.5-2 KB (≈ 400-500 tokens) y el user message varía de 50 tokens (un backup-complete limpio) a ~1500 tokens (un error de disco con 30 líneas de contexto del journal).",
"<strong>Tokens de salida</strong> — lo que el modelo escribe de vuelta. El Monitor lo limita con <code>max_tokens</code> (mira la tabla de abajo). El límite es un <em>tope</em>, no un cargo: si el modelo produce 250 tokens con un tope de 1500, pagas 250."
],
"capsIntro": "Estos son los topes reales que aplica el dispatcher, tomados directamente de <code>AI_DETAIL_TOKENS</code> en <code>notification_templates.py</code>:",
"headerLevel": "Nivel de detalle",
"headerCap": "Tope de salida (tokens)",
"headerConsumption": "Consumo real típico",
"capRows": [
{
"level": "brief",
"cap": "500",
"consumption": "50-200 tokens de salida para eventos cortos."
},
{
"level": "standard",
"cap": "1500",
"consumption": "200-700 tokens de salida para eventos típicos con contexto ligero."
},
{
"level": "detailed",
"cap": "3000",
"consumption": "500-2000 tokens de salida para reportes completos de email con logs y tablas SMART."
}
],
"customNote": "El modo de prompt personalizado usa un tope fijo de 500 tokens de salida independientemente del nivel de detalle — el prompt personalizado está bajo tu control y el tope protege contra respuestas descontroladas.",
"sizingTitle": "Dimensionamiento práctico",
"sizingBody": "Un homelab con 50-100 eventos al día en <code>standard</code> consume típicamente unos pocos miles de tokens al día. Con los niveles gratuitos que ofrecen Groq y Gemini, eso encaja sin tocar un plan de pago. Con OpenAI o Anthropic, facturados por token, el coste se queda en el rango de céntimos al mes para ese volumen. Si tu volumen de eventos es mucho mayor, la sección <link>Nivel de detalle por canal</link> explica cómo mantener los canales de chat en <code>brief</code> dejando que Email lleve el reporte completo."
},
"providers": {
"heading": "Proveedores de IA",
"intro": "Seis proveedores están cableados al Monitor. El dropdown de proveedor en la UI los muestra todos; un botón de información al lado abre un modal con una descripción de una línea para cada uno. Abajo está la referencia completa, con la URL para conseguir una API key, la descripción mostrada en la UI y las notas relevantes del codebase.",
"imageAlt": "Modal de AI Providers Information listando los seis proveedores soportados — Groq, OpenAI, Anthropic Claude, Google Gemini, Ollama, OpenRouter — cada uno con su icono y descripción de una línea, y una nota especial de OpenAI-Compatible APIs para OpenAI",
"imageCaption": "El modal in-app — seis tarjetas, una por proveedor, con las mismas descripciones documentadas abajo.",
"groq": {
"heading": "Groq",
"tagline": "Muy rápido, nivel gratuito generoso (30 req/min). Ideal para empezar.",
"items": [
"API key: <a>console.groq.com/keys</a>",
"Modelos verificados: <code>llama-3.3-70b-versatile</code>, <code>llama-3.1-70b-versatile</code>, <code>llama-3.1-8b-instant</code>, <code>llama3-70b-8192</code>, <code>llama3-8b-8192</code>, <code>mixtral-8x7b-32768</code>, <code>gemma2-9b-it</code>.",
"Recomendado: <strong><code>llama-3.3-70b-versatile</code></strong> — mejor calidad a la velocidad de inferencia completa de Groq."
]
},
"openai": {
"heading": "OpenAI",
"tagline": "Estándar de la industria. Muy preciso y ampliamente usado.",
"items": [
"API key: <a>platform.openai.com/api-keys</a>",
"Modelos verificados: <code>gpt-4.1-nano</code>, <code>gpt-4.1-mini</code>, <code>gpt-4o-mini</code>, <code>gpt-4.1</code>, <code>gpt-4o</code>, <code>gpt-5-chat-latest</code>, <code>gpt-5.4-nano</code>, <code>gpt-5.4-mini</code>.",
"Recomendado: <strong><code>gpt-4.1-nano</code></strong> — el miembro más barato de la familia chat, calidad suficiente para traducción y reformateo. Los modelos de razonamiento (serie o, gpt-5 non-chat) están soportados por el plumbing del proveedor pero se mantienen fuera de la lista verificada: mayor latencia sin ganancia medible de calidad en esta carga de trabajo."
],
"baseUrlTitle": "Base URL compatible con OpenAI",
"baseUrlBody": "El proveedor OpenAI también acepta una <em>Base URL</em> personalizada, que te permite apuntar el Monitor a cualquier endpoint compatible con OpenAI. Confirmado que funciona con <strong>BytePlus / ByteDance (Kimi K2.5)</strong>, <strong>LocalAI</strong>, <strong>LM Studio</strong>, <strong>vLLM</strong>, <strong>Together AI</strong>, <strong>Fireworks AI</strong> y cualquier otro servicio que hable el dialecto OpenAI <code>/v1/chat/completions</code>. Configura la URL en la pestaña OpenAI junto al campo de API key."
},
"anthropic": {
"heading": "Anthropic (Claude)",
"tagline": "Excelente para escritura y traducción. Rápido y económico.",
"items": [
"API key: <a>console.anthropic.com/settings/keys</a>",
"Modelos verificados: <code>claude-3-5-haiku-latest</code>, <code>claude-3-5-sonnet-latest</code>, <code>claude-3-opus-latest</code>.",
"Recomendado: <strong><code>claude-3-5-haiku-latest</code></strong> — el modelo más pequeño y rápido de Claude, con calidad lingüística fuerte para la carga de traducción."
]
},
"gemini": {
"heading": "Google Gemini",
"tagline": "Nivel gratuito disponible, gran ratio calidad/precio.",
"items": [
"API key: <a>aistudio.google.com/app/apikey</a>",
"Modelos verificados: <code>gemini-2.5-flash-lite</code>, <code>gemini-2.5-flash</code>, <code>gemini-3-flash-preview</code>.",
"Recomendado: <strong><code>gemini-2.5-flash-lite</code></strong> — flash y flash-lite pasan el verificador consistentemente. Las variantes pro rechazan el ajuste <code>thinkingBudget=0</code> que usa el Monitor y son excesivas para esta carga."
]
},
"openrouter": {
"heading": "OpenRouter",
"tagline": "Agregador con acceso a más de 100 modelos usando una única API key. Máxima flexibilidad.",
"items": [
"API key: <a>openrouter.ai/keys</a>",
"Modelos verificados: <code>meta-llama/llama-3.3-70b-instruct</code>, <code>meta-llama/llama-3.1-70b-instruct</code>, <code>meta-llama/llama-3.1-8b-instruct</code>, <code>anthropic/claude-3.5-haiku</code>, <code>anthropic/claude-3.5-sonnet</code>, <code>google/gemini-flash-1.5</code>, <code>openai/gpt-4o-mini</code>, <code>mistralai/mistral-7b-instruct</code>, <code>mistralai/mixtral-8x7b-instruct</code>.",
"Recomendado: <strong><code>meta-llama/llama-3.3-70b-instruct</code></strong> — mismo modelo que la entrada de Groq pero enrutado por OpenRouter, lo que significa una sola key para todos los modelos listados."
]
},
"ollama": {
"heading": "Ollama (Local)",
"tagline": "Usa los modelos disponibles en tu servidor Ollama. 100% local, sin costes, privacidad total.",
"items": [
"Sin API key. Configura el campo <em>Ollama URL</em> a tu servidor (por defecto <code>http://localhost:11434</code> o el host que ejecute tu instancia de Ollama).",
"Modelos: <strong>no filtrados.</strong> El Monitor lee los modelos que hayas descargado en el lado de Ollama vía <code>ollama pull &lt;model&gt;</code>. El dropdown se llena desde <code>GET /api/tags</code> en tu servidor Ollama.",
"Instalación: <a>ollama.com/download</a> — corre en Linux, macOS, Windows. Para mejores resultados elige un modelo que entre en RAM con una ventana de contexto suficientemente grande para los bloques de journal que inyecta el dispatcher."
]
}
},
"models": {
"heading": "Por qué estos modelos en concreto",
"intro": "El dropdown de modelos para cada proveedor comercial se llena desde una lista curada que viene con el Monitor (<code>verified_ai_models.json</code>). Los modelos en esta lista se han probado de principio a fin con el formato de la API chat / completions que usa el Monitor, con la forma exacta <code>system_prompt + user_message + max_tokens</code> que envía el AI Enhancer. La lista se refresca antes de cada release de ProxMenux con una herramienta verificadora privada que prueba cada modelo candidato y poda los que se comportan mal.",
"consequencesIntro": "Dos consecuencias que merece la pena conocer:",
"consequences": [
"<strong>El modelo recomendado</strong> para cada proveedor es el que tiene el mejor equilibrio de calidad, latencia y coste específicamente para traducción de notificaciones — no el modelo más capaz que vende el proveedor. Las reescrituras de notificaciones no necesitan razonamiento de modelo frontera; necesitan rapidez y bajo coste.",
"<strong>Aun así puedes elegir otro modelo verificado</strong> del dropdown — a veces tienes una cuota de nivel gratuito que quieres gastar en un modelo concreto, o tienes una preferencia fuerte. Elige cualquiera de las entradas listadas; todas han pasado el verificador."
],
"ollamaTitle": "Ollama es la excepción",
"ollamaBody": "Los modelos de Ollama son locales y el Monitor no los filtra — el dropdown refleja lo que hayas descargado. Elige un modelo del rango 7B-13B con al menos una ventana de contexto de 8K para que la reescritura con IA se comporte razonablemente con los bloques de contexto de journal."
},
"defaultPrompt": {
"heading": "Prompt por defecto",
"intro": "Con el modo de prompt en <em>Default</em>, el Monitor usa el system prompt de abajo. El prompt se plantilla en tiempo de ejecución: <code>'{'language'}'</code>, <code>'{'detail_level'}'</code>, <code>'{'emoji_instructions'}'</code> y <code>'{'suggestions_addon'}'</code> se reemplazan antes de la llamada. Las variantes para canales rich vs plain y el addon AI Suggestions se muestran inmediatamente después.",
"showFullSummary": "Mostrar system prompt completo por defecto",
"passagesIntro": "Dos pasajes del prompt de arriba son placeholders que se intercambian según el toggle <em>Rich messages</em> por canal:",
"passages": [
"<strong>Rich activado</strong> → se inyecta un bloque de emojis listando los iconos que el LLM puede usar, más una regla de hostname (el LLM debe mantener literalmente el prefijo de hostname del título) y un puñado de ejemplos formateados (inicio de backup, backup completo, actualizaciones, arranque de VM, salud degradada). Esto es lo que produce los mensajes con prefijo de emoji en Telegram y Discord.",
"<strong>Rich desactivado</strong> → un bloque de una línea le dice al LLM que use solo ASCII plano — sin emojis, sin símbolos Unicode. Usado para email y cualquier canal donde el ruido de formato perjudique las reglas de inbox o la legibilidad."
],
"suggestionsPlaceholder": "Y el placeholder <code>'{'suggestions_addon'}'</code> está vacío salvo que actives AI Suggestions (siguiente sección), en cuyo caso se inyecta este bloque:",
"showAddonSummary": "Mostrar addon de AI Suggestions"
},
"customPrompt": {
"heading": "Modo de prompt personalizado",
"intro": "Cambiar el modo de prompt a <em>Custom</em> intercambia el system prompt por defecto entero por uno que escribes tú. El prompt personalizado se guarda en la configuración SQLite del Monitor y se envía literalmente en cada llamada de reescritura con IA. Es la salida de emergencia correcta cuando quieres una voz, estructura o foco completamente distintos a los que ofrece el prompt empaquetado.",
"imageAlt": "Modo Custom Prompt mostrando un textarea con reglas de traducción y botones Export Import más un enlace a Community prompts",
"imageCaption": "Custom Prompt — textarea grande con el prompt del usuario, más <em>Export</em>, <em>Import</em> y un enlace a la galería comunitaria en GitHub.",
"changesTitle": "Qué cambia cuando Custom está activado",
"changes": [
"<strong>El prompt por defecto se reemplaza por completo.</strong> Los mappings de Proxmox, las reglas de manejo de contexto y las instrucciones de emoji desaparecen todas. Si quieres conservar cualquiera de ellas, pégalas en tu prompt — el <code>EXAMPLE_CUSTOM_PROMPT</code> empaquetado mostrado abajo es un punto de partida.",
"<strong>El selector de Language se ignora.</strong> El prompt por defecto tiene un placeholder <code>'{'language'}'</code>; el prompt personalizado no. Si quieres salida en un idioma específico, declárala dentro de tu prompt (\"Translate to Spanish\", \"Output everything in French\").",
"<strong>El nivel de detalle sigue aplicando</strong> en el sentido de que está disponible como ajuste por canal, pero el tope de tokens de salida pasa a ser fijo de 500 en modo custom (vs la rampa 500 / 1500 / 3000 del prompt por defecto). Si tu prompt personalizado pide un reporte largo, sube el tope editando el prompt o divide la petición.",
"<strong>Los marcadores de Output Format siguen siendo obligatorios.</strong> El Monitor parsea la respuesta buscando <code>[TITLE]</code> y <code>[BODY]</code> en sus propias líneas. Un prompt personalizado que no emita esos marcadores romperá el parser y caerá al cuerpo templated original.",
"<strong>Las reglas de emoji de Rich messages no se autoinyectan.</strong> Si quieres emojis, dile al prompt que los use. Si quieres texto plano, dile que no. El toggle solo gatea los bloques empaquetados del prompt por defecto, no tu cadena personalizada."
],
"starterTitle": "Prompt inicial",
"starterIntro": "El textarea de <em>Custom Prompt</em> viene precargado con un ejemplo mínimo que puedes adaptar:",
"showStarterSummary": "Mostrar prompt personalizado inicial",
"shareTitle": "Compartir prompts con la comunidad",
"shareIntro": "El botón <em>Export</em> escribe tu prompt personalizado actual en un archivo (<code>.txt</code> / <code>.md</code>) que puedes guardar como backup o pasar a otra persona. <em>Import</em> lo trae de vuelta. El tercer botón al lado enlaza con una galería comunitaria pública en GitHub:",
"shareLinkLabel": "github.com/MacRimi/ProxMenux/discussions — Comparte prompts personalizados para notificaciones de IA",
"shareOutro": "Navega la discusión para ver qué han construido otros operadores — alertas escuetas tipo pager, reportes técnicos verbosos, variantes específicas por idioma. Si tuneas el tuyo y te gusta el resultado, publícalo allí: incluso una descripción de un párrafo de para qué optimiza tu prompt ayuda a la gente a elegir un buen punto de partida. El feedback sobre lo que funciona y lo que no es igualmente bienvenido."
},
"suggestions": {
"heading": "AI Suggestions (BETA)",
"intro": "AI Suggestions es un addon opt-in que deja al LLM añadir <strong>un</strong> consejo corto y accionable al final del cuerpo. Solo se activa cuando el modo de prompt es <em>Default</em>, el toggle maestro de IA está activado y el switch <em>AI Suggestions</em> está pulsado — e incluso entonces, el prompt instruye al modelo a saltarse el consejo cuando la causa o solución no esté clara.",
"formatIntro": "Cuando se añade un consejo, sigue este formato exacto:",
"rulesIntro": "Las reglas integradas en el addon (visibles en el bloque colapsable bajo la sección Default prompt de arriba):",
"rules": [
"El consejo se incluye <em>solo</em> si el contexto del journal o la base de datos de errores conocidos apunta claramente a una solución específica.",
"El consejo está limitado a 100 caracteres.",
"Debe ser específico (comando o ruta concretos) — los consejos genéricos los rechaza el propio prompt.",
"Si un error conocido proporciona una solución, el LLM debe usar esa solución, no inventar una nueva.",
"Si nada en la entrada le da al LLM suficiente certeza para sugerir un arreglo concreto, el consejo se omite — sin adivinar."
],
"betaTitle": "Por qué BETA",
"betaBody": "La calidad del consejo depende de dos cosas fuera de ProxMenux: el modelo elegido y lo rico que era el contexto del journal para el evento. Con un modelo fuerte (Claude 3.5 Haiku, GPT-4.1 Mini, Llama 3.3 70B) y un error de disco que viene con smartctl + líneas de journal, el consejo es consistentemente útil. Con un modelo Ollama local pequeño y un evento de una línea, el consejo puede quedar pobre o saltarse por completo. Desactiva el toggle si encuentras los consejos ruidosos y reactívalo cuando lo quieras de vuelta."
},
"detailLevel": {
"heading": "Nivel de detalle por canal",
"intro": "Cada uno de los cuatro canales (Telegram, Discord, Gotify, Email) tiene su propio dropdown de nivel de detalle. Hay tres valores disponibles, mapeados a topes específicos de tokens de salida y a instrucciones específicas en el prompt por defecto:",
"headerLevel": "Nivel",
"headerLabel": "Etiqueta UI",
"headerCap": "Tope de salida",
"headerProduce": "Qué le pide el prompt al LLM que produzca",
"rows": [
{
"level": "brief",
"label": "2-3 líneas, solo esencial",
"cap": "500 tokens",
"produce": "\"Qué pasó + dónde\". Nada más."
},
{
"level": "standard",
"label": "Conciso con contexto básico",
"cap": "1500 tokens",
"produce": "3-6 líneas: qué, dónde, causa, dispositivos afectados."
},
{
"level": "detailed",
"label": "Detalles técnicos completos",
"cap": "3000 tokens",
"produce": "Reporte completo: qué, dónde, causa, afectados, logs, datos SMART, historial."
}
],
"defaultsIntro": "Valores por defecto que el Monitor aplica en la primera instalación:",
"defaults": [
"<strong>Telegram, Discord, Gotify</strong> — <code>standard</code>.",
"<strong>Email</strong> — <code>detailed</code>. Email es el canal donde típicamente quieres la foto completa para archivo."
],
"emailTitle": "El nivel de detalle de Email añade el original",
"emailBody": "Cuando Email está en <code>detailed</code> y el cuerpo templated original tiene contenido sustancial (más de 50 caracteres), el dispatcher añade el mensaje original al final de la reescritura con IA, separado por un divisor de 40 guiones y una etiqueta <code>Original message:</code>. Esto significa que un email detallado siempre lleva tanto la versión amigable de IA como el template crudo amigable de máquina — útil cuando quieres hacer grep de una alerta antigua más tarde."
},
"language": {
"heading": "Idioma",
"intro": "Doce idiomas están cableados. El dropdown configura <code>ai_language</code> en la config y el valor se interpola en el system prompt en el sitio donde el prompt dice <em>\"translate alerts into '{'language'}'\"</em>. La lista completa:",
"list": "Inglés (<code>en</code>), Español (<code>es</code>), Francés (<code>fr</code>), Alemán (<code>de</code>), Portugués (<code>pt</code>), Italiano (<code>it</code>), Ruso (<code>ru</code>), Sueco (<code>sv</code>), Noruego (<code>no</code>), Japonés (<code>ja</code>), Chino (<code>zh</code>), Neerlandés (<code>nl</code>).",
"rulesIntro": "Dos reglas importantes sacadas directamente del prompt:",
"rules": [
"<strong>Traducir</strong>: etiquetas, descripciones, palabras de estado, unidades (p. ej. GB → Go en francés).",
"<strong>No traducir</strong>: hostnames, IPs, paths, IDs de VM/CT, nombres de dispositivo como <code>/dev/sdX</code>, identificadores técnicos. Se mantienen literales independientemente del idioma."
],
"customNote": "El modo de prompt personalizado <strong>no usa</strong> el selector de Language. Si cambias a Custom y quieres un idioma de salida específico, decláralo dentro de tu prompt."
},
"templates": {
"heading": "Una nota sobre templates",
"body1": "El cuerpo que recibe la IA no es data cruda de evento — es una template prerrenderizada. Cada tipo de evento (<code>backup_complete</code>, <code>vm_start</code>, <code>auth_fail</code>, <code>health_degraded</code>, etc.) tiene una template en <code>notification_templates.py</code> que sabe cómo formatear ese evento específico en un cuerpo estructurado de texto plano. La IA reescribe ese cuerpo, no reemplaza el paso de templating.",
"body2": "Dos implicaciones prácticas: la IA nunca ve un hostname o VMID que tenga que inventar — esos campos los pone la template antes de la reescritura. Y si la IA está desactivada, el cuerpo templated es lo que se despacha directamente. La página de <link>Notifications</link> documenta la pipeline de despacho completa y es la referencia cruzada correcta para todo lo que le pasa a un evento antes de llegar a esta capa."
},
"privacy": {
"heading": "Privacidad y flujo de datos",
"intro": "Con la reescritura con IA activada, el Monitor envía el cuerpo de notificación renderizado más los bloques de contexto enriquecidos al proveedor configurado. Eso puede incluir hostnames, IPs, usernames, paths de dispositivo, líneas de log del journal y atributos SMART del dispositivo afectado. Si eso sale del host depende del proveedor que hayas elegido:",
"headerProvider": "Proveedor",
"headerDestination": "Destino de los datos",
"rows": [
{
"provider": "Ollama",
"destination": "Se queda en el host Ollama. Si Ollama corre en el mismo nodo Proxmox, nada sale de la red en absoluto."
},
{
"provider": "OpenAI",
"destination": "<code>api.openai.com</code> (o tu endpoint Base URL personalizado). Sujeto a la política de manejo de datos de OpenAI en el momento de la llamada."
},
{
"provider": "Anthropic",
"destination": "<code>api.anthropic.com</code>."
},
{
"provider": "Google Gemini",
"destination": "<code>generativelanguage.googleapis.com</code>."
},
{
"provider": "Groq",
"destination": "<code>api.groq.com</code>."
},
{
"provider": "OpenRouter",
"destination": "<code>openrouter.ai</code>, que reenvía al proveedor de modelo subyacente elegido en el campo <code>model</code>. Dos saltos en lugar de uno."
}
],
"calloutTitle": "Si el contenido del evento no puede salir de la red",
"calloutBody": "Usa Ollama, o desactiva el reescritor de IA. No hay terreno intermedio — el dispatcher no intenta redactar hostnames o IPs antes de enviar; el prompt se construye a partir del payload real del evento tal como lo ve el Monitor."
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — la pipeline de despacho, canales, toggles por evento y la integración del webhook de PVE que rodea esta capa."
},
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — el mayor productor individual de eventos que la IA acaba reescribiendo, con sus propias duraciones de supresión por categoría."
},
{
"label": "Arquitectura",
"href": "/docs/monitor/architecture",
"tail": " — dónde encaja el AI Enhancer en el proceso más amplio del Monitor (es un módulo, no un servicio separado)."
}
],
"communityLabel": "Prompts comunitarios en GitHub",
"communityTail": " — navega, comparte, pregunta."
}
}
@@ -0,0 +1,681 @@
{
"meta": {
"title": "API de Proxmox Monitor — Referencia de integración | ProxMenux",
"description": "Endpoints HTTP expuestos por ProxMenux Monitor para integraciones: Home Assistant, Homepage, Grafana, Prometheus, n8n y paneles propios. Exportación de datos en solo lectura más las operaciones de escritura seguras que necesitan las automatizaciones — control de VMs, disparo de backup, despacho de notificaciones, acknowledgement de alertas.",
"ogTitle": "API de Proxmox Monitor — Referencia de integración",
"ogDescription": "Endpoints expuestos por ProxMenux Monitor para Home Assistant, Homepage, Grafana, Prometheus, n8n y paneles propios.",
"twitterTitle": "API de Proxmox Monitor | ProxMenux",
"twitterDescription": "Endpoints para Home Assistant, Homepage, Grafana, Prometheus, n8n y paneles propios."
},
"header": {
"title": "API Reference",
"description": "Los endpoints HTTP que usan los integradores para leer estado y disparar acciones seguras en ProxMenux Monitor — sensores de Home Assistant, tarjetas de Homepage, paneles de Grafana, scrapes de Prometheus, flujos de n8n y scripts propios. Cada categoría, más una lista completa de métricas Prometheus, con ejemplos en curl.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Para qué es esta página",
"body": "Esta página lista los endpoints que esperamos que usen las integraciones externas — exportación de datos en solo lectura para cada parte del Monitor, más el pequeño conjunto de operaciones de escritura que las automatizaciones necesitan legítimamente (disparar un backup, enviar una notificación personalizada, dar acknowledgement a una alerta). Toda la API corre desde el mismo proceso Flask que sirve la UI del panel en TCP <strong>8008</strong>; la dirección de bind y TLS se configuran en <link>Access & Authentication</link>."
},
"headerEndpoint": "Endpoint",
"headerMethod": "Método",
"headerUse": "Uso",
"auth": {
"heading": "Autenticación",
"intro": "Cada endpoint marcado como \"authenticated\" espera un token bearer JWT en la cabecera de la petición:",
"tokensIntro": "Dos formas de obtener el token:",
"items": [
"<strong>API tokens (recomendado para integraciones).</strong> Tokens de larga duración emitidos desde <strong>Settings → Security → API Tokens</strong> en el panel. Cada token tiene un nombre, se puede revocar individualmente y es lo que deberías pasar a Home Assistant / Homepage / Grafana / n8n.",
"<strong>Flujo de login (JWT de corta duración).</strong> <code>POST /api/auth/login</code> con un username, password y token TOTP si el 2FA está activado. El JWT devuelto es de corta duración y el panel lo refresca automáticamente; útil para scripts ad-hoc que se autentican como un usuario humano."
],
"flowLink": "El flujo de auth, la política de contraseñas, la configuración de 2FA, el log de auditoría y la configuración TLS viven todos en <link>Access & Authentication</link>.",
"rows": [
{
"endpoint": "/api/auth/login",
"method": "POST",
"use": "Body: <code>'{'\"username\",\"password\",\"totp_token?\"'}'</code>. Devuelve un JWT de corta duración."
},
{
"endpoint": "/api/auth/api-tokens",
"method": "GET",
"use": "Lista los API tokens (solo metadatos — nombres, prefijos, fechas; nunca el secret real)."
},
{
"endpoint": "/api/auth/api-tokens",
"method": "POST",
"use": "Emite un nuevo API token de larga duración. Body: <code>'{'\"name\":\"'<'label'>'\"'}'</code>. El valor del token se devuelve una vez y no se puede recuperar de nuevo."
},
{
"endpoint": "/api/auth/api-tokens/<id>",
"method": "DELETE",
"use": "Revoca un API token específico por su ID."
}
]
},
"conventions": {
"heading": "Convenciones",
"items": [
"Todas las peticiones y respuestas son JSON salvo que se indique explícitamente (la descarga de logs es texto plano, <code>/api/prometheus</code> es text/plain en formato OpenMetrics, el log de tareas es texto plano).",
"Los endpoints que modifican estado con éxito devuelven <code>'{'\"success\": true, ...'}'</code>. Las respuestas de error usan un estado HTTP no-2xx con <code>'{'\"success\": false, \"error\": \"'<'motivo'>'\"'}'</code>.",
"Los endpoints de listado aceptan <code>limit</code>, <code>offset</code>, <code>since</code> opcionales y filtros específicos por categoría vía query string.",
"Los campos de tiempo se devuelven como segundos epoch Unix o ISO-8601 con zona horaria explícita, nunca como cadenas de locale."
]
},
"system": {
"heading": "Sistema y hardware",
"rows": [
{
"endpoint": "/api/system",
"method": "GET",
"use": "CPU, memoria, swap, uptime, load — snapshot actual."
},
{
"endpoint": "/api/info",
"method": "GET",
"use": "Información estática del host: hostname, kernel, versión de PVE, modelo de CPU, distro."
},
{
"endpoint": "/api/system-info",
"method": "GET",
"use": "Snapshot extendido del sistema usado por la cabecera del panel (métricas globales + boot time)."
},
{
"endpoint": "/api/hardware",
"method": "GET",
"use": "Inventario hardware detallado — dispositivos PCI, GPUs, mapa de sensores."
},
{
"endpoint": "/api/hardware/live",
"method": "GET",
"use": "Valores en vivo para sensores que cambian de segundo en segundo."
},
{
"endpoint": "/api/temperature/history",
"method": "GET",
"use": "Serie temporal de temperaturas CPU / package."
},
{
"endpoint": "/api/gpu/<slot>/realtime",
"method": "GET",
"use": "Métricas en vivo de GPU NVIDIA / Intel / AMD por slot PCI."
}
]
},
"health": {
"heading": "Monitor de salud",
"rows": [
{
"endpoint": "/api/health",
"method": "GET",
"use": "Probe pequeño de salud — devuelve JSON con <code>status</code>, <code>timestamp</code>, <code>version</code>. Adecuado para keyword checks de Uptime Kuma; el receptor debe enviar la cabecera bearer."
},
{
"endpoint": "/api/health/status",
"method": "GET",
"use": "Veredicto global de salud — severidad única + cadena de resumen."
},
{
"endpoint": "/api/health/details",
"method": "GET",
"use": "Las diez categorías con estados por categoría y el payload estructurado que produjo cada uno."
},
{
"endpoint": "/api/health/full",
"method": "GET",
"use": "Snapshot completo — categorías + errores activos + lista de dismissed + ajustes de supresión personalizados. Alimenta el modal en un round-trip; usa una caché de fondo de 6 min para respuesta instantánea."
},
{
"endpoint": "/api/health/active-errors",
"method": "GET",
"use": "Lista activa, filtrable por <code>?category=&lt;name&gt;</code>."
},
{
"endpoint": "/api/health/dismissed",
"method": "GET",
"use": "Lista de dismissed con las horas de supresión restantes."
},
{
"endpoint": "/api/health/settings",
"method": "GET",
"use": "Valores de Suppression Duration por categoría configurados actualmente."
},
{
"endpoint": "/api/health/remote-storages",
"method": "GET",
"use": "Inventario de almacenamientos remotos definidos por Proxmox, con estado online."
},
{
"endpoint": "/api/health/interfaces",
"method": "GET",
"use": "Inventario de interfaces de red con tipo (bridge / bond / physical), IP y velocidad de enlace."
},
{
"endpoint": "/api/health/acknowledge",
"method": "POST",
"use": "Body: <code>'{'\"error_key\":\"smart_sdh\"'}'</code>. Descarta una alerta con la Suppression Duration configurada de la categoría."
},
{
"endpoint": "/api/health/cleanup-orphans",
"method": "POST",
"use": "Limpieza manual de errores cuyo dispositivo o VM subyacente ha desaparecido. Idempotente."
}
],
"outro": "Las formas de respuesta y la semántica de las categorías viven en <link>Monitor de salud</link>."
},
"storage": {
"heading": "Almacenamiento",
"rows": [
{
"endpoint": "/api/storage",
"method": "GET",
"use": "Todos los discos visibles al host (block devices, pools ZFS, LVM)."
},
{
"endpoint": "/api/storage/summary",
"method": "GET",
"use": "Resumen compacto usado por las tarjetas del panel."
},
{
"endpoint": "/api/proxmox-storage",
"method": "GET",
"use": "Almacenamientos definidos por Proxmox desde <code>/etc/pve/storage.cfg</code> con estado online y espacio libre."
},
{
"endpoint": "/api/storage/observations",
"method": "GET",
"use": "Historial permanente de observaciones de disco — advertencias SMART, errores I/O, eventos de pool ZFS, conservados a través de auto-resoluciones de errores."
},
{
"endpoint": "/api/storage/smart/<disk>",
"method": "GET",
"use": "Atributos SMART actuales para un disco."
},
{
"endpoint": "/api/storage/smart/<disk>/latest",
"method": "GET",
"use": "Self-test SMART más reciente para el disco."
},
{
"endpoint": "/api/storage/smart/<disk>/history",
"method": "GET",
"use": "Lista de reportes SMART almacenados para el disco."
},
{
"endpoint": "/api/storage/smart/<disk>/history/<file>",
"method": "GET",
"use": "Lee un reporte SMART almacenado específico."
},
{
"endpoint": "/api/storage/smart/<disk>/test",
"method": "POST",
"use": "Dispara un self-test SMART. Body: <code>'{'\"type\":\"short\"|\"long\"'}'</code>."
},
{
"endpoint": "/api/storage/smart/schedules",
"method": "GET",
"use": "Lista los tests SMART programados actualmente."
},
{
"endpoint": "/api/storage/smart/tools",
"method": "GET",
"use": "Detecta si <code>smartctl</code> y compañía están instalados."
}
]
},
"network": {
"heading": "Red",
"rows": [
{
"endpoint": "/api/network",
"method": "GET",
"use": "Todas las interfaces con estado de enlace y direcciones."
},
{
"endpoint": "/api/network/summary",
"method": "GET",
"use": "Vista compacta usada por el panel."
},
{
"endpoint": "/api/network/<iface>/metrics",
"method": "GET",
"use": "RX / TX por interfaz, contadores de errores, serie temporal RRD."
},
{
"endpoint": "/api/network/latency/current",
"method": "GET",
"use": "Último probe de latencia al gateway."
},
{
"endpoint": "/api/network/latency/history",
"method": "GET",
"use": "Serie temporal de latencia al gateway."
}
]
},
"vms": {
"heading": "VMs y contenedores",
"rows": [
{
"endpoint": "/api/vms",
"method": "GET",
"use": "Lista de todas las VMs y CTs con estado, vmid, nombre."
},
{
"endpoint": "/api/vms/<vmid>",
"method": "GET",
"use": "Detalle completo de un guest (config, red, discos)."
},
{
"endpoint": "/api/vms/<vmid>/metrics",
"method": "GET",
"use": "Serie temporal de CPU / memoria / I/O de disco para un guest (RRD)."
},
{
"endpoint": "/api/vms/<vmid>/logs",
"method": "GET",
"use": "Logs de tareas recientes acotados a ese guest."
},
{
"endpoint": "/api/vms/<vmid>/backups",
"method": "GET",
"use": "Lista los backups actualmente conservados para este guest."
},
{
"endpoint": "/api/vms/<vmid>/control",
"method": "POST",
"use": "Body: <code>'{'\"action\":\"start|stop|reboot|shutdown\"'}'</code>. Power-cycle de un guest."
},
{
"endpoint": "/api/vms/<vmid>/backup",
"method": "POST",
"use": "Dispara <code>vzdump</code> para ese guest. El body elige storage y modo (<code>snapshot</code> / <code>suspend</code> / <code>stop</code>)."
},
{
"endpoint": "/api/vms/<vmid>/config",
"method": "PUT",
"use": "Actualiza el campo descripción (notes) de una VM / CT. Otras claves de config no son modificables desde este endpoint."
},
{
"endpoint": "/api/node/metrics",
"method": "GET",
"use": "Métricas agregadas a nivel de nodo (RRD)."
}
]
},
"backups": {
"heading": "Backups",
"rows": [
{
"endpoint": "/api/backups",
"method": "GET",
"use": "Lista de backups a nivel de cluster."
},
{
"endpoint": "/api/backup-storages",
"method": "GET",
"use": "Almacenamientos marcados como destinos de backup, con espacio libre."
}
]
},
"logs": {
"heading": "Logs, tareas, eventos",
"rows": [
{
"endpoint": "/api/logs",
"method": "GET",
"use": "Entradas del journal filtradas. Query: <code>?level=&service=&limit=</code>."
},
{
"endpoint": "/api/logs/download",
"method": "GET",
"use": "Volcado en texto plano del rango filtrado."
},
{
"endpoint": "/api/events",
"method": "GET",
"use": "Stream interno de eventos — el mismo que alimenta las notificaciones."
},
{
"endpoint": "/api/task-log/<upid>",
"method": "GET",
"use": "Log completo en texto plano para una tarea Proxmox por UPID."
}
]
},
"notifications": {
"heading": "Notifications e IA",
"intro": "La pipeline de despacho, los walk-throughs de canales y la configuración del reescritor de IA viven en <notifLink>Notifications</notifLink> y <aiLink>Asistente de IA</aiLink>.",
"rows": [
{
"endpoint": "/api/notifications",
"method": "GET",
"use": "Notificaciones recientes mostradas en el panel."
},
{
"endpoint": "/api/notifications/download",
"method": "GET",
"use": "Exporta notificaciones como texto."
},
{
"endpoint": "/api/notifications/status",
"method": "GET",
"use": "Estado del dispatcher — si el hilo de fondo está corriendo, profundidad de cola, último envío."
},
{
"endpoint": "/api/notifications/settings",
"method": "GET",
"use": "Lee la configuración completa de notificaciones (canales, toggles por evento, reescritor de IA, Display Name)."
},
{
"endpoint": "/api/notifications/history",
"method": "GET",
"use": "Historial de despacho. Query: <code>?limit=&offset=&severity=&channel=</code>."
},
{
"endpoint": "/api/notifications/history",
"method": "DELETE",
"use": "Borra la tabla de historial de despacho."
},
{
"endpoint": "/api/notifications/test",
"method": "POST",
"use": "Envía una notificación de prueba a un canal. Body: <code>'{'\"channel\":\"telegram\"'}'</code>."
},
{
"endpoint": "/api/notifications/send",
"method": "POST",
"use": "Emite un evento personalizado. Body: <code>'{'\"event_type\":\"custom\",\"severity\":\"WARNING\",\"title\":\"...\",\"body\":\"...\",\"data\":'{''}''}'</code>."
},
{
"endpoint": "/api/notifications/test-ai",
"method": "POST",
"use": "Prueba la conexión del proveedor de IA. Body: <code>'{'\"provider\",\"api_key\",\"model\",\"ollama_url?\"'}'</code>."
},
{
"endpoint": "/api/notifications/provider-models",
"method": "POST",
"use": "Lista modelos disponibles para el proveedor de IA seleccionado."
},
{
"endpoint": "/api/notifications/proxmox/setup-webhook",
"method": "POST",
"use": "Registra el Monitor como destino webhook en <code>/etc/pve/notifications.cfg</code>."
},
{
"endpoint": "/api/notifications/proxmox/cleanup-webhook",
"method": "POST",
"use": "Elimina el destino del Monitor de la config de notificaciones de PVE."
},
{
"endpoint": "/api/notifications/proxmox/read-cfg",
"method": "GET",
"use": "Lee el <code>notifications.cfg</code> actual de PVE como lo ve PVE."
}
]
},
"security": {
"heading": "Seguridad (lectura)",
"rows": [
{
"endpoint": "/api/security/firewall/status",
"method": "GET",
"use": "Estado del firewall de PVE y reglas activas."
},
{
"endpoint": "/api/security/fail2ban/details",
"method": "GET",
"use": "Estado del jail Fail2Ban — solo útil cuando el jail opcional está instalado."
},
{
"endpoint": "/api/security/fail2ban/activity",
"method": "GET",
"use": "Eventos recientes de Fail2Ban (bans, unbans, arranques de jail)."
},
{
"endpoint": "/api/security/lynis/status",
"method": "GET",
"use": "Estado de última ejecución de Lynis (si está instalado, timestamp de último scan)."
},
{
"endpoint": "/api/security/lynis/report",
"method": "GET",
"use": "Último reporte de auditoría Lynis (warnings, sugerencias, hardening index)."
},
{
"endpoint": "/api/security/tools",
"method": "GET",
"use": "Detecta qué herramientas opcionales de seguridad (Fail2Ban, Lynis) están instaladas."
}
]
},
"proxmenuxIntegration": {
"heading": "Integración ProxMenux",
"rows": [
{
"endpoint": "/api/proxmenux/update-status",
"method": "GET",
"use": "Si ProxMenux Monitor tiene actualización disponible, versión actual y última."
},
{
"endpoint": "/api/proxmenux/installed-tools",
"method": "GET",
"use": "Lista de cada optimización post-instalación de ProxMenux registrada actualmente en el host (desde <code>/usr/local/share/proxmenux/installed_tools.json</code>)."
},
{
"endpoint": "/api/proxmenux/tool-source/<key>",
"method": "GET",
"use": "Código fuente de una función post-instalación específica — el bash exacto que se aplicó."
}
]
},
"prometheus": {
"heading": "Métricas Prometheus",
"intro": "ProxMenux Monitor expone un endpoint de scrape formato Prometheus en <code>GET /api/prometheus</code> (autenticado) devolviendo texto formato OpenMetrics. Cada métrica está etiquetada con <code>node=\"&lt;hostname&gt;\"</code> y lleva un timestamp explícito para que ingese limpio en Prometheus, VictoriaMetrics, Mimir o cualquier TSDB compatible.",
"exportedTitle": "Métricas exportadas",
"headerGroup": "Grupo",
"headerMetric": "Métrica",
"headerDesc": "Descripción",
"groups": [
{
"group": "Sistema",
"metrics": [
{
"metric": "proxmox_cpu_usage",
"desc": "Porcentaje de uso de CPU (gauge)."
},
{
"metric": "proxmox_memory_total_bytes",
"desc": "Memoria física total en bytes."
},
{
"metric": "proxmox_memory_used_bytes",
"desc": "Memoria usada en bytes."
},
{
"metric": "proxmox_memory_usage_percent",
"desc": "Porcentaje de uso de memoria."
},
{
"metric": "proxmox_load_average",
"desc": "Load average del sistema. Etiqueta <code>period=\"1m\" | \"5m\" | \"15m\"</code>."
}
]
},
{
"group": "Uptime",
"metrics": [
{
"metric": "proxmox_uptime_seconds",
"desc": "Segundos desde el último boot."
}
]
},
{
"group": "Hardware",
"metrics": [
{
"metric": "proxmox_cpu_temperature_celsius",
"desc": "Temperatura del package de CPU."
},
{
"metric": "proxmox_disk_temperature_celsius",
"desc": "Temperatura por disco. Etiqueta <code>device</code>."
},
{
"metric": "proxmox_fan_speed_rpm",
"desc": "Velocidades de ventilador. Etiqueta <code>fan</code>."
}
]
},
{
"group": "Espacio en disco",
"metrics": [
{
"metric": "proxmox_disk_total_bytes",
"desc": "Espacio total de disco por mount. Etiqueta <code>mountpoint</code>."
},
{
"metric": "proxmox_disk_used_bytes",
"desc": "Espacio usado de disco por mount."
},
{
"metric": "proxmox_disk_usage_percent",
"desc": "Porcentaje de uso de disco por mount."
}
]
},
{
"group": "Red",
"metrics": [
{
"metric": "proxmox_network_bytes_sent_total",
"desc": "Total de bytes enviados (counter)."
},
{
"metric": "proxmox_network_bytes_received_total",
"desc": "Total de bytes recibidos (counter)."
},
{
"metric": "proxmox_interface_bytes_sent_total",
"desc": "Bytes enviados por interfaz. Etiqueta <code>interface</code>."
},
{
"metric": "proxmox_interface_bytes_received_total",
"desc": "Bytes recibidos por interfaz."
}
]
},
{
"group": "VMs / CTs",
"metrics": [
{
"metric": "proxmox_vms_total",
"desc": "Número total de VMs y LXCs."
},
{
"metric": "proxmox_vms_running",
"desc": "Número de guests en ejecución."
},
{
"metric": "proxmox_vms_stopped",
"desc": "Número de guests parados."
},
{
"metric": "proxmox_vm_status",
"desc": "Estado por VM/CT (1 = running, 0 = stopped). Etiquetas <code>vmid</code>, <code>name</code>, <code>type</code>."
},
{
"metric": "proxmox_vm_cpu_usage",
"desc": "Uso de CPU por VM/CT. Mismas etiquetas."
},
{
"metric": "proxmox_vm_memory_used_bytes / _max_bytes",
"desc": "Memoria usada por VM/CT y máximo configurado."
}
]
},
{
"group": "GPU",
"metrics": [
{
"metric": "proxmox_gpu_temperature_celsius",
"desc": "Temperatura de GPU. Etiquetas <code>slot</code>, <code>vendor</code>."
},
{
"metric": "proxmox_gpu_utilization_percent",
"desc": "Porcentaje de utilización de GPU."
},
{
"metric": "proxmox_gpu_memory_total_bytes",
"desc": "Total de memoria de GPU."
},
{
"metric": "proxmox_gpu_power_draw_watts",
"desc": "Consumo de potencia de GPU en vatios."
},
{
"metric": "proxmox_gpu_clock_speed_mhz",
"desc": "Velocidad de reloj del core de GPU."
},
{
"metric": "proxmox_gpu_memory_clock_mhz",
"desc": "Velocidad de reloj de memoria de GPU."
}
]
},
{
"group": "UPS",
"metrics": [
{
"metric": "proxmox_ups_battery_charge_percent",
"desc": "Porcentaje de carga de batería."
},
{
"metric": "proxmox_ups_load_percent",
"desc": "Carga actual de la UPS."
},
{
"metric": "proxmox_ups_runtime_seconds",
"desc": "Autonomía estimada en batería."
},
{
"metric": "proxmox_ups_input_voltage_volts",
"desc": "Voltaje de entrada."
}
]
}
],
"scrapeTitle": "Configuración de scrape de Prometheus",
"scrapeIntro": "El endpoint requiere autenticación. Pasa el API token como cabecera bearer en tu configuración de scrape de Prometheus:",
"perHostTitle": "Scrape por host",
"perHostBody": "Cada instancia de ProxMenux Monitor exporta métricas para el host en el que corre. En un cluster, apunta Prometheus a cada nodo — la etiqueta <code>node</code> en cada serie te permite distinguirlos en consultas Grafana (<code>proxmox_vms_running'{'node=\"pve01\"'}'</code>)."
},
"puttingItTogether": {
"heading": "Juntándolo todo",
"body": "Para guías de principio a fin que conectan estos endpoints con sensores de Home Assistant, tarjetas de Homepage, paneles de Grafana, flujos de n8n y otras herramientas, mira la página dedicada <link>Integrations</link> — recorre la configuración típica de cada plataforma con ejemplos copia-pega. Esta página se mantiene centrada en el catálogo en sí."
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — emisión de tokens, log de auditoría, jail Fail2Ban opcional, configuración TLS."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tailRich": " — qué transporta cada tipo de evento en <code>data</code> cuando llamas a <code>/api/notifications/send</code>."
},
{
"label": "Asistente de IA",
"href": "/docs/monitor/ai-assistant",
"tailRich": " — cómo están cableados <code>/api/notifications/test-ai</code> y <code>/api/notifications/provider-models</code>."
},
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tailRich": " — la forma de respuesta de <code>/api/health/*</code> y la semántica de las diez categorías."
}
]
}
}
@@ -0,0 +1,303 @@
{
"meta": {
"title": "Arquitectura de ProxMenux Monitor — AppImage, Flask, SQLite, WebSocket | ProxMenux",
"description": "Cómo está construido ProxMenux Monitor: estructura del AppImage, blueprints de Flask, hilos de fondo, fuentes de datos (psutil, pvesh, smartctl, journalctl), persistencia en SQLite, terminal WebSocket, proveedores de IA, canales de notificación, reverse proxy e integración opcional con Fail2Ban.",
"ogTitle": "Arquitectura de ProxMenux Monitor",
"ogDescription": "Dentro de ProxMenux Monitor — estructura del AppImage, blueprints de Flask, hilos de fondo, SQLite, WebSocket, proveedores de IA, canales de notificación.",
"twitterTitle": "Arquitectura de ProxMenux Monitor",
"twitterDescription": "AppImage, Flask, SQLite, WebSocket, proveedores de IA y canales de notificación — por dentro del Monitor."
},
"header": {
"title": "Arquitectura",
"description": "Cómo se empaqueta ProxMenux Monitor, qué corre dentro del AppImage y cómo fluyen las peticiones desde el navegador a través del backend Flask hasta las herramientas del host y el almacén SQLite.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Un proceso, muchas responsabilidades",
"body": "Un único proceso Python escucha en el puerto TCP 8008. Sirve el build estático de Next.js, expone la API REST, gestiona el terminal WebSocket, ejecuta el Monitor de salud periódico y despacha notificaciones. No hay un servidor web aparte, ni un broker de mensajes, ni una base de datos externa."
},
"requestFlow": {
"heading": "Flujo de petición",
"intro": "Del navegador al kernel, cada vista del panel sigue el mismo camino:",
"diagramCaption": "Cada petición se autentica por JWT (cuando la autenticación está activada), se enruta a un blueprint y se responde con datos recogidos bajo demanda desde las herramientas del host. Si Fail2Ban está instalado y el jail proxmenux está activo, el middleware también comprueba la petición contra la lista de IPs baneadas del jail. El reverse proxy opcional es transparente para Flask — reenvía las cabeceras X-Forwarded-* y la app recupera la IP real del cliente a partir de ellas. El estado que necesita sobrevivir a una petición vive en SQLite.",
"diagramArrowLabel": "HTTP / WS",
"nodes": {
"clientLabel": "Cliente",
"clientDetail": "Navegador o PWA\n+ proxy opcional\nNginx / Caddy /\nTraefik",
"flaskLabel": "Flask :8008",
"flaskDetail": "Blueprints\nMiddleware JWT\nHook Fail2Ban\n(si está instalado)",
"hostLabel": "Herramientas del host",
"hostDetail": "psutil\npvesh\nsmartctl\njournalctl",
"stateLabel": "Estado local",
"stateDetail": "DB SQLite\n+ auth.json"
},
"threadsIntro": "El mismo proceso también ejecuta cuatro <strong>hilos de fondo</strong> arrancados al boot — no sirven HTTP, empujan estado a SQLite o a la cola de notificaciones mientras el host está activo:",
"headerThread": "Hilo",
"headerCadence": "Cadencia",
"headerJob": "Tarea",
"rows": [
{
"thread": "_temperature_collector_loop",
"cadence": "60 s",
"job": "Registra la temperatura de la CPU y una muestra de latencia de red en la DB de historial para que las gráficas del panel tengan datos incluso cuando ningún cliente está conectado."
},
{
"thread": "_health_collector_loop",
"cadence": "5 min",
"job": "Ejecuta el ciclo completo del Monitor de salud (10 categorías), persiste errores activos, dismissals y observaciones de disco, y alimenta nuevos eventos al motor de notificaciones."
},
{
"thread": "_vital_signs_sampler",
"cadence": "~1 s",
"job": "Muestreador de alta frecuencia de CPU + temperatura usado por los widgets en vivo del panel Overview."
},
{
"thread": "notification_manager.start()",
"cadence": "dirigido por eventos",
"job": "Lanza los watchers de journal / task / hook (<code>JournalWatcher</code>, <code>TaskWatcher</code>, <code>ProxmoxHookWatcher</code>) y despacha a los canales configurados con reescritura opcional con IA."
}
]
},
"systemd": {
"heading": "Unidad systemd",
"intro": "El instalador deja una unidad en <code>/etc/systemd/system/proxmenux-monitor.service</code>. Contenido por defecto:",
"items": [
"<strong><code>User=root</code></strong> — obligatorio: SMART, <code>pvesh</code>, scopes de journal, comandos ZFS y el terminal web requieren todos root.",
"<strong><code>Restart=on-failure</code></strong> con back-off de 10 segundos — las salidas con código distinto de cero relanzan automáticamente.",
"<strong><code>After=network.target</code></strong> — espera a que el stack de red del host esté online."
],
"inspectTitle": "Inspeccionar la unidad en vivo"
},
"appimage": {
"heading": "Qué contiene el AppImage",
"intro": "El AppImage es un sistema de archivos automontable. <code>AppRun</code> en la raíz prepara el entorno y ejecuta <code>flask_server.py</code>:",
"consequencesIntro": "Dos consecuencias de esta estructura:",
"consequences": [
"<strong>Sin polución del Python del host.</strong> El intérprete y los paquetes empaquetados están aislados dentro del AppImage — actualizar el Python del sistema host no afecta al Monitor y viceversa.",
"<strong>Las herramientas de hardware también vienen incluidas.</strong> <code>ipmitool</code>, <code>lm-sensors</code> y <code>upsc</code> viajan dentro del AppImage para que el panel pueda leer sensores fuera de banda y el estado de la UPS sin forzar al usuario a instalar paquetes Debian."
]
},
"flask": {
"heading": "Estructura de la app Flask",
"intro": "<code>flask_server.py</code> crea una única instancia <code>Flask(__name__)</code>, habilita CORS y registra seis blueprints más un inicializador de WebSocket:",
"headerBlueprint": "Blueprint / módulo",
"headerPrefix": "Prefijo de rutas",
"headerOwns": "Responsable de",
"rows": [
{
"blueprint": "flask_server.py",
"prefix": [
"/api/system",
"/api/storage",
"/api/network",
"/api/vms",
"/api/hardware",
"/api/logs",
"/api/prometheus"
],
"owns": "Endpoints de datos principales + servir el panel estático + comprobación opcional de Fail2Ban a nivel de aplicación (activa solo cuando Fail2Ban está instalado en el host con el jail <code>proxmenux</code>)."
},
{
"blueprint": "flask_auth_routes.py",
"prefix": [
"/api/auth/*"
],
"owns": "Login, emisión de JWT, configuración / verificación de TOTP, cambio de contraseña, generación de API tokens."
},
{
"blueprint": "flask_health_routes.py",
"prefix": [
"/api/health/*"
],
"owns": "Probe de salud público, estado detallado, errores activos / dismissed, ajustes de supresión."
},
{
"blueprint": "flask_terminal_routes.py",
"prefix": [
"/api/terminal/* + WS"
],
"owns": "Asignación de PTY por sesión y pipe WebSocket hacia <code>xterm.js</code> en el navegador."
},
{
"blueprint": "flask_notification_routes.py",
"prefix": [
"/api/notifications/*"
],
"owns": "CRUD de canales, envío de prueba, configuración del proveedor de IA, historial, envíos manuales."
},
{
"blueprint": "flask_security_routes.py",
"prefix": [
"/api/security/*"
],
"owns": "Fallos de autenticación y, cuando Fail2Ban está instalado, estado del jail, eventos de ban y desbaneo manual."
},
{
"blueprint": "flask_proxmenux_routes.py",
"prefix": [
"/api/proxmenux/*"
],
"owns": "Lee qué optimizaciones post-instalación de ProxMenux están instaladas en el host."
},
{
"blueprint": "flask_oci_routes.py",
"prefix": [
"/api/oci/*"
],
"owns": "Ayudantes de despliegue de apps OCI / container (Proxmox VE 9.1+)."
}
],
"endpointsLink": "La lista completa de endpoints con la forma de petición / respuesta está en <link>API Reference</link>."
},
"dataSources": {
"heading": "Fuentes de datos",
"intro": "Nada se recoge a través de un agente propio — el Monitor lee los mismos archivos y ejecuta los mismos comandos que un administrador humano:",
"headerSource": "Fuente",
"headerUsedFor": "Usado para",
"rows": [
{
"source": "psutil",
"usedFor": "Carga de CPU, memoria, swap, uso de puntos de montaje, contadores de NIC, lista de procesos."
},
{
"source": "pvesh / qm / pct",
"usedFor": "Información del nodo Proxmox, inventario y configuración de VMs y CTs, pools de almacenamiento, historial de tareas."
},
{
"source": "smartctl",
"usedFor": "Atributos SATA / NVMe, salud SMART, desgaste / vida útil, modelo y número de serie."
},
{
"source": "zpool / zfs",
"usedFor": "Estado del pool (ONLINE / DEGRADED / FAULTED / UNAVAIL), progreso de scrub, uso de datasets."
},
{
"source": "journalctl",
"usedFor": "Logs del sistema, OOM kills, errores ATA / NVMe / dm, eventos de seguridad, unidades de servicio propias."
},
{
"source": "ip / iproute2",
"usedFor": "Interfaces, direcciones, bridges, bonds, dispositivos gestionados por OVS."
},
{
"source": "nvidia-smi · intel_gpu_top",
"usedFor": "Utilización de GPU, VRAM, temperatura, carga de encoder / decoder."
},
{
"source": "lspci · lscpu · dmidecode",
"usedFor": "Topología PCIe, modelo y topología de CPU, información de placa y BIOS."
},
{
"source": "ipmitool · sensors",
"usedFor": "Sensores fuera de banda, velocidades de ventilador, temperaturas de placa (cuando son compatibles)."
},
{
"source": "upsc (NUT)",
"usedFor": "Estado de batería de UPS, carga, autonomía — cuando hay un servidor NUT configurado en el host."
}
],
"cacheTitle": "La salida se cachea — no toda petición llega al host",
"cacheBody": "Las fuentes costosas (<code>smartctl -a</code>, <code>pvesh get</code>) se envuelven en cachés temporizadas dentro del proceso Flask para que una pestaña ocupada del panel no martillee el disco o la API del cluster. Los TTLs de la caché están ajustados por fuente (unos pocos segundos para métricas en vivo, varios minutos para SMART)."
},
"persistence": {
"heading": "Persistencia",
"intro": "Dos ubicaciones del sistema de archivos separan el estado por sensibilidad:",
"headerPath": "Ruta",
"headerOwner": "Propietario",
"headerContents": "Contenido",
"rows": [
{
"path": "/usr/local/share/proxmenux/health_monitor.db",
"owner": "root:root",
"contents": "DB SQLite. Tablas: <code>errors</code>, <code>events</code>, <code>disk_registry</code>, <code>disk_observations</code>, <code>user_settings</code>, <code>notification_history</code>, <code>excluded_storages</code>, <code>excluded_interfaces</code>. Modo journal WAL."
},
{
"path": "/usr/local/share/proxmenux/.notification_key",
"owner": "root <code>0600</code>",
"contents": "Clave XOR de 32 bytes usada para cifrar ajustes sensibles de notificaciones antes de guardarlos en la DB (tokens de Telegram, API keys de IA, etc.)."
},
{
"path": "/root/.config/proxmenux-monitor/auth.json",
"owner": "root:root",
"contents": "Estado de autenticación: flag de activación, nombre de usuario, hash SHA-256 de la contraseña, secret TOTP, códigos de backup, lista de API tokens emitidos, lista de hashes de tokens revocados."
},
{
"path": "/var/log/proxmenux-auth.log",
"owner": "root:root",
"contents": "Log de eventos de autenticación en texto plano. Siempre se escribe. Si Fail2Ban está instalado con el jail <code>[proxmenux]</code>, el jail lee este archivo para banear intentos de fuerza bruta; si no, el archivo simplemente acumula las entradas del log."
}
],
"backupTitle": "Haz backup de auth.json antes de reinstalar",
"backupBody": "Reinstalar el AppImage reemplaza el binario pero deja <code>/root/.config/proxmenux-monitor/auth.json</code> y <code>/usr/local/share/proxmenux/health_monitor.db</code> intactos. Si restauras desde un backup del host, mantén ambos archivos juntos — los API tokens guardados en <code>auth.json</code> se validan contra <code>JWT_SECRET</code>; si la DB y auth.json se desincronizan, los errores dismissed y los tokens guardados pueden comportarse mal."
},
"health": {
"heading": "Ciclo del Monitor de salud",
"intro": "Cada 5 minutos <code>health_monitor.py</code> ejecuta un ciclo determinista a través de las diez categorías mostradas en el panel:",
"items": [
"Servicios críticos de PVE (<code>pveproxy</code>, <code>pvedaemon</code>, <code>pvestatd</code>, <code>pve-cluster</code>).",
"Pools de almacenamiento Proxmox (<code>pvesh get /storage</code> + disponibilidad por almacenamiento).",
"Discos y sistemas de archivos: SMART, errores de I/O en dmesg, salud de pool ZFS, capacidad de puntos de montaje.",
"VMs y CTs: arranques fallidos, guests caídos, errores QMP, fallos de apagado.",
"Red: estado de bridge / bond, estado de enlace, latencia al gateway.",
"Actualizaciones: actualizaciones de paquetes pendientes y parches de seguridad.",
"Logs: detección de patrones persistentes / spike / cascada en el journal del sistema.",
"Memoria: actividad del OOM killer, presión alta sostenida.",
"Temperatura: sensores CPU / chasis contra umbrales del fabricante.",
"Seguridad: fallos de autenticación, eventos de ban, estado del jail fail2ban."
],
"afterIntro": "Cada hallazgo se normaliza a un <code>error_key</code> + categoría + severidad estable. La capa de persistencia deduplica contra la tabla <code>errors</code> existente — los eventos repetidos actualizan <code>last_seen</code> y el contador de ocurrencias sin spamear notificaciones.",
"cycleEnd": "El ciclo también auto-resuelve errores obsoletos usando el ajuste de <em>Suppression Duration</em> por categoría, limpia errores de recursos que ya no existen (VMs eliminadas / discos retirados / almacenamientos desmontados) y poda el log <code>events</code> con más de 30 días. El catálogo completo de categorías y la vista del panel que las expone está documentado en <link>Dashboard → Monitor de salud</link>."
},
"notifications": {
"heading": "Motor de notificaciones",
"intro": "<code>notification_manager.py</code> es el orquestador. Carga los canales configurados, posee la cola de entrega y expone tanto una API Python (para rutas Flask y el ciclo del Monitor de salud) como un punto de entrada CLI (para los scripts <code>.sh</code> de hooks que vienen con ProxMenux).",
"items": [
"<strong>Los watchers</strong> empujan eventos: <code>JournalWatcher</code> sigue el journal del sistema, <code>TaskWatcher</code> hace polling de la lista de tareas Proxmox, <code>ProxmoxHookWatcher</code> reacciona a hooks de backup / replicación / snapshot y <code>PollingCollector</code> gestiona fuentes de datos lentas.",
"<strong>Las templates</strong> convierten un evento en un par (título, cuerpo). La misma template puede pasar por el proveedor de IA configurado (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter) para producir una reescritura en lenguaje natural; ambas versiones se guardan en <code>notification_history</code>.",
"<strong>Los canales</strong> entregan los mensajes: Telegram, Discord, Email, Gotify y Apprise (multicanal). Cada uno está implementado en <code>notification_channels.py</code> detrás de la misma interfaz <code>create_channel()</code> / <code>send()</code>, así que añadir un canal nuevo es una sola clase.",
"<strong>Cifrado.</strong> Los ajustes sensibles (<code>telegram.token</code>, <code>discord.webhook_url</code>, <code>ai_api_key_*</code>, <code>email.password</code>) se cifran con XOR usando la clave en <code>.notification_key</code> antes de escribirse en la DB. El texto plano nunca toca disco."
],
"linksFooter": "Los toggles por evento, los overrides por canal y la configuración de IA se exponen en <notifLink>Settings → Notifications</notifLink> y <aiLink>Settings → AI Assistant</aiLink>."
},
"websocket": {
"heading": "Terminal WebSocket",
"intro": "La pestaña <em>Terminal</em> del panel es un cliente fino <code>xterm.js</code> cableado a un PTY del lado servidor a través de un WebSocket. Dos modos de transporte:",
"items": [
"<strong>Modo HTTP (por defecto):</strong> el servidor de desarrollo de Flask con <code>flask-sock</code> gestiona las peticiones de upgrade. Suficiente para LAN / acceso directo.",
"<strong>Modo HTTPS / WSS:</strong> cuando hay un certificado SSL configurado, el proceso cambia a <code>gevent.pywsgi.WSGIServer</code> con <code>geventwebsocket.handler.WebSocketHandler</code>, para que los WebSockets funcionen sobre TLS sin polyfills."
],
"outro": "El PTY es un hijo del proceso Flask, así que hereda <code>User=root</code> de la unidad. Cada petición de terminal pasa por auth JWT; el usuario debe estar ya logueado en el panel antes de que se asigne un PTY.",
"proxyNote": "Si accedes al Monitor a través de un reverse proxy, asegúrate de habilitar el reenvío de WebSocket (cabeceras <code>Upgrade</code> y <code>Connection</code>). Sin eso, el terminal no funcionará."
},
"proxy": {
"heading": "Reverse proxy y Fail2Ban",
"intro": "Dos salvaguardas se aseguran de que la seguridad funcione igual tanto si el panel se accede directamente como a través de un reverse proxy:",
"items": [
"<strong>Recuperación de la IP real del cliente.</strong> Un hook <code>before_request</code> lee <code>X-Forwarded-For</code> y <code>X-Real-IP</code> en ese orden, cayendo a <code>request.remote_addr</code>. La dirección recuperada es la que ven el log de autenticación y el rate limiting. Esto está siempre activo.",
"<strong>Comprobación de Fail2Ban a nivel de aplicación (opcional).</strong> Cuando el panel está detrás de un proxy, el firewall del kernel no puede bloquear la IP real del atacante — la conexión siempre viene del proxy. Para tapar ese hueco, el mismo hook de arriba consulta el jail <code>proxmenux</code> de Fail2Ban cada 30 segundos, cachea el conjunto de IPs baneadas y corta las peticiones desde esas IPs con HTTP 403 dentro de Flask."
],
"calloutTitle": "Fail2Ban no viene incluido",
"calloutBody": "Fail2Ban <strong>no</strong> lo instala ProxMenux Monitor por sí mismo. La comprobación a nivel de aplicación es un no-op hasta que instales Fail2Ban en el host (p. ej. vía <link>Seguridad → Fail2Ban</link> en el menú de ProxMenux). Cuando el binario <code>fail2ban-client</code> o el jail <code>proxmenux</code> está ausente, la llamada falla silenciosamente y las peticiones no se filtran — la autenticación sigue aplicándose, pero no hay baneo a nivel de IP.",
"outro": "Los snippets de reverse proxy (Nginx / Caddy / Traefik) y el walkthrough del jail Fail2Ban están en <accessLink>Access & Authentication</accessLink> y <fail2banLink>Seguridad → Fail2Ban</fail2banLink>."
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — configuración de primer arranque, contraseña + TOTP 2FA, snippets de reverse proxy, jail Fail2Ban."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — cada endpoint, gestión de tokens, mejores prácticas de seguridad."
},
{
"label": "Settings → ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — el toggle del servicio dentro del menú y el flujo de verificación del estado dentro de la TUI de ProxMenux."
}
]
}
}
@@ -0,0 +1,246 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Hardware | ProxMenux Documentation",
"description": "La pestaña Hardware inventaría la máquina física: CPU y placa base, módulos de memoria, sensores térmicos, GPUs (con monitorización en tiempo real por slot e instalador de drivers en un clic), aceleradoras Coral TPU, resumen de almacenamiento con comprobaciones de velocidad de enlace, listas completas de dispositivos PCI y USB, consumo de energía, PSUs, ventiladores y estado del UPS."
},
"header": {
"title": "Panel: pestaña Hardware",
"description": "La máquina física en una sola pantalla — identidad de CPU y placa base, cada módulo de memoria, sensores térmicos en todos los subsistemas, GPUs con utilización en vivo e instalador de drivers integrado, Coral TPUs, cada dispositivo PCI y USB con su kernel driver, el inventario completo de discos con las velocidades de enlace negociadas, además de energía, refrigeración y el UPS.",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "Construido a partir de herramientas estándar",
"body": "La mayor parte de esta pestaña se parsea de <code>lscpu</code>, <code>dmidecode</code>, <code>lspci</code>, <code>lsusb</code>, <code>lsblk</code>, <code>smartctl</code>, <code>nvme</code>, <code>sensors</code>, <code>nvidia-smi</code>, <code>intel_gpu_top</code>, <code>amdgpu_top</code>, <code>ipmitool</code> y <code>upsc</code>. Las secciones solo se renderizan cuando la herramienta correspondiente devuelve datos, así que un host sin UPS no mostrará la tarjeta UPS y un host sin IPMI no mostrará cifras de energía out-of-band."
},
"thresholds": {
"title": "Colores de estado y umbrales aplicados aquí",
"intro": "Cada chip de temperatura y lectura de esta pestaña sigue la misma clasificación — <green/> <strong>verde</strong> por debajo de Warning, <amber/> <strong>ámbar</strong> entre Warning y Critical, <red/> <strong>rojo</strong> en Critical y por encima. Valores por defecto recomendados que vienen con ProxMenux:",
"items": [
"<strong>Temperatura de CPU</strong> — Warning 80 °C, Critical 90 °C.",
"<strong>Temperatura de disco</strong> — HDD 60/65 °C · SSD 70/75 °C · NVMe 80/85 °C · SAS 55/65 °C (warning / critical)."
],
"outro": "Cada valor es configurable por host — <link>Settings → Health Monitor Thresholds</link> es la fuente única de verdad y explica cómo ajustarlos."
},
"sections": {
"heading": "Secciones",
"intro": "La pestaña renderiza de arriba abajo en este orden. Algunas secciones solo aparecen cuando el host tiene el hardware o la herramienta correspondiente instalada — se marcan <em>(condicional)</em> abajo.",
"systemInfoTitle": "System Information",
"systemInfoIntro": "Dos bloques uno al lado del otro, siempre presentes:",
"systemInfoItems": [
"<strong>CPU</strong> — nombre del modelo, microarquitectura, sockets / cores / threads, frecuencia base / boost, flags de virtualización (VT-x / AMD-V), topología de caché.",
"<strong>Placa base</strong> — vendor, modelo, versión de BIOS, fecha de BIOS, UUID SMBIOS. Útil para emparejar con páginas de descarga del fabricante al buscar actualizaciones de firmware."
],
"memoryTitle": "Memory Modules",
"memoryBody": "Una fila por slot poblado desde <code>dmidecode</code>: etiqueta del slot, tamaño del módulo, tipo (DDR4 / DDR5 / variantes ECC), velocidad (configurada y nominal), fabricante, part number y serial. Los slots vacíos se listan atenuados para que veas de un vistazo el margen de ampliación.",
"thermalTitle": "Thermal Monitoring",
"thermalIntro": "Cinco sub-bloques, cada uno alimentado por <code>lm-sensors</code> + scrapers específicos por herramienta. Un bloque se oculta cuando no hay sensores reportados en esa categoría.",
"thermalItems": [
"<strong>CPU</strong> — temperaturas de package y por core.",
"<strong>GPU</strong> — sensores de GPU discreta vía <code>nvidia-smi</code> / <code>amdgpu_top</code> / iGPU Intel. Incluye hot-spot y memory-junction cuando el driver los expone.",
"<strong>NVME</strong> — temperaturas composite + por sensor de <code>nvme</code>.",
"<strong>PCI</strong> — sensores que aparecen como dispositivos conectados a PCI (HBAs, tarjetas de red con sensores internos).",
"<strong>OTHER</strong> — chipset, VRM, sensores ambiente que no encajan en otro sitio."
]
},
"graphics": {
"heading": "Graphics Cards",
"intro": "Cada controlador de vídeo detectado renderiza como su propia tarjeta con vendor, modelo, tipo (<em>Integrada</em> / <em>PCI</em> / BMC), slot PCI (BDF), kernel driver y lista de módulos. La tarjeta también expone un control inline <strong>Switch Mode</strong> que alterna la GPU entre compartición LXC (driver nativo) y passthrough a VM (<code>vfio-pci</code>) — mira <link>Switch GPU Mode (VM ↔ LXC)</link> para entender qué pasa en el host cuando lo pulsas.",
"vfioImageAlt": "Sección Graphics Cards mostrando una GPU integrada Matrox G200EH atada a mgag200 (Ready for LXC) y una NVIDIA Quadro P400 atada a vfio-pci (Ready for VM passthrough)",
"vfioImageCaption": "Dos GPUs detectadas: el chip BMC Matrox está en el driver nativo y listo para LXC; la NVIDIA Quadro P400 está atada a <code>vfio-pci</code>, lista para passthrough a VM.",
"lxcImageAlt": "Sección Graphics Cards mostrando una iGPU Intel UHD Graphics en i915 y una NVIDIA Quadro P1000 en el driver nvidia, ambas etiquetadas Ready for LXC containers",
"lxcImageCaption": "Mismo nodo después de devolver la tarjeta NVIDIA al driver nativo — ambas GPUs ahora Ready for LXC containers.",
"realtimeTitle": "Modal de monitorización en tiempo real",
"realtimeBody": "Pulsar una tarjeta de GPU abre una modal de monitorización por slot que sondea la herramienta del vendor adecuada cada tres segundos. La modal expone vendor, tipo, slot PCI, driver, módulo(s) del kernel, utilización en vivo de motores (Render/3D, Video, Blitter, VideoEnhance), clocks de gráficos y memoria, temperatura, consumo de potencia (cuando se reporta), uso de VRAM y una tabla Active Processes con carga de motor por proceso. Los datos se sirven desde <code>/api/gpu/&lt;slot&gt;/realtime</code>.",
"toolsIntro": "La herramienta de vendor usada por GPU:",
"headerVendor": "Vendor",
"headerTool": "Herramienta",
"headerProject": "Proyecto",
"tools": [
{
"vendor": "NVIDIA",
"tool": "nvidia-smi",
"projectLabel": "developer.nvidia.com",
"projectHref": "https://developer.nvidia.com/nvidia-system-management-interface"
},
{
"vendor": "Intel iGPU",
"tool": "intel_gpu_top (igt-gpu-tools)",
"projectLabel": "gitlab.freedesktop.org",
"projectHref": "https://gitlab.freedesktop.org/drm/igt-gpu-tools"
},
{
"vendor": "AMD",
"tool": "amdgpu_top",
"projectLabel": "github.com/Umio-Yasuno/amdgpu_top",
"projectHref": "https://github.com/Umio-Yasuno/amdgpu_top"
},
{
"vendor": "Matrox / ASPEED (BMC)",
"tool": "— (solo display)",
"projectLabel": "Detectado y etiquetado como BMC; sin bloque realtime."
}
],
"nvidiaImageAlt": "Modal de monitorización de GPU para una NVIDIA Quadro P1000: vendor NVIDIA, driver nvidia cargado, clock gráfico 1.26 GHz, clock de memoria 2.50 GHz, temperatura 50 °C, todas las barras de utilización de motor al 0 %, sin procesos activos, memoria total 4096 MiB",
"nvidiaImageCaption": "NVIDIA Quadro P1000 con el driver propietario cargado — clocks, temperatura, barras de motores y procesos activos todos visibles.",
"intelImageAlt": "Modal de monitorización de GPU para una iGPU Intel UHD Graphics en driver i915, mostrando 11.31 W de consumo, 1 % de carga en motor de video y un proceso ffmpeg consumiendo 8 MB",
"intelImageCaption": "iGPU Intel con <code>i915</code> activo. La tabla Active Processes recoge un job ffmpeg usando el motor de video.",
"amdImageAlt": "Modal de monitorización de GPU para una GPU integrada AMD Lucienne en driver amdgpu, con barras de utilización de motor al 0 % y amdgpu_top listado como proceso activo",
"amdImageCaption": "iGPU AMD monitorizada a través de <code>amdgpu_top</code> — la propia herramienta aparece como proceso activo porque es el backend de polling en vivo.",
"installTitle": "Instalar el driver NVIDIA desde la modal",
"installBody": "Cuando una GPU NVIDIA está atada a <code>nouveau</code>/<code>nvidiafb</code> (sin driver propietario instalado), el bloque realtime no puede leer clocks, potencia ni carga por proceso. La modal entonces reemplaza las métricas con un botón <strong>Install NVIDIA Drivers</strong> que conecta directamente con el mismo script documentado en <link>Install NVIDIA Drivers (Host)</link>.",
"noDriverAlt": "Modal de monitorización de GPU para una NVIDIA Quadro P620 con módulos de kernel nvidiafb y nouveau cargados, un callout Extended Monitoring Not Available y un botón azul Install NVIDIA Drivers",
"noDriverCaption": "Sin driver propietario instalado todavía — la modal muestra un instalador de un solo clic.",
"promptAlt": "Diálogo de confirmación NVIDIA GPU Driver Installation listando las GPUs detectadas, contenedores LXC con passthrough NVIDIA y un par Yes/Cancel",
"promptCaption": "Resumen pre-instalación: GPUs detectadas, contenedores LXC que ya tienen passthrough NVIDIA y qué hará el script. No se toca nada hasta que confirmas.",
"successAlt": "Salida de terminal mostrando el driver NVIDIA 580.105.08 instalado correctamente y nvidia-smi reportando una Quadro P620",
"successCaption": "Instalación correcta — el <code>.run</code> de NVIDIA construido vía DKMS, el servicio de persistencia en su sitio y <code>nvidia-smi</code> reportando la GPU.",
"warningTitle": "Elige una versión de driver que tu GPU soporte de verdad",
"warningBody": "Las ramas más nuevas de driver NVIDIA dejan de dar soporte a familias de GPU antiguas (p. ej. Maxwell / Kepler). Si la instalación termina pero <code>nvidia-smi</code> reporta <em>\"No devices were found\"</em> o DKMS da error, lo más probable es que la rama elegida no cubra tu GPU — vuelve a lanzar el instalador y elige una rama más antigua (legacy 470.x para tarjetas de era Kepler, etc.). NVIDIA publica la compatibilidad por GPU en la <a>página oficial de búsqueda de drivers</a>.",
"whereGoIntro": "Por dónde seguir desde aquí:",
"whereGoItems": [
"<link1>Install NVIDIA Drivers (Host)</link1> — recorrido completo del instalador, matriz de compatibilidad de kernel, parche opcional NVENC y propagación a LXC.",
"<link2>Switch GPU Mode (VM ↔ LXC)</link2> — qué hace realmente el control inline <em>Switch Mode</em>.",
"<link3>Add GPU to VM (Passthrough)</link3> y <link4>Add GPU to LXC</link4> — asignación por primera vez de una GPU sin atar."
]
},
"coral": {
"heading": "Coral TPU / Aceleradoras de IA",
"subHeading": "(condicional)",
"intro": "Se renderiza cuando el host tiene dispositivos Google Coral u otras aceleradoras de IA conectadas. Cada dispositivo abre una modal con su tipo de conexión (M.2 / mini-PCIe / USB), ancho de enlace PCIe, vendor / product ID, kernel driver (<code>apex</code> para PCIe, <code>libedgetpu</code> para USB), módulos del kernel (<code>gasket</code> + <code>apex</code>), nodos de dispositivo (<code>/dev/apex_*</code>), estado del runtime Edge TPU, temperatura en vivo y los umbrales de aviso de hardware del firmware.",
"imageAlt": "Modal de detalle Coral Edge TPU: conexión PCIe / M.2, enlace PCIe 5.0 GT/s x1, vendor 1ac1:089a, kernel driver apex, módulos gasket y apex cargados, /dev/apex_0 presente, Edge TPU Runtime no instalado, temperatura 53.5 °C con umbrales de aviso de hardware",
"imageCaption": "Coral M.2 con los módulos de kernel del host cargados, el nodo de dispositivo arriba y los avisos de temperatura del firmware expuestos. La línea del runtime se pone verde una vez instalado el runtime Edge TPU correspondiente.",
"pathsIntro": "Existen dos rutas de instalación dependiendo del form factor:",
"pathsItems": [
"<strong>M.2 / Mini-PCIe</strong> — el host necesita los módulos de kernel <code>gasket</code> + <code>apex</code> construidos vía DKMS para que el nodo de dispositivo <code>/dev/apex_0</code> aparezca en el arranque.",
"<strong>USB Accelerator</strong> — el host solo necesita el runtime de espacio de usuario Edge TPU (<code>libedgetpu1-std</code>) desde el repositorio APT de Google."
],
"outro": "Ambas las gestiona una única entrada de ProxMenux — <installLink>Install Coral TPU on the Host</installLink> — que auto-detecta lo que tienes. El contexto y el runtime oficial viven en <a>coral.ai/docs</a>. Una vez listo el lado del host, entrega el dispositivo a un contenedor con <lxcLink>Add Coral TPU to LXC</lxcLink>."
},
"storage": {
"heading": "Storage Summary",
"intro": "Cada dispositivo de bloque que conoce el kernel, agrupado por tipo. Para cada disco obtienes el nombre del kernel (<code>sda</code>, <code>nvme0n1</code>, <code>zram0</code> …), la etiqueta de tipo (<em>SSD</em>, <em>HDD</em>, <em>NVMe SSD</em>), la cadena del modelo y la información del enlace negociado. Pulsa cualquier disco para abrir una modal de info de hardware con modelo, serial, capacidad, interfaz y velocidad de enlace actual vs máxima.",
"imageAlt": "Tarjeta Storage Summary listando once dispositivos de bloque (SSDs SATA, HDDs SATA, SSDs NVMe y zram) con cadenas de modelo y velocidades de enlace negociadas; los dos discos NVMe muestran 3.0 x4 con la velocidad actual resaltada",
"imageCaption": "Once dispositivos en este nodo. Los enlaces SATA se imprimen como <em>SATA &lt;version&gt;, &lt;Gb/s&gt; (current: ...)</em>; los discos NVMe se imprimen como <em>&lt;PCIe gen&gt; x&lt;width&gt;</em>.",
"nvmeBody": "Para los discos NVMe la línea por tarjeta muestra tanto el enlace negociado como el máximo que soporta el dispositivo. Cuando ambos no coinciden (p. ej. un SSD Gen3 x4 corriendo a <strong>3.0 x1</strong> porque está sentado en un slot del chipset cableado a un solo lane), la velocidad actual se renderiza en ámbar para que el downgrade sea visible de un vistazo — útil al diagnosticar discos inesperadamente lentos o después de que una actualización de BIOS reorganice los lanes.",
"nvmeModalAlt": "Modal de detalle de disco NVMe para nvme0n1: tipo NVMe SSD, 953.9 GB de capacidad, velocidad actual de enlace 3.0 x1 resaltada en ámbar, velocidad máxima 3.0 x4, modelo WDC CL SN720, número de serie, interfaz PCIe/NVMe",
"nvmeModalCaption": "Modal NVMe mostrando el downgrade de lanes — el disco soporta x4 pero el slot está cableado x1.",
"outro": "Los datos SMART, los self-tests, el historial y el informe PDF de disco viven una pestaña a la derecha, en <storageLink>Panel: pestaña Almacenamiento</storageLink>. Los mismos datos alimentan el script en <smartLink>SMART Disk Health & Test</smartLink> — lanzar un test long desde el script escribe el JSON que el Monitor muestra en <em>Storage → History</em>."
},
"pci": {
"heading": "PCI Devices",
"intro": "Cada dispositivo direccionable por PCI, identificado por su <strong>BDF PCI</strong> (Bus:Device.Function — p. ej. <code>03:00.0</code>) y su clase de dispositivo (<em>Storage Controller</em>, <em>USB Controller</em>, <em>Graphics Card</em>, <em>Network Controller</em>, <em>Audio Controller</em> …). Cada tarjeta muestra el fabricante, el nombre del dispositivo y el <strong>kernel driver actualmente atado</strong> — que es el campo que realmente quieres al diagnosticar passthrough, grupos IOMMU o una tarjeta que el host no esté manejando correctamente.",
"imageAlt": "Sección PCI Devices listando quince dispositivos agrupados por clase: storage controllers en ahci/nvme, USB controllers, tarjetas gráficas (una en vfio-pci, otra en el driver nativo), network controllers en igb / tg3, un audio controller junto a una GPU pasada por passthrough",
"imageCaption": "Quince dispositivos en este nodo. Fíjate en la GPU y su función de audio compañera, ambas atadas a <code>vfio-pci</code> — esa es una tarjeta preparada para passthrough a VM.",
"bdfTitle": "Leer el BDF",
"bdfBody": "<code>03:00.0</code> significa bus PCI <code>03</code>, dispositivo <code>00</code>, función <code>0</code>. Los dispositivos multifunción como las GPUs discretas suelen reclamar <code>.0</code> para la GPU y <code>.1</code> para la función de audio HDMI — ambos hay que pasarlos por passthrough juntos, por eso <link>Switch GPU Mode</link> también gestiona la limpieza de la función de audio huérfana al salir del modo VM."
},
"usb": {
"heading": "USB Devices",
"intro": "Cada dispositivo USB que enumera el host, con cadenas de fabricante / producto, versión USB, la dirección <code>bus:device</code>, el par <code>vendor:product</code> y el kernel driver. El renderer también clasifica roles comunes — <em>Communications</em> (sticks Z-Wave / Zigbee), <em>UPS</em>, almacenamiento, HID — para que veas de un vistazo cuál de tus sticks es cuál sin cruzar IDs.",
"imageAlt": "Tarjeta USB Devices listando tres dispositivos: un Z-Stick Z-Wave Aeotec, un coordinador Zigbee ConBee II y un UPS Ellipse ECO, cada uno con versión USB, dirección, vendor:product ID y driver atado",
"imageCaption": "Tres dispositivos USB — dos radios de domótica en <code>usbfs</code> y un UPS en <code>usbfs</code> (NUT le habla a través de libusb)."
},
"power": {
"heading": "Power Consumption",
"subHeading": "(condicional)",
"intro": "Se renderiza solo cuando el host expone telemetría de energía. Se exponen dos fuentes independientes cuando están disponibles:",
"items": [
"<strong>Consumo total ACPI / IPMI</strong> — watios de todo el sistema desde un sensor a nivel de placa o el BMC. Típico en placas de servidor.",
"<strong>Consumo de package CPU</strong> — leído de los contadores Intel RAPL (o equivalente AMD). Útil para separar el consumo de CPU del resto del sistema en placas consumer que no exponen una cifra total."
],
"supplyImageAlt": "Sección Power Consumption mostrando 198 W de consumo total vía interfaz ACPI, más una tarjeta Power Supplies con dos PSUs ambas reportando OK (salida de 185 W y 5 W)",
"supplyImageCaption": "Placa de servidor con un único sensor de energía ACPI y PSUs duales reportadas a través de IPMI — la segunda PSU es la redundante, en idle a 5 W.",
"cpuImageAlt": "Sección Power Consumption en una placa consumer mostrando solo CPU Power 8.7 W vía Intel RAPL",
"cpuImageCaption": "Placa consumer sin sensor de todo el sistema — la sección cae a RAPL solo-CPU."
},
"psu": {
"heading": "Power Supplies",
"subHeading": "(condicional)",
"body": "Máquinas con placa de servidor / PSU dual vía IPMI: presencia (PSU 1 / PSU 2 / …), voltaje de entrada, watios de salida, flag OK / failed. Lo primero que compruebas tras un parpadeo de luz en un nodo con PSUs redundantes."
},
"fans": {
"heading": "System Fans",
"subHeading": "(condicional)",
"body": "RPM por ventilador con un pequeño sparkline (cuando se soporta). En placas sin reporte por ventilador la sección cae a una única lectura del ventilador de chasis."
},
"ups": {
"heading": "UPS Status",
"subHeading": "(condicional)",
"body": "Se renderiza cuando hay un servidor NUT (Network UPS Tools) configurado y accesible. Muestra: estado (online / on battery / charging / low battery), porcentaje de carga de batería, estimación de runtime, porcentaje de carga, voltaje de entrada, modelo y firmware. Los mismos datos alimentan la categoría <em>Security & Certificates</em> del Monitor de salud — un UPS que pasa a batería sale inmediatamente."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerSection": "Sección de la pestaña",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"section": "Inventario estático (PCI, CPU, BIOS)",
"endpoint": "/api/hardware",
"source": "<code>lspci -vmm</code>, <code>/proc/cpuinfo</code>, <code>dmidecode</code>; cacheado durante toda la vida del proceso."
},
{
"section": "Valores de sensores en vivo",
"endpoint": "/api/hardware/live",
"source": "<code>sensors</code> (lm-sensors), temperaturas de package, RPM de ventiladores. Refrescado en cada petición."
},
{
"section": "Historial de temperatura de CPU",
"endpoint": "/api/temperature/history",
"source": "Serie temporal muestreada por el Monitor de salud cada 5 min y persistida a SQLite."
},
{
"section": "Métricas en vivo de GPU",
"endpoint": "/api/gpu/<slot>/realtime",
"source": "NVIDIA: <code>nvidia-smi --query-gpu=...</code>. Intel: <code>intel_gpu_top</code>. AMD: sysfs <code>/sys/class/drm/cardN</code>."
}
],
"codeComment1": "# Cross-check del inventario contra la vista del SO",
"codeComment2": "# Confirmar la tarjeta GPU que ve el panel"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Install NVIDIA Drivers (Host)",
"href": "/docs/hardware/nvidia-host",
"tail": " — lo que ejecuta el botón de instalación de la modal de GPU."
},
{
"label": "Switch GPU Mode (VM ↔ LXC)",
"href": "/docs/hardware/switch-gpu-mode",
"tail": " — lo que el conmutador de modo inline en cada tarjeta de GPU le hace al host."
},
{
"label": "Install Coral TPU on the Host",
"href": "/docs/hardware/install-coral-tpu-host",
"tail": " — la instalación del módulo de kernel / runtime de Coral."
},
{
"label": "SMART Disk Health & Test",
"href": "/docs/disk-manager/smart-disk-test",
"tail": " — el script detrás de los datos SMART que muestra la vista en detalle de disco de la pestaña Almacenamiento."
},
{
"label": "Panel: pestaña Almacenamiento",
"href": "/docs/monitor/dashboard/storage",
"tail": " — tabla completa de atributos SMART, historial de self-tests e informe PDF."
},
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — la categoría CPU y Temperatura que consume los mismos sensores."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tail": " — los endpoints de hardware y GPU."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — el resto de pestañas."
}
]
}
}
@@ -0,0 +1,91 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel | ProxMenux Documentation",
"description": "El panel es la UI principal de ProxMenux Monitor: nueve pestañas (Resumen del sistema, Almacenamiento, Red, VMs y LXCs, Hardware, Logs del sistema, Terminal, Seguridad, Settings) más la cabecera global con la información de estado del Monitor de salud."
},
"header": {
"title": "Panel",
"description": "El panel es la vista del día a día de ProxMenux Monitor — nueve pestañas, cada una centrada en una parte del host, más una cabecera global con la información de estado del Monitor de salud, la identidad del nodo y el control de refresco rápido.",
"section": "ProxMenux Monitor"
},
"oneHeader": {
"title": "Una cabecera, nueve pestañas",
"body": "La cabecera (logo, nombre del nodo, información de estado, uptime, refresco, conmutador de tema) permanece visible en todo momento. La pestaña activa que hay debajo cambia el área de contenido entera. El color de la información de estado refleja la peor categoría del <link>Monitor de salud</link> — es el mismo dato visto desde el panel."
},
"tabs": {
"heading": "Las nueve pestañas",
"intro": "Cada pestaña tiene su propia página dedicada. Las páginas se añaden de forma incremental a medida que se completa la documentación; abajo está la lista completa con lo que cubre cada una.",
"headerTab": "Pestaña",
"headerOwns": "De qué se encarga",
"rows": [
{
"name": "Resumen del sistema",
"linksTo": "/docs/monitor/dashboard/system-overview",
"owns": "Widgets de CPU / memoria / temperatura, contador de VMs y LXCs activos, gráficas de métricas históricas, resúmenes de almacenamiento y red. Pestaña por defecto al entrar."
},
{
"name": "Almacenamiento",
"owns": "Pools de Proxmox, discos físicos, datos SMART, estado de ZFS, desgaste y vida útil, historial de observaciones."
},
{
"name": "Red",
"owns": "Cada interfaz (física / bond / bridge / OVS), IP/MAC, gráficas RX/TX, RRD histórica por interfaz."
},
{
"name": "VMs y LXCs",
"owns": "Inventario de guests, vista en detalle de config / métricas / logs, acciones start / stop / reboot / shutdown."
},
{
"name": "Hardware",
"owns": "Modelo y topología de CPU, distribución de memoria, topología PCIe, GPUs con monitorización en tiempo real por slot."
},
{
"name": "Logs del sistema",
"owns": "<code>journalctl</code> en vivo con filtros, historial de tareas de Proxmox, log de notificaciones, paquetes de logs descargables."
},
{
"name": "Terminal",
"owns": "Shell en el navegador al host o a cualquier VM/CT, sobre <code>xterm.js</code> y WebSockets."
},
{
"name": "Seguridad",
"owns": "Configuración de autenticación, contraseña / 2FA / tokens API, log de auditoría, panel opcional de Fail2Ban, despliegue de Secure Gateway."
},
{
"name": "Settings",
"owns": "Canales de notificación, proveedor de IA, duraciones de supresión, branding, flags avanzados."
}
]
},
"headerAnatomy": {
"heading": "Anatomía de la cabecera",
"items": [
"<strong>Logo de ProxMenux.</strong> El logo cambia a la variante \"actualización disponible\" cuando se detecta una nueva release del Monitor.",
"<strong>Identidad del nodo</strong> — el nombre del nodo Proxmox resuelto desde <code>pvesh get /nodes</code>, con fallback a <code>hostname</code>.",
"<strong>Información del estado de salud</strong> — Healthy (verde), Warning (amarillo), Critical (rojo). Pulsa encima para abrir la modal del Monitor de salud. Aparece una insignia azul extra de <em>info</em> cuando hay items descartados que siguen dentro de su ventana de supresión.",
"<strong>Uptime</strong> — tiempo desde el último arranque del host, formateado de forma legible.",
"<strong>Botón de refresco</strong> — relanza todas las llamadas API en vivo sin recargar la página entera.",
"<strong>Conmutador de tema</strong> — claro / oscuro / sistema. Persiste en <code>localStorage</code>."
]
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Pestaña Resumen del sistema",
"href": "/docs/monitor/dashboard/system-overview",
"tail": " — la pestaña por defecto, documentada al completo."
},
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — la modal detrás de la información de estado, vista en profundidad de las diez categorías."
},
{
"label": "Arquitectura",
"href": "/docs/monitor/architecture",
"tail": " — cómo habla el panel con el backend Flask."
}
]
}
}
@@ -0,0 +1,225 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Red | ProxMenux Documentation",
"description": "La pestaña Red inventaría cada interfaz del host: NICs físicas, bridges, bonds, VLANs y las interfaces virtuales de VM/LXC. La vista en detalle por interfaz muestra IP / MAC / estado / miembros del bond / tráfico desde el arranque y una gráfica RRD histórica."
},
"header": {
"title": "Panel: pestaña Red",
"description": "Cada interfaz que reporta el kernel — NICs físicas, bridges, bonds, VLANs y puertos virtuales de VM/LXC — agrupadas en tres tarjetas. Cada fila es pulsable y abre una vista en detalle con direccionamiento, contadores de tráfico y datos RRD históricos.",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "En vivo + histórico, ambos incluidos",
"body": "El estado en vivo viene de <code>psutil.net_if_stats()</code> y <code>ip</code>; el ancho de banda histórico del almacén RRD de Proxmox vía <code>/api/network/&lt;interface&gt;/metrics</code>. La página refresca cada ~5 segundos los contadores en vivo y obtiene datos RRD frescos bajo demanda para la gráfica."
},
"topRow": {
"heading": "Fila superior: cuatro tarjetas de estadísticas",
"headerCard": "Tarjeta",
"headerWhat": "Qué muestra",
"rows": [
{
"card": "Network Traffic",
"what": "Tasa agregada RX / TX a lo largo de todas las interfaces, formateada en la unidad correcta (bps / Kbps / Mbps / Gbps)."
},
{
"card": "Active Interfaces",
"what": "Dos contadores: <em>Physical X / Y</em> y <em>Bridges X / Y</em> (activas sobre total). El primer contador que miras cuando algo deja de funcionar."
},
{
"card": "Network Status",
"what": "Veredicto rápido — Healthy / Warning / Critical en función del estado del enlace, alcanzabilidad del gateway e integridad del bridge. Refleja la categoría <em>Network Interfaces</em> del Monitor de salud."
},
{
"card": "Network Latency",
"what": "Round-trip time al gateway con un sparkline. Pulsar la tarjeta abre la <strong>modal Network Latency</strong> documentada más abajo — vista histórica + test de ping bajo demanda contra gateway / Cloudflare / Google con un informe PDF descargable."
}
]
},
"groups": {
"heading": "Tres grupos de interfaces",
"intro": "Bajo la fila superior, tres tarjetas dividen el inventario por rol. Cada tarjeta tiene su propia insignia de recuento de activas en la cabecera. El <strong>tipo</strong> de interfaz se identifica de un vistazo mediante una insignia coloreada en cada fila:",
"badges": [
"Azul <strong>Physical</strong> — NIC real.",
"Verde <strong>Bridge</strong> — bridge Linux o bridge OVS (<code>vmbr*</code>).",
"Morado <strong>Bond</strong> — agregador bond / LACP / active-backup.",
"Cian <strong>VLAN</strong> — sub-interfaz VLAN (<code>vmbr0.10</code>, <code>eno1.42</code>, …)."
],
"clickable": "<strong>Cada fila es pulsable</strong> — física, virtual, bridge o bond — y abre la vista en detalle por interfaz descrita más abajo (info básica, IPs, contadores de tráfico, gráfica RX/TX histórica del almacén RRD de Proxmox).",
"physicalTitle": "Physical Interfaces",
"physicalBody": "Cada NIC que el kernel ve como un dispositivo real — <code>eno1</code>, <code>enp4s0</code>, <code>eth0</code>, <code>wlp3s0</code>, etc. Una fila por dispositivo con la insignia azul <strong>Physical</strong> y el estado del enlace. Los <em>miembros del bond</em> (NICs esclavizadas a un bond) también se muestran aquí, con una pista que apunta al bond padre.",
"bridgeTitle": "Bridge Interfaces",
"bridgeBody": "Bridges Linux (<code>vmbr0</code>, <code>vmbr1</code>, …) y los bridges OVS que gestiona Proxmox. Cada fila muestra la insignia verde <strong>Bridge</strong>, la interfaz física subyacente (cuando es un bridge de un solo puerto) y el estado del bridge. Los bonds visibles en esta capa reciben la insignia morada <strong>Bond</strong>; las sub-interfaces VLAN reciben la insignia cian <strong>VLAN</strong>.",
"vmTitle": "VM / LXC Interfaces",
"vmBody": "Las interfaces <code>tap*</code> y <code>veth*</code> creadas cuando arrancan los guests — una por NIC virtual. La cabecera de la tarjeta muestra <em>X / Y Active</em>; las filas enlazan con el VM/CT al que pertenecen, así que puedes saltar directamente al guest en la pestaña VMs y LXCs. Las entradas inactivas quedan por un instante después de que un guest se pare; envejecen y se eliminan en el siguiente ciclo de refresco."
},
"drillIn": {
"heading": "Vista en detalle por interfaz",
"intro": "Pulsar cualquier fila abre una modal con cinco bloques:",
"headerBlock": "Bloque",
"headerContents": "Contenido",
"rows": [
{
"block": "Basic Information",
"contents": "Nombre de la interfaz, tipo (física / bridge / bond / VLAN / vm), dirección MAC, estado (up / down), MTU y la interfaz física subyacente para los tipos no físicos."
},
{
"block": "Bond Members",
"contents": "Solo para bonds. Lista cada NIC esclavizada con el flag active / failed, el modo del bond (active-backup / 802.3ad / balance-alb / …) y la interfaz primaria cuando está configurada."
},
{
"block": "IP Addresses",
"contents": "Cada dirección IPv4 / IPv6 con su longitud de prefijo. Las direcciones link-local autoconfiguradas se listan pero salen atenuadas."
},
{
"block": "Gráfica histórica",
"contents": "Ancho de banda RX / TX sobre el timeframe seleccionado (1 hora / 24 horas / 7 días / 30 días / 1 año), traído de <code>/api/network/&lt;interface&gt;/metrics</code> (RRD de Proxmox)."
},
{
"block": "Tráfico desde el último arranque",
"contents": "Bytes y paquetes totales RX / TX desde el último arranque del host, más contadores de errores y descartes."
}
],
"inactiveTitle": "Las interfaces inactivas siguen abriendo la vista en detalle",
"inactiveBody": "Para una interfaz <em>down</em>, la modal renderiza un pequeño banner \"Interface Inactive\" y omite los contadores en vivo. La configuración (direcciones, miembros del bond) y los datos históricos siguen mostrándose — útil al diagnosticar por qué falló algo y cuándo."
},
"latency": {
"heading": "Modal Network Latency",
"intro": "Pulsar la tarjeta <em>Network Latency</em> de la fila superior abre una modal dedicada. Tiene dos modos (histórico y test bajo demanda), tres opciones de destino y un informe PDF descargable.",
"targetsTitle": "Destinos",
"targetsIntro": "Un desplegable de destino en lo alto de la modal selecciona contra qué se hace ping:",
"targets": [
"<strong>Gateway</strong> — tu router de la LAN. Solo testea el tramo de red local; útil cuando sospechas de un problema de switch / cableado y quieres descartar la WAN.",
"<strong>Cloudflare (1.1.1.1)</strong> — resolutor DNS público, red anycast. Testea el tramo WAN.",
"<strong>Google (8.8.8.8)</strong> — destino público alternativo, útil como verificación sanity o cuando Cloudflare está degradado regionalmente."
],
"mode1Title": "Modo 1 — Vista histórica",
"mode1Alt": "Modal Network Latency en modo histórico — destino Gateway con un timeframe de 1 hora y las muestras pasadas ploteadas",
"mode1Caption": "Vista histórica — destino Gateway sobre la última hora, alimentada desde la base de datos de historial de latencia que el hilo recolector de temperatura/latencia escribe cada 60 segundos.",
"mode1Body1": "El modo por defecto al abrir la modal. Un segundo desplegable elige el timeframe (<em>1 Hour / 24 Hours / 7 Days / 30 Days / 1 Year</em>); la resolución de los datos baja con la ventana para que la gráfica se mantenga legible. Las estadísticas titulares — Current / Min / Avg / Max — se renderizan encima de la gráfica, con una pastilla de estado (Excellent / Good / Fair / Poor) que refleja el valor actual frente a los umbrales de abajo.",
"mode1Body2": "Fuente: las mismas muestras de latencia que usa el Monitor de salud para detectar ralentizaciones persistentes de red — muestreadas cada 60 segundos contra el gateway por el hilo en background <code>_temperature_collector_loop</code>, escritas a un historial SQLite local.",
"mode2Title": "Modo 2 — Test en tiempo real",
"mode2Alt": "Modal Network Latency ejecutando un test de ping en tiempo real contra Cloudflare — barra de progreso al 50%, muestras en vivo acumulándose en la gráfica",
"mode2Caption": "Test en tiempo real contra Cloudflare — ejecución de 2 minutos con una lectura cada 5 segundos, muestras ploteadas según llegan. Pulsa <em>Stop</em> para terminar antes; <em>Test Again</em> añade más muestras al mismo dataset.",
"mode2Intro": "Cambiar el destino a Cloudflare o Google arranca un test de ping bajo demanda. Comportamiento:",
"mode2Items": [
"<strong>Duración</strong> — 2 minutos por ejecución, con barra de progreso y un contador de segundos restantes.",
"<strong>Cadencia</strong> — una lectura cada 5 segundos (24 lecturas por ejecución).",
"<strong>Método</strong> — ICMP Echo Request (<code>ping</code>), 3 pings consecutivos por muestra, latencia promediada.",
"<strong>Stop</strong> — termina el test inmediatamente; los datos parciales se preservan.",
"<strong>Test Again</strong> — añade nuevas muestras al dataset existente en lugar de empezar de cero, así puedes construir un registro más largo a lo largo de varias ejecuciones.",
"<strong>Pastilla de estado en vivo</strong> — se reevalúa tras cada muestra con los mismos umbrales Excellent / Good / Fair / Poor."
],
"thresholdsTitle": "Umbrales de rendimiento",
"headerStatus": "Estado",
"headerRange": "Rango",
"headerImpact": "Impacto práctico",
"thresholdRows": [
{
"status": "Excellent",
"range": "< 50 ms",
"impact": "Óptimo para apps en tiempo real, gaming y videollamadas."
},
{
"status": "Good",
"range": "50 100 ms",
"impact": "Aceptable para la mayoría de aplicaciones con impacto mínimo."
},
{
"status": "Fair",
"range": "100 200 ms",
"impact": "Retardo perceptible. Puede afectar a VoIP y apps interactivas."
},
{
"status": "Poor",
"range": "> 200 ms",
"impact": "Latencia significativa. Se recomienda investigar."
}
],
"reportTitle": "Network Latency Report (PDF)",
"reportIntro": "Ambos modos tienen un botón <strong>Report</strong> junto al selector de destino. Pulsarlo genera un PDF con todo lo que enviarías a tu ISP si quisieras argumentar un mal servicio.",
"reportPreviewAlt": "Primera página del PDF Network Latency Report — Executive Summary con el gauge, estadísticas de latencia, la gráfica de latencia y la guía de umbrales",
"reportPreviewCaption": "Primera página del Network Latency Report — Executive Summary con el dial del gauge y las estadísticas titulares, la gráfica de latencia por segundo y la guía de umbrales. De la página 2 en adelante está la tabla por muestra y la metodología.",
"downloadLabel": "Descargar informe de ejemplo Network Latency (PDF)",
"sectionsIntro": "El informe tiene seis secciones:",
"sections": [
"<strong>Executive Summary</strong> — dial del gauge (0300+ ms con zonas verde / amarilla / roja), el veredicto de estado (EXCELLENT / GOOD / FAIR / POOR), el destino / modo / recuento de muestras y un resumen de una línea sobre packet loss.",
"<strong>Latency Statistics</strong> — Current / Min / Avg / Max como cuatro tiles grandes, más Sample Count, Packet Loss (avg) y Test Period.",
"<strong>Latency Graph</strong> — gráfica de área de cada muestra a lo largo de la ventana del test con una rejilla en el eje y de min/avg/max.",
"<strong>Performance Thresholds</strong> — la misma escala de cuatro niveles documentada arriba, con un punto coloreado por nivel.",
"<strong>Detailed Test Results</strong> — tabla numerada con timestamp, latencia, packet loss y estado para cada muestra. Útil para detectar micro-ráfagas que esconden los promedios titulares.",
"<strong>Methodology</strong> — método del test (ICMP Echo Request), muestras por test (3 pings consecutivos), nombre del destino, IP del destino y un párrafo final \"Performance Assessment\" derivado del veredicto."
],
"useCaseTitle": "Caso de uso: reclamaciones a tu ISP",
"useCaseBody": "Ejecuta el test en tiempo real contra Cloudflare durante 2 minutos en un momento de lentitud percibida, después pulsa <em>Test Again</em> unas cuantas veces para extender el dataset y finalmente <em>Report</em>. El PDF lleva la tabla completa por muestra más el bloque de metodología — los ISPs suelen aceptar esto como evidencia, sobre todo si está correlacionado con timestamps de una reclamación aparte."
},
"excluding": {
"heading": "Excluir interfaces ruidosas",
"body1": "Igual que los almacenamientos, las interfaces individuales se pueden excluir de la monitorización de salud — útil para bridges deshabilitados a propósito, interfaces de test o NICs físicamente retiradas pero que siguen en la configuración. El flag se guarda en la tabla <code>excluded_interfaces</code> y lo respeta el ciclo del Monitor de salud: sin warnings, sin notificaciones, sin contribución a la pastilla de estado de la cabecera.",
"body2": "Desde el menú contextual de la fila, elige <em>Exclude from monitoring</em>. La interfaz sigue visible en el panel con una insignia morada <strong>excluded</strong>, y puedes reactivar la monitorización desde el mismo menú."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerSection": "Sección de la pestaña",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"section": "Inventario de interfaces",
"endpoint": "/api/network",
"source": "<code>ip -j addr</code> + <code>ip -j link</code> + introspección de bond / bridge."
},
{
"section": "Tarjetas resumen",
"endpoint": "/api/network/summary",
"source": "Agregación sobre el inventario más recuentos up/down por interfaz."
},
{
"section": "Serie temporal RX/TX por interfaz",
"endpoint": "/api/network/<iface>/metrics",
"source": "<code>/proc/net/dev</code> muestreado por el Monitor de salud con cálculo de byte-rate."
},
{
"section": "Latencia: actual",
"endpoint": "/api/network/latency/current",
"source": "Una ráfaga corta de <code>ping</code> contra el gateway / destino configurado."
},
{
"section": "Latencia: histórica",
"endpoint": "/api/network/latency/history",
"source": "Muestras persistidas — cada 5 min por el ciclo del Monitor de salud."
}
],
"codeComment1": "# Cross-check del estado de interfaz que ve el panel",
"codeComment2": "# Verificar una sonda de latencia actual de extremo a extremo"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — la categoría Red y los umbrales del historial de latencia."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tail": " — los endpoints de red y latencia."
},
{
"label": "Integraciones",
"href": "/docs/monitor/integrations",
"tail": " — el scrape de Prometheus expone las mismas métricas de red."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — el resto de pestañas."
},
{
"label": "ProxMenux → Red",
"href": "/docs/network",
"tail": " — la cara de las acciones: análisis de bridges, nombres persistentes de interfaz, backup y reinicio, iperf3."
}
]
}
}
@@ -0,0 +1,246 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Seguridad | ProxMenux Documentation",
"description": "La pestaña Seguridad agrupa cada control relacionado con protección en dos columnas: ProxMenux Monitor (Autenticación, SSL/HTTPS, tokens API, Secure Gateway) y Proxmox VE (Firewall, Fail2Ban, auditoría Lynis). Asistente paso a paso de Secure Gateway, recorrido de auditoría Lynis, instalación de Fail2Ban y ajuste de reglas."
},
"header": {
"title": "Panel: pestaña Seguridad",
"description": "Cada control de seguridad del panel, agrupado en dos bloques claramente etiquetados: configuración del propio Monitor (auth, SSL, tokens, Secure Gateway) y configuración del host Proxmox al que vigila (firewall, Fail2Ban, Lynis).",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "Dos ámbitos, una pestaña",
"body": "La pestaña Seguridad está dividida en dos secciones claramente separadas: <strong>ProxMenux Monitor</strong> (settings para el propio panel) y <strong>Proxmox VE</strong> (settings para el host de debajo). Las tarjetas se renderizan de forma condicional — Fail2Ban y Lynis solo aparecen una vez instalados."
},
"monitor": {
"heading": "ProxMenux Monitor",
"intro": "Cuatro tarjetas controlan cómo se alcanza y autentica el propio panel."
},
"auth": {
"heading": "Autenticación",
"imageAlt": "Tarjeta Authentication mostrando estado Enabled, Logout, Change Password, info de Two-Factor Authentication, botones Enable Two-Factor Authentication y Disable Authentication",
"imageCaption": "Tarjeta Authentication con auth activa — insignia de estado, Change Password, Enable 2FA y la acción (destructiva) Disable Authentication.",
"intro": "La tarjeta te permite gestionar el login del propio panel. El flujo completo de primer arranque, política de contraseñas, pantallas de alta de TOTP y recuperación de authenticator perdido están documentados en <link>Acceso y autenticación</link> — esta tarjeta es la superficie del día a día para esos settings:",
"items": [
"<strong>Authentication Status</strong> — insignia mostrando <em>Enabled</em> / <em>Disabled</em> / <em>Declined</em>.",
"<strong>Change Password</strong> — contraseña actual + nueva contraseña + confirmación.",
"<strong>Enable / Disable Two-Factor Authentication</strong> — abre el diálogo de alta con QR al activar, pide la contraseña actual al desactivar.",
"<strong>Disable Authentication</strong> — acción destructiva que vuelve a mostrar el diálogo de primer arranque <em>Protect your dashboard?</em> en la siguiente visita."
]
},
"ssl": {
"heading": "SSL / HTTPS",
"imageAlt": "Tarjeta SSL / HTTPS mostrando estado HTTP No SSL, certificado del host Proxmox detectado con Subject, Issuer, Expires, botón Use Proxmox Certificate y opción Use Custom Certificate",
"imageCaption": "Tarjeta SSL / HTTPS con HTTPS apagado. El Monitor detecta el certificado ya instalado en el host Proxmox y lo ofrece como opción de un solo clic, con un fallback a <em>Use Custom Certificate</em> si tienes tus propios archivos en otro sitio.",
"intro": "Sirve el panel sobre HTTPS sin ningún reverse proxy por delante. La tarjeta auto-detecta el certificado que usa el propio Proxmox (bajo <code>/etc/pve/local/</code>) y muestra el subject, issuer y expiración para que lo puedas verificar antes de activar. Dos rutas para activar HTTPS:",
"items": [
"<strong>Use Proxmox Certificate</strong> — un clic. El Monitor reutiliza el certificado instalado en el host. Buena opción para usuarios que ya tienen su PVE corriendo en el mismo nombre DNS que el panel.",
"<strong>Use Custom Certificate</strong> — pega rutas absolutas a tus propios archivos <code>.pem</code> de certificado y <code>.key</code> de clave privada. Las rutas se validan antes de reiniciar el servicio; si la carga falla, el panel cae a HTTP automáticamente (sin estado roto)."
],
"enabledAlt": "Tarjeta SSL/HTTPS con estado HTTPS Enabled, Active Certificate mostrando rutas pve-ssl.pem y pve-ssl.key, y un botón Disable HTTPS",
"enabledCaption": "HTTPS activo — la tarjeta expone el certificado actualmente en uso, las rutas de archivos y una acción <em>Disable HTTPS</em> que vuelve a HTTP en el mismo puerto.",
"acmeTitle": "ACME / Let's Encrypt vía Proxmox",
"acmeBody": "Si tu nodo Proxmox ya tiene Let's Encrypt configurado en <em>Datacenter → Certificates → ACME</em>, ese es el certificado que el host sirve a los navegadores — y eso es lo que el panel reutiliza al pulsar <em>Use Proxmox Certificate</em>. No necesitas fontanería ACME separada para el Monitor.",
"walkthroughLink": "Para un recorrido paso a paso — incluyendo cómo el Monitor auto-detecta el certificado subido por ACME, qué se escribe a disco y cómo caer a un par <code>.pem</code> / <code>.key</code> custom — mira <link>HTTPS para ProxMenux Monitor</link>."
},
"apiTokens": {
"heading": "Tokens de acceso API",
"emptyAlt": "Tarjeta API Access Tokens en estado vacío con caja info About API Tokens y botón Generate New API Token",
"emptyCaption": "Tarjeta API Access Tokens en una instalación recién hecha — la caja <em>About API Tokens</em> resume lifetime, uso y cómo embeber el token en cabeceras <code>Authorization: Bearer</code>.",
"intro": "Tokens de vida larga (1 año) para integraciones desatendidas — widgets Homepage, sensores REST de Home Assistant, scrapers de Grafana, flujos n8n, scripts propios. La tarjeta te lleva por tres estados: vacío → formulario → generado.",
"generateBody": "<strong>Generar un token.</strong> Pulsa <em>Generate New API Token</em>. El formulario pide un <em>Token Name</em> descriptivo (ayuda a identificarlo después en la lista activa) y tu <em>contraseña</em> como confirmación de segundo factor. Si 2FA está activo, el formulario pide adicionalmente el código TOTP actual.",
"generateAlt": "Formulario API Access Tokens generate con input Token Name, input Password, botones Generate Token y Cancel",
"generateCaption": "El formulario Generate API Token — rellena un nombre y confirma con tu contraseña (y TOTP si 2FA está activo).",
"saveBody": "<strong>Guarda el token inmediatamente.</strong> La cadena completa del token se muestra <strong>solo una vez</strong> tras generarlo. La tarjeta lo destaca con un aviso ámbar y un botón de copia. No hay forma de recuperarlo después — solo verás el prefix en la lista Active Tokens.",
"generatedAlt": "Token API generado correctamente con token enmascarado, botón de copia, instrucciones para cabecera Authorization Bearer y lista Active Tokens con prefix",
"generatedCaption": "Token generado — el valor se muestra una vez con un botón de copia y el snippet exacto <code>Authorization: Bearer</code>. Debajo, la lista Active Tokens mantiene nombre + prefix + fecha de creación para que puedas revocar tokens individuales después.",
"outro": "La tarjeta muestra cada token activo con un botón <em>Revoke</em> por fila. Revocar invalida el token inmediatamente; cualquier integración que lo use deja de funcionar desde ese momento. Los cookbooks para Homepage, Home Assistant, n8n y Prometheus están en <link>Integraciones</link>."
},
"gateway": {
"heading": "Secure Gateway",
"cardAlt": "Tarjeta Secure Gateway con botón Deploy Secure Gateway antes de que se haya desplegado ningún gateway",
"cardCaption": "Tarjeta Secure Gateway en setup recién hecho — un botón arranca el asistente.",
"intro": "Alcanza el panel, la UI web de Proxmox y cualquier guest desde cualquier sitio en tu tailnet de <a>Tailscale</a>, sin exponer ningún puerto a la internet pública. El Monitor despliega un contenedor LXC Alpine en el host corriendo <code>tailscaled</code> como subnet router; una vez aprobado en la consola de admin de Tailscale, tus dispositivos remotos alcanzan la IP de LAN del host desde cualquier sitio.",
"wizardTitle": "Asistente paso a paso",
"wizardIntro": "Antes de pulsar <em>Deploy Secure Gateway</em>, genera una auth key en tu consola de admin de Tailscale — el asistente la pedirá en el paso 2.",
"step0Title": "0. Generar la auth key de Tailscale",
"step0Body": "Entra en <a>login.tailscale.com/admin/settings/keys</a> y pulsa <em>Generate auth key…</em>. Elige una key <em>pre-autenticada</em> (para que el gateway no necesite un login interactivo de Tailscale) y copia el valor — se muestra solo una vez.",
"step0Alt": "Consola de admin de Tailscale, página Settings Keys con el botón Generate auth key resaltado",
"step0Caption": "Consola de admin de Tailscale — <em>Settings → Keys → Generate auth key…</em>. Usa una cuenta gratuita de Tailscale si aún no tienes (link dentro del asistente).",
"step1Title": "1. Abrir el asistente",
"step1Body": "De vuelta en la pestaña Seguridad, pulsa <em>Deploy Secure Gateway</em>. El primer paso es una intro con lo que vas a obtener y lo que necesitas.",
"step1Alt": "Paso intro del asistente Secure Gateway Setup explicando qué provee el gateway: acceso VPN, sin port forwarding, cifrado de extremo a extremo",
"step1Caption": "Paso 1 — resumen de lo que provee el Secure Gateway y recordatorio de que necesitarás una cuenta gratuita de Tailscale.",
"step2Title": "2. Tailscale Authentication",
"step2Body": "Pega la auth key del paso 0 y elige un hostname (así es como aparecerá el gateway en la consola de admin de Tailscale — típicamente <code>proxmox-gateway</code> o el nombre de tu nodo).",
"step2Alt": "Paso del asistente Secure Gateway pidiendo Tailscale Auth Key y Device Hostname con link para generar la key",
"step2Caption": "Paso 2 — pega la pre-auth key y elige el hostname del dispositivo. El link debajo del campo abre la página de Tailscale del paso 0 si te lo saltaste.",
"step3Title": "3. Access Scope",
"step3Intro": "Elige a qué puede llegar tu tailnet a través del gateway:",
"step3Items": [
"<strong>Proxmox Only</strong> — solo la UI de Proxmox y el Monitor. La menor superficie de ataque.",
"<strong>Full Local Network</strong> — la subred LAN entera (auto-detectada desde la interfaz primaria del host). Te permite alcanzar NAS, impresoras, VMs y cualquier otro dispositivo de la LAN.",
"<strong>Custom Subnets</strong> — lista CIDRs específicos. Para setups multi-VLAN donde quieres exponer algunos segmentos pero no otros."
],
"step3Alt": "Paso Access Scope del asistente Secure Gateway con tres opciones: Proxmox Only, Full Local Network, Custom Subnets",
"step3Caption": "Paso 3 — elige el access scope. <em>Full Local Network</em> se autorrellena con la subred LAN detectada.",
"step4Title": "4. Advanced Options (opcional)",
"step4Intro": "Dos toggles opcionales. Ambos <strong>off por defecto</strong>:",
"step4Items": [
"<strong>Exit Node</strong> — cuando se activa y se selecciona desde un dispositivo remoto, todo el tráfico de internet de ese dispositivo sale por la WAN del host Proxmox. Útil para escenarios de viaje donde quieres que el tráfico de tu móvil parezca de casa.",
"<strong>Accept Routes</strong> — deja que este gateway alcance redes anunciadas por <em>otros</em> subnet routers del tailnet (para setups multi-sitio)."
],
"step4Alt": "Paso Advanced Options del asistente Secure Gateway con checkboxes Exit Node y Accept Routes",
"step4Caption": "Paso 4 — Exit Node y Accept Routes. Salta ambos si lo único que quieres es acceso al panel desde tu móvil o portátil.",
"step5Title": "5. Review & Deploy",
"step5Body": "Resumen final antes de que arranque el deploy. El asistente te recuerda que aún queda un paso manual en el admin de Tailscale tras desplegar: <strong>aprobar la subnet route</strong>.",
"step5Alt": "Paso Review and Deploy del asistente Secure Gateway con Configuration Summary mostrando hostname, access mode, networks, exit node, accept routes y un botón Deploy Gateway",
"step5Caption": "Paso 5 — revisa la configuración y despliega. El aviso azul al pie señala la aprobación de ruta pendiente.",
"approvalTitle": "Un último paso manual en el admin de Tailscale",
"approvalBody": "Tras desplegar, vuelve a <a>login.tailscale.com/admin/machines</a> y aprueba la subnet route que el gateway está anunciando. Hasta que lo hagas, los dispositivos remotos de tu tailnet no podrán alcanzar realmente IPs de LAN a través del gateway. Tailscale marca las rutas pendientes con un aviso amarillo en la fila del dispositivo — pulsa <em>Edit route settings</em> y marca la casilla de la ruta."
},
"pve": {
"heading": "Proxmox VE",
"intro": "Las protecciones del propio host — firewall, prevención de intrusiones y auditoría de seguridad. Los dos últimos solo se renderizan cuando sus herramientas respectivas están instaladas."
},
"firewall": {
"heading": "Proxmox Firewall",
"imageAlt": "Tarjeta Proxmox Firewall mostrando estado de Cluster Firewall y Host Firewall, Quick Access Rules para ProxMenux Monitor y Proxmox Web UI, contadores Rules Overview y una lista de Firewall Rules con botón Add Rule",
"imageCaption": "Tarjeta Proxmox Firewall — toggles enable / disable a nivel cluster y host, puertos comunes como <em>Quick Access Rules</em>, totales en <em>Rules Overview</em> y la lista completa de reglas con <em>+ Add Rule</em>.",
"intro": "La tarjeta expone el firewall integrado de Proxmox VE (que es independiente de cualquier <code>iptables</code> / <code>nftables</code> a nivel host que puedas correr en paralelo). Tres bloques:",
"items": [
"<strong>Cluster Firewall + Host Firewall</strong> — toggles globales. El cluster firewall debe estar activo para que cualquier regla a nivel host surta efecto; la tarjeta señala esta dependencia inline.",
"<strong>Quick Access Rules</strong> — filas predefinidas para puertos que importan al propio ProxMenux: <code>8008/TCP</code> (Monitor), <code>8006/TCP</code> (UI web de Proxmox). Cada fila muestra el estado actual allow / deny / unprotected. La UI web de Proxmox se permite vía el macro de firewall <em>integrado</em> de Proxmox y no se puede eliminar por accidente.",
"<strong>Rules Overview</strong> — contadores de reglas totales, reglas accept, reglas drop / reject y puertos distintos protegidos. Los números se leen de <code>/etc/pve/firewall/cluster.fw</code> y <code>/etc/pve/nodes/&lt;node&gt;/host.fw</code>.",
"<strong>Firewall Rules</strong> — lista completa con action / protocolo / puerto / source / level. <em>+ Add Rule</em> abre un editor inline; el icono de papelera en cada fila elimina la regla. Las ediciones escriben a los mismos archivos que usa Proxmox, así que los cambios también aparecen en la UI de Proxmox (Datacenter / Node → Firewall)."
]
},
"fail2ban": {
"heading": "Fail2Ban",
"subHeading": "(condicional)",
"whatIs": "<strong>Qué es.</strong> Fail2Ban es un daemon open-source de prevención de intrusiones que vigila archivos de log buscando intentos repetidos fallidos de login y banea la IP ofensora a nivel de firewall. Es la respuesta de facto a los escáneres de fuerza bruta que pegan SSH y formularios de login web 24/7. ProxMenux lo conecta a tres jails por defecto: SSH, el login de la UI web de Proxmox (puerto 8006) y el login del ProxMenux Monitor (puerto 8008).",
"notBundled": "Fail2Ban <strong>no viene de fábrica</strong>. La tarjeta detecta si está instalado y se adapta: cuando falta ofrece una instalación de un clic; una vez instalado muestra estado en vivo de jails, IPs baneadas y te deja ajustar retries / ban time por jail.",
"notInstalledAlt": "Tarjeta Fail2Ban mostrando estado Not Installed con explicación de lo que configuraría: SSH, UI web de Proxmox y protección de ProxMenux Monitor con backend nftables, más un botón Install and Configure Fail2Ban",
"notInstalledCaption": "Tarjeta Fail2Ban antes de instalar — la caja azul previsualiza lo que configuraría la instalación.",
"clickBody": "Pulsa <em>Install and Configure Fail2Ban</em> y obtienes una modal de confirmación listando cada cambio que hará el script en el host:",
"confirmAlt": "Modal de confirmación Install Fail2Ban listando protección SSH modo agresivo, protección de interfaz web Proxmox puerto 8006, protección ProxMenux Monitor puerto 8008, backend nftables auto-detectado, ajuste del log level de journald y hardening de SSH MaxAuthTries",
"confirmCaption": "Confirmación de instalación — lista explícita de jails, ajustes al log level de journald (para que el jail de auth pueda leer eventos SSH) y un efecto colateral de hardening SSH (<code>MaxAuthTries=3</code>).",
"confirmIntro": "La confirmación dispara un panel de instalación en streaming (apt + config de jails + tests). La misma fontanería que el instalador CLI de ProxMenux.",
"progressAlt": "Panel Fail2Ban Installation mostrando log de instalación en vivo: instalación del paquete, journald MaxLevelStore ajustado para logging de auth, jails configurados, backend nftables detectado, hardening MaxAuthTries, test de comunicación fail2ban-client, mensaje de finalización",
"progressCaption": "Instalación en curso — cada paso se loguea en el panel. Connection-closed al final marca el fin de la sesión de streaming.",
"afterInstall": "Tras instalar la tarjeta pasa a la vista de estado en vivo: jails configurados, contador de IPs baneadas, eventos recientes de ban. Las pestañas grandes separan <em>Jails & Banned IPs</em> de <em>Recent Activity</em> (las últimas N entradas del log de Fail2Ban).",
"activeAlt": "Tarjeta Fail2Ban tras instalar con estado Active, tres jails configurados (proxmenux, proxmox, sshd), contador Banned IPs, Total Bans, Failed Attempts, y filas por jail con retries, ban time, window e icono de rueda dentada",
"activeCaption": "Fail2Ban activo — los tres jails por defecto (<code>proxmenux</code>, <code>proxmox</code>, <code>sshd</code>) con sus settings de retries / ban time / window.",
"tuneBody": "<strong>Ajustar reglas del jail.</strong> Pulsa el icono de rueda dentada en cualquier fila de jail para ajustar <em>Max Retries</em>, <em>Ban Time</em> (usa ban permanente si quieres que los ofensores queden bloqueados hasta que tú los desbanees manualmente) y <em>Find Time</em> (la ventana deslizante para contar retries). Los valores comunes están documentados dentro del formulario.",
"configAlt": "Formulario Configure jail sshd con Max Retries, Ban Time en segundos con opción Permanent Ban, Find Time, recordatorio de valores comunes y botón Save Configuration",
"configCaption": "Editando el jail sshd — elige un <em>Max Retries</em> más estricto para SSH si solo te logueas desde tu propia subred, o extiende el <em>Ban Time</em> para el panel de cara al público.",
"outro": "El recorrido completo <em>Qué instala / cómo se configura / cómo desinstalar</em> — incluyendo la ruta de instalación manual, el efecto colateral de SSH MaxAuthTries y la relación con el journal <code>proxmenux-auth.log</code> — está en <link>ProxMenux → Seguridad → Fail2Ban</link>.",
"calloutTitle": "Sin Fail2Ban, la protección contra fuerza bruta es best-effort",
"calloutBody": "ProxMenux Monitor tiene su propio hook de ban a <em>nivel de aplicación</em> en el pipeline de peticiones de Flask — pero solo surte efecto si Fail2Ban está instalado y escribe a la tabla de bans. Sin Fail2Ban, el Monitor loguea los logins fallidos a <code>proxmenux-auth.log</code> para inspección futura pero no bloquea IPs activamente."
},
"lynis": {
"heading": "Lynis Security Audit",
"subHeading": "(condicional)",
"whatIs": "<strong>Qué es.</strong> Lynis es una herramienta open-source de auditoría de seguridad que ejecuta ~280 tests en el host (permisos de archivos, hardening del kernel, config SSH, vulnerabilidades de paquetes, política de cripto, tareas programadas, banner grabbing, etc.) y produce una puntuación de hardening 0100, una lista de warnings y una lista de sugerencias. Es la baseline de facto para \"¿este servidor está en buena forma?\" en servidores basados en Debian.",
"whyUseful": "<strong>Por qué es útil.</strong> Conocer la postura de seguridad de tu servidor es difícil de hacer leyendo archivos de config uno a uno. Lynis captura las cosas que rutinariamente se pasan por alto: flags de hardening del kernel ausentes, cifrados SSH débiles activos, journal no persistente, <code>NOPASSWD</code> en sudoers para cuentas por defecto, y muchas más. Volver a ejecutarlo tras aplicar los ajustes post-instalación de ProxMenux te da un número objetivo de la mejora.",
"notInstalledAlt": "Tarjeta Lynis Security Audit con estado Not Installed y botón Install Lynis, listando features: scoring de hardening, detección de vulnerabilidades, comprobación de compliance y fuente GitHub",
"notInstalledCaption": "Tarjeta Lynis antes de instalar — la caja azul resume lo que hace la herramienta.",
"notBundled": "Lynis tampoco <strong>viene de fábrica</strong>. ProxMenux instala la última release directamente desde la fuente oficial en GitHub (no el paquete Debian, que va varias versiones menores por detrás).",
"confirmAlt": "Modal de confirmación Install Lynis listando lo que hace Lynis: scoring de hardening, detección de vulnerabilidades, análisis de configuración, comprobación de compliance, fuente desde el repositorio oficial de GitHub",
"confirmCaption": "Confirmación de instalación — explícita sobre la fuente GitHub.",
"progressAlt": "Panel en streaming Lynis Installation: instalando la última herramienta de scan, versión 3.1.6 confirmada, mensaje de instalación completada",
"progressCaption": "Instalación en curso — el mismo patrón de panel en streaming que Fail2Ban.",
"afterInstall": "Tras instalar la tarjeta muestra la versión y un historial de auditorías vacío. Pulsa <em>Run Security Audit</em> para arrancar el primer scan.",
"installedAlt": "Tarjeta Lynis Security Audit tras instalar con insignia versión 3.1.6 Installed, timestamp Last Scan, Hardening Index 0, Warnings 0, Suggestions 0, fila de audit report vacía y botón Run Security Audit",
"installedCaption": "Lynis instalado, sin auditoría todavía. La tarjeta prerrellena los tiles de métricas con ceros.",
"runningAlt": "Tarjeta Lynis Security Audit mientras la auditoría está corriendo mostrando mensaje Security audit in progress, duración estimada de 2-5 minutos y un botón Running Audit deshabilitado",
"runningCaption": "Auditoría en curso — el botón de acción muestra un spinner y la tarjeta avisa explícitamente de que el scan puede llevar 25 minutos.",
"finishedBody": "Cuando termina, la tarjeta pasa a la vista de resultados: hardening index, warnings, suggestions y una lista <em>Audit Reports</em> con cada scan histórico.",
"resultsAlt": "Tarjeta Lynis Security Audit con resultados: Hardening Index 71 con desglose Lynis 66 PVE 71, 3 warnings, 40 suggestions, barra de progreso Security Hardening Score Proxmox Adjusted 71 de 100 en el rango Good, lista de audit reports con descarga PDF y botón Run Security Audit",
"resultsCaption": "Resultados de auditoría — Hardening Index <strong>71/100 (Good)</strong> en una ejecución de ejemplo. La tarjeta también muestra la \"puntuación raw de Lynis\" (66) frente a la puntuación ajustada para Proxmox (71) que devuelve 11 puntos por hallazgos que el corpus de tests de Lynis marca pero que son comportamiento esperado en Proxmox VE.",
"scoreTitle": "Puntuación raw de Lynis vs puntuación ajustada para Proxmox",
"scoreIntro": "Lynis trae reglas ajustadas para Debian de propósito general. Proxmox diverge legítimamente de algunas (servicios corriendo como root por razones de cluster, tuning custom de <code>journald</code>, etc.). La tarjeta muestra ambos números para que puedas:",
"scoreItems": [
"Trackear tu <em>puntuación raw de Lynis</em> igual que lo harían auditores externos.",
"Trackear la puntuación <em>ajustada para Proxmox</em> — una baseline más justa si estás comparando nodos dentro del mismo cluster."
],
"reportBody": "<strong>El informe completo.</strong> Cada fila de auditoría en la lista tiene un botón <em>PDF</em> que descarga un informe de varias páginas con el resumen ejecutivo, info del sistema, postura de seguridad, cada warning con explicación, cada sugerencia rankeada por impacto y el inventario de paquetes. Es el artefacto que adjuntarías a una revisión de seguridad.",
"reportAlt": "Primera página de ejemplo del PDF Lynis Security Audit Report mostrando resumen ejecutivo con hardening 71 de 100, contadores de warnings y suggestions, bloque de System Information con hostname, kernel, versión de Lynis, fecha del informe, resumen de postura de seguridad",
"reportCaption": "Primera página de un informe descargado — resumen ejecutivo, System Information y resumen de postura de seguridad. El informe completo continúa con warnings detallados, sugerencias y la lista de paquetes instalados. Hay un <a>PDF de ejemplo</a> adjunto como referencia.",
"runPeriodically": "Ejecuta la auditoría periódicamente (tras grandes upgrades de Proxmox, tras aplicar ajustes post-instalación, antes de abrir una ruta de acceso remoto) y guarda los informes — la tendencia importa más que cualquier número aislado.",
"outro": "El recorrido completo <em>Qué instala / cómo se configura / cómo desinstalar</em> y un análisis escrito del informe de ejemplo están en <link>ProxMenux → Seguridad → Lynis</link>."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerCard": "Tarjeta",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"card": "Autenticación, 2FA, cambio de contraseña",
"endpoint": "/api/auth/*",
"source": "SQLite local + JWT emitido por el Monitor."
},
{
"card": "SSL / HTTPS",
"endpoint": "/api/auth/ssl/*",
"source": "<code>openssl x509</code> sobre <code>/etc/pve/local/pve-ssl.pem</code> + <code>/etc/proxmenux/ssl_config.json</code>."
},
{
"card": "Listar / generar / revocar tokens API",
"endpoint": "/api/auth/api-tokens",
"source": "Filas de token guardadas localmente; nada sale del host."
},
{
"card": "Secure Gateway (deploy + estado)",
"endpoint": "/api/oci/*",
"source": "Provisiona LXC Alpine + <code>tailscaled</code> vía <code>pct create</code> / <code>pct exec</code>."
},
{
"card": "Estado y reglas de firewall",
"endpoint": "/api/security/firewall/*",
"source": "<code>pve-firewall</code> + <code>/etc/pve/firewall/&lt;cluster|host&gt;.fw</code>."
},
{
"card": "Fail2Ban (solo cuando está instalado)",
"endpoint": "/api/security/fail2ban/*",
"source": "<code>fail2ban-client status</code>, <code>/var/log/fail2ban.log</code>, <code>/etc/fail2ban/jail.local</code>."
},
{
"card": "Auditoría Lynis (solo cuando está instalada)",
"endpoint": "/api/security/lynis/*",
"source": "Ejecuta <code>lynis audit system</code> en background; informe parseado desde <code>/var/log/lynis-report.dat</code>."
}
]
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Acceso y autenticación",
"href": "/docs/monitor/access-auth",
"tail": " — flujo completo de primer arranque, selector de app 2FA, recuperación de authenticator perdido, snippets de reverse proxy."
},
{
"label": "Integraciones",
"href": "/docs/monitor/integrations",
"tail": " — cookbooks para usar tokens API con Homepage, Home Assistant, Prometheus, n8n y el Secure Gateway de extremo a extremo."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tailRich": " — cada endpoint <code>/api/auth</code>, <code>/api/security</code> y <code>/api/oci</code> con método, body y ejemplos curl."
},
{
"label": "ProxMenux → Seguridad → Fail2Ban",
"href": "/docs/security/fail2ban",
"tail": " — recorrido de instalación, jails configurados, ruta de instalación manual."
},
{
"label": "ProxMenux → Seguridad → Lynis",
"href": "/docs/security/lynis",
"tail": " — informe de ejemplo, interpretación del score, cuándo volver a ejecutarlo."
}
]
}
}
@@ -0,0 +1,327 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Settings | ProxMenux Documentation",
"description": "La pestaña Settings agrupa las preferencias del panel (unidades de red, duraciones de supresión, exclusiones de almacenamiento / interfaz), el panel embebido de notificaciones + IA y un inventario transparente de cada optimización post-instalación de ProxMenux actualmente activa en el host con acceso al código fuente."
},
"header": {
"title": "Panel: pestaña Settings",
"description": "Preferencias del panel, exclusiones de monitorización, el panel embebido de configuración de notificaciones + IA y un inventario en vivo de las optimizaciones post-instalación de ProxMenux actualmente activas en el host.",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "Dónde vive realmente cada setting",
"body": "La pestaña Settings es una superficie única para varias preocupaciones distintas: cómo renderiza el panel, qué vigila el Monitor de salud, cómo salen las alertas y qué ha cambiado ya ProxMenux en el host. Las tarjetas que tienen su propia página de documentación profunda enlazan en lugar de duplicar el contenido aquí — Settings es el punto de entrada, no el manual."
},
"networkUnits": {
"heading": "Network Units",
"imageAlt": "Tarjeta Network Units con desplegable Network Unit Display puesto en Bytes",
"imageCaption": "Elige entre bits por segundo y bytes por segundo para cada rate de red mostrado en el panel.",
"body": "Elige cómo se muestra el throughput de red a lo largo del panel: <strong>bits por segundo</strong> (Mbps / Gbps) o <strong>bytes por segundo</strong> (MB/s / GB/s). Bits es el valor por defecto porque es como los fabricantes de NICs e ISPs etiquetan sus productos; bytes es lo que reportan la mayoría de herramientas de transferencia de archivos. El setting afecta cada gráfica, insignia y tooltip que muestra rate de red — aplicado inmediatamente, sin recargar."
},
"health": {
"heading": "Monitor de salud",
"intro": "La tarjeta expone el setting <strong>Suppression Duration</strong> por categoría — una vez se descarta una alerta, cuánto tiene que pasar antes de que se permita al escáner volver a dispararla. Cada una de las diez categorías del Monitor de salud (CPU, Memoria, Almacenamiento, Discos, Red, VMs, Servicios PVE, Logs, Updates, Seguridad) tiene su propio desplegable con estos valores:",
"items": [
"<strong>24 h</strong> — por defecto para la mayoría de categorías transitorias.",
"<strong>72 h</strong> — para eventos sobre los que quieres unos días de silencio.",
"<strong>168 h</strong> (1 semana) y <strong>720 h</strong> (1 mes) — chequeos periódicos.",
"<strong>8760 h</strong> (1 año) — efectivamente \"silencio en el futuro previsible\".",
"<strong>-1</strong> — silencio permanente hasta que lo reactives manualmente.",
"<strong>Custom hours</strong> — cualquier entero si necesitas un valor intermedio."
],
"imageAlt": "Card Settings → Monitor de salud con los desplegables de supresión por categoría y la sección Active Suppressions",
"imageCaption": "Card Monitor de salud — los desplegables por categoría fijan los valores por defecto para nuevos dismisses; la sección Active Suppressions debajo lista cada alerta actualmente silenciada y permite revertirlas.",
"editTitle": "Modo Edit",
"editBody": "La tarjeta es de solo-lectura por defecto. Pulsa <strong>Edit</strong> en la esquina superior derecha de la card para activar los desplegables y los botones Re-enable. <strong>Save</strong> confirma todos los cambios pendientes (cambios de Suppression Duration y re-enables encolados) en un solo lote; <strong>Cancel</strong> los descarta todos. El botón Save solo se activa cuando hay al menos un cambio pendiente.",
"activeTitle": "Active Suppressions",
"activeIntro": "Debajo de los desplegables de Suppression Duration, la sección <strong>Active Suppressions</strong> lista cada alerta actualmente silenciada — tanto los dismisses time-limited (24 h, 7 días, ventanas custom) como los <em>Permanent</em>. Cada fila muestra:",
"activeItems": [
"Un badge coloreado — <strong>Permanent</strong> (ámbar) o una cuenta atrás como <strong>24h remaining</strong> / <strong>7d remaining</strong> (azul).",
"El identificador de la alerta, normalizado para legibilidad (p. ej. <code>pve_storage_full_PBS-Cloud</code> → <em>PVE Storage Full: PBS-Cloud</em>).",
"Categoría, severidad y el timestamp en que se descartó la alerta.",
"Un botón <strong>Re-enable</strong> (activo solo en modo Edit) que encola la alerta para ser un-acknowledged al siguiente Save."
],
"activeReenableTitle": "Flujo de Re-enable",
"activeReenableBody": "Pulsar <strong>Re-enable</strong> en modo Edit marca la fila en verde y tacha su identificador — está encolada pero todavía no aplicada. Volver a hacer clic en la misma fila la <strong>Undo</strong> (la saca de la cola). Cuando pulsas <strong>Save</strong>, cada re-enable encolado dispara <code>POST /api/health/un-acknowledge</code> en paralelo y las filas afectadas desaparecen de la lista. Si la condición subyacente sigue presente y la categoría soporta re-fire, la alerta reaparece en la lista Active del Monitor de salud en el siguiente ciclo de escaneo.",
"activePermanentNote": "Los dismisses permanentes (alertas descartadas con <em>Permanently</em> desde el modal del Monitor, o aquellas cuya categoría tenga el default puesto a <code>-1</code>) <strong>solo se pueden revertir desde aquí</strong>. El modal del dashboard no expone un botón un-dismiss para ellas — el panel Active Suppressions es el único log de auditoría + UI de revert.",
"activeAutoRefreshTitle": "Auto-refresh",
"activeAutoRefreshBody": "La lista se refresca automáticamente cuando descartas o un-dismiss una alerta desde el modal del Monitor de salud (vía un evento in-browser), cuando la pestaña recupera el foco y al cambio de visibilidad. No necesitas recargar la página tras descartar una alerta desde el dashboard.",
"calloutTitle": "La semántica completa vive en la página del Monitor de salud",
"calloutBody": "Las reglas de escalada (cuándo un re-fire pasa a critical), el comportamiento de auto-resolve para eventos cuyo dispositivo subyacente desaparece y la diferencia entre dismissed y resolved — todo documentado bajo <link>Monitor de salud → Descartar alertas y la Suppression Duration</link>. Esta tarjeta solo expone los desplegables por categoría y el panel Active Suppressions."
},
"thresholds": {
"heading": "Health Monitor Thresholds",
"intro": "Donde la tarjeta anterior decide <em>cuánto tiempo quedarse callado tras un dismiss</em>, esta decide <strong>a qué valor se dispara una alerta en primer lugar</strong>. Cada chequeo que ejecuta el Monitor de salud está parametrizado por un par de números — un umbral <strong>Warning</strong> y un umbral <strong>Critical</strong> — y ambos se exponen aquí para que el operador los ajuste.",
"whatForTitle": "Para qué sirve",
"whatForIntro": "Los valores por defecto que vienen con ProxMenux son sensatos para el host Proxmox medio, pero cada entorno tiene su propio sobre operativo:",
"whatForItems": [
"Un homelab pequeño con un SSD único puede querer avisar antes en capacidad (75 / 90 %) para dejar margen a snapshots.",
"Un host de datacenter con nodos Ceph redundantes puede ser más relajado en avisos de memoria (un working set al 90 % es normal bajo ARC de ZFS).",
"Un mini-PC con refrigeración pasiva necesita umbrales de temperatura más bajos que un servidor con refrigeración forzada por aire — misma clase de drive, sobre físico distinto.",
"Un host muy virtualizado que clava CPU durante builds no debería avisar en cada pico del 80 %, pero sí debe seguir alertando sobre presión sostenida."
],
"whatForOutro": "Editar un umbral surte efecto <strong>en el siguiente scan</strong> — el Monitor de salud relee los valores desde <code>/usr/local/share/proxmenux/health_thresholds.json</code> en cada ciclo, sin reinicio de servicio. Los mismos números también alimentan los rangos de color de los widgets del panel (la línea de temperatura en la modal de temperatura de disco, las barras de las tarjetas de almacenamiento) para que la clasificación visual coincida con lo que dispara la alerta.",
"coloursTitle": "Colores de estado: cómo renderizan Warning y Critical en el panel",
"coloursIntro": "Cada umbral de abajo produce la misma clasificación de tres estados a lo largo del panel — los mismos colores para barras de almacenamiento, anillos de CPU/memoria, chips de temperatura y el punto de la modal de disco. Leer un color en cualquier sitio del Monitor mapea a un rango definido relativo al par configurado:",
"headerColour": "Color",
"headerRange": "Rango",
"headerMeaning": "Significado",
"colourRows": [
{
"colour": "Verde",
"range": "valor < Warning",
"meaning": "Rango operativo normal. No se dispara alerta."
},
{
"colour": "Ámbar",
"range": "Warning ≤ valor < Critical",
"meaning": "Estado warning. El Monitor de salud dispara un evento de severidad WARNING; las notificaciones respetan los filtros del canal y las Quiet Hours."
},
{
"colour": "Rojo",
"range": "valor ≥ Critical",
"meaning": "Estado critical. El Monitor de salud dispara un evento CRITICAL; CRITICAL salta las Quiet Hours y siempre alcanza al canal."
}
],
"sectionsTitle": "Secciones y valores por defecto recomendados",
"sectionsIntro": "Estos son los valores con los que viene ProxMenux — la baseline recomendada. Es lo que ves en un host recién montado hasta que sobreescribes algo. Las secciones están ordenadas de arriba abajo de <em>cómputo</em> → <em>calor</em> → <em>capacidad de almacenamiento</em>, así que leer hacia abajo va de lo concreto (carga actual) al estado acumulado (espacio libre).",
"headerSection": "Sección",
"headerWarning": "Warning",
"headerCritical": "Critical",
"headerGates": "Qué controla",
"thresholdRows": [
{
"section": "Uso de CPU",
"warning": "85 %",
"critical": "95 %",
"gates": "Alerta de carga sostenida cuando la CPU promedia por encima del umbral durante la ventana de scan."
},
{
"section": "Memoria",
"warning": "85 %",
"critical": "95 %",
"gates": "Presión de RAM en el host."
},
{
"section": "Swap (solo critical)",
"warning": "—",
"critical": "5 %",
"gates": "Swap realmente en uso. El número es intencionadamente bajo: un host Proxmox sano apenas debería tocar swap, así que incluso un 5 % es una señal significativa de presión de RAM."
},
{
"section": "Temperatura de CPU",
"warning": "80 °C",
"critical": "90 °C",
"gates": "Lectura de temperatura de package / core de CPU desde <code>lm-sensors</code>."
},
{
"section": "Temp de disco — HDD",
"warning": "60 °C",
"critical": "65 °C",
"gates": "Drives spinning estándar. El sobre del fabricante topa alrededor de 6065 °C, así que Critical se fija justo en el límite duro."
},
{
"section": "Temp de disco — SSD",
"warning": "70 °C",
"critical": "75 °C",
"gates": "SSDs SATA 2.5'' / M.2 — corren más frescos que NVMe pero más calientes que HDDs."
},
{
"section": "Temp de disco — NVMe",
"warning": "80 °C",
"critical": "85 °C",
"gates": "Los drives NVMe corren más calientes por diseño; los controladores auto-throttlean por encima de ~85 °C, así que Warning captura la escalada antes de que entre el throttling."
},
{
"section": "Temp de disco — SAS",
"warning": "55 °C",
"critical": "65 °C",
"gates": "Los drives SAS enterprise comparten el mismo límite de fabricante de ~65 °C que los HDDs, pero se despliegan normalmente en chasis rack con refrigeración activa. Una lectura a 55 °C ya señala un problema de refrigeración (ventilador fallando, problema de HVAC) <em>antes</em> de que el propio drive esté en riesgo — de ahí un Warning más bajo que HDD, no porque SAS sea menos tolerante al calor."
},
{
"section": "Espacio de disco — host",
"warning": "85 %",
"critical": "95 %",
"gates": "Capacidad de <code>/</code> y cada mountpoint del host (<code>/var/lib/vz</code>, <code>/mnt/*</code>…)."
},
{
"section": "Espacio de disco — rootfs LXC",
"warning": "85 %",
"critical": "95 %",
"gates": "Disco raíz por contenedor, evaluado contra el tamaño del rootfs según PVE."
},
{
"section": "Mount points LXC",
"warning": "85 %",
"critical": "95 %",
"gates": "Capacidad de mountpoints dentro de CTs en ejecución (mp0, mp1, NFS, bind mounts). Excluye rootfs."
},
{
"section": "Almacenamiento PVE",
"warning": "85 %",
"critical": "95 %",
"gates": "Almacenamientos PVE estilo bloque (LVM, LVM-thin, ZFS-pool, RBD/Ceph, PBS)."
},
{
"section": "Pool ZFS",
"warning": "85 %",
"critical": "95 %",
"gates": "Pools ZFS a nivel host — independiente del registro PVE."
}
],
"defaultsTitle": "Valores por defecto, overrides y reset",
"defaultsBody": "El backend expone una vista fundida: cada sección parte de los valores por defecto de ProxMenux (los que ves cuando el host está recién hecho) y sobreescribes solo los knobs que te importan. La tarjeta muestra el valor <em>efectivo</em> — la sobreescritura si pones una, en otro caso el valor por defecto. Un botón <strong>Reset</strong> limpia cada override y vuelve a los valores por defecto en todas las secciones de una vez.",
"validationTitle": "Validación",
"validationBody": "Guardar rechaza valores que no tienen sentido (porcentajes fuera de 0100, critical por debajo de warning, temperaturas negativas). El frontend muestra el error inline; el backend valida otra vez antes de persistir, así que no se puede engañar a la API con un PUT hecho a mano para que acepte un umbral roto."
},
"lxcDetection": {
"heading": "LXC Update Detection",
"imageAlt": "Tarjeta LXC Update Detection con un único switch — cuando está activo, el Monitor escanea periódicamente contenedores LXC Debian/Ubuntu/Alpine en ejecución buscando paquetes con update pendiente.",
"imageCaption": "El toggle para el scan periódico <code>apt list --upgradable</code> / <code>apk list -u</code> a lo largo de cada CT en ejecución. Por defecto ON. El toggle de notificación correspondiente en Notifications → Services solo aparece mientras la detección está activa.",
"intro": "Un toggle dedicado para el scan de actualizaciones LXC, situado entre Health Monitor Thresholds y la tarjeta Notifications. Cuando está ON, ProxMenux recorre cada CT en ejecución del host y consulta al gestor de paquetes dentro del contenedor por updates pendientes; los resultados aterrizan en los contadores de insignias de la pestaña Hardware y alimentan la notificación <code>lxc_updates_available</code>. Cuando está OFF, el scan se detiene por completo (sin llamadas <code>pct exec</code>) y cualquier entrada LXC existente en <code>managed_installs.json</code> se purga inmediatamente, así el panel y el endpoint <code>/api/managed-installs</code> dejan de reportar estado de update LXC sin esperar al siguiente ciclo de 24h.",
"whatRunsTitle": "Qué ejecuta realmente el scan",
"whatRunsIntro": "Para cada CT en estado <code>running</code> con un gestor de paquetes soportado:",
"whatRunsItems": [
"<strong>Gate de frescura de caché.</strong> Si la caché de metadatos apt/apk dentro del contenedor es más vieja que <strong>24 horas</strong>, primero corre un refresh best-effort (<code>apt-get update -qq</code> en Debian/Ubuntu, <code>apk update</code> en Alpine) con un timeout de 60 s. Cualquier fallo (sin red, repo roto, timeout) se traga en silencio — el listado de abajo sigue corriendo contra la caché que exista, así que un problema transitorio de repo nunca puede empeorar la detección.",
"<strong>Listing.</strong> Después ProxMenux ejecuta <code>apt list --upgradable</code> / <code>apk list -u</code> y parsea la salida en un recuento estructurado más una muestra de los nombres de paquetes top.",
"<strong>Dedup por CT.</strong> Una fingerprint construida a partir del recuento, security-count y los nombres top ordenados se almacena para que un conjunto estable de updates pendientes no re-notifique diariamente, mientras que un conjunto significativamente distinto sí lo haga."
],
"selfUpdateTitle": "Los CTs que se auto-actualizan fuera de apt pueden legítimamente reportar 0",
"selfUpdateBody": "La detección solo ve lo que el gestor de paquetes dentro del contenedor conoce. Un CT cuyo software clave se actualiza fuera de apt (el cron <code>plexupdate</code> de Plex, contenedores Docker actualizados vía <code>docker pull</code>, el actualizador integrado de Frigate, etc.) seguirá reportando updates apt bajos o cero aunque el appliance se mantenga al día activamente — eso es correcto, no es un bug. El sistema base a nivel apt del mismo CT puede aún tener sus propios updates pendientes, que sí saca a la luz el scan.",
"refreshTitle": "Por qué el auto-refresh de 24 h",
"refreshBody": "Los CTs appliance de larga vida con frecuencia acaban con cachés apt meses desactualizadas porque nadie ejecuta rutinariamente <code>apt update</code> dentro de ellos. Sin el refresh, <code>apt list --upgradable</code> reporta 0 updates desde una snapshot congelada y el operador nunca ve el backlog. El umbral coincide con el resto del ciclo de chequeo — si el CT se refrescó en las últimas 24 h, ProxMenux confía en esa señal y se salta el refresh.",
"toggleTitle": "Toggle de notificación condicional",
"toggleBody": "El toggle de notificación por canal <code>lxc_updates_available</code> en <strong>Notifications → Services</strong> solo se renderiza mientras la detección está activa. Cuando pones la detección en OFF, esa fila desaparece de la lista de categorías de cada canal — pero su preferencia almacenada se preserva en la DB, así que reactivar la detección trae el toggle de vuelta al valor que tenía antes.",
"purgeTitle": "Qué se purga al desactivar la detección",
"purgeBody": "Apagar el switch elimina inmediatamente cada entrada <code>type=lxc</code> de <code>/usr/local/share/proxmenux/managed_installs.json</code>. Las insignias de la pestaña Hardware caen a cero en el siguiente refresco del panel. Volver a activarlo repuebla el registro en el siguiente ciclo de detección (o antes si disparas un refresh manual desde la API)."
},
"storageExclusions": {
"heading": "Remote Storage Exclusions",
"imageAlt": "Tarjeta Remote Storage Exclusions listando almacenamientos PBS-Cloud, PBS y PBS2 con toggles Health y Alerts por fila",
"imageCaption": "Toggles <em>Health</em> y <em>Alerts</em> por almacenamiento. Los almacenamientos con ambos toggles en off dejan de contar contra el Monitor de salud y dejan de generar notificaciones — pero siguen renderizándose en la pestaña Almacenamiento marcados como excluidos.",
"intro": "Marca los almacenamientos gestionados por Proxmox (NFS / CIFS / PBS / Ceph / iSCSI / etc.) como excluidos de monitorización. Dos toggles independientes por almacenamiento:",
"items": [
"<strong>Health</strong> — cuando está off, el almacenamiento deja de contribuir a la categoría Almacenamiento del Monitor de salud. Útil para volúmenes de archivo que están intencionadamente offline la mayor parte del tiempo o destinos de backup remotos que solo se encienden a horario.",
"<strong>Alerts</strong> — cuando está off, las alertas sobre este almacenamiento dejan de salir a través de los canales configurados, aunque los chequeos Health sigan activos. Útil cuando quieres la vista del panel pero no las notificaciones."
],
"outro": "Los almacenamientos excluidos siguen renderizándose en la <link>pestaña Almacenamiento</link> con una insignia morada <em>excluded</em> para que la entrada no desaparezca silenciosamente de tu inventario. El estado se persiste en la tabla SQLite <code>excluded_storages</code>."
},
"interfaceExclusions": {
"heading": "Network Interface Exclusions",
"imageAlt": "Tarjeta Network Interface Exclusions listando vmbr0, vmbr1, vmbr2, bond0 y eno1 con toggles Health y Alerts por interfaz",
"imageCaption": "La misma forma que Storage Exclusions — toggles <em>Health</em> y <em>Alerts</em> por interfaz. Cada fila muestra la interfaz, insignia de tipo (bridge / bond / física), la IP y la velocidad del enlace.",
"intro": "La misma forma que Storage Exclusions pero para interfaces de red. Por interfaz: excluir de los chequeos Health y/o excluir de las notificaciones. Casos de uso típicos:",
"items": [
"Un bridge spare intencionadamente down.",
"Una NIC que se retiró físicamente pero sigue referenciada en <code>/etc/network/interfaces</code>.",
"Una sub-interfaz VLAN usada solo durante ventanas de mantenimiento.",
"Un bridge de gestión que está up pero no lleva tráfico — flappeando ruidosamente en cada ciclo."
],
"outro": "El estado se persiste en la tabla SQLite <code>excluded_interfaces</code>. La misma insignia morada <em>excluded</em> en la <link>pestaña Red</link> para que las interfaces excluidas sigan visibles."
},
"notifications": {
"heading": "Notificaciones e IA",
"body1": "Esta sección de la pestaña Settings es donde se activan las notificaciones de ProxMenux Monitor y el reescritor con IA. Pulsar <em>Enable Notifications</em> arranca el hilo de envío en background, registra un target de webhook de Proxmox VE en el host para que los eventos emitidos por PVE fluyan al mismo pipeline y despliega el formulario de canales para que puedas conectar Telegram, Discord, Email, Gotify y el resto. El reescritor con IA vive dentro del mismo panel como una sección avanzada colapsable.",
"body2": "Ambas superficies tienen muchas piezas en movimiento — canales, toggles por evento, mensajes Rich, el Display Name, el pipeline de envío (dedup, cooldown, agregación, quiet hours), la integración del webhook PVE, proveedores de IA, modos de prompt — y viven en sus propias páginas dedicadas en lugar de repetirse aquí:",
"items": [
"<notifLink>Notificaciones</notifLink> — recorridos por canal (Telegram, Discord, Gotify, Email + app passwords de Gmail / Microsoft, ntfy, Slack, Teams, webhook genérico), categorías por evento, mensajes Rich, Display Name, pipeline de envío, integración del webhook PVE, historial y API.",
"<aiLink>Asistente de IA</aiLink> — proveedores (OpenAI, Anthropic, Gemini, Groq, OpenRouter, Ollama), selección de modelo, modos de prompt (default / custom), idioma de salida, niveles de detalle por canal y sugerencias de IA."
]
},
"optimizations": {
"heading": "ProxMenux Optimizations",
"intro": "Un inventario en vivo y transparente de cada optimización post-instalación de ProxMenux actualmente activa en el host. Cada vez que aplicas una opción post-instalación desde el lado Scripts — ya sea vía el <autoLink>Automated post-install</autoLink> o vía el <customLink>Customizable post-install</customLink> a la carta — el script correspondiente se registra a sí mismo en <code>/usr/local/share/proxmenux/installed_tools.json</code>. El Monitor lee ese archivo y renderiza esta tarjeta para que veas, de un vistazo, qué se ha cambiado en tu servidor.",
"imageAlt": "Tarjeta ProxMenux Optimizations con rejilla de herramientas instaladas, cada fila mostrando un punto verde, nombre de la herramienta y versión. Ejemplos incluyen APT IPv4 Force, Bashrc Customization, Fastfetch, Log2ram SSD Protection, Memory Settings Optimization, Setting persistent network interfaces, System Limits Increase, APT Language Skip, Entropy Generation haveged con insignia Legacy, Kernel Panic Configuration, Logrotate Optimization, Network Optimizations, Subscription Banner Removal, VFIO IOMMU Passthrough — 14 activas en total",
"imageCaption": "La tarjeta lista cada optimización activa con su nombre, versión, un punto coloreado y un contador naranja <em>14 active</em> arriba a la derecha. Las herramientas cuyo source es alcanzable son pulsables.",
"dotsTitle": "Qué significan los puntos",
"dotsItems": [
"<green/> <strong>Punto verde</strong> — optimización actual, registrada por la versión activa de ProxMenux. El código fuente es alcanzable: pulsa la fila para abrirlo.",
"<amber/> <strong>Punto ámbar + insignia <em>legacy</em></strong> — aplicada por una versión más vieja de ProxMenux cuyo script ha sido renombrado o reemplazado desde entonces. Sigue activa en el host; el source abre en modo \"legacy\" (con un acento ámbar) para que puedas auditar qué se ejecutó realmente."
],
"clickTitle": "Acceso al código fuente",
"clickBody": "Pulsar una herramienta abre una modal con la función bash exacta que aplicó el cambio, más la ruta del archivo de script en el que vive (<code>auto_post_install.sh</code> para el bundle Automated, <code>customizable_post_install.sh</code> para el lado à la carte). Los comentarios y constructos de shell tienen syntax highlighting; un botón Copy pone el source en tu portapapeles. Esta es la superficie \"muestra tu trabajo\" — verifica lo que ProxMenux le hizo a tu host antes de cualquier cambio manual que añadas encima.",
"detailAlt": "Modal de código fuente de herramienta para APT IPv4 Force mostrando la función bash force_apt_ipv4 desde customizable_post_install.sh versión 1.0 con código resaltado que configura /etc/apt/apt.conf.d/99-force-ipv4 con Acquire ForceIPv4 true, registra la herramienta y emite un mensaje translate APT IPv4 configuration completed",
"detailCaption": "Modal de source para <em>APT IPv4 Force</em> — función <code>force_apt_ipv4()</code> exacta de <code>customizable_post_install.sh v1.0</code>, con syntax highlighting y un Copy de un clic.",
"whyTitle": "Por qué importa esto",
"whyBody": "ProxMenux cambia cosas en tu host: parámetros de kernel, configuración de repositorios, bits de red, rotación de logs, passthrough de GPU, etc. Saber exactamente qué está activo es esencial antes de empezar a añadir customización manual encima — y aún más si un admin distinto opera el host del que lo montó. Esta tarjeta es el registro auditable de cada optimización actualmente en efecto, con el código exacto que la produjo.",
"updatesTitle": "Banner Updates available",
"updatesBody": "Cuando una optimización post-instalación tiene en disco una versión más nueva que la actualmente registrada en el host, la tarjeta muestra un banner \"Updates available\" arriba con el recuento y un botón <strong>Apply</strong>. Pulsar <strong>Apply</strong> abre un selector por optimización (el mismo disponible desde la entrada <em>Apply available updates</em> del menú Post-Install). Elige qué optimizaciones aplicar; ProxMenux relanza la función correspondiente y refresca la versión en el registro. Cuando todo está al día, el banner desaparece.",
"updatesAlt": "Tarjeta ProxMenux Optimizations con un banner Updates available arriba — recuento de updates pendientes más un botón Apply que abre el selector por optimización",
"updatesCaption": "El banner solo se renderiza cuando al menos una optimización tiene una versión más nueva en disco. Mira <link>Apply Available Updates</link> para el flujo completo de update y el equivalente Path-A en el menú de la shell.",
"revertTitle": "Revertir una optimización",
"revertBody": "La tarjeta es de solo lectura — para deshacer una optimización, ejecuta la opción correspondiente <link>Uninstall Optimizations</link> del menú ProxMenux Scripts. El paso de desinstalación elimina la entrada de <code>installed_tools.json</code>, así que desaparece de esta tarjeta en el siguiente refresco."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerCard": "Tarjeta",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"card": "Network Units",
"endpoint": "/api/settings",
"source": "Persistido en la tabla SQLite de settings del panel."
},
{
"card": "Duraciones del Monitor de salud",
"endpoint": "/api/health/settings",
"source": "Duraciones de supresión por categoría en la DB de Health."
},
{
"card": "Exclusiones de almacenamiento / interfaz",
"endpoint": "/api/storage/exclusions, /api/network/exclusions",
"source": "Tablas SQLite <code>excluded_storages</code> y <code>excluded_interfaces</code>."
},
{
"card": "Panel Notificaciones e IA",
"endpoint": "/api/notifications/*",
"source": "Mira las páginas dedicadas <notifLink>Notificaciones</notifLink> / <aiLink>Asistente de IA</aiLink>."
},
{
"card": "Lista ProxMenux Optimizations",
"endpoint": "/api/proxmenux/installed-tools",
"source": "Lee <code>/usr/local/share/proxmenux/installed_tools.json</code>, escrito por llamadas <code>register_tool</code> dentro de los scripts post-instalación."
},
{
"card": "Modal de código fuente de optimización",
"endpoint": "/api/proxmenux/tool-source",
"source": "Extrae la función bash correspondiente de <code>auto_post_install.sh</code> o <code>customizable_post_install.sh</code> en el host."
}
]
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Notificaciones",
"href": "/docs/monitor/notifications",
"tail": " — canales, toggles por evento, overrides de canal, historial, test-send."
},
{
"label": "Asistente de IA",
"href": "/docs/monitor/ai-assistant",
"tail": " — proveedores, modelos, modos de prompt, idiomas, niveles de detalle por canal."
},
{
"label": "Monitor de salud → Descartar alertas y la Suppression Duration",
"href": "/docs/monitor/health-monitor#dismissing-alerts-and-the-suppression-duration",
"tail": " — la semántica detrás de los desplegables por categoría de arriba."
},
{
"label": "ProxMenux Scripts → Automated post-install",
"href": "/docs/post-install/automated",
"tailRich": " y <customLink>Customizable post-install</customLink> — los scripts reales que se registran en la lista de optimizaciones de arriba."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — cómo revertir una optimización registrada arriba."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — volver al resumen de la pestaña."
}
]
}
}
@@ -0,0 +1,268 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Almacenamiento | ProxMenux Documentation",
"description": "La pestaña Almacenamiento consolida cuatro vistas: almacenamientos gestionados por Proxmox con su estado, pools ZFS, discos físicos internos con datos SMART y unidades externas (USB). La vista en detalle de cada disco expone atributos SMART, desgaste y vida útil y el historial permanente de observaciones."
},
"header": {
"title": "Panel: pestaña Almacenamiento",
"description": "El estado de almacenamiento del host en una pantalla — pools de Proxmox (NFS / CIFS / LVM / ZFS / dir), salud de pools ZFS, discos internos SATA / NVMe con SMART y unidades USB externas. Pulsa cualquier disco para abrir una vista en detalle con la tabla completa de atributos SMART y el historial de observaciones por disco.",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "Respaldado por tres fuentes",
"body": "Los almacenamientos Proxmox vienen de <code>pvesm status</code>; el estado ZFS de <code>zpool status</code>; los discos físicos de <code>lsblk</code> + <code>smartctl</code> (y <code>nvme</code> para campos específicos de NVMe). La pestaña refresca cada ~60 segundos; la vista en detalle por disco dispara una lectura SMART fresca bajo demanda."
},
"thresholds": {
"title": "Colores de estado y umbrales aplicados aquí",
"intro": "Cada barra, chip y punto de esta pestaña sigue la misma clasificación de tres estados — <green/> <strong>verde</strong> por debajo de Warning, <amber/> <strong>ámbar</strong> entre Warning y Critical, <red/> <strong>rojo</strong> en Critical y por encima. Valores por defecto recomendados que vienen con ProxMenux:",
"items": [
"<strong>Capacidad</strong> (discos del host, almacenamientos PVE, pools ZFS, mounts de LXC) — Warning 85 %, Critical 95 %.",
"<strong>Temperatura de disco</strong> — HDD 60/65 °C · SSD 70/75 °C · NVMe 80/85 °C · SAS 55/65 °C (warning / critical)."
],
"outro": "Cada valor es configurable por host — <link>Settings → Health Monitor Thresholds</link> es la fuente única de verdad y explica cómo ajustarlos."
},
"topRow": {
"heading": "Fila superior: almacenamiento de un vistazo",
"intro": "Al abrir la pestaña Almacenamiento aterrizas en un resumen de cuatro tarjetas del estado de almacenamiento del host — capacidad total, qué se está usando localmente, qué se está usando en almacenamientos remotos y el inventario de discos físicos. Cada tarjeta es una respuesta de una línea a una pregunta común; las tarjetas debajo de la fila son donde profundizas en el detalle.",
"imageAlt": "Pestaña Almacenamiento — fila superior de cuatro tarjetas de estadísticas: Total Storage, Local Used, Remote Used, Physical Disks",
"imageCaption": "Fila superior de la pestaña Almacenamiento — capacidad total y recuento de discos, bytes usados separados en almacenamientos locales vs remotos y un desglose por tipo de discos físicos con su resumen de salud.",
"headerCard": "Tarjeta",
"headerWhat": "Qué muestra",
"totalLabel": "Total Storage",
"totalWhat": "Capacidad bruta combinada de todos los discos físicos. La línea al pie muestra el recuento de discos físicos descubiertos.",
"localLabel": "Local Used",
"localWhat": "Bytes usados en almacenamientos locales (LVM / LVM-thin / ZFS / dir en los discos del propio host). Muestra los bytes usados de forma prominente, con una línea al pie <em>X.XX % de Y TB</em> para que veas el porcentaje de llenado al mismo tiempo.",
"remoteLabel": "Remote Used",
"remoteWhat": "La misma forma que Local Used pero para almacenamientos remotos (NFS / CIFS / PBS / Ceph / iSCSI). Se cuentan por separado porque las caídas remotas no afectan a los datos locales y normalmente los dimensionas y monitorizas de forma diferente.",
"disksLabel": "Physical Disks",
"disksIntro": "Dos líneas de desglose para el inventario:",
"disksItems": [
"<strong>Por tipo</strong> — recuentos de NVMe (morado), SSD (azul) y HDD (azul) descubiertos. Los hosts con discos mixtos reciben los tres; un host todo-NVMe muestra solo el recuento NVMe.",
"<strong>Por salud</strong> — recuentos de discos <em>normal</em> (verde), <em>warning</em> (amarillo) y <em>critical</em> (rojo). El estado sano normalmente muestra solo \"X normal\"; warnings y critical aparecen solo cuando algo escala."
]
},
"pveStorage": {
"heading": "Tarjeta Proxmox Storage",
"intro": "Una fila por almacenamiento configurado en <code>/etc/pve/storage.cfg</code>. Cada fila muestra la insignia de tipo (<code>nfs</code> / <code>cifs</code> / <code>zfspool</code> / <code>lvm</code> / <code>lvmthin</code> / <code>dir</code> / <code>pbs</code>), el nombre del almacenamiento, una insignia active / error / not-monitored, el porcentaje de uso y una barra de progreso coloreada:",
"items": [
"<strong>&lt; 75 %</strong> — barra de progreso azul, valor en azul.",
"<strong>75 90 %</strong> — barra de progreso amarilla, valor en amarillo (el Monitor de salud avisa en este punto).",
"<strong>> 90 %</strong> — barra de progreso roja, valor en rojo (el Monitor de salud escala).",
"<strong>error</strong> — fila entera con borde rojo, se usa cuando el almacenamiento está configurado pero inalcanzable (servidor NFS caído, credenciales CIFS caducadas).",
"<strong>excluded</strong> — borde morado + la insignia \"not monitored\". Almacenamientos excluidos explícitamente por el usuario de los chequeos de salud (cómodo para volúmenes manuales / de archivo que están intencionadamente offline)."
],
"calloutTitle": "Excluir un almacenamiento ruidoso",
"calloutBody": "Desde la fila del almacenamiento, el menú por almacenamiento te permite marcarlo como <em>excluded from monitoring</em>. El flag se guarda en la tabla <code>excluded_storages</code> y lo respetan tanto la vista del panel como el ciclo del Monitor de salud — no se disparan notificaciones para almacenamientos excluidos, y no empujan la pastilla de la cabecera."
},
"zfs": {
"heading": "Tarjeta ZFS Pools",
"intro": "Se renderiza solo cuando ZFS está instalado y existe al menos un pool. Una fila por pool con una insignia de salud, size / allocated / free y un icono que refleja el estado de salud:",
"items": [
"<strong>ONLINE</strong> — verde. Todo sano.",
"<strong>DEGRADED</strong> — amarillo. El pool sigue sirviendo datos pero al menos un dispositivo no está disponible; arranca la ventana de reemplazo.",
"<strong>FAULTED</strong> / <strong>UNAVAIL</strong> / <strong>SUSPENDED</strong> — rojo. El pool no sirve datos; se requiere intervención inmediata."
],
"outro": "Tanto el estado ZFS como el estado SMART por disco alimentan la categoría <em>Disks & I/O</em> del <link>Monitor de salud</link>."
},
"physical": {
"heading": "Physical Disks & SMART Status",
"intro": "Discos internos (SATA / NVMe). Cada fila condensa los campos más útiles de un vistazo:",
"items": [
"<strong>Ruta del dispositivo</strong> — <code>/dev/sda</code>, <code>/dev/nvme0n1</code>.",
"<strong>Insignia de tipo</strong> — SATA / NVMe (y el icono correspondiente).",
"<strong>Insignia System</strong> — etiqueta naranja que marca los discos desde los que se está ejecutando el SO del host. El panel lo deriva de los mountpoints de <code>/</code> y <code>/boot</code>: cualquier disco físico que los aloje recibe la etiqueta <em>System</em> para que no lo borres o reasignes por accidente. Los discos sin la etiqueta son unidades puras de datos.",
"<strong>Modelo</strong> — vendor + cadena del modelo de <code>smartctl -i</code>.",
"<strong>Capacidad</strong> — formateada de forma legible.",
"<strong>Temperatura</strong> — °C actuales, coloreada por el umbral de tipo de disco (NVMe corre más caliente que SATA).",
"<strong>Estado SMART</strong> — passed / failed / unknown.",
"<strong>Insignia de observaciones</strong> — cuando el historial permanente <code>disk_observations</code> tiene entradas no descartadas para este disco, aparece una insignia azul con el recuento (p. ej. <em>3 obs.</em>). Pulsa el disco para entrar y revisarlas.",
"<strong>Insignia de salud</strong> — Healthy / Warning / Critical, derivada del chequeo SMART + observaciones recientes."
],
"clickHint": "La fila entera es pulsable y abre la vista en detalle por disco descrita abajo.",
"warningTitle": "No toques los discos con etiqueta System a la ligera",
"warningBody": "Los discos con la insignia naranja <strong>System</strong> alojan el SO en ejecución. El panel expone la etiqueta como guardarraíl — las acciones destructivas lanzadas desde <link>ProxMenux → Disk Manager → Format / Wipe</link> se niegan explícitamente a actuar sobre ellos. Si de verdad necesitas reasignar el disco de arranque, hazlo desde un entorno de rescate, no desde dentro de Proxmox."
},
"external": {
"heading": "External Storage (USB)",
"body": "Una tarjeta separada para unidades conectadas por USB, solo se renderiza cuando hay al menos una presente. Los mismos campos que los discos internos más una etiqueta naranja <strong>USB</strong>. Las unidades USB suelen aparecer y desaparecer (backups en frío, jobs ocasionales de descarga), así que el Monitor de salud es conservador con ellas — las observaciones se retienen, pero los errores de E/S en una unidad USB desconectada no escalan."
},
"drillIn": {
"heading": "Modal de vista en detalle de disco",
"intro": "Pulsar cualquier fila de disco abre una modal con cuatro pestañas: <strong>Overview</strong> · <strong>SMART</strong> · <strong>History</strong> · <strong>Schedule</strong>. La cabecera siempre muestra la ruta del dispositivo, el modelo + capacidad y la insignia naranja <em>System</em> si aplica.",
"overviewTitle": "Pestaña 1 — Overview",
"overviewImageAlt": "Modal de vista en detalle de disco — pestaña Overview con estado de salud, anillo Wear & Lifetime y atributos SMART rápidos",
"overviewImageCaption": "Pestaña Overview — identidad, insignia de salud, anillo de vida restante con el desgaste actual y los datos escritos, además de un bloque rápido con los atributos SMART más vigilados.",
"overviewIntro": "La pestaña por defecto al entrar — todo lo que necesitas para responder \"¿este disco está bien?\" sin lanzar un test. Tres bloques:",
"overviewItems": [
"<strong>Identity</strong> — modelo, serial, capacidad, insignia Health (Healthy / Warning / Critical).",
"<strong>Wear & Lifetime</strong> — anillo grande de vida restante (97 %, 50 %, …) con el atributo de origen explícito (<em>Media Wearout Indicator</em>, <em>Percentage Used</em>, …), una barra de desgaste (% de consumo actual), una proyección <em>Est. Life</em> en años y los Data Written totales. Los discos NVMe también muestran <em>Available Spare</em>.",
"<strong>SMART Attributes</strong> — seis campos titulares en una rejilla de 2 columnas: Temperature, Power On Hours (con duración humanizada como <em>3y 116d</em>), Rotation Rate (o <em>SSD</em>), Power Cycles, SMART Status, Reallocated Sectors, Pending Sectors, CRC Errors. La tabla de atributos completa vive en la pestaña SMART."
],
"smartTitle": "Pestaña 2 — SMART",
"smartImageAlt": "Modal de vista en detalle de disco — pestaña SMART con botones Run SMART Test (Short / Extended), resultado del último test y la tabla completa de atributos SMART",
"smartImageCaption": "Pestaña SMART — lanza un test Short o Extended, mira el resultado del último test, scrollea la tabla completa de atributos SMART y genera el informe PDF completo de salud.",
"smartIntro": "Donde viven las acciones. Tres secciones:",
"smartItems": [
"<strong>Run SMART Test</strong> — dos botones. <em>Short Test (~2 min)</em> corre síncrono y muestra el resultado inline. <em>Extended Test (background)</em> puede tardar horas en discos grandes, corre en el servidor y dispara una notificación cuando termina.",
"<strong>Last Test</strong> — tipo, insignia de estado (<em>passed</em> / <em>failed</em>) y timestamp de la ejecución más reciente.",
"<strong>SMART Attributes</strong> — la tabla completa de atributos (ID / nombre / valor / worst / estado con iconos OK / warning / critical). Para SATA / SAS, la lista numerada clásica. Para NVMe, los campos estructurados de <code>nvme smart-log</code> (temperatura, available spare, percentage used, data units written / read, host reads / writes, controller busy time, power cycles, unsafe shutdowns, media errors, error-log entries, warning / critical composite temperature time)."
],
"pdfTitle": "View Full SMART Report (PDF)",
"pdfIntro": "Al pie de la pestaña SMART, el botón <strong>View Full SMART Report</strong> genera un PDF imprimible y listo para archivo — el mismo informe estructurado que enviarías a un fabricante para un RMA.",
"pdfPreviewAlt": "Primera página del PDF SMART Health Report generado — Executive Summary con el anillo PASSED + bloque Disk Information",
"pdfPreviewCaption": "Primera página del SMART Health Report — Executive Summary con el anillo PASSED y el bloque Disk Information completo. El PDF completo de abajo lleva el anillo de desgaste SSD, cada atributo SMART y el historial de tests.",
"pdfDownloadLabel": "Descargar informe SMART de ejemplo (PDF)",
"pdfSectionsIntro": "El informe tiene cinco secciones de alto nivel:",
"pdfSections": [
"<strong>Executive Summary</strong> — gran veredicto PASSED / FAILED, párrafo de evaluación de salud del disco en lenguaje claro (\"tu disco está sano / muestra signos de desgaste / está fallando\") y cuatro estadísticas rápidas (timestamp del informe, tipo del último test, resultado del test, atributos comprobados).",
"<strong>Disk Information</strong> — modelo, serial, capacidad, tipo (HDD / SSD / NVMe), familia, form factor, interfaz (SATA 3.3 · 6.0 Gb/s, …), soporte de TRIM, temperatura actual con el umbral óptimo, tiempo de power-on, ciclos de encendido, estado SMART, además de los contadores titulares (pending sectors, CRC errors, reallocated sectors).",
"<strong>SSD Wear & Lifetime</strong> (solo SSD / NVMe) — anillo de vida restante, atributo de origen, nivel actual de desgaste, datos escritos, horas de power-on.",
"<strong>SMART Attributes (full)</strong> — cada atributo que reporta el drive, con ID, nombre, valor, worst, threshold, valor raw y una pastilla de estado. Los más relevantes para el usuario (Reallocated Sector Ct, Power On Hours, Reported Uncorrect, UDMA CRC Error Count, Media Wearout Indicator, …) incluyen una explicación de una línea en lenguaje claro bajo la fila.",
"<strong>Last Self-Test Result + Full Self-Test History</strong> — el último test (tipo, resultado, mensaje de finalización, en qué marca de power-on-hours) más una tabla numerada de cada test retenido.",
"<strong>Recommendations</strong> — items de acción basados en el veredicto: <em>Disk is Healthy / Schedule periodic tests / Backup strategy</em> para discos sanos, lenguaje en escalada con guía de reemplazo cuando los atributos se salen de rango."
],
"pdfOutro": "El PDF se produce en el servidor y se descarga con un patrón de nombre estable (<code>SMART-&lt;short-id&gt;.pdf</code>) para que múltiples snapshots a lo largo del tiempo puedan convivir en tu archivo. Útil cuando estás rastreando degradación a lo largo de meses o enviando evidencia al soporte del fabricante.",
"historyTitle": "Pestaña 3 — History",
"historyImageAlt": "Modal de vista en detalle de disco — pestaña History listando tests SMART pasados con acciones de descarga y borrado",
"historyImageCaption": "Pestaña History — cada test SMART retenido para este disco. Por fila: tipo, timestamp, etiqueta \"X days ago\", marca latest, descargar (salida raw de <code>smartctl</code>) y acciones de borrado.",
"historyIntro": "El pool retenido de tests SMART para este disco — tanto las ejecuciones short como extended que se completaron. Cada entrada es la salida raw de <code>smartctl</code> capturada en tiempo de ejecución, más los campos estructurados que el Monitor parseó para el panel. Acciones por fila:",
"historyItems": [
"<strong>Download</strong> — guarda la salida raw de <code>smartctl -a</code> como un archivo de texto. Idéntico a lo que parsea el informe PDF, útil cuando necesitas la línea exacta que pide un fabricante.",
"<strong>Delete</strong> — elimina el test del historial. El límite de retención fijado en la pestaña Schedule (<em>Last 5 / 10 / 20</em>) borra el más viejo primero automáticamente; esta acción es la sobreescritura manual."
],
"scheduleTitle": "Pestaña 4 — Schedule",
"scheduleImageAlt": "Modal de vista en detalle de disco — pestaña Schedule con el toggle Automatic SMART Tests, la lista de schedules configurados y el botón Add Schedule",
"scheduleImageCaption": "Pestaña Schedule — elige tipo de test, frecuencia y retención; el Monitor lo conecta a <code>cron</code> para que los tests corran sin atención.",
"scheduleIntro": "Tests SMART automáticos guiados por cron, sin shell. La página tiene tres áreas:",
"scheduleItems": [
"<strong>Toggle Automatic SMART Tests</strong> — interruptor global on/off para cada schedule de este disco. Útil cuando quieres pausar todo durante mantenimiento sin perder las definiciones de schedule.",
"<strong>Configured Schedules</strong> — una fila por schedule existente con la insignia de tipo de test (<em>short</em> / <em>long</em>), la expresión cron en forma humana (<em>\"Day 1 of month at 03:00\"</em>, <em>\"Every Sunday at 02:00\"</em>), los discos que cubre y el ajuste de retención.",
"<strong>Add Schedule / Edit Schedule</strong> — formulario con: Test Type (<em>Short ~2 min</em> / <em>Long 1-4 h</em>), Frequency (<em>Daily / Weekly / Monthly</em>), Day of Month / Day of Week, Time, Keep Results (<em>Last 5 / 10 / 20</em>)."
],
"scheduleOutro": "El schedule se materializa como una entrada cron en el host que llama de vuelta al Monitor; los resultados se guardan en el mismo historial SMART mostrado en la pestaña 3, y el ajuste de retención auto-poda el test más viejo cuando termina uno nuevo.",
"tempTitle": "Modal de historial de temperatura",
"tempIntro": "Cada disco que expone un sensor de temperatura tiene sus lecturas muestreadas de forma continua por el Monitor y persistidas a una serie temporal local. El valor actual aparece como uno de los seis atributos SMART titulares en la pestaña Overview; pulsar ese bloque abre una modal dedicada de historial de temperatura con la imagen completa.",
"tempImageAlt": "Modal de historial de temperatura de disco — cabecera con la ruta y modelo del disco, un selector de timeframe (1 Hour / 24 Hours / 7 Days / 30 Days), una fila de cuatro tarjetas de estadísticas (Current / Min / Avg / Max) y una gráfica de línea de la temperatura sobre el rango seleccionado coloreada por los umbrales por tipo de disco",
"tempImageCaption": "Detalle de temperatura — se abre desde la pestaña Overview en cualquier disco cuyo sensor devuelva una lectura no-cero. La gráfica se colorea contra el umbral de tipo de disco (HDD / SSD / NVMe / SAS).",
"tempShowsTitle": "Lo que muestra la modal",
"tempShowsItems": [
"<strong>Selector de timeframe</strong> con cuatro rangos: <em>1 Hour</em>, <em>24 Hours</em> (por defecto), <em>7 Days</em>, <em>30 Days</em>. Cada uno consulta al mismo backend con un downsampling distinto para que la gráfica siga legible en cada horizonte.",
"<strong>Cuatro tarjetas de estadísticas</strong> en lo alto de la modal: <em>Current</em>, <em>Min</em>, <em>Avg</em>, <em>Max</em> para el rango seleccionado. La tarjeta <em>Current</em> se colorea con los mismos umbrales de estado que usan la pestaña Almacenamiento y las notificaciones, para que veas de un vistazo si el disco está en territorio normal / warm / hot.",
"<strong>Gráfica de línea</strong> de la temperatura a lo largo del tiempo, con la línea y el área sombreada coloreadas por tipo de disco:"
],
"tempDiskTypes": [
"HDD — umbrales típicamente más frescos.",
"SSD — umbrales moderados.",
"NVMe — umbrales más altos (NVMe corre más caliente por diseño).",
"SAS — mismos valores por defecto que HDD."
],
"tempConfigurable": "Los cuatro son configurables desde <em>Settings → Health Monitor Thresholds</em>.",
"tempWhyTitle": "Por qué importa aquí un historial",
"tempWhyItems": [
"<strong>Detección de drift.</strong> Los discos que se calientan progresivamente a lo largo de semanas (ventilador fallando, acumulación de polvo, disco vecino muriéndose y empujando aire caliente) son invisibles para una lectura única de \"temperatura actual\". Las vistas de 7 días y 30 días sacan el drift a la superficie.",
"<strong>Correlación de picos.</strong> Cuando una ventana de backup o un rebuild empujaron el disco brevemente por encima de su umbral, los rangos de 1 hora y 24 horas muestran si fue puntual o un patrón recurrente.",
"<strong>Ajuste de umbrales.</strong> Antes de subir o bajar un umbral en <em>Settings → Health Monitor Thresholds</em>, la gráfica de 30 días muestra el rango operativo real del disco para que el nuevo valor encaje con lo que el hardware realmente hace en vez de un cálculo a ojo."
],
"obsTitle": "Historial de observaciones (a lo largo de pestañas)",
"obsIntro": "Los discos modernos fallan de forma gradual. Un disco puede reportar SMART <strong>PASSED</strong> y aún así loguear errores ocasionales de lectura en dmesg, perder enlaces SATA o exponer pending sectors que van y vienen. La UI estándar de Proxmox te muestra el veredicto SMART actual — no mantiene un historial de esas <em>señales</em>. ProxMenux sí, y las expone directamente dentro de la modal de disco.",
"obsImageAlt": "Pestaña Overview de la modal Disk Details mostrando un disco sano con estado SMART Passed, 0 errores reallocated/pending/CRC y una sección Observations listando un evento I/O Error registrado con el mensaje raw del kernel, una traducción humana del código de error ATA, timestamps de primera y última ocurrencia y un contador de ocurrencias",
"obsImageCaption": "Un disco que <strong>SMART dice que está bien</strong> puede aún así tener un historial de observaciones. La tarjeta es la capa de señales histórica bajo el veredicto SMART.",
"obsWhatTitle": "Qué es una observación",
"obsWhatIntro": "Cualquier cosa que ProxMenux capture en el log del kernel, dmesg o salida SMART que parezca un evento a nivel de disco — y que por sí sola sería demasiado granular para una notificación — se registra como una <strong>observación</strong>. Cada fila muestra:",
"obsWhatItems": [
"<strong>Insignia de tipo</strong> (I/O Error, SMART Error, Filesystem Error, ZFS Pool Error, Connection Error).",
"<strong>Mensaje raw del kernel</strong> tal cual apareció en dmesg — útil al copiar y pegar en un buscador o en un ticket de soporte.",
"<strong>Una frase humana</strong> bajo el mensaje raw para códigos ATA conocidos (<code>IDNF</code> → \"Sector address not found — posible bad sector o problema de cable\", <code>UNC</code> → \"Uncorrectable read error — bad sector\", y el resto de códigos estándar).",
"<strong>Timestamps de primera y última ocurrencia</strong>, más un <strong>contador de ocurrencias</strong> deduplicado por signature de error."
],
"obsWhyTitle": "Por qué ProxMenux las registra y las muestra",
"obsWhyItems": [
"<strong>El fallo de disco rara vez es un evento único.</strong> Normalmente empieza con errores esporádicos de bus ATA, algún sector UNC o un par de errores medium semanas antes de que SMART pase a <em>FAILED</em>. Sin persistencia esos avisos tempranos desaparecen de dmesg en el siguiente arranque.",
"<strong>SMART puede mentir.</strong> Un drive puede mostrar todos los atributos en verde y aún así estar a punto de irse — la capa de observaciones captura los síntomas que SMART no expone (en especial ICRC, IDNF, link resets a velocidades SATA más bajas).",
"<strong>Separa \"está pasando ahora\" de \"pasó recientemente\".</strong> El Monitor de salud auto-resuelve errores transitorios en cuanto dejan de dispararse, lo cual es genial para mantener limpia la lista de alertas activas — pero aún quieres ver, días después, que este disco tuvo tres errores de E/S esa noche. La tabla de observaciones es la respuesta.",
"<strong>Alimenta el modelo de notificación por niveles.</strong> El detector disk_io lee la tasa de observaciones de esta tabla para decidir silent / WARNING / CRITICAL (la ventana deslizante de 24h introducida en 1.2.1.2). El historial es lo que hace posible esa clasificación."
],
"obsDedupTitle": "Cómo funcionan dedup y re-notificación",
"obsDedupBody1": "Las observaciones se deduplican por su <strong>signature</strong> — una huella estable del tipo de error, dispositivo y campos clave de la línea del kernel. El mismo evento repitiéndose sube el <code>occurrence_count</code> de la fila existente en lugar de crear una nueva. Una <strong>signature diferente</strong> en el mismo disco crea una nueva observación y se trata como un evento nuevo para efectos de notificación.",
"obsDedupBody2": "Las notificaciones siguen una regla anti-cascada: la primera ocurrencia de una combinación (disco, signature, severidad) dada avisa al operador, y entonces ProxMenux espera 24 horas antes de volver a pingar sobre la misma combinación — aunque el contador siga subiendo. Una severidad escalando (WARNING → CRITICAL) rompe el cooldown para que se le cuente al operador cuando las cosas empeoran, no solo cuando ocurren.",
"obsDismissTitle": "Descartar vs resolver",
"obsDismissBody1": "Cada fila tiene una acción <strong>dismiss</strong>. Descartar una observación le dice a ProxMenux \"ya lo he visto, deja de notificarme\". <strong>No</strong> congela el contador de ocurrencias — si la misma falla sigue pasando, el contador sigue subiendo en background, listo para alertar de nuevo si alguna vez escala a un nivel de severidad o signature diferente. Una observación descartada sigue visible en la tarjeta con un estilo atenuado, para que un operador futuro pueda seguir viendo \"este disco tuvo historial aquí\".",
"obsDismissBody2": "Resolver del lado de error activo (Monitor de salud) es independiente del dismiss de observaciones — la observación persiste más allá del auto-resolve del error activo. Ese es justo el punto: sobrevive, para que un warning transitorio de la semana pasada siga visible hoy en la tarjeta del disco. Mira <link>Monitor de salud</link> para el lado de error activo de la misma imagen."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerSection": "Sección de la pestaña",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"section": "Tarjetas resumen superiores",
"endpoint": "/api/storage/summary",
"source": "Agregado desde <code>lsblk</code>, <code>zpool list</code>, <code>vgs</code> / <code>lvs</code>."
},
{
"section": "Inventario por disco",
"endpoint": "/api/storage",
"source": "<code>lsblk -O</code> + <code>smartctl -i</code> por dispositivo, con caché estable de identidad de disco (limpiado en eventos de hot-plug)."
},
{
"section": "Almacenamientos Proxmox",
"endpoint": "/api/proxmox-storage",
"source": "<code>pvesh get /nodes/&lt;node&gt;/storage</code> con el estado active/online de cada uno."
},
{
"section": "Valores SMART actuales",
"endpoint": "/api/storage/smart/<disk>",
"source": "<code>smartctl -A &lt;dev&gt;</code> — refrescado bajo demanda, no cacheado."
},
{
"section": "Historial de self-tests SMART",
"endpoint": "/api/storage/smart/<disk>/history",
"source": "Almacenado bajo <code>/var/lib/proxmenux-monitor/smart/&lt;disk&gt;/</code> como snapshots JSON."
},
{
"section": "Observaciones permanentes",
"endpoint": "/api/storage/observations",
"source": "Tabla SQLite alimentada por el Monitor de salud cada ciclo (se mantiene tras auto-resolve)."
}
],
"outro": "Verificar la cadena de recolección en el host:",
"codeComment1": "# Traer la snapshot actual desde un script",
"codeComment2": "# Cross-check de lo que ve el panel contra la vista raw del SO"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — la categoría discos y E/S y el modelo de supresión."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tail": " — los endpoints de storage y SMART."
},
{
"label": "Notificaciones",
"href": "/docs/monitor/notifications",
"tailRich": " — qué disparan aguas abajo <code>disk_io_error</code>, <code>storage_unavailable</code> y <code>smart_test_failed</code>."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — el resto de pestañas."
},
{
"label": "ProxMenux → Disk Manager",
"href": "/docs/disk-manager",
"tail": " — la cara de las acciones: format / wipe / SMART tests / importar discos a VMs y CTs desde la TUI."
},
{
"label": "ProxMenux → SMART Disk Health & Test",
"href": "/docs/disk-manager/smart-disk-test",
"tail": " — la contraparte CLI de esta pestaña: programar tests SMART, exportar el JSON que renderiza el panel y la referencia más profunda de tipos de test / interpretación."
}
]
}
}
@@ -0,0 +1,120 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Logs del sistema | ProxMenux Documentation",
"description": "La pestaña Logs del sistema reúne tres fuentes en una sola pantalla: journalctl en vivo con filtros y descarga, historial de tareas de Proxmox (UPIDs) y log de notificaciones — todo buscable, filtrable por severidad / rango temporal y descargable como paquetes de texto."
},
"header": {
"title": "Panel: pestaña Logs del sistema",
"description": "Tres sub-pestañas bajo un mismo techo: el journal del sistema (journalctl con filtros), el historial de tareas de Proxmox y el log de notificaciones. Las tres son buscables, filtrables y descargables como paquetes de texto.",
"section": "ProxMenux Monitor · Panel"
},
"readOnly": {
"title": "Solo lectura por diseño",
"body": "Nada en esta pestaña modifica los archivos de log. Los filtros viven en la URL / estado, las descargas son paquetes generados en el servidor. El panel nunca borra entradas de log — para mantenimiento usa el propio <code>journalctl --vacuum-time=&lt;N&gt;</code> o <code>logrotate</code> del host."
},
"topRow": {
"heading": "Fila superior: cuatro contadores",
"items": [
"<strong>Total Entries</strong> — número de registros dentro de la ventana de filtro activa.",
"<strong>Errors</strong> — recuento de severidad ≤ 3 (<code>err</code> / <code>crit</code> / <code>alert</code> / <code>emerg</code>).",
"<strong>Warnings</strong> — recuento de severidad 4 (<code>warning</code>).",
"<strong>Backups</strong> — recuento de entradas de tareas vzdump / PBS en la misma ventana."
]
},
"subtabs": {
"heading": "Tres sub-pestañas",
"logsTitle": "Logs",
"logsIntro": "El journal del sistema, servido por <code>journalctl</code> en el backend. Filtros disponibles en la barra de herramientas:",
"logsFilters": [
"<strong>Severidad</strong> — emerg / alert / crit / err / warning / notice / info / debug, o cualquier combinación.",
"<strong>Rango temporal</strong> — últimos 5 min / 15 min / 1 h / 6 h / 24 h / 7 d / personalizado.",
"<strong>Búsqueda de texto libre</strong> — substring o regex (<code>journalctl --grep</code>).",
"<strong>Filtro por unidad</strong> — restringir a una unidad systemd concreta (<code>pveproxy.service</code>, <code>nginx.service</code>, …)."
],
"logsRowsAfter": "Cada fila muestra timestamp, insignia de severidad, unidad de origen y el mensaje. Los mensajes largos se colapsan con un conmutador \"mostrar más\". La acción <strong>Download</strong> empaqueta el filtro actual en un único archivo <code>.txt</code> vía <code>GET /api/logs/download</code> — útil cuando quieres compartir un trozo del journal con alguien.",
"logDetailsModalTitle": "Modal Log Details",
"logDetailsBody": "Pulsar cualquier fila abre una modal <strong>Log Details</strong> con cada campo estructurado que journald capturó para esa entrada — la misma vista que construirías a mano ejecutando <code>journalctl --output=verbose</code> en el host.",
"logDetailsImageAlt": "Modal Log Details — una entrada del journal desplegada con Level, Service, Timestamp, Source, Systemd Unit, Process ID, Hostname y el mensaje completo",
"logDetailsImageCaption": "Modal Log Details — cada campo estructurado que journald lleva para esta entrada, con el mensaje íntegro sin truncar al final. Útil para logs de cron y de servicios donde importa la línea de comandos ejecutada.",
"fieldsIntro": "Campos mostrados:",
"fields": [
"<strong>Level</strong> — insignia de severidad coloreada (INFO / WARNING / ERROR / CRITICAL).",
"<strong>Service</strong> — nombre corto de la unidad / proceso que emitió la entrada.",
"<strong>Timestamp</strong> — fecha y hora completas de la línea de log.",
"<strong>Source</strong> — origen de la entrada (journal, kernel, audit, …).",
"<strong>Systemd Unit</strong> — la unidad <code>.service</code> / <code>.timer</code> / <code>.socket</code> real si la entrada estaba asociada a una.",
"<strong>Process ID</strong> — PID del proceso emisor.",
"<strong>Hostname</strong> — útil cuando los journals se reenvían entre nodos de cluster.",
"<strong>Message</strong> — el mensaje completo sin truncar en un bloque monoespaciado, listo para copiar."
],
"maxLevelStoreTitle": "MaxLevelStore de journald",
"maxLevelStoreBody": "En una instalación recién hecha de Proxmox, journald usa por defecto <code>MaxLevelStore=warning</code>, lo que descarta en silencio los mensajes de nivel info. El Monitor lo detecta en el arranque y añade un drop-in (<code>/etc/systemd/journald.conf.d/proxmenux-loglevel.conf</code>) que sube el umbral a <code>info</code> para que la pestaña Logs tenga algo que mostrar en todas las severidades.",
"backupsTitle": "Backups",
"backupsBody": "Historial de tareas de Proxmox filtrado a las entradas relacionadas con backup. Una fila por tarea (<code>vzdump</code>, transferencias PBS, Garbage Collect, Verify) con el estado (OK / WARNINGS / ERROR), el guest implicado, el almacenamiento de origen, la duración y el UPID. Pulsa una fila para cargar el log completo de la tarea vía <code>GET /api/task-log/&lt;upid&gt;</code> — los mismos datos que Proxmox expone a través de <em>Datacenter → Tasks</em>, acotado a backups.",
"notificationsTitle": "Notifications",
"notificationsBody1": "Cada notificación enviada por el Monitor — Telegram, Discord, Email, Gotify, ntfy, Slack, Teams, webhook. Cada fila: timestamp, canal, tipo de evento, severidad, el título renderizado, el cuerpo renderizado y (si IA está activa) un conmutador para ver la reescritura con IA junto al original.",
"notificationsBody2": "Usa esta pestaña para verificar que un canal está entregando de verdad y para comparar lo que produjo la reescritura con IA frente a la plantilla base. La configuración de canales vive en la página detallada de <link>Notificaciones</link>."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerSubtab": "Sub-pestaña",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"subtab": "Logs (filtro en vivo)",
"endpoint": "/api/logs",
"source": "<code>journalctl --output json --since &lt;range&gt;</code> con filtros de severidad / unidad / búsqueda aplicados en el servidor."
},
{
"subtab": "Download",
"endpoint": "/api/logs/download",
"source": "La misma consulta, devuelta como texto plano para grep / less."
},
{
"subtab": "Backups",
"endpoint": "/api/backups",
"source": "Historial de tareas PVE filtrado por <code>vzdump</code>, transferencias PBS, Garbage Collect, Verify."
},
{
"subtab": "Vista en detalle de una tarea de backup",
"endpoint": "/api/task-log/&lt;upid&gt;",
"source": "Log completo de la tarea en texto plano leído de <code>/var/log/pve/tasks/&lt;index&gt;/&lt;upid&gt;</code>."
},
{
"subtab": "Historial de notificaciones",
"endpoint": "/api/notifications/history",
"source": "Tabla SQLite <code>notification_history</code> alimentada por el loop de envío."
}
],
"apiIntro": "Tanto el filtro en vivo como las descargas también son accesibles vía API:",
"codeComment1": "# Última hora de errores y peores, con una keyword",
"codeComment2": "# Descargar el journal completo de las últimas 6 horas como texto plano",
"codeComment3": "# Consultar la salida completa de una tarea concreta por UPID"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — la categoría Logs del sistema que vigila patrones persistentes / picos / cascadas."
},
{
"label": "Notificaciones",
"href": "/docs/monitor/notifications",
"tail": " — el watcher del journal lee la misma fuente y convierte coincidencias en notificaciones."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tail": " — los endpoints logs y task-log con sus parámetros de consulta."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — el resto de pestañas."
}
]
}
}
@@ -0,0 +1,153 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Resumen del sistema | ProxMenux Documentation",
"description": "La pestaña por defecto al abrir ProxMenux Monitor: cuatro tarjetas de métricas (CPU, memoria, VMs y LXCs activos, temperatura) con actualizaciones en vivo y sparkline, la gráfica de métricas históricas y los paneles condensados de Almacenamiento y Red con acceso directo a sus pestañas dedicadas."
},
"header": {
"title": "Panel: pestaña Resumen del sistema",
"description": "La primera pestaña que abre el panel. Cuatro tarjetas de métricas en vivo arriba, la gráfica de métricas históricas en el medio y paneles condensados de almacenamiento / red abajo — todo derivado de las mismas APIs que alimentan las pestañas dedicadas.",
"section": "ProxMenux Monitor · Panel"
},
"readOnly": {
"title": "Un vistazo de solo lectura",
"body": "Nada en esta pestaña es una superficie de control — todos los paneles son informativos. Las acciones viven en las pestañas dedicadas a las que enlazan: entra en Almacenamiento para gestionar discos, en VMs y LXCs para arrancar / parar guests, en la pestaña Seguridad para configurar autenticación, y así sucesivamente."
},
"captureAlt": "Pestaña Resumen del sistema — cuatro tarjetas de métricas (CPU, Memoria, VMs activos, Temperatura), gráfica de métricas del nodo y tarjetas resumen de Almacenamiento / Red",
"captureCaption": "La pestaña Resumen del sistema — la que abre el panel. Las cuatro tarjetas están en vivo, la gráfica de debajo es histórica y las dos tarjetas de abajo resumen Almacenamiento y Red.",
"topRow": {
"heading": "Fila superior: tarjetas de métricas en vivo",
"intro": "Cuatro tarjetas en una rejilla 2×2 en móvil, una sola fila en escritorio. Cada una se actualiza desde <code>/api/system</code> cada pocos segundos.",
"headerCard": "Tarjeta",
"headerWhat": "Qué muestra",
"headerSource": "Fuente",
"rows": [
{
"card": "CPU Usage",
"what": "Porcentaje actual con barra de progreso. Se actualiza cada ~1 s vía el sampler de signos vitales.",
"source": "psutil.cpu_percent()"
},
{
"card": "Memory Usage",
"what": "GB usados, porcentaje, GB totales. La barra de progreso sigue al porcentaje.",
"source": "psutil.virtual_memory()"
},
{
"card": "Active VM & LXC",
"what": "Recuento de guests actualmente en ejecución, con una insignia de desglose Running / Stopped y una línea al pie con los totales de VMs y LXCs.",
"source": "/api/vms (consolidado)"
},
{
"card": "Temperature",
"what": "Temperatura de CPU en °C con insignia de estado (cool / warm / hot) y un sparkline de 5 minutos detrás. Muestra <em>N/A</em> cuando no se detecta sensor. Pulsa para abrir la modal de detalle de temperatura.",
"source": "sensors / coretemp"
}
],
"thresholdsTitle": "Colores de estado y umbrales aplicados aquí",
"thresholdsIntro": "Cada anillo, barra y sparkline en las cuatro tarjetas de métricas sigue la misma clasificación — <green/> <strong>verde</strong> por debajo de Warning, <amber/> <strong>ámbar</strong> entre Warning y Critical, <red/> <strong>rojo</strong> en Critical y por encima. Valores por defecto recomendados que vienen con ProxMenux:",
"thresholdsItems": [
"<strong>Uso de CPU</strong> — Warning 85 %, Critical 95 %.",
"<strong>Memoria</strong> — Warning 85 %, Critical 95 % (el swap también dispara Critical al 5 % usado — un host Proxmox sano apenas debería tocar swap).",
"<strong>Temperatura de CPU</strong> — Warning 80 °C, Critical 90 °C."
],
"thresholdsOutro": "Cada valor es configurable por host — <link>Settings → Health Monitor Thresholds</link> es la fuente única de verdad y explica cómo ajustarlos.",
"sparklineTitle": "El sparkline es significativo",
"sparklineBody": "La tarjeta de temperatura dibuja una traza de 5 minutos bajo el valor, con la línea y el degradado siguiendo el mismo par Warning/Critical documentado arriba. Es la forma más rápida de ver si el host está en escalada térmica sin abrir la modal de detalle."
},
"middle": {
"heading": "Medio: gráficas de métricas del nodo",
"body1": "Bajo la fila superior se encuentra el componente <code>NodeMetricsCharts</code> — gráficas históricas de CPU, memoria y E/S de disco tomadas del propio almacén RRD de Proxmox vía <code>/api/node/metrics</code>. Un selector de timeframe alterna entre <em>1 hora / 24 horas / 7 días / 30 días / 1 año</em>; la resolución de los datos baja a medida que crece la ventana para que la gráfica se mantenga fluida.",
"body2": "Son las mismas gráficas que la UI web de Proxmox renderiza para un nodo, simplemente consolidadas en el tema oscuro del Monitor y alineadas con el resto de paneles."
},
"bottom": {
"heading": "Fila inferior: resúmenes de Almacenamiento y Red",
"storageTitle": "Tarjeta Storage Overview",
"storageIntro": "Una vista condensada del estado de almacenamiento del host, dividida en tres bloques:",
"storageItems": [
"<strong>Total Node Capacity</strong> — suma de todos los almacenamientos de VM/LXC más el almacenamiento local de sistema, con una barra de progreso en degradado del reparto total usado / libre.",
"<strong>Total Capacity / Physical Disks</strong> — titular de capacidad bruta y el recuento de discos físicos descubiertos.",
"<strong>VM/LXC Storage</strong> — usado / libre / porcentaje para los almacenamientos donde viven los guests, más un contador cuando hay más de uno configurado.",
"<strong>Local Storage (System)</strong> — el propio mount raíz / sistema del host, separado del pool de guests."
],
"storageDrillIn": "La vista en detalle vive en la <link>pestaña Almacenamiento</link> — SMART por disco, detalles de pool ZFS, historial de observaciones, etc.",
"networkTitle": "Tarjeta Network Overview",
"networkBody1": "La línea superior muestra el recuento de interfaces activas (físicas + bridges combinados). Debajo, dos filas de insignias coloreadas para las interfaces en <code>up</code> — NICs físicas en azul, bridges en un color secundario. Un selector de timeframe arriba a la derecha (1 hora / 24 horas / 7 días / 30 días / 1 año) controla una pequeña gráfica de tráfico RX / TX.",
"networkBody2": "La vista en detalle por interfaz (IP/MAC, gráfica RRD, miembros del bridge, modo del bond, etc.) vive en la <link>pestaña Red</link>."
},
"refresh": {
"heading": "Modelo de refresco",
"intro": "Cada panel gestiona su propio estado de carga (<code>loadingStates.cpu</code>, <code>loadingStates.storage</code>, …) para que una fuente lenta no bloquee al resto. Mientras un panel está obteniendo datos, muestra un skeleton con animación pulse; los fetchs fallidos degradan con elegancia — por ejemplo, un sensor de temperatura ausente renderiza la tarjeta como <em>N/A</em> en vez de un error.",
"items": [
"<strong>Tarjetas de métricas superiores</strong> — refresco cada ~5 s. Los paneles de CPU y temperatura también reciben un push de 1 s del sampler de signos vitales.",
"<strong>Gráfica de métricas del nodo</strong> — refresco cada 30 s, o al cambiar de timeframe.",
"<strong>Tarjeta de almacenamiento</strong> — refresco cada 60 s. Los datos SMART se cachean más tiempo (la pestaña Almacenamiento dispara una lectura fresca bajo demanda).",
"<strong>Tarjeta de red</strong> — refresco cada 5 s en el timeframe activo.",
"<strong>Refresco manual</strong> — el botón Refresh en la cabecera fuerza a todos los paneles a recargar inmediatamente."
]
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerCard": "Tarjeta",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"card": "Pastilla de estado de la cabecera",
"endpoint": "/api/health",
"source": "El estado global cacheado que produce el Monitor de salud en cada ciclo."
},
{
"card": "CPU / RAM / Swap / Uptime",
"endpoint": "/api/system",
"source": "<code>/proc/stat</code>, <code>/proc/meminfo</code>, <code>/proc/uptime</code> con muestreo de CPU en ventana corta."
},
{
"card": "Info del host (kernel, BIOS, distro)",
"endpoint": "/api/info",
"source": "<code>uname -a</code>, <code>dmidecode</code>, versión de PVE. Cacheado por proceso."
},
{
"card": "Tarjetas de almacenamiento / red / VMs",
"endpoint": "/api/storage/summary, /api/network/summary, /api/vms",
"source": "Mira las pestañas dedicadas para cada una. Las tarjetas de la cabecera muestran una vista compactada de los mismos endpoints."
},
{
"card": "Cadencia de refresco",
"endpoint": "—",
"source": "CPU / red 5 s; almacenamiento / VMs 30 s; info estática cada 5 min. El botón Refresh de la cabecera fuerza una recarga inmediata en todos los paneles."
}
],
"codeComment1": "# Llamada única que alimenta la pastilla de la cabecera",
"codeComment2": "# pública, sin token",
"codeComment3": "# Snapshot autenticada que usan las tarjetas"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — la modal detrás de la pastilla de estado de la cabecera (diez categorías, descartes, supresión)."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tail": " — los endpoints system, info y health."
},
{
"label": "Notificaciones",
"href": "/docs/monitor/notifications",
"tail": " — cómo los mismos estados se convierten en mensajes de Telegram / Discord / Email."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — las otras ocho pestañas de un vistazo."
},
{
"label": "Arquitectura",
"href": "/docs/monitor/architecture",
"tail": " — los hilos en background y las APIs que alimentan esta vista."
}
]
}
}
@@ -0,0 +1,169 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña Terminal | ProxMenux Documentation",
"description": "Shell en el navegador al host Proxmox: hasta 4 terminales a la vez con vista en rejilla, ayudas de teclado para móvil (ESC, TAB, flechas, combinaciones con Ctrl), una chuleta de comandos integrada con cheat.sh, protegida con JWT."
},
"header": {
"title": "Panel: pestaña Terminal",
"description": "Una sesión real de shell en el navegador, sobre el host Proxmox. Hasta cuatro terminales a la vez, ayudas de teclado para móvil, una chuleta de comandos integrada — todo en el mismo tema que el resto del panel.",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "Un PTY real en el navegador",
"body": "El terminal asigna una PTY del lado del servidor a través de <code>flask_terminal_routes</code>, la canaliza por un WebSocket hacia <code>xterm.js</code> en el navegador y se ejecuta como <code>root</code> (el usuario de la unidad systemd). Cualquier cosa que puedas hacer en <code>ssh root@&lt;host&gt;</code> funciona aquí — incluidos <code>vim</code>, <code>tmux</code>, herramientas ncurses y las CLIs de Proxmox (<code>qm</code>, <code>pct</code>, <code>pvesh</code>, <code>pvecm</code>)."
},
"singleAlt": "Pestaña Terminal de ProxMenux Monitor — una única sesión de terminal mostrando el resumen del sistema de Fastfetch al hacer login",
"singleCaption": "Un terminal del host abierto — la barra de arriba muestra el recuento (<em>1 / 4 terminals</em>), <em>+ New</em>, <em>Search</em>, <em>Clear</em> y <em>Close</em>. Las ayudas de teclado para móvil aparecen bajo el terminal en dispositivos táctiles.",
"target": {
"heading": "Destino de la conexión",
"body1": "La pestaña Terminal abre una shell en el <strong>propio host Proxmox</strong> — el mismo login que obtendrías por SSH. Cada pestaña abre un terminal del host completamente nuevo.",
"body2": "Para llegar a un <strong>contenedor LXC</strong> desde el navegador, usa el botón <em>Console</em> dedicado en cada tarjeta de CT en ejecución de la <link>pestaña VMs y LXCs</link>. Abre una modal que ejecuta <code>pct enter &lt;vmid&gt;</code> y reutiliza la misma barra para móvil descrita abajo."
},
"fourTerminals": {
"heading": "Hasta cuatro terminales a la vez",
"intro": "La pestaña te permite abrir hasta cuatro terminales del host simultáneamente. Cada uno obtiene su propia PTY y su propio WebSocket — son sesiones totalmente independientes. Dos layouts se alternan con los iconos junto al botón \"New\":",
"items": [
"<strong>Vista en pestañas</strong> — un terminal visible a la vez, los demás como pestañas nombradas arriba (<em>Terminal 1</em>, <em>Terminal 2</em>…). Ideal para trabajar en una tarea con el resto en background.",
"<strong>Vista en rejilla</strong> — todos los terminales abiertos visibles a la vez en una rejilla 2×2. Útil para vigilar <code>htop</code> en un panel, <code>iftop</code> en otro y editar en un tercero sin saltar entre ellos."
],
"outro": "La barra muestra el recuento actual (<em>1/4 terminals</em>, <em>4/4 terminals</em>). Las nuevas pestañas se abren con <strong>+ New</strong> y las individuales se cierran desde la pequeña <code>×</code> en la cabecera de la pestaña. El botón rojo grande <strong>Close</strong> de arriba derriba todos los terminales a la vez."
},
"gridAlt": "Pestaña Terminal de ProxMenux Monitor — vista en rejilla con cuatro terminales del host ejecutando ls, configuración de red, iftop y el menú principal de ProxMenux uno al lado del otro",
"gridCaption": "Vista en rejilla (4 / 4 terminals) — cuatro PTYs del host independientes corriendo en paralelo: listado de directorio, <code>/etc/network/interfaces</code> en un lado, <code>iftop</code> en otro y el menú principal de ProxMenux en el cuarto. Alterna entre rejilla y pestañas con el conmutador de layout en la barra.",
"keyboard": {
"heading": "Ayudas de teclado para móvil",
"intro": "Los teclados de móvil y tablet normalmente no exponen ESC, TAB, las flechas ni combinaciones con modificadores. Sin ellos, navegar por <code>vim</code>, <code>nano</code>, <code>htop</code> o cualquier menú TUI es imposible. La pestaña Terminal lo resuelve renderizando una fila de botones táctiles bajo el terminal siempre que el dispositivo sea suficientemente pequeño o tenga capacidad táctil:",
"headerButton": "Botón",
"headerSends": "Envía",
"headerUse": "Uso típico",
"rows": [
{
"button": "ESC",
"sends": "\\x1b",
"use": "Salir del modo insertar en <code>vim</code>, cancelar un diálogo TUI, abandonar una búsqueda."
},
{
"button": "TAB",
"sends": "\\t",
"use": "Autocompletado de rutas, navegación de campos en dialog/whiptail."
},
{
"button": "↑ ↓ ← →",
"sends": "\\x1bO[ABCD]",
"use": "Historial de la shell, movimiento del cursor, navegación de menús."
},
{
"button": "↵ Enter",
"sends": "\\r",
"use": "Confirmar. Algunos teclados en pantalla cambian Enter por Go/Done — este botón es inequívoco."
},
{
"button": "Ctrl ▾",
"sends": "Desplegable",
"useRich": true
}
],
"ctrlIntro": "Tres secuencias de control:",
"ctrlItems": [
"<code>Ctrl+C</code> — cancelar / interrumpir el comando en ejecución (<code>\\x03</code>).",
"<code>Ctrl+X</code> — salir de <code>nano</code> (<code>\\x18</code>).",
"<code>Ctrl+R</code> — búsqueda inversa en el historial de bash (<code>\\x12</code>)."
],
"modalTitle": "Misma barra en la modal de consola LXC",
"modalBody": "La consola del contenedor que lanzas desde <link>VMs y LXCs → Console</link> renderiza las mismas ayudas de teclado bajo la modal. La modal además auto-tipea <code>pct enter &lt;vmid&gt;</code> al conectar, para que aterrices directamente dentro del contenedor."
},
"lxcAlt": "Modal de consola LXC de ProxMenux Monitor — Terminal: ubuntu (ID: 103) con la misma barra para móvil (ESC, TAB, flechas, Enter, Ctrl) bajo el terminal",
"lxcCaption": "La modal de consola LXC — abierta desde <em>VMs y LXCs → Console</em>. La cabecera muestra el contenedor de destino (<em>Terminal: ubuntu (ID: 103)</em>) y la misma barra táctil aparece bajo el terminal.",
"search": {
"heading": "Search Commands — chuleta integrada",
"intro": "El botón azul <strong>Search</strong> de la barra abre una modal con búsqueda difusa de comandos. Escribe unas letras de cualquier comando de Linux o Proxmox (<code>ls</code>, <code>tar</code>, <code>qm</code>, <code>pct</code>, <code>zpool</code>, <code>systemctl</code>…) y la modal lista ejemplos de uso con <em>Send to active terminal</em> de un solo toque. Elimina el viaje de ida y vuelta \"espera, ¿qué flag era esa?\" a otra pestaña del navegador.",
"modalAlt": "Modal Search Commands de ProxMenux Monitor — búsqueda difusa de comandos de Linux y Proxmox con cheat.sh, mostrando varios ejemplos de uso de ls",
"modalCaption": "La modal Search Commands consultando <code>ls</code> — cada resultado muestra el comando, su descripción y una pequeña flecha \"send\" que lo canaliza al terminal activo. La esquina inferior derecha indica la fuente de los datos (<em>Powered by cheat.sh</em>).",
"aboutLabel": "Sobre cheat.sh:",
"aboutBody": "es una chuleta unificada de código abierto y curada por la comunidad que agrega ejemplos cortos y prácticos de uso para cientos de comandos de Linux, herramientas de sysadmin y lenguajes de programación. Diseñada originalmente para consultarse desde un terminal con <code>curl cheat.sh/&lt;command&gt;</code>, también es accesible desde cualquier navegador. ProxMenux Monitor pasa las consultas por un proxy en el servidor para que la modal siga funcionando bajo el mismo origen que el panel.",
"headerSource": "Fuente",
"headerWhen": "Cuándo se usa",
"headerWhat": "Lo que ves",
"onlineLabel": "(online)",
"onlineWhen": "Cuando el host tiene acceso a internet y el proxy de cheat.sh responde.",
"onlineWhat": "Varios ejemplos del mundo real por comando, tipeados con su descripción encima. El punto de estado en la cabecera de la modal es <green>verde</green>.",
"fallbackLabel": "Fallback local",
"fallbackWhen": "Cuando cheat.sh no está disponible (host offline, firewall restrictivo, caída de cheat.sh).",
"fallbackWhat": "Una lista empaquetada de comandos comunes de Linux + Proxmox. Catálogo más pequeño pero siempre disponible. El punto de estado es <red>rojo</red>.",
"sendingNote": "<strong>Cómo funciona el envío</strong>: pulsar la pequeña flecha \"send\" junto a un resultado reenvía el texto del comando al terminal que esté activo en ese momento (la pestaña enfocada, o la última en la que pulsaste en la vista en rejilla). La modal se cierra automáticamente para que puedas darle a Enter inmediatamente."
},
"auth": {
"heading": "Autenticación",
"items": [
"El upgrade WebSocket lleva el JWT en la cabecera <code>Authorization</code>. Si la autenticación está activa y el token falta o ha caducado, la conexión se rechaza con HTTP 401 antes de asignar una PTY.",
"Si el Monitor está detrás de un reverse proxy, el proxy debe reenviar los upgrades WebSocket. Mira la página <link>Acceso y autenticación</link> para snippets de Nginx / Caddy / Traefik."
]
},
"clipboard": {
"heading": "Portapapeles, scrollback y resize",
"items": [
"<strong>Copiar / pegar</strong> — usa el portapapeles nativo del navegador. Selecciona texto con el ratón / trackpad y usa el atajo del SO (<code>Cmd+C</code> en macOS, <code>Ctrl+Shift+C</code> en Linux/Windows). Los escritorios Linux también soportan pegar con el botón central del ratón.",
"<strong>Scrollback</strong> — rueda / scroll con dos dedos. xterm.js mantiene las últimas varios miles de líneas en memoria.",
"<strong>Resize</strong> — el terminal renegocia el tamaño de ventana de la PTY cuando redimensionas el panel del dashboard, así <code>htop</code> y <code>vim</code> renderizan bien.",
"<strong>Reconexión al recuperar foco de la pestaña</strong> — si cambias de app en móvil o tablet (comportamiento habitual en iPad), el WebSocket normalmente caería. La pestaña Terminal detecta el cambio de visibilidad y reconecta automáticamente al volver, con un timeout de 15 segundos para rutas VPN lentas."
]
},
"disconnect": {
"heading": "Causas de desconexión",
"intro": "Las razones más comunes por las que termina una sesión y qué hacer con cada una:",
"headerCause": "Causa",
"headerFix": "Solución",
"rows": [
{
"cause": "JWT de sesión caducado (ventana de 24 h).",
"fix": "Refresca la página y vuelve a hacer login. El terminal no está pensado para sesiones desatendidas, así que el tiempo de vida del JWT coincide con el del login normal del panel."
},
{
"cause": "Timeout de idle del reverse proxy.",
"fix": "Sube <code>proxy_read_timeout</code> en Nginx o el equivalente en Caddy / Traefik (snippets en Acceso y autenticación)."
},
{
"cause": "Móvil o tablet en sleep.",
"fix": "Cuando el dispositivo despierta, la pestaña auto-reconecta (timeout de 15 s para rutas VPN). Si no lo hace, recarga la pestaña."
},
{
"cause": "Reinicio del servicio en el host.",
"fix": "Cualquier reinicio de <code>proxmenux-monitor.service</code> tira todas las PTY. Abre nuevos terminales una vez el panel termine de recargar."
}
]
},
"warning": {
"title": "El terminal es una shell de root sobre el host",
"body": "El terminal hereda la identidad de la unidad systemd (<code>root</code>) y por tanto tiene privilegios totales sobre el host Proxmox. Configura un usuario, contraseña y 2FA en <authLink>Acceso y autenticación</authLink> antes de exponer el panel más allá de tu red local: cualquiera que llegue al puerto 8008 sin autenticación aterrizaría directamente en una shell de root — sin prompts adicionales, sin credenciales SSH. Para acceso desde fuera de la LAN, enruta el panel a través de <gatewayLink>Secure Gateway</gatewayLink> (Tailscale) o un reverse proxy con HTTPS, en lugar de abrir el puerto a la internet pública."
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Acceso y autenticación",
"href": "/docs/monitor/access-auth",
"tail": " — snippets de reverse proxy incluyendo las líneas de upgrade WebSocket que requiere el terminal."
},
{
"label": "Arquitectura",
"href": "/docs/monitor/architecture",
"tail": " — el transporte WebSocket (HTTP vía flask-sock vs HTTPS / WSS vía gevent)."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tail": " — los endpoints WebSocket /ws/terminal y /ws/script/<sid> junto al resto de la API."
},
{
"label": "Integraciones → Secure Gateway",
"href": "/docs/monitor/integrations",
"tail": " — cuando quieres acceso al terminal desde fuera de la LAN sin exponer el puerto 8008."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tail": " — el resto de pestañas."
}
]
}
}
@@ -0,0 +1,248 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel: pestaña VMs y LXCs | ProxMenux Documentation",
"description": "La pestaña VMs y LXCs inventaría cada guest del host con uso de CPU / memoria / disco en vivo. La vista en detalle por guest muestra configuración, recursos, backups, logs completos del guest, notas y controles Start / Shutdown / Reboot / Stop."
},
"header": {
"title": "Panel: pestaña VMs y LXCs",
"description": "El inventario completo de guests del nodo. Cuatro métricas titulares arriba, una lista ordenable con cada VM y LXC abajo y una vista en detalle por guest con config, recursos, backups, logs y los cuatro controles de ciclo de vida (Start / Shutdown / Reboot / Stop).",
"section": "ProxMenux Monitor · Panel"
},
"intro": {
"title": "La superficie de control para guests",
"body": "El resto de pestañas son de solo lectura; esta es desde la que actúas. Todo lo que cambia el estado de un guest pasa por <code>POST /api/vms/&lt;vmid&gt;/control</code> con una confirmación explícita y la respuesta se refleja de vuelta en la fila del guest. No hay force-shutdown sin pasar por el botón Stop dedicado."
},
"topRow": {
"heading": "Fila superior: cuatro tarjetas de estadísticas",
"intro": "Al abrir la pestaña VMs y LXCs aterrizas en un resumen de cuatro tarjetas del estado de los guests — totales, utilización de CPU, compromiso de memoria vs capacidad del host y asignación de disco.",
"imageAlt": "Pestaña VMs y LXCs — fila superior de cuatro tarjetas de estadísticas: Total VMs & LXCs, Total CPU, Total Memory, Total Disk",
"imageCaption": "Fila superior de la pestaña VMs y LXCs — totales + insignias Running / Stopped, utilización actual de CPU, memoria desglosada en used / running-allocated / total-allocated (con una insignia Within Limits) y espacio de disco asignado.",
"headerCard": "Tarjeta",
"headerWhat": "Qué muestra",
"totalLabel": "Total VMs & LXCs",
"totalWhat": "Recuento total con dos insignias — <em>X Running</em> (verde) y <em>Y Stopped</em> (rojo, solo cuando > 0). El número que miras cuando algo no volvió tras un reinicio.",
"cpuLabel": "Total CPU",
"cpuWhat": "Utilización agregada de CPU en vivo a lo largo de todos los guests como porcentaje de la CPU física del host, con una línea al pie <em>\"Allocated CPU usage\"</em>.",
"memoryLabel": "Total Memory",
"memoryIntro": "Tres lecturas apiladas verticalmente:",
"memoryItems": [
"<strong>Currently used</strong> — valor grande (p. ej. <em>15.4 GB</em>) más <em>X.X % de Y GB</em> contra la RAM total del host. Una barra de progreso azul sigue al porcentaje.",
"<strong>Running allocated</strong> + <strong>Total allocated</strong> — suma de <code>maxmem</code> a lo largo de los guests que están <em>actualmente up</em> junto a la misma suma a lo largo de <em>todos</em> los guests incluyendo los parados. El primero importa hoy; el segundo importa cuando arrancas todo a la vez.",
"<strong>Insignia Within Limits</strong> (verde) — pasa a <em>Over-committed</em> si el total asignado excede la RAM del host. Un over-commit sano de memoria está bien en hosts con KSM, pero la insignia es el aviso temprano cuando ya no es cómodo."
],
"diskLabel": "Total Disk",
"diskWhat": "Suma del espacio de disco asignado a lo largo de todos los guests, en la unidad adecuada (GB / TB), con la línea al pie <em>\"Allocated disk space\"</em>."
},
"inventory": {
"heading": "Lista Virtual Machines & Containers",
"intro": "Una fila por guest. La lista se nutre de una única fuente, <code>/api/vms</code>, que consolida <code>qm list</code> + <code>pct list</code> + <code>pvesh /cluster/resources</code> en el host.",
"imageAlt": "Lista Virtual Machines & Containers — una fila por guest con estado, insignia de tipo, nombre, ID y porcentajes inline de CPU / memoria / disco",
"imageCaption": "El layout optimizado para móvil del inventario — los mismos datos que muestra la vista de escritorio, reapilados en una sola columna con los porcentajes e indicadores de estado compactos.",
"rowsIntro": "Cada fila muestra:",
"rows": [
"<strong>Icono de estado</strong> — play verde (running) o cuadrado rojo (stopped). Para guests parados, el resto de la fila se atenúa para que veas al instante qué está offline.",
"<strong>Insignia de tipo</strong> — <em>LXC</em> (cian) para contenedores, <em>VM</em> (morado) para máquinas virtuales.",
"<strong>Nombre</strong> — hostname / nombre de display del guest.",
"<strong>VMID</strong> — el ID numérico de Proxmox bajo el nombre.",
"<strong>Métricas inline</strong> — tres porcentajes con su icono (CPU %, Memory %, Disk %). Cada icono se pone naranja cuando la métrica cruza un umbral de atención (p. ej. memoria por encima del 90 %), así un vistazo rápido te dice qué guest está bajo presión sin abrirlo."
],
"clickHint": "Pulsar cualquier fila — running o stopped — abre la modal de vista en detalle descrita abajo.",
"mobileTitle": "La lista está construida mobile-first",
"mobileBody": "En móviles y ventanas estrechas el inventario reflowea a una única columna con insignia de tipo, nombre, ID y los tres porcentajes de métricas, uno por línea — exactamente la captura de arriba. En viewports más anchos los mismos datos se reparten horizontalmente con más espacio para los porcentajes. De cualquier modo, cada fila es el mismo target completo: pulsa para entrar."
},
"drillIn": {
"heading": "Modal de vista en detalle por guest",
"intro": "La modal abre con una cabecera que muestra el nombre del guest, VMID, insignia de tipo (LXC / VM), insignia de estado (RUNNING / STOPPED / …) y el uptime actual. Bajo la cabecera hay <strong>dos pestañas</strong> — <em>Status</em> y <em>Backups</em> — y una barra de acciones fija al pie de la modal con los cuatro controles de ciclo de vida (Start / Shutdown / Reboot / Force Stop) y, en contenedores LXC en ejecución, un botón Console.",
"statusTitle": "Pestaña 1 — Status",
"statusImageAlt": "Modal de vista en detalle por guest — pestaña Status con tarjetas en vivo de CPU / Memoria / Disco, totales de E/S de disco y red, el logo de distro del SO y el bloque Resources / IP Addresses",
"statusImageCaption": "Pestaña Status — CPU / Memoria / Disco en vivo con barras de progreso arriba, totales de E/S acumulados (lectura/escritura de disco, descarga/subida de red) abajo, después el bloque estático Resources con expansiones de Notes y + Info y la lista de pastillas IP Addresses.",
"statusIntro": "La pestaña por defecto — la vista \"¿este guest se está portando?\". Tres bloques:",
"liveTitle": "1. Fila de métricas en vivo",
"liveItems": [
"<strong>CPU Usage (X cores)</strong> — porcentaje actual con barra de progreso. La cabecera muestra el recuento de cores configurado para que sepas qué significaría un 100 %.",
"<strong>Memory</strong> — <em>used / max</em> en GB con barra de progreso.",
"<strong>Disk</strong> — <em>used / max</em> a lo largo de la imagen de disco primaria del guest, misma forma."
],
"ioTitle": "2. Totales de E/S + logo del SO",
"ioItems": [
"<strong>Disk I/O</strong> — totales acumulados de lectura (↓) y escritura (↑) desde el arranque. Útil para detectar un guest que se ha vuelto de repente intensivo en E/S comparado con su baseline.",
"<strong>Network I/O</strong> — descarga (↓) y subida (↑) acumuladas. Misma idea en el lado de red.",
"<strong>Logo de distro del SO</strong> — el icono de Debian / Ubuntu / Alpine / Windows / etc. detectado del tipo de SO del guest. Una pista visual rápida cuando scrolleas varias modales abiertas."
],
"resourcesTitle": "3. Bloque Resources",
"resourcesIntro": "La configuración del guest tal como la ve Proxmox — CPU Cores, Memory (<code>maxmem</code> configurado), Swap. Dos botones colapsables en la cabecera del bloque:",
"resourcesItems": [
"<strong>Notes</strong> — el campo de descripción del guest. Editable: escribir aquí y guardar llama <code>PUT /api/vms/&lt;vmid&gt;/config</code> y escribe de vuelta en <code>/etc/pve/qemu-server/&lt;vmid&gt;.conf</code> o <code>/etc/pve/lxc/&lt;vmid&gt;.conf</code>.",
"<strong>+ Info</strong> — campos extra que son demasiado verbosos para la vista por defecto: bios mode, machine type, agent state, entradas de hostpci passthrough, mount points (CT), boot order."
],
"ipsTitle": "4. IP Addresses",
"ipsBody": "Lista de pastillas con cada dirección IPv4 / IPv6 que el guest expone actualmente — pastilla verde por dirección. Vacía cuando el guest está parado o cuando el QEMU agent no está instalado en una VM (los LXCs siempre reportan direcciones directamente).",
"mountsTitle": "Pestaña 2 — Mounts (solo LXC)",
"mountsImageAlt": "Modal de vista en detalle LXC — pestaña Mounts listando cada mount point que está usando el contenedor: volúmenes PVE, host binds, binds desde almacenamiento PVE y montajes ad-hoc NFS/CIFS que el operador montó desde dentro del CT. Cada tarjeta lleva una insignia de tipo, barra de capacidad, bytes used/total, opciones de montaje y un punto de estado por color (verde sano, ámbar readonly/divergente, rojo stale)",
"mountsImageCaption": "Pestaña Mounts — solo se renderiza para contenedores LXC, y solo cuando hay al menos un mount point o un montaje remoto ad-hoc presente. Un CT sin mounts no recibe pestaña.",
"mountsIntro": "La propia UI de Proxmox muestra las entradas de mount-point definidas en la config del contenedor (<code>mpX</code>) pero se queda ahí — cualquier cosa que montes desde dentro del CT después (<code>mount.cifs</code>, NFS vía <code>autofs</code>, …) es invisible. Esta pestaña funde <strong>ambas vistas</strong>: los mounts configurados <strong>y</strong> los mounts en runtime que ProxMenux sonda desde dentro del contenedor, con un estado de salud por mount y una barra de capacidad cuando el backend la puede resolver.",
"mountTypesTitle": "Tipos de mount detectados",
"mountTypesItems": [
"<strong>PVE volume</strong> — respaldado por un almacenamiento gestionado por Proxmox (un subvol ZFS, una entrada de directorio, un Ceph RBD, …). La capacidad viene de las stats del almacenamiento PVE para que la barra coincida con lo que el propio Proxmox muestra.",
"<strong>Bind from PVE storage</strong> — entrada <code>mpX</code> apuntando a una ruta en un almacenamiento conocido por PVE.",
"<strong>Bind from host</strong> — entrada <code>mpX</code> apuntando a una ruta arbitraria del host (<code>/mnt/something</code>). La capacidad es el <code>df</code> de esa ruta del host.",
"<strong>Ad-hoc inside CT</strong> — mount que <em>solo</em> existe en el namespace de mounts del contenedor (p. ej. un share NFS que el CT monta por su cuenta). La capacidad se lee vía <code>pct exec &lt;vmid&gt; df</code>, que es la única forma de verla — <code>/proc/&lt;pid&gt;/root</code> desde el host no expone las stats reales del mount remoto."
],
"mountStateTitle": "Punto de estado por tarjeta y avisos",
"mountStateItems": [
"<green/> <strong>Verde</strong> — mount sano y alcanzable.",
"<amber/> <strong>Ámbar</strong> — divergente (configurado pero no montado en realidad), read-only o <em>zombie bind</em> (el origen en el host fue retirado pero el CT sigue viendo el bind como montado — típico cuando se desconectó una unidad USB o hubo un <code>umount</code> manual en el host).",
"<red/> <strong>Rojo</strong> — stale: la sonda de runtime no pudo alcanzar el mount (común con exports NFS cuyo servidor está caído)."
],
"mountsCalloutTitle": "Lo que esto te da sobre la UI nativa",
"mountsCalloutBody": "Una vista veraz y consciente de la capacidad de cada sitio donde el contenedor lee o escribe. Shares NFS o CIFS montados desde dentro del CT — invisibles para la UI web de Proxmox — aparecen aquí con el mismo aspecto y la misma sonda de salud que cualquier mount point configurado. Mounts remotos stale y zombie binds salen marcados antes de que muerdan durante un backup.",
"backupsTitle": "Pestaña 3 — Backups",
"backupsImageAlt": "Modal de vista en detalle por guest — pestaña Backups con la lista de backups disponibles, etiqueta de destino, tamaños y el botón Create Backup",
"backupsImageCaption": "Pestaña Backups — cada backup almacenado en los almacenamientos Proxmox configurados para este guest, ordenados de más nuevo a más viejo. La cabecera de la pestaña lleva la insignia de recuento.",
"backupsIntro": "Lista cada backup almacenado en los almacenamientos Proxmox configurados para este guest, ordenados de más nuevo a más viejo. El título de la pestaña lleva una insignia de recuento para que veas de un vistazo si el guest está backupeado. Por fila:",
"backupsItems": [
"<strong>Timestamp</strong> — fecha y hora de la ejecución.",
"<strong>Etiqueta de destino</strong> — el almacenamiento donde vive (PBS-Cloud, PBS-Local, NFS-Backup, …) coloreada por estado.",
"<strong>Size</strong> — tamaño final en disco del backup."
],
"backupsOutro": "El botón <strong>+ Create Backup</strong> arriba a la derecha arranca una nueva ejecución en el almacenamiento marcado como \"Backup target\" en la config de almacenamiento de Proxmox. El restore vive en la UI web de Proxmox — el Monitor expone la vista \"¿este guest tiene backup reciente?\", no el flujo de recuperación.",
"updatesTitle": "Insignia de updates (solo LXC)",
"updatesImageAlt": "Modal de vista en detalle LXC — insignia violeta pulsable 'updates available' en la cabecera de un contenedor que tiene updates pendientes de apt o apk. Pulsarla expande un panel listando cada paquete actualizable con sus versiones actual y objetivo, más un contador security-only cuando el repo subyacente marca alguno como security",
"updatesImageCaption": "La insignia solo aparece en contenedores LXC en ejecución que tengan al menos un paquete actualizable. Pulsa para abrir la lista de paquetes dentro de la modal — no hay pestaña separada en la barra de navegación.",
"updatesIntro": "ProxMenux sondea cada contenedor en ejecución del host una vez al día y cuenta los paquetes actualizables. Soportado actualmente en esta fase: <strong>Debian / Ubuntu</strong> vía <code>apt list --upgradable</code> y <strong>Alpine</strong> vía <code>apk list -u</code>. Los contenedores corriendo otras distribuciones (CentOS, Arch, …) se omiten por ahora — no muestran insignia en lugar de un cero engañoso.",
"updatesPanelTitle": "Lo que muestra el panel",
"updatesPanelItems": [
"<strong>Recuento total de actualizables</strong> arriba, más un contador <strong>security</strong> separado cuando el repositorio subyacente marca alguno de los paquetes como security (suite \"-security\" de Debian/Ubuntu). Alpine no expone una suite security separada vía metadatos de apk, así que security siempre es 0 en contenedores Alpine.",
"<strong>Lista por paquete</strong> con nombre, versión actual y versión objetivo. Úsala para decidir si lanzar la actualización ahora o esperar a una ventana de mantenimiento."
],
"updatesScopeTitle": "Qué rastrea el sistema vs qué cuenta el script",
"updatesScopeBody": "Este detector de actualizaciones sigue lo que ya hay instalado dentro del contenedor — <strong>no</strong> instala nada nuevo y <strong>no</strong> sabe de aplicaciones desplegadas fuera de apt / apk (un contenedor Docker corriendo dentro del LXC, un Vaultwarden instalado desde fuente, un binario soltado en <code>/usr/local/bin</code>). Es una vista de <em>gestor de paquetes</em>, no una vista de <em>aplicación</em>. Las fases futuras de este trabajo integrarán metadatos de aplicación de community-scripts para que el seguimiento upstream por app (Vaultwarden, Jellyfin, …) sea posible.",
"updatesToggleTitle": "Detección vs notificación — semántica del toggle",
"updatesToggleCalloutTitle": "La detección siempre está activa; el toggle solo controla la notificación",
"updatesToggleCalloutBody": "La detección de actualizaciones de paquetes en contenedores en ejecución corre incondicionalmente — la insignia aparece en esta modal siempre que haya updates pendientes, independientemente de cualquier otro ajuste. El toggle de notificación <code>lxc_updates_available</code> en <strong>Settings → Notifications</strong> solo controla si se entrega a tus canales un mensaje agrupado \"N CT(s) have pending updates\". Esto mantiene la semántica del toggle consistente con los otros streams de update (driver NVIDIA, driver Coral, optimizaciones ProxMenux): apagar las notificaciones nunca oculta la información en el panel.",
"updatesApplyTitle": "Aplicar las actualizaciones",
"updatesApplyBody": "Abre la shell del contenedor desde la barra de acciones del pie, o usa <code>pct exec &lt;vmid&gt; -- apt full-upgrade -y</code> / <code>pct exec &lt;vmid&gt; -- apk upgrade -y</code> desde el host. El panel reescanea en su ciclo de 24h (o tras el siguiente refresco manual) y la insignia se actualiza.",
"firewallTitle": "Pestaña 5 — Firewall",
"firewallIntro": "Lee el log de firewall de Proxmox por guest directamente del host (sin servicio extra, sin polling). La pestaña siempre está presente en la barra de navegación; el panel decide qué renderizar dependiendo de si el firewall está activo para ese guest y si alguna regla está logueando realmente:",
"firewallItems": [
"<strong>Firewall disabled</strong> — un aviso ámbar explica exactamente dónde activarlo en la UI de Proxmox (<em>&lt;Container|VM&gt; → Firewall → Options</em>) y te recuerda que al menos una regla necesita <code>log: info</code> (o superior) antes de que aparezcan paquetes.",
"<strong>Firewall enabled, no events yet</strong> — pista de estado vacío con el mismo requisito de logging, útil cuando acabas de activar el firewall.",
"<strong>Events present</strong> — un panel monoespaciado scrolleable con las entradas raw coloreadas por acción: <green>ACCEPT</green> (verde), <orange>REJECT</orange> (naranja), <red>DROP</red> (rojo). Una insignia de recuento en la cabecera muestra cuántas entradas hay cargadas en este momento."
],
"firewallRefresh": "Un botón <em>Refresh</em> arriba a la derecha del panel trae las últimas entradas bajo demanda — no hay auto-refresh dentro de la modal, así que la lista es una snapshot del momento en que abriste la pestaña o pulsaste refresh. Los datos vienen del archivo de log por guest que Proxmox escribe bajo <code>/var/log/pve-firewall.log</code> filtrado por VMID, expuesto vía <code>GET /api/vms/&lt;vmid&gt;/firewall/log</code>.",
"firewallCalloutTitle": "¿Por qué tenerlo aquí cuando la UI de Proxmox ya lo muestra?",
"firewallCalloutBody": "Dos razones: elimina el viaje de ida y vuelta a la UI web de Proxmox cuando ya estás inspeccionando un guest desde el panel, y mantiene la misma vista acotada por VMID que usa el resto de la modal — arrancar el guest, comprobar sus mounts, mirar los hits recientes del firewall y pararlo otra vez sin salir del panel. El Monitor nunca edita reglas de firewall; la edición de reglas se queda en la interfaz nativa de Proxmox donde corresponde.",
"actionBarTitle": "Barra de acciones del pie",
"actionBarIntro": "Siempre visible al pie de la modal independientemente de qué pestaña esté activa:",
"consoleItem": "<strong>Console</strong> (solo LXC, running) — abre una modal que ejecuta <code>pct enter &lt;vmid&gt;</code> y te deja dentro del contenedor. La misma fontanería xterm.js + WebSocket que la <link>pestaña Terminal</link> independiente, incluyendo la <strong>barra para móvil</strong> con ESC, TAB, flechas, Enter y las combinaciones Ctrl (Ctrl+C / Ctrl+X / Ctrl+R) bajo el terminal — haciendo la modal usable desde el teclado de un móvil o tablet. Las VMs no exponen un botón Console aquí; usa la consola web de Proxmox (noVNC) para acceso al guest.",
"lifecycleIntro": "Debajo, cuatro botones de ciclo de vida en una rejilla 2×2. Cada uno dispara <code>POST /api/vms/&lt;vmid&gt;/control</code> con la <code>action</code> correspondiente; el estado de enabled depende de si el guest está actualmente en ejecución:",
"headerButton": "Botón",
"headerEnabled": "Habilitado cuando",
"headerAction": "Acción enviada al host",
"lifecycleRows": [
{
"button": "Start",
"color": "green",
"enabled": "El guest está parado.",
"action": "qm start / pct start"
},
{
"button": "Shutdown",
"color": "blue",
"enabled": "El guest está en ejecución.",
"action": "qm shutdown / pct shutdown — graceful, ACPI"
},
{
"button": "Reboot",
"color": "blue",
"enabled": "El guest está en ejecución.",
"action": "qm reboot / pct reboot — reinicio graceful"
},
{
"button": "Force Stop",
"color": "red",
"enabled": "El guest está en ejecución.",
"action": "qm stop / pct stop — apagado en duro"
}
],
"forceStopTitle": "Force Stop es el kill switch, no la opción educada",
"forceStopBody": "<strong>Force Stop</strong> salta la secuencia de apagado del guest — equivalente a tirar del cable de la luz. Usa <strong>Shutdown</strong> cuando el guest responde; recurre a Force Stop solo cuando Shutdown se cuelga y aceptas el riesgo de pérdida de datos de un apagado no coordinado. El botón es rojo y está etiquetado a propósito para que no lo pulses por reflejo."
},
"dataCollected": {
"heading": "Cómo se recopilan los datos",
"headerSection": "Sección de la pestaña",
"headerEndpoint": "Endpoint",
"headerSource": "Fuente",
"rows": [
{
"section": "Lista de inventario",
"endpoint": "/api/vms",
"source": "<code>pvesh get /cluster/resources --type vm</code> para VMs y CTs."
},
{
"section": "Panel de detalle (config, red, discos)",
"endpoint": "/api/vms/<vmid>",
"source": "<code>qm config &lt;id&gt;</code> para VMs / <code>pct config &lt;id&gt;</code> para CTs."
},
{
"section": "Gráfica de métricas por guest",
"endpoint": "/api/vms/<vmid>/metrics",
"source": "Datos RRD de PVE (<code>pvesh get /nodes/&lt;node&gt;/qemu/&lt;id&gt;/rrddata</code>) condensados a una forma amigable para gráficas."
},
{
"section": "Logs recientes de tareas (modal)",
"endpoint": "/api/vms/<vmid>/logs",
"source": "Tareas para ese <code>vmid</code> desde <code>/var/log/pve/tasks/index</code>."
},
{
"section": "Backups disponibles para el guest",
"endpoint": "/api/vms/<vmid>/backups",
"source": "<code>pvesm list &lt;storage&gt;</code> filtrado por VMID."
},
{
"section": "Log de firewall por guest (pestaña Firewall)",
"endpoint": "/api/vms/<vmid>/firewall/log",
"source": "<code>/var/log/pve-firewall.log</code> filtrado por VMID."
},
{
"section": "Botones de power (Start / Stop / Reboot / Shutdown)",
"endpoint": "/api/vms/<vmid>/control",
"source": "<code>qm start|stop|reboot|shutdown</code> o equivalentes <code>pct</code>."
}
],
"codeComment1": "# Cross-check de lo que ve el panel contra PVE",
"codeComment2": "# Inspeccionar la config de un guest concreto tal como la ve la modal",
"codeComment3": "# VM",
"codeComment4": "# CT"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tailRich": " — la categoría VMs y Contenedores (boot fallido, timeouts QMP, fallos de shutdown de CT)."
},
{
"label": "Notificaciones",
"href": "/docs/monitor/notifications",
"tailRich": " — qué disparan aguas abajo los eventos <code>vm_*</code>, <code>ct_*</code>, <code>migration_*</code> y <code>backup_*</code>."
},
{
"label": "Referencia de la API",
"href": "/docs/monitor/api",
"tailRich": " — los endpoints de VM y backup."
},
{
"label": "Índice del panel",
"href": "/docs/monitor/dashboard",
"tailRich": " — el resto de pestañas."
},
{
"label": "ProxMenux → Create VM",
"href": "/docs/create-vm",
"tailRich": " — la cara de provisión: plantillas de System NAS (Synology y otros), VMs Linux / Windows, valores por defecto pensados para Proxmox."
}
]
}
}
@@ -0,0 +1,369 @@
{
"meta": {
"title": "Monitor de salud de Proxmox — CPU, memoria, almacenamiento, SMART, ZFS, logs | ProxMenux",
"description": "Monitorización proactiva de salud de Proxmox VE: diez categorías escaneadas cada cinco minutos (CPU y temperatura, memoria y swap, almacenamiento, discos/SMART, red, VMs, servicios, logs, actualizaciones, seguridad), cuatro niveles de severidad, duraciones de supresión por categoría, limpieza automática de errores resueltos, un historial permanente de observaciones de disco y el camino desde un evento crudo a una notificación a Telegram, Discord, Gotify o email.",
"ogTitle": "Monitor de salud de Proxmox — CPU, memoria, almacenamiento, SMART, ZFS, logs",
"ogDescription": "Monitorización proactiva de salud de Proxmox VE a través de diez categorías con niveles de severidad, duraciones de supresión y notificaciones dirigidas por eventos.",
"twitterTitle": "Monitor de salud de Proxmox | ProxMenux",
"twitterDescription": "Monitorización proactiva de salud de Proxmox VE a través de diez categorías con niveles de severidad y notificaciones."
},
"header": {
"title": "Monitor de salud",
"description": "El auto-chequeo continuo que escanea diez categorías de estado del host en un ciclo de cinco minutos, muestrea signos vitales continuamente entre ciclos, deduplica hallazgos en un stream de eventos estructurado, y alimenta el panel, el motor de notificaciones y el reescritor opcional de IA desde una única fuente de verdad.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Un escáner, tres consumidores",
"body": "Un hilo de fondo ejecuta el ciclo completo de salud cada 5 minutos, persiste cada hallazgo en SQLite bajo un <code>error_key</code> estable, y deja que <strong>(1)</strong> el panel renderice el estado actual, <strong>(2)</strong> el motor de notificaciones reparta los eventos nuevos a los canales configurados y <strong>(3)</strong> el asistente opcional de IA reescriba las alertas en lenguaje natural. Configuras el escáner una vez; todo lo de aguas abajo se mantiene en sync."
},
"howItWorks": {
"heading": "Cómo funciona",
"intro": "El Monitor de salud corre en dos carriles paralelos dentro del proceso del Monitor. Un <strong>muestreador de signos vitales</strong> ligero lee CPU, memoria y temperatura cada pocos segundos para que las condiciones de umbral sostenido se detecten rápido; en paralelo, el <strong>ciclo completo de salud</strong> corre cada cinco minutos y ejercita cada categoría de principio a fin. Ambos carriles convergen en las mismas tablas SQLite — y desde ahí, tres consumidores leen el estado independientemente.",
"scannerTitle": "Del muestreo al hallazgo guardado",
"scannerCaption": "El escáner. Los signos vitales se muestrean rápido para que la presión sostenida de CPU / memoria se detecte antes del siguiente ciclo de 5 min. El ciclo completo lee esos buffers y ejecuta los chequeos más pesados (SMART, estado de pool ZFS, escaneo de journal, salud de servicio, etc.) antes de escribir los hallazgos estructurados a SQLite.",
"scannerArrowLabel": "paso",
"scannerNodes": {
"samplerLabel": "Muestreador de signos vitales",
"samplerDetail": "Uso de CPU 30 s\nMemoria 30 s\nTemperatura 15 s\n→ buffers de historial",
"cycleLabel": "Ciclo completo de salud",
"cycleDetail": "Cada 5 min\nLee buffers\n+ probes en vivo\n(SMART, ZFS,\nservicios, journal…)",
"checksLabel": "Chequeos por categoría",
"checksDetail": "Diez categorías\n(CPU, memoria,\nalmacenamiento, discos,\nred, VMs,\nservicios, logs,\nactualizaciones, seguridad)",
"sqliteLabel": "SQLite",
"sqliteDetail": "tabla errors\n(activos +\ndismissed)\n+ disk_observations\n(historial\npermanente por disco)"
},
"notifTitle": "Del hallazgo guardado al usuario",
"notifCaption": "El camino de la notificación. La misma tabla errors también dirige la vista del panel (listas Active / Dismissed renderizadas en vivo) y la consume la rutina de limpieza al final de cada ciclo para auto-resolver entradas obsoletas — ambas corren desde los mismos datos sin pasar por el dispatcher.",
"notifArrowLabel": "evento",
"notifNodes": {
"errorsLabel": "tabla errors",
"errorsDetail": "Filas activas +\ndismissed\nclaveadas por\nerror_key",
"dispatcherLabel": "Dispatcher de notificaciones",
"dispatcherDetail": "Eventos nuevos +\nescalados encolados\nA través de toggles\n+ cooldown",
"templatesLabel": "Templates + reescritura con IA",
"templatesDetail": "Template\npor evento\n→ reescritura\nopcional con IA\nen lenguaje natural",
"channelsLabel": "Canales",
"channelsDetail": "Telegram\nDiscord\nGotify\nEmail (SMTP)"
}
},
"categories": {
"heading": "Las diez categorías",
"imageAlt": "Vista del Monitor de salud mostrando las diez categorías con sus estados actuales (CPU, Memoria, Almacenamiento, Discos, Red, VMs, Servicios, Logs, Actualizaciones, Seguridad)",
"imageCaption": "Vista del Monitor de salud — las diez categorías con su estado actual. Las categorías en un host sano todas muestran OK; warnings y eventos críticos aparecen inline con las filas que los produjeron.",
"intro": "Cada ciclo ejercita diez checkers independientes. Cada uno produce uno de cuatro estados (<strong>OK</strong>, <strong>INFO</strong>, <strong>WARNING</strong>, <strong>CRITICAL</strong>) más un payload estructurado — nombres de dispositivo, líneas de log de muestra, umbrales exactos — que aparecen en el panel y viajan hasta el cuerpo de la notificación.",
"headerCategory": "Categoría",
"headerChecks": "Sub-chequeos",
"headerEvents": "Eventos típicos",
"rows": [
{
"category": "CPU y Temperatura",
"checks": "Uso de CPU con histéresis, temperatura de sensor",
"events": "Carga sostenida alta; temperatura de CPU cruzando los umbrales warning / critical del fabricante."
},
{
"category": "Memoria y Swap",
"checks": "Uso de RAM, uso de swap",
"events": "Presión de memoria sostenida; actividad del OOM-killer; swap agotado."
},
{
"category": "Almacenamiento",
"checks": "Almacenamientos Proxmox, sistema de archivos raíz",
"events": "Almacenamiento offline (servidor NFS inalcanzable, credenciales CIFS caducadas); montaje raíz > 90 %; pool LVM thin cerca de lleno."
},
{
"category": "Discos y SMART",
"checks": "SMART, errores I/O en dmesg, pools ZFS, LVM, errores de filesystem",
"events": "SMART health failed; sectores reasignados / pendientes; errores I/O ATA; pool ZFS DEGRADED / FAULTED; remontaje de ext4 en solo lectura."
},
{
"category": "Red",
"checks": "Conectividad, estado de enlace, latencia al gateway",
"events": "Bridge o bond down; gateway inalcanzable; picos persistentes de latencia."
},
{
"category": "VMs y Contenedores",
"checks": "Comunicación QMP, arranque de VM, arranque de contenedor",
"events": "Boot de VM fallido; fallo de shutdown de CT; timeout de socket QMP; configuración / disco faltante tras un clone."
},
{
"category": "Servicios PVE",
"checks": "<code>pveproxy</code>, <code>pvedaemon</code>, <code>pvestatd</code>, <code>pve-cluster</code>, modo cluster",
"events": "Servicio caído; cluster quorum perdido; <code>pmxcfs</code> bloqueado."
},
{
"category": "Logs del sistema",
"checks": "Errores persistentes, picos de errores, cascadas de errores, mensajes críticos del kernel",
"events": "Errores idénticos repetidos; ráfaga súbita de warnings (patrón cascada); <code>BUG:</code> / <code>OOPS:</code> / <code>oom-killer</code> en dmesg."
},
{
"category": "Actualizaciones del sistema",
"checks": "Actualizaciones pendientes, actualizaciones de seguridad, kernel / versión de PVE, antigüedad del sistema",
"events": "Actualizaciones de seguridad disponibles; kernel pinneado varias versiones menores por detrás; uptime del host > 90 días."
},
{
"category": "Seguridad y Certificados",
"checks": "Intentos de login, certificados caducando, estado del jail Fail2Ban opcional",
"events": "Fallos repetidos de autenticación SSH / web; certificado PVE a < 30 días de caducar; bans activos de Fail2Ban."
}
]
},
"severity": {
"heading": "Modelo de severidad",
"headerStatus": "Estado",
"headerColour": "Color",
"headerMeaning": "Significado",
"headerNotification": "Notificación",
"rows": [
{
"status": "OK",
"colour": "Verde",
"meaning": "Sano. Sin hallazgos en esta categoría.",
"notification": "Silencioso."
},
{
"status": "INFO",
"colour": "Azul",
"meaning": "Condición transitoria o ya resuelta que merece la pena mencionar una vez. También se usa para categorías que tienen <em>solo</em> items dismissed restantes.",
"notification": "Opcional. Cada tipo de evento se puede activar o desactivar por canal."
},
{
"status": "WARNING",
"colour": "Amarillo",
"meaning": "Se necesita atención pero el host sigue funcional. La causa no es trivial — lee los detalles.",
"notification": "Se envía cuando el toggle por evento está activado para el canal."
},
{
"status": "CRITICAL",
"colour": "Rojo",
"meaning": "Funcionalidad rota o posible pérdida de datos. Acción requerida.",
"notification": "Se envía cuando el toggle por evento está activado para el canal. La temperatura de CPU CRITICAL se trata como alerta de seguridad que re-dispara incluso si se hizo dismiss previamente."
}
],
"infoNote": "Una categoría que está <strong>OK</strong> pero tiene eventos dismissed todavía dentro de su ventana de supresión se renderiza como <strong>INFO</strong> — para recordarte que algo está siendo silenciado en vez de que nunca hubo nada mal.",
"unknownTitle": "UNKNOWN, cuando un chequeo no puede completar",
"unknownBody": "Un chequeo que falla en producir un veredicto durante tres ciclos seguidos (un probe que caduca, un sensor que ha desaparecido, una herramienta que sale con error) se registra internamente como <code>UNKNOWN</code>. El panel lo muestra como un estado amarillo — la vista global capa el <code>UNKNOWN</code> a <strong>WARNING</strong> para que nunca escale un host sano a CRITICAL por sí solo."
},
"dashboardView": {
"heading": "La vista del panel",
"intro": "El Monitor de salud vive dentro de la pestaña <strong>Overview</strong>. La pildora de estado de la cabecera (Healthy / Warning / Critical) abre un modal que divide los hallazgos en dos listas:",
"items": [
"<strong>Active</strong> — cada categoría con un hallazgo sin resolver. Cada fila expande para mostrar los chequeos individuales que produjeron el estado, la cadena <code>reason</code> cruda, el dispositivo o VM ID involucrado, y (para categorías que enlazan a una pestaña) un click-through a Almacenamiento / Red / VMs / Logs / Hardware para investigar.",
"<strong>Dismissed</strong> — items previamente reconocidos por el usuario que aún están dentro de su ventana de supresión. Cada fila muestra cuánto queda de la supresión y la duración configurada. Cuando la ventana caduca, el item desaparece de esta lista; si la condición subyacente sigue presente y la categoría soporta re-firing, reaparece en <em>Active</em>."
],
"pillTitle": "La pildora refleja la peor categoría",
"pillBody": "El color de la cabecera del panel es la severidad más alta entre las diez categorías: cualquier CRITICAL → rojo, si no cualquier WARNING → amarillo, si no cualquier INFO → azul, si no verde. La misma lógica dirige el punto del favicon y el badge del PWA."
},
"dismiss": {
"heading": "Hacer dismiss de alertas y la Suppression Duration",
"intro": "Algunos eventos son ruidosos por naturaleza — un <em>System Updates: actualizaciones pendientes disponibles</em> permanece cierto hasta que parches el host, y no quieres una notificación cada cinco minutos durante una semana. El Monitor de salud resuelve esto con dos mecanismos acoplados:",
"step1": "<strong>Acción Dismiss por evento</strong> en el modal. El botón Dismiss abre un dropdown con tres opciones — <strong>24 horas</strong>, <strong>7 días</strong> o <strong>Permanently</strong> — que te permite elegir cuánto tiempo se silencia esta alerta concreta independientemente del valor por defecto de la categoría. Elegir una llama a <code>POST /api/health/acknowledge</code> con el <code>error_key</code> y el <code>suppression_hours</code> escogido (<code>-1</code> para permanente). El evento se mueve a la lista Dismissed con un <code>acknowledged_at</code> con timestamp.",
"dropdownImageAlt": "Dropdown de Dismiss sobre una alerta del Monitor de salud — 24 horas, 7 días o Permanently",
"dropdownImageCaption": "Dropdown Dismiss por evento. La ventana elegida aplica solo a esta alerta; si no eliges ninguna por evento se usa el valor por defecto de la categoría. Los dismisses permanentes se marcan con un badge ámbar distinto <em>Permanent</em> en la lista Dismissed y no se re-disparan.",
"step2": "<strong>Ajuste de Suppression Duration por categoría</strong>. Desde la card Settings → Health Monitor (o <code>POST /api/health/settings</code>), cada una de las diez categorías tiene su propia ventana por defecto, aplicada cuando se hace un Dismiss sin elegir ventana por evento:",
"imageAlt": "Card Settings → Health Monitor con los dropdowns de supresión por categoría y la sección Active Suppressions",
"imageCaption": "Card Health Monitor — un dropdown por categoría fija los valores por defecto para nuevos dismisses; la sección Active Suppressions debajo lista todas las alertas actualmente silenciadas (ver más abajo).",
"outro": "Mientras un evento está suprimido, el escáner sigue corriendo y actualiza el timestamp <code>last_seen</code> de la fila, pero no se despacha ninguna notificación nueva y el panel se mantiene calmado. Cuando la ventana caduca, el siguiente ciclo reevalúa la condición y o bien re-dispara fresco o, si la condición se ha aclarado por sí sola, retira la fila de las listas.",
"activeSuppressionsTitle": "Revisar y revertir dismisses — el panel Active Suppressions",
"activeSuppressionsBody": "Cada alerta actualmente silenciada (time-limited y permanente) aparece en <strong>Settings → Health Monitor → Active Suppressions</strong>. Cada fila muestra el identificador de la alerta, categoría, severidad, cuándo se descartó y cuánto tiempo le queda, más un botón <strong>Re-enable</strong> que limpia el reconocimiento para que la alerta pueda volver a disparar en el próximo escaneo. Los dismisses permanentes solo se pueden revertir desde aquí; los time-limited también se pueden revivir a la fuerza sin esperar a la cuenta atrás. La acción Re-enable está protegida por el modo <em>Edit</em> del Health Monitor arriba de la card — pulsa Edit, haz clic en Re-enable en cada fila que quieras revivir (las filas en cola muestran un borde verde y el identificador tachado) y luego pulsa Save para confirmar. Cancel descarta la cola.",
"autoTitle": "Auto-supresión cuando cambias la Duration",
"autoBody": "Poner una Suppression Duration de categoría a cualquier cosa distinta del valor por defecto de 24 h tiene un segundo efecto más allá de los dismissals iniciados por el usuario: <strong>los futuros hallazgos en esa categoría entran en la tabla ya reconocidos</strong> con esa duración. Esto es por diseño — si le has dicho al Monitor que quieres los eventos de disco silenciados durante una semana, los hallazgos de disco nuevos honran esa intención sin que tengas que hacer dismiss de cada uno a mano. Aparecen directamente en la lista Dismissed con el tiempo restante configurado. Las categorías dejadas en 24 h no se ven afectadas y se comportan de la forma clásica (los hallazgos nuevos aterrizan en Active hasta que actúes).",
"tempTitle": "La temperatura de CPU CRITICAL es el override de seguridad",
"tempBody": "Un hallazgo específico saltea la supresión por completo: <strong>temperatura de CPU CRITICAL</strong>. Si el sensor cruza el umbral crítico, la alerta re-dispara independientemente de cualquier dismissal previo — una CPU achicharrada es una CPU achicharrada. Este es el único override integrado del modelo de dismiss.",
"nonDismissableTitle": "Hallazgos a los que no se les puede hacer dismiss",
"nonDismissableBody": "Un puñado de hallazgos están marcados como no-descartables a propósito — señalan una condición donde silenciar la alerta podría costar datos, hardware o conectividad. El botón Dismiss está oculto para estas filas; la alerta se aclara solo cuando la condición subyacente se recupera y la limpieza auto-resolve la coge. Otros hallazgos (eventos I/O transitorios en un disco sano, estados recuperados) también están marcados no-descartables pero por la razón opuesta: no hay nada que silenciar porque la fila ya es informativa y se auto-aclara.",
"headerFinding": "Hallazgo",
"headerWhy": "Por qué no se puede hacer dismiss",
"rows": [
{
"finding": "Advertencia / crítico de temperatura de CPU",
"why": "Riesgo hardware — sobre-temperatura sostenida daña el silicio. Silenciar dejaría a una CPU achicharrándose pasar desapercibida."
},
{
"finding": "Espacio crítico de filesystem (montaje raíz)",
"why": "Riesgo de pérdida de datos — un raíz lleno impide escrituras y corrompe estado. La alerta debe permanecer visible hasta que liberes espacio."
},
{
"finding": "Pool ZFS DEGRADED / FAULTED",
"why": "Riesgo de integridad de datos — el fallo del pool amenaza cada dataset en él. Silenciar mientras el pool está enfermo nunca es la respuesta correcta."
},
{
"finding": "Errores I/O de disco con SMART FAILED",
"why": "Fallo de unidad confirmado por SMART — enmascarar oculta hardware real muriendo. La alerta se queda hasta que el dispositivo sea reemplazado (o eliminado del host)."
},
{
"finding": "Interfaz de red DOWN",
"why": "Pérdida de conectividad — bridges, bonds e interfaces físicas con tráfico activo deben permanecer visibles. Silenciarlos enmascararía una pérdida de acceso remoto."
},
{
"finding": "Eventos I/O en discos sanos (INFO)",
"why": "Eventos ATA / dmesg transitorios en un disco cuyo SMART dice OK — marcado INFO y auto-aclarándose. Nada que descartar porque el siguiente ciclo ya los retira."
}
],
"principle": "Todo lo demás se puede descartar. El principio es: alertas que indican \"daño real en progreso\" o que ya se han auto-resuelto se mantienen fuera del camino de dismiss; las alertas sobre condiciones sostenidas que puede que quieras reconocer y revisar más tarde (uso alto de CPU, actualizaciones pendientes, certificado cerca de caducar, warnings de log, hipos de arranque de VM, etc.) todas exponen el botón Dismiss."
},
"autoresolve": {
"heading": "Auto-resolución y limpieza",
"intro": "Muchas alertas deberían aclararse solas cuando la condición desaparece — una VM que estaba fallando al arrancar y ahora está corriendo, un disco que ya no está en el sistema, una temperatura que ha bajado a la normalidad. Una rutina de limpieza corre al final de cada ciclo de cinco minutos y aplica estas reglas:",
"headerTrigger": "Disparador",
"headerAction": "Acción",
"rows": [
{
"trigger": "Uso de CPU de vuelta al rango normal tras un warning relacionado con CPU.",
"action": "Marcado como resuelto. Sale de la lista Active."
},
{
"trigger": "Presión de memoria de vuelta por debajo del umbral de warning tras un warning OOM / memoria.",
"action": "Marcado como resuelto."
},
{
"trigger": "VM / CT referenciada por el error ya no existe (<code>qm status</code> / <code>pct status</code> distinto de cero).",
"action": "Marcado como resuelto por recurso eliminado."
},
{
"trigger": "Disco referenciado por el error ya no presente en <code>/dev/</code>.",
"action": "Marcado como resuelto por dispositivo eliminado. El historial permanente de observaciones se preserva (mira la siguiente sección)."
},
{
"trigger": "Hallazgos provenientes del journal (categoría <code>logs</code>, entradas SMART, errores ATA / I/O) cuando su ventana de supresión caduca.",
"action": "Retirados limpiamente. Cada scan inspecciona entradas frescas del journal desde ese punto en adelante; la misma línea histórica en el journal no se re-emite."
},
{
"trigger": "Errores resueltos con más de siete días.",
"action": "Borrados de la base de datos para mantener la tabla pequeña. El historial de notificaciones es independiente y se conserva más tiempo."
}
],
"permanentTitle": "La supresión permanente no es lo mismo que resuelto",
"permanentBody": "Poner una Suppression Duration de categoría a <code>-1</code> (<em>permanente</em>) silencia alertas futuras para items que descartas en esa categoría — pero no salta el chequeo de auto-resolve de arriba. Si la condición subyacente desaparece (recurso borrado, umbral ya no rebasado), el item igualmente se limpia automáticamente."
},
"observations": {
"heading": "Observaciones de disco — el historial permanente",
"intro": "Los eventos de disco son especiales. Un warning SMART en <code>/dev/sdh</code> a las 02:14 AM es algo que quieres recordar incluso después de que la tormenta I/O se calmase y el error se auto-resolviese — el disco tiene ahora un track record. Para ese propósito, el Monitor de salud guarda una tabla <strong>permanente</strong> aparte: <code>disk_observations</code>.",
"headerProperty": "Propiedad",
"headerErrors": "tabla <code>errors</code> (Active)",
"headerObs": "tabla <code>disk_observations</code>",
"rows": [
{
"property": "Propósito",
"errors": "Dirige la vista <em>actual</em> de salud + despacho de notificaciones.",
"obs": "Audit trail permanente por disco."
},
{
"property": "Auto-resolve",
"errors": "Sí — las filas se aclaran cuando la condición desaparece.",
"obs": "No — las entradas persisten para siempre salvo que el usuario las descarte explícitamente."
},
{
"property": "Clave de dedup",
"errors": "<code>error_key</code> (p. ej. <code>smart_sdh</code>).",
"obs": "<code>(disk_registry_id, error_type, error_signature)</code> con firmas estables despojadas de datos volátiles."
},
{
"property": "Dónde se muestra",
"errors": "Modal del Monitor de salud (listas Active / Dismissed).",
"obs": "Tarjeta de detalle de disco en la pestaña <strong>Almacenamiento</strong>, con un badge \"X obs.\" por disco."
},
{
"property": "Qué registra",
"errors": "Lo que esté fallando actualmente.",
"obs": "Warnings SMART (problemas de sector / temperatura / CRC / self-tests fallidos), errores I/O (ATA / NVMe / dm), errores de filesystem, eventos de pool ZFS."
}
],
"outro": "Consecuencia práctica: una alerta puede aclararse del panel mientras el mismo incidente sigue registrado en el historial del disco. Cuando entras a un disco bajo Almacenamiento, la tarjeta muestra el conteo de observaciones pendientes y una lista con timestamps, severidad y el mensaje crudo original — útil cuando estás decidiendo si una unidad necesita reemplazo.",
"renameTitle": "Los renombres entre dispositivos se fusionan automáticamente",
"renameBody": "Los discos a veces aparecen bajo nombres transitorios (<code>ata8</code>, <code>nvme0n1p3</code>) antes de conseguir un nombre estable de block-device. La capa de observaciones consolida entradas por número de serie cuando se conoce: si un evento se registró primero como <code>ata8</code> y el mismo disco se identifica más tarde como <code>sdh</code>, las observaciones históricas se reasocian a <code>sdh</code> en el siguiente ciclo para que el historial no se fragmente."
},
"notification": {
"heading": "De un hallazgo a una notificación",
"intro": "Cada error activo es también un candidato para el motor de notificaciones. El flujo:",
"items": [
"El escáner registra el hallazgo con categoría + severidad + detalles estructurados.",
"Si el tipo de evento está <strong>activado</strong> en los ajustes globales de notificación, y el canal no ha silenciado esta categoría, se encola un evento.",
"El motor de templates renderiza un par (título, cuerpo) desde los detalles estructurados. Si el reescritor de IA está activado, el mismo par también pasa por el proveedor configurado para una versión en lenguaje natural.",
"La implementación del canal lo envía: mensaje de Telegram, embed de Discord, push de Gotify o email. El resultado del despacho se guarda en <code>notification_history</code>.",
"Si un dismiss llega más tarde, la ventana de supresión entra en juego y cualquier re-firing posterior del mismo <code>error_key</code> se queda en la cola hasta que la ventana cierre."
],
"outro": "La configuración de canales (token de bot de Telegram, URLs de webhook, keys de proveedor de IA, toggles por evento, overrides por canal) está documentada en <notifLink>Notifications</notifLink> y <aiLink>Asistente de IA</aiLink>."
},
"rest": {
"heading": "Endpoints REST",
"intro": "Todo lo que hace el modal se puede llamar desde la API — útil para scripts, paneles propios o tu propia integración de chat-bot.",
"headerEndpoint": "Endpoint",
"headerMethod": "Método",
"headerUse": "Uso",
"rows": [
{
"endpoint": "/api/health",
"method": "GET",
"use": "Probe pequeño de salud — devuelve JSON con <code>status</code>, <code>timestamp</code> y <code>version</code>. Adecuado para keyword checks de Uptime Kuma; el receptor debe enviar la cabecera bearer."
},
{
"endpoint": "/api/health/status",
"method": "GET",
"use": "Veredicto global de salud — severidad única + cadena de resumen. Autenticado."
},
{
"endpoint": "/api/health/details",
"method": "GET",
"use": "Las diez categorías con sus estados por categoría y el payload estructurado que produjo cada uno."
},
{
"endpoint": "/api/health/full",
"method": "GET",
"use": "Snapshot completo — categorías + errores activos + lista de dismissed + ajustes de supresión personalizados. Alimenta el modal en un round-trip y usa una caché de fondo de 6 min para respuesta instantánea."
},
{
"endpoint": "/api/health/active-errors",
"method": "GET",
"use": "Solo la lista Active. Filtrable por <code>?category=&lt;name&gt;</code>."
},
{
"endpoint": "/api/health/dismissed",
"method": "GET",
"use": "Solo la lista Dismissed, con las horas de supresión restantes."
},
{
"endpoint": "/api/health/acknowledge",
"method": "POST",
"use": "Body: <code>'{'\"error_key\":\"smart_sdh\"'}'</code>. Descarta una alerta con la ventana configurada de la categoría."
},
{
"endpoint": "/api/health/settings",
"method": "GET / POST",
"use": "Lee o escribe los valores de Suppression Duration por categoría."
},
{
"endpoint": "/api/health/cleanup-orphans",
"method": "POST",
"use": "Limpieza manual de errores cuyo dispositivo / VM subyacente ha desaparecido. Idempotente."
}
],
"codeComment1": "# Snapshot del estado actual de salud para un script",
"codeComment2": "# Descarta un error específico",
"codeComment3": "# Pon la supresión de la categoría discos a una semana"
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Dashboard",
"href": "/docs/monitor/dashboard",
"tail": " — desde donde se abre el modal del Monitor de salud en la UI."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — canales, toggles por evento, el hook de reescritura con IA, historial."
},
{
"label": "Asistente de IA",
"href": "/docs/monitor/ai-assistant",
"tail": " — configuración del proveedor (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter), modo de prompt, nivel de detalle por canal, idioma."
},
{
"label": "Arquitectura",
"href": "/docs/monitor/architecture",
"tailRich": " — el esquema SQLite (<code>errors</code>, <code>disk_observations</code>, <code>events</code>) y la cadencia del hilo de fondo."
}
]
}
}
+151
View File
@@ -0,0 +1,151 @@
{
"meta": {
"title": "ProxMenux Monitor — Panel web autoalojado para Proxmox VE | ProxMenux",
"description": "ProxMenux Monitor es un panel web autoalojado para Proxmox VE: métricas del host en tiempo real, almacenamiento y datos SMART, red, VMs y contenedores, hardware, logs, terminal web integrado, un Health Monitor proactivo, notificaciones a Telegram / Discord / Email, asistente IA opcional, una API REST e integraciones con herramientas como Homepage y Home Assistant.",
"ogTitle": "ProxMenux Monitor — Panel web autoalojado para Proxmox VE",
"ogDescription": "Panel de Proxmox VE en tiempo real: métricas del host, SMART de almacenamiento, red, VMs y contenedores, hardware, logs, terminal web, Health Monitor, notificaciones, asistente IA, API REST.",
"twitterTitle": "ProxMenux Monitor | ProxMenux",
"twitterDescription": "Panel autoalojado de Proxmox VE con Health Monitor, notificaciones, asistente IA y API REST."
},
"header": {
"title": "ProxMenux Monitor",
"description": "Un panel web autoalojado para Proxmox VE distribuido como AppImage. Se ejecuta en el host como un único servicio systemd, escucha en el puerto TCP 8008 y sirve tanto la API como la interfaz desde un único proceso.",
"section": "ProxMenux Monitor"
},
"atGlance": {
"title": "De un vistazo",
"body": "Un único AppImage en el host de Proxmox → backend Flask (puerto 8008) que recoge datos en vivo mediante <code>psutil</code>, <code>pvesh</code>, <code>smartctl</code>, <code>journalctl</code> → panel Next.js servido desde el mismo proceso. Autenticación opcional (contraseña + 2FA), asistente IA opcional, notificaciones opcionales, API REST para integraciones."
},
"hero": {
"alt": "Panel de ProxMenux Monitor — pantalla principal con widgets de CPU, memoria, temperatura y uptime",
"caption": "Pantalla principal por defecto — métricas del host y estado de salud de un vistazo."
},
"coverage": {
"heading": "Lo que cubre el panel",
"intro": "Ocho secciones principales, cada una respaldada por sus propios endpoints de API:",
"tableSection": "Sección",
"tableWhat": "Qué muestra",
"sections": [
{
"name": "Health Monitor",
"description": "Alertas activas y descartadas para CPU, memoria, almacenamiento, discos, red, servicios, logs, VMs, actualizaciones y seguridad. Alimenta el motor de notificaciones."
},
{
"name": "Almacenamiento",
"description": "Pools de almacenamiento de Proxmox, discos físicos (SATA / NVMe / USB), atributos SMART, estado de pools ZFS, desgaste y vida útil, actividad de I/O."
},
{
"name": "Red",
"description": "Todas las interfaces (físicas, bonds, bridges, OVS), IP/MAC/estado, gráficos RX/TX en tiempo real, datos RRD históricos por interfaz."
},
{
"name": "VMs y contenedores",
"description": "Inventario de todas las VMs y LXCs con estado, recursos y uptime. El detalle muestra config, métricas históricas, logs completos del guest y acciones de start/stop/reboot/shutdown."
},
{
"name": "Hardware",
"description": "Modelo y topología de CPU, esquema de memoria, dispositivos PCIe, lista de GPUs con driver y monitorización en tiempo real por slot (NVIDIA / iGPU Intel)."
},
{
"name": "Logs y eventos",
"description": "<code>journalctl</code> en vivo con filtros de severidad / rango temporal / palabra clave, historial de tareas de Proxmox, log de notificaciones, paquetes de logs descargables."
},
{
"name": "Terminal",
"description": "Shell en el navegador hacia el host o cualquier VM/CT, mediante <code>xterm.js</code> sobre WebSockets. Autenticado y auditado igual que el resto de la API."
},
{
"name": "Seguridad",
"description": "Fallos de autenticación, estado de jails de Fail2Ban, eventos de bloqueo recientes, integración con el jail <code>[proxmenux]</code> del host."
}
],
"footer": "Cada sección tiene su propia página de documentación bajo <link>Dashboard</link> en la barra lateral."
},
"howItRuns": {
"heading": "Cómo se ejecuta",
"intro": "ProxMenux Monitor se distribuye como un AppImage autocontenido. Una única unidad systemd (<code>proxmenux-monitor.service</code>) arranca un proceso Flask que:",
"bullets": [
"Escucha en <strong>TCP 8008</strong> en el host (HTTP).",
"Sirve el panel Next.js como activos estáticos bajo <code>/</code> y la API bajo <code>/api/*</code> desde el mismo proceso.",
"Obtiene datos en vivo con herramientas estándar del host: <code>psutil</code>, <code>pvesh</code>, <code>smartctl</code>, <code>journalctl</code>, <code>zpool</code>, <code>ip</code>, <code>nvidia-smi</code>, etc.",
"Persiste su propio estado en una base de datos SQLite local (<code>/usr/local/share/proxmenux/health_monitor.db</code>): alertas descartadas, observaciones de discos, configuración de notificaciones, configuración de IA. El estado de autenticación vive aparte en <code>/root/.config/proxmenux-monitor/auth.json</code>."
],
"footer": "El flujo completo de petición, la disposición de archivos y la integración systemd se describen en <link>Architecture</link>."
},
"noAgent": {
"title": "Sin agente en los guests",
"body": "El Monitor lee todo desde el host. Las VMs y CTs no necesitan ningún agente instalado — los datos del guest provienen de la API de Proxmox y de la visibilidad a nivel de kernel del propio host sobre los guests en ejecución."
},
"access": {
"heading": "Acceder al panel",
"intro": "Se soportan dos patrones de acceso y la aplicación detecta cuál está en uso:",
"codeComment1": "# 1) Acceso directo al host",
"codeComment2": "# 2) Mediante proxy inverso (Nginx / Caddy / Traefik)",
"afterCode": "Cuando hay un proxy inverso por delante, el Monitor respeta <code>X-Forwarded-For</code>, <code>X-Forwarded-Proto</code> y <code>X-Forwarded-Host</code> para que las URLs y CORS funcionen correctamente sin configuración manual.",
"footer": "La configuración inicial, contraseña + TOTP 2FA y snippets de proxy inverso se cubren en <link>Access & Authentication</link>."
},
"mobile": {
"heading": "Uso móvil e instalación en la pantalla de inicio",
"intro": "El panel es responsive y se distribuye como Progressive Web App. El <code>public/manifest.json</code> empaquetado declara <code>display: standalone</code> con nombre, icono y color de tema de la app, por lo que añadir la URL a la pantalla de inicio produce un lanzador autónomo real — sin barra de direcciones, splash personalizada, tema oscuro acorde al panel.",
"phoneAlt": "ProxMenux Monitor en un móvil — vista principal del panel",
"phoneCaption": "Panel principal en un móvil — el layout se adapta a pantallas pequeñas.",
"addHeading": "Añadir a la pantalla de inicio",
"iosLabel": "iOS Safari:",
"iosBody": "botón de compartir → <em>Añadir a pantalla de inicio</em>. El icono viene de <code>/apple-touch-icon.png</code> incluido en el AppImage.",
"androidLabel": "Android Chrome / Edge:",
"androidBody": "menú de tres puntos → <em>Instalar app</em> (o <em>Añadir a pantalla de inicio</em> en versiones antiguas).",
"afterInstall": "Una vez instalado, abrir el icono lanza el panel en modo standalone con su propia entrada en el conmutador de tareas.",
"onlineOnlyTitle": "Solo online",
"onlineOnlyBody": "La PWA es instalable pero <strong>no</strong> funciona sin conexión — no hay service worker. El lanzador se comporta como una app nativa, pero el dispositivo necesita poder llegar al host en TCP 8008 (LAN, VPN o HTTPS tras proxy inverso) para que el panel cargue."
},
"health": {
"heading": "El Health Monitor y las notificaciones",
"alt": "Pantalla del Health Monitor mostrando las 10 categorías rastreadas (CPU, memoria, almacenamiento, discos, red, servicios, logs, VMs, actualizaciones, seguridad) con su estado actual",
"caption": "Vista del Health Monitor — las 10 categorías rastreadas, con su estado actual. Las alertas activas y descartadas aparecen aquí cuando el sistema genera alguna.",
"body1": "Dentro del panel, el <strong>Health Monitor</strong> se ejecuta continuamente en segundo plano y produce un flujo estructurado de eventos: alta temperatura de CPU, avisos SMART de discos, degradación de pools ZFS, OOM kills, fallos de VM/CT, incidentes de seguridad, etc. Cada evento tiene una categoría, una severidad (INFO / WARNING / CRITICAL) y un <code>error_key</code> estable para que los duplicados se colapsen en vez de inundar la pantalla.",
"feedsIntro": "Los eventos alimentan tres cosas al mismo tiempo:",
"feedsHealth": "La <strong>vista del Health Monitor</strong> en el panel (listas de activas + descartadas).",
"feedsChannels": "El <strong>motor de notificaciones</strong> — Telegram, Discord, Email, Gotify y Apprise (multicanal). Cada canal se configura independientemente y se pueden silenciar categorías por evento.",
"feedsAI": "El <strong>asistente IA</strong> opcional — cuando está activado, el proveedor configurado (OpenAI, Anthropic, Gemini, Groq, Ollama u OpenRouter) explica los eventos entrantes en lenguaje claro y propone próximos pasos si está activado en los ajustes de la IA.",
"suppressionTitle": "Supresión en vez de silenciar todo",
"suppressionBody": "Cada categoría tiene su propia <em>duración de supresión</em>: una vez que descartas una alerta, la misma alerta se silencia durante esa ventana (24 horas por defecto, configurable por categoría hasta permanente). Las escalaciones reales — p. ej. la temperatura de CPU cruzando el umbral crítico — siempre se vuelven a disparar independientemente de la supresión."
},
"api": {
"heading": "API REST e integraciones",
"intro": "Todo lo que muestra la interfaz está disponible como JSON sobre HTTP/HTTPS. Los mismos endpoints alimentan widgets de Homepage, sensores de Home Assistant, dashboards de Grafana (vía el exporter Prometheus en <code>/api/prometheus</code>), pruebas de Uptime Kuma y cualquier script personalizado que hable <code>curl</code>.",
"tokens": "Los tokens API de larga duración (365 días) se generan desde <strong>Settings → API Access Tokens</strong> o vía <code>POST /api/auth/generate-api-token</code>.",
"bearer": "Los tokens viajan como <code>Authorization: Bearer …</code>. Los endpoints públicos (<code>/api/health</code>, <code>/api/auth/*</code>) funcionan sin token para que las pruebas externas de uptime puedan llegar al host sin entregar credenciales.",
"catalog": "El catálogo completo de endpoints, la guía de rotación de tokens y las buenas prácticas de seguridad viven en <linkApi>API Reference</linkApi>; los ejemplos listos para Homepage, Home Assistant, Grafana, Uptime Kuma y un patrón genérico de cURL están en <linkIntegrations>Integrations</linkIntegrations>."
},
"serviceControl": {
"heading": "Control del servicio",
"intro": "Día a día, el Monitor se gestiona exactamente como cualquier otro servicio systemd. También está expuesto como dos entradas dentro del TUI de ProxMenux bajo <em>Settings</em>:",
"codeComment": "# Control manual",
"footer": "Mira <link>Settings → ProxMenux Monitor</link> para el conmutador del menú y el flujo de verificación de estado."
},
"nextSteps": {
"heading": "A dónde ir ahora",
"items": [
{
"label": "Architecture",
"description": "— backend Flask, unidad systemd, esquema SQLite, proveedores IA, canales de notificación."
},
{
"label": "Access & Authentication",
"description": "— primer arranque, configuración de contraseña, TOTP 2FA, configuración de proxy inverso, integración con Fail2Ban."
},
{
"label": "Dashboard",
"description": "— cada sección de la interfaz, una página por cada una."
},
{
"label": "API Reference",
"description": "— cada endpoint, forma de petición / respuesta y gestión de tokens."
},
{
"label": "Integrations",
"description": "— Homepage, Home Assistant, Grafana / Prometheus, Uptime Kuma, patrón genérico de cURL."
}
]
}
}
@@ -0,0 +1,255 @@
{
"meta": {
"title": "Integraciones de Proxmox — Homepage, Home Assistant, Grafana, Prometheus | ProxMenux Monitor",
"description": "Guías copia-pega para conectar ProxMenux Monitor con los paneles de tu homelab: Homepage, Home Assistant, Grafana vía Prometheus, Uptime Kuma. Cada guía con la configuración exacta que esperan los paneles, los endpoints de la API usados y el patrón de cabecera de auth.",
"ogTitle": "Integraciones de Proxmox — Homepage, Home Assistant, Grafana, Prometheus",
"ogDescription": "Conjunto de guías para conectar ProxMenux Monitor con Homepage, Home Assistant, Grafana, Prometheus y Uptime Kuma.",
"twitterTitle": "Integraciones de Proxmox | ProxMenux Monitor",
"twitterDescription": "Guías para Homepage, Home Assistant, Grafana, Prometheus y Uptime Kuma."
},
"header": {
"title": "Integraciones",
"description": "Guías copia-pega para conectar ProxMenux Monitor en los paneles y herramientas que tu homelab ya usa — Homepage, Home Assistant, Grafana vía Prometheus, Uptime Kuma. Cada guía muestra la configuración exacta que espera la herramienta receptora, el endpoint del Monitor con el que habla y el patrón de cabecera de auth que lo une todo.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Qué puedes construir desde esta página",
"body": "Cada guía de abajo está lista para copiar a tu herramienta elegida. Los endpoints de la API usados aquí están documentados en la <link>API Reference</link> — esta página es el compañero \"cómo usarlos realmente en Homepage / Home Assistant / Grafana\". Las capturas muestran la salida real que verás una vez la guía esté en su sitio."
},
"auth": {
"heading": "Autenticación: lo único que cada guía necesita",
"intro": "La mayoría de los endpoints usados por estas integraciones están autenticados. Tienes dos formas de satisfacer ese requisito.",
"optAtitle": "Opción A — API token (recomendado para integraciones)",
"optAbody1": "Abre el panel y ve a <strong>Settings → Security → API Tokens</strong>. Pulsa <em>Generate token</em>, dale un nombre (p. ej. <em>homepage</em>, <em>home-assistant</em>, <em>prometheus</em>), y copia el token — se muestra <em>una vez</em>. De larga duración (un año de expiración por defecto), revocable individualmente, y lo que deberías usar para cualquier cliente no-navegador.",
"optAbody2": "A partir de ahí cada petición es simplemente:",
"optBtitle": "Opción B — flujo de login (usuario + contraseña)",
"optBbody": "Útil para scripts que se autentican como un usuario humano. El token devuelto es de corta duración; la mayoría de integraciones deberían preferir la Opción A.",
"outro": "El campo TOTP solo es requerido cuando el 2FA está activado en la cuenta. La rotación de tokens, la revocación, la política de contraseñas y el log de auditoría viven en <link>Access & Authentication</link>.",
"httpsTitle": "Usando HTTPS en lugar de HTTP",
"httpsIntro": "Cada guía de abajo usa <code>http://</code> en las URLs para mantener los ejemplos cortos. Si has activado TLS en el Monitor (<strong>Settings → Security → SSL/HTTPS</strong>), cambia <code>http://</code> por <code>https://</code> en cada URL — ese es el único cambio. Dos notas específicas para ciertas herramientas:",
"httpsItems": [
"<strong>Certificados autofirmados.</strong> La integración <code>rest:</code> de Home Assistant verifica TLS por defecto. Si el Monitor está usando su propio cert autofirmado, añade <code>verify_ssl: false</code> a cada bloque REST (junto a <code>scan_interval:</code>), o importa la CA del Monitor al trust store de HA. Lo mismo para cualquier herramienta que rechace certs no confiables.",
"<strong>Prometheus</strong> ya tiene <code>scheme: https</code> listo en la configuración de scrape de abajo; descomenta / déjalo como <code>https</code> si TLS está activado en el Monitor."
]
},
"homepage": {
"heading": "Homepage",
"headingHref": "https://gethomepage.dev",
"intro": "Homepage es un panel de aplicaciones totalmente estático y personalizable. ProxMenux Monitor se enchufa vía el widget <code>customapi</code> integrado — pega una entrada de servicio en <code>services.yaml</code>, reinicia Homepage y la tarjeta aparece con números en vivo.",
"iconCalloutTitle": "El logo oficial de ProxMenux está en dashboardicons.com",
"iconCalloutBody": "Las guías de abajo usan <code>icon: proxmenux.png</code>. Homepage resuelve automáticamente los nombres de archivo simples contra <a1>dashboardicons.com</a1> — una librería de iconos curada para paneles autoalojados. La entrada de ProxMenux vive en <a2>dashboardicons.com/icons/external/proxmenux</a2> y Homepage la descarga en el primer render. La misma búsqueda funciona para miles de otras herramientas (Telegram, Discord, Grafana, Tailscale, etc.) — basta con escribir <code>icon: &lt;nombre&gt;.png</code> en cualquier entrada de servicio.",
"imageAlt": "Panel Homepage mostrando tres tarjetas de ProxMenux Monitor (EDGE, VOID, DREAM) con uptime, CPU, RAM y temperatura para cada host Proxmox",
"imageCaption": "Tres instancias de ProxMenux Monitor renderizadas como tarjetas Homepage — uptime, CPU, RAM y temperatura de CPU leídas en vivo desde <code>/api/system</code> en cada host cada 10 s.",
"basicTitle": "Widget básico — sin autenticación",
"basicIntro": "Usa esto cuando ProxMenux Monitor esté en una red de confianza y aún no hayas activado la autenticación en el lado del Monitor. La entrada más simple posible en <code>services.yaml</code>:",
"authedTitle": "Widget autenticado",
"authedIntro": "Genera un API token en <strong>Settings → Security → API Tokens</strong> en el Monitor, cópialo y pégalo en la cabecera <code>Authorization</code> de abajo — reemplaza el token de ejemplo mostrado tras <code>Bearer</code> con el que acabas de copiar:",
"authedOutro": "Reinicia Homepage y la tarjeta se enciende con valores en vivo. Reutiliza el mismo token en todos los widgets Homepage que apunten al mismo host de ProxMenux Monitor.",
"multiTitle": "Setup multi-widget — sistema, almacenamiento, red",
"multiIntro": "Para una vista más rica, renderiza tres tarjetas separadas respaldadas por distintos endpoints — una para métricas del sistema, una para almacenamiento, una para red. Usa el mismo token en cada tarjeta; es la misma instancia del Monitor.",
"multiCalloutTitle": "Múltiples hosts Proxmox",
"multiCalloutBody": "Repite el bloque de entrada por host para obtener el layout multi-tarjeta de la captura de arriba — cada entrada apunta a la URL <code>http://&lt;host&gt;:8008</code> de su propia instancia de ProxMenux Monitor. El token puede ser distinto por host (una entrada secret por host) o compartido, según cómo los generes."
},
"homeAssistant": {
"heading": "Home Assistant",
"headingHref": "https://www.home-assistant.io",
"intro": "No hay una integración HACS nativa para ProxMenux Monitor (todavía) — pero no la necesitas. La integración <code>rest</code> integrada en Home Assistant puede consumir cada endpoint documentado en la <link>API Reference</link> y convertir las respuestas en sensores, atributos y triggers. El build de referencia completo de abajo expone ~25 sensores cubriendo recursos del sistema, el Monitor de salud, VMs / CTs, almacenamiento, red, latencia al gateway y estado de actualización de ProxMenux — pega el YAML en <code>configuration.yaml</code>, reinicia y tienes una capa completa de observabilidad de Proxmox dentro de HA.",
"imageAlt": "Panel Home Assistant mostrando entidades de ProxMenux Monitor — badge de estado de salud, gauges de CPU / RAM / Temp, contador de VMs, uso de almacenamiento y contador de errores activos",
"imageCaption": "ProxMenux Monitor como integración de primera clase en Home Assistant — sensores construidos desde la guía YAML de abajo.",
"step1Title": "1 · Guarda el API token",
"step1Body": "Mete el token en el <code>secrets.yaml</code> de Home Assistant para que nunca se filtre en un volcado de config. El prefijo bearer entero va en una línea — eso permite al YAML referenciarlo directamente como valor de cabecera. El nombre y ubicación del archivo depende de tu instalación de HA (típicamente <code>/config/secrets.yaml</code> para HA OS / Container).",
"step2Title": "2 · Añade la configuración REST",
"step2Body": "Seis bloques REST cubren toda la superficie — uno por área principal del Monitor. Cada bloque tiene un <code>scan_interval</code> sensato ajustado a cuán a menudo cambian los datos subyacentes (recursos del sistema cada 30 s, salud cada 60 s, inventarios que cambian despacio cada 5-10 min). Pega en <code>configuration.yaml</code>:",
"step3Title": "3 · Añade sensores binarios y helpers de template",
"step3Body": "Dos sensores binarios y un par de sensores template redondean la integración — hacen que las automatizaciones y las tarjetas condicionales de Lovelace queden mucho más limpias que encadenar Jinja en cada sitio.",
"step4Title": "4 · Recarga y verifica",
"step4Body": "Desde la UI de HA: <em>Developer Tools → YAML → Check Configuration</em> primero para validar la sintaxis, luego recarga <em>All YAML configuration</em> (o reinicia completo). Después de que vuelva, filtra <em>Settings → Devices & Services → Entities</em> por <em>proxmenux</em> — deberías ver las ~25 entidades llenándose dentro de un intervalo de scan.",
"replaceTitle": "¿Reemplazando una versión anterior de esta guía?",
"replaceBody": "Si probaste una versión previa de estos bloques YAML, el registro de entidades de Home Assistant puede haber cacheado los IDs de entidad viejos y entidades obsoletas seguirán apareciendo (con warnings <em>Entidad no encontrada</em> en tus tarjetas Lovelace). Estado limpio en dos pasos: borra los bloques <code>rest:</code> y <code>template:</code> previos de <code>configuration.yaml</code>, recarga, y luego bajo <em>Settings → Devices & Services → Entities</em> filtra por <em>proxmenux</em> y quita cualquier entrada marcada como \"Restored\" o mostrada como indisponible. Luego pega el YAML actual y recarga de nuevo — las entidades nuevas se registran limpiamente.",
"step5Title": "5 · Panel Lovelace",
"step5Body": "El YAML de abajo es una única tarjeta <strong>vertical-stack</strong> que combina todas las sub-tarjetas en un bloque — cabecera con logo, KPIs rápidos, detalle del sistema, VMs, almacenamiento, red y una tarjeta condicional de problemas de salud. Para usarla: abre tu panel, pulsa el lápiz (editar), pulsa <em>Add card</em>, baja al final y elige <em>Manual</em>, luego pega:",
"viewTipTitle": "¿Lo quieres como vista completa de panel en lugar de una sola tarjeta?",
"viewTipBody": "Abre el menú de 3 puntos del panel → <em>Raw configuration editor</em> y añade una vista nueva con esta cabecera (encima de la lista <code>cards:</code> del YAML de arriba):",
"viewTipOutro": "Eso te da una pestaña/vista dedicada en tu panel con su propio icono y título, en vez de una tarjeta larga en una vista existente.",
"altViewTitle": "Alternativa — una vista de panel dedicada",
"altViewIntro": "Si prefieres tener una página dedicada completa (su propia pestaña en la barra lateral del panel) en vez de una tarjeta dentro de una vista existente, Home Assistant te deja crear una vista nueva directamente con YAML. Pasos:",
"altViewSteps": [
"Abre el panel donde quieres la nueva pestaña.",
"Pulsa el lápiz (editar panel) arriba a la derecha.",
"Pulsa la pestaña <em>+</em> al final de las pestañas existentes para crear una vista nueva.",
"En el diálogo que se abre, cambia a la pestaña <em>Code editor</em> (arriba a la derecha del diálogo — alterna entre editor visual y YAML).",
"Pega el YAML de abajo.",
"Guarda. La nueva pestaña <em>ProxMenux Monitor</em> aparece en la barra lateral con todas las tarjetas renderizadas."
],
"twoEditorsTitle": "Dos editores YAML en HA — elige el correcto",
"twoEditorsIntro": "Home Assistant tiene dos editores YAML que parecen similares pero esperan formatos distintos:",
"twoEditorsItems": [
"<strong>Editor de una sola vista</strong> (esta guía) — abierto desde la pestaña <em>+</em> o desde <em>Edit view → Code editor</em>. Espera el cuerpo de una vista directamente: <code>title:</code>, <code>path:</code>, <code>cards:</code> al top level, sin guion inicial.",
"<strong>Editor Raw del panel entero</strong> — abierto desde el menú de 3 puntos del panel. Espera la lista <code>views:</code> entera, con cada vista como item de lista (<code>-</code> inicial)."
],
"twoEditorsOutro": "Pegar YAML de cuerpo de vista en el editor de panel entero (o viceversa) te deja con una <em>Vista sin nombre</em> y <code>cards: []</code>. El YAML de abajo es para el editor de una sola vista — pega exactamente como se muestra.",
"viewImageAlt": "Vista dedicada de Home Assistant renderizando ProxMenux Monitor — cabecera picture-entity, KPIs glance y tarjetas de entidad Sistema / VMs / Almacenamiento / Red distribuidas automáticamente por HA en múltiples columnas",
"viewImageCaption": "La vista dedicada <em>ProxMenux Monitor</em> como la renderiza Home Assistant en una pantalla ancha — el layout por defecto de HA divide las tarjetas en múltiples columnas automáticamente.",
"twoColTipTitle": "¿Quieres un layout fijo de dos columnas en lugar del auto layout?",
"twoColTipBody": "Reemplaza cualquier par de tarjetas (p. ej. <em>Sistema</em> + <em>VMs</em>, o <em>Almacenamiento</em> + <em>Red</em>) con un único <code>horizontal-stack</code> envolviendo ambas, para que siempre se rendericen lado a lado independientemente del ancho de pantalla:",
"twoColTipOutro": "En móvil la fila se mantiene comprimida; el auto layout de HA (sin horizontal-stack) refluye mejor a anchos estrechos.",
"step6Title": "6 · Automatizaciones",
"step6Body": "Tres automatizaciones que cubren los escenarios reactivos más comunes — reemplaza <code>notify.mobile_app_&lt;tu_movil&gt;</code> por el servicio notify que uses:",
"logoTitle": "Sobre el logo de ProxMenux",
"logoBody": "La tarjeta picture-entity en la parte superior del YAML Lovelace descarga el logo oficial de ProxMenux desde <a1>dashboardicons.com</a1> — una librería de iconos gratuita curada para paneles autoalojados. La entrada de ProxMenux vive en <a2>dashboardicons.com/icons/external/proxmenux</a2>. Home Assistant descarga el SVG sobre HTTPS en el primer render y lo cachea.",
"logoBrokenTitle": "Si la tarjeta del logo muestra una imagen rota",
"logoBrokenIntro": "Algunas instalaciones de HA (redes con firewall, bloqueadores de contenido, hosts sin internet pública) no pueden alcanzar jsdelivr.net en el momento del render. El arreglo es una copia local:",
"logoBrokenSteps": [
"Descarga el SVG desde <a>cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/proxmenux.svg</a>.",
"Guárdalo en <code>/config/www/icons/proxmenux.svg</code> en tu host HA.",
"En el YAML Lovelace, reemplaza la URL <code>image:</code> por <code>/local/icons/proxmenux.svg</code>. Guarda y recarga — la imagen se renderiza desde el archivo local, sin internet necesaria."
],
"scanTipTitle": "Regla práctica para scan_interval",
"scanTipBody": "<code>/api/system</code> es barato de llamar — 30 s está bien. <code>/api/health/full</code> usa una caché interna de 6 min, así que hacer polling más a menudo de ~60 s no te aporta nada. <code>/api/storage/summary</code> cambia despacio — cada 5 min sobra. <code>/api/proxmenux/update-status</code> solo importa una vez por hora. Ajusta a tu presupuesto de hardware si tienes muchos sensores en muchos hosts."
},
"grafana": {
"heading": "Prometheus + Grafana",
"promHref": "https://prometheus.io",
"grafanaHref": "https://grafana.com",
"intro": "ProxMenux Monitor expone un endpoint de scrape formato Prometheus en <code>GET /api/prometheus</code> (autenticado) devolviendo texto OpenMetrics. Cabléalo a Prometheus, luego construye un panel Grafana encima — los mismos datos que muestra la UI del panel, en el formato que tu TSDB espera.",
"imageAlt": "Panel Grafana renderizando métricas de ProxMenux Monitor — gauge de uso de CPU, timeseries de uso de memoria, contador de VMs en ejecución, throughput de red",
"imageCaption": "Un panel Grafana básico construido desde el scrape Prometheus de ProxMenux — CPU, memoria, VMs en ejecución, throughput de red. El catálogo completo de métricas vive en la <link>API Reference → Métricas Prometheus</link>.",
"step1Title": "1 · Añade el job de scrape a Prometheus",
"step1Body": "Pasa el API token vía el bloque nativo <code>authorization</code> de Prometheus (más limpio que cabeceras personalizadas y funciona con secret stores):",
"step1After": "Recarga Prometheus (<code>kill -HUP</code> o <code>systemctl reload prometheus</code>, o <code>docker compose restart prometheus</code> si lo corres como contenedor) y comprueba <em>Status → Targets</em> — el job proxmenux debería ponerse verde dentro de un intervalo de scrape. Cada métrica lleva una etiqueta <code>node=\"&lt;hostname&gt;\"</code> para que puedas distinguir hosts en las queries.",
"tokenTipTitle": "Token vía archivo o env, no inline",
"tokenTipBody": "Para despliegues en producción evita poner el token inline. Prometheus soporta <code>credentials_file: /etc/prometheus/secrets/proxmenux.token</code> como alternativa — guarda el token en un archivo 0600 y deja que Prometheus lo lea.",
"step2Title": "2 · Verifica el scrape con un par de queries",
"step2Body": "Antes de configurar Grafana, confirma que Prometheus realmente tiene los datos. Abre la propia UI de Prometheus en <code>http://&lt;host-prometheus&gt;:9090</code>, pulsa <em>Query</em> y ejecuta cualquiera de estas — deberías obtener números en vivo de tu host Proxmox:",
"headerQuery": "Query",
"headerConfirms": "Qué confirma",
"verifyRows": [
{
"query": "up{job=\"proxmenux\"}",
"confirms": "Devuelve <code>1</code> si Prometheus está haciendo scrape del Monitor con éxito, <code>0</code> si no. La comprobación de cordura más rápida."
},
{
"query": "proxmox_cpu_usage",
"confirms": "Porcentaje de uso de CPU actual del host Proxmox. Debería cambiar si refrescas la query con unos segundos de diferencia."
},
{
"query": "proxmox_vms_running",
"confirms": "Número de guests en ejecución. Compara con lo que ves en la UI de Proxmox."
},
{
"query": "proxmox_uptime_seconds / 86400",
"confirms": "Uptime del host en días. Debería coincidir con el valor que verías en <code>uptime</code> en la shell de Proxmox."
}
],
"calloutTitle": "El 401 que puedes ver al pulsar la URL del endpoint es normal",
"calloutBody": "En la página <em>Status → Targets</em>, pulsar el enlace del endpoint (<code>/api/prometheus</code>) hace que tu navegador lo descargue directamente — sin la cabecera bearer que Prometheus usa para sus propios scrapes. Así que verás <code>'{'\"error\":\"Authentication required\"'}'</code>. Eso confirma que la API está correctamente protegida; el propio Prometheus se autentica correctamente porque tiene el token de la configuración de scrape. Confía en el verde <em>State: UP</em>, no en el click-through.",
"step3Title": "3 · Añade Prometheus como fuente de datos en Grafana",
"step3Body": "En Grafana: <em>Connections → Data sources → Add new → Prometheus</em>. Configura la URL a tu instancia de Prometheus (p. ej. <code>http://prometheus.lan:9090</code>), guarda y prueba. No se necesita auth extra en esta capa — Prometheus ya se ha autenticado a ProxMenux.",
"step4Title": "4 · Construye paneles con estas queries PromQL",
"step4Body": "Un set inicial que mapea directamente a lo que los usuarios típicamente vigilan en un host Proxmox:",
"headerPanel": "Idea de panel",
"headerPromql": "Query PromQL",
"panelRows": [
{
"panel": "Gauge de uso de CPU por host",
"promql": "proxmox_cpu_usage"
},
{
"panel": "Gauge de uso de memoria por host",
"promql": "proxmox_memory_usage_percent"
},
{
"panel": "Memoria usada vs total (timeseries)",
"promql": "proxmox_memory_used_bytes / 1024 / 1024 / 1024"
},
{
"panel": "VMs / CTs en ejecución por host",
"promql": "proxmox_vms_running"
},
{
"panel": "Temperatura de CPU",
"promql": "proxmox_cpu_temperature_celsius"
},
{
"panel": "Throughput de red RX (bytes/s)",
"promql": "rate(proxmox_interface_bytes_received_total[5m])"
},
{
"panel": "Throughput de red TX (bytes/s)",
"promql": "rate(proxmox_interface_bytes_sent_total[5m])"
},
{
"panel": "Load average (1m)",
"promql": "proxmox_load_average{period=\"1m\"}"
},
{
"panel": "% espacio en disco usado por mountpoint",
"promql": "proxmox_disk_usage_percent"
},
{
"panel": "Carga de batería de UPS",
"promql": "proxmox_ups_battery_charge_percent"
},
{
"panel": "Temperatura de GPU por slot",
"promql": "proxmox_gpu_temperature_celsius"
}
],
"outro": "Añade cada query como un panel Grafana, configura la visualización adecuada (<em>Stat</em> para gauges, <em>Time series</em> para tendencias) y agrupa paneles en filas por categoría. Usa la etiqueta <code>node</code> como variable de panel (<em>Settings → Variables → New → Query → label_values(proxmox_cpu_usage, node)</em>) para filtrar todos los paneles por host."
},
"uptimeKuma": {
"heading": "Uptime Kuma y otros status checkers",
"href": "https://github.com/louislam/uptime-kuma",
"intro": "Para probes externos, usa <code>GET /api/system-info</code> — es el único endpoint que funciona sin token, devolviendo un payload JSON pequeño con hostname, uptime y el estado global de salud (mapeado a <code>healthy</code> / <code>warning</code> / <code>critical</code>). Eso es exactamente lo que necesita un monitor basado en keyword.",
"kumaTitle": "Uptime Kuma — HTTP keyword monitor",
"kumaSteps": [
"En Uptime Kuma, pulsa <em>+ Add New Monitor</em>.",
"Monitor Type: <em>HTTP(s) - Keyword</em>.",
"Friendly Name: <em>ProxMenux Monitor — pve01</em>.",
"URL: <code>http://pve01.lan:8008/api/system-info</code>.",
"Keyword: <code>healthy</code> (el valor de <code>health.status</code> cuando el host está OK).",
"Heartbeat Interval: 60 segundos basta.",
"Guarda. Sin cabeceras necesarias — el endpoint es público."
],
"healthchecksTitle": "healthchecks.io / pings tipo cron",
"healthchecksBody": "Mismo endpoint, misma forma — apunta tu ping tipo cron a <code>/api/system-info</code> y comprueba <code>.health.status == \"healthy\"</code>. La mayoría de estos servicios aceptan un estado HTTP 2xx como señal de \"up\" también, en cuyo caso incluso un curl sin parsing basta.",
"richTitle": "¿Quieres datos de salud más ricos?",
"richBody": "Para el estado completo (las diez categorías del Monitor de salud + errores activos + lista dismissed), usa <code>GET /api/health/full</code> en su lugar — ese requiere un API token pero te da todo lo que el modal del panel renderiza en una sola respuesta."
},
"workflows": {
"heading": "n8n, Zapier y scripts propios",
"intro": "Para herramientas de workflow y scripts ad-hoc que necesitan <em>levantar</em> notificaciones a través del Monitor (un fallo de CI, un sensor de smart-home, un cron job que tardó demasiado), la guía es un POST a <code>/api/notifications/send</code>. El evento fluye por la misma pipeline de despacho que cualquier cosa emitida internamente — dedup, cooldown, reescritura con IA opcional, fan-out a los canales configurados.",
"n8nBody": "En n8n, el equivalente es un nodo <em>HTTP Request</em> con método POST, la URL de arriba, una cabecera <em>Authorization</em> configurada a <code>Bearer '{''{'$credentials.proxmenux.token'}''}'</code> (usando credentials de n8n) y un body JSON coincidiendo con el payload de curl. Cabléa cualquier nodo precedente como el trigger (cron, webhook, condición).",
"severityBody": "Los valores de severidad son <code>INFO</code>, <code>WARNING</code> o <code>CRITICAL</code> (en mayúsculas). El payload <code>data</code> es JSON libre — el reescritor de IA, cuando está activado, sacará cualquier cosa útil de ahí para el cuerpo renderizado. La semántica completa de tipos de evento vive en <link>Notifications → Catálogo de eventos</link>."
},
"pveWebhook": {
"heading": "Webhook nativo de Proxmox VE (entrante)",
"intro1": "Proxmox VE 8.1+ tiene su propio sistema de notificaciones. ProxMenux Monitor se registra como destino webhook para que todo lo que PVE emite por sí mismo (fencing HA, replicación, vzdump desde la GUI, renovación de certificado) aterrice en la misma pipeline de despacho que los propios eventos del Monitor. Esto ocurre automáticamente cuando pulsas <em>Enable Notifications</em> en la pestaña Settings — sin trabajo de integración requerido por parte del usuario.",
"intro2": "La mecánica, la plantilla de body que PVE envía, las entradas escritas en <code>/etc/pve/notifications.cfg</code> y el comportamiento en clusters están documentados en <link>Notifications → Integración del webhook de PVE</link>."
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — cada endpoint con método, path y el catálogo completo de métricas Prometheus."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — fuentes de eventos, canales, la pipeline de despacho, la integración del webhook de PVE en detalle."
},
{
"label": "Asistente de IA",
"href": "/docs/monitor/ai-assistant",
"tail": " — el reescritor opcional que convierte cuerpos templated en lenguaje natural antes de llegar a Telegram / Discord / email / Gotify."
},
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — emitir y revocar los API tokens que consumen estas guías, log de auditoría, configuración TLS."
}
]
}
}
@@ -0,0 +1,483 @@
{
"meta": {
"title": "Notificaciones de Proxmox — Telegram, Discord, Email, Gotify, Apprise | ProxMenux Monitor",
"description": "Envía notificaciones de Proxmox VE a Telegram, Discord, Email, Gotify y ~80 servicios extra vía Apprise. ProxMenux Monitor convierte eventos del Monitor de salud, el journal watcher y el webhook de Proxmox VE en mensajes ricos con deduplicación, cooldown, agregación de ráfagas, una reescritura con IA opcional y un historial completo.",
"ogTitle": "Notificaciones de Proxmox — Telegram, Discord, Email, Gotify, Apprise",
"ogDescription": "Envía alertas de Proxmox VE a Telegram, Discord, Email, Gotify y ~80 servicios extra vía Apprise — con deduplicación, cooldown, agregación de ráfagas y una reescritura con IA opcional.",
"twitterTitle": "Notificaciones de Proxmox | ProxMenux Monitor",
"twitterDescription": "Envía alertas de Proxmox VE a Telegram, Discord, Email, Gotify y ~80 servicios extra vía Apprise."
},
"header": {
"title": "Notifications",
"description": "El motor de fan-out que toma eventos de cada colector dentro del Monitor y los entrega a Telegram, Discord, Email, Gotify y ~80 servicios extra vía Apprise — con deduplicación, cooldown, agregación de ráfagas, toggles por evento y por canal, un reescritor de IA opcional y un historial consultable.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "De dónde vienen los mensajes",
"body": "Las notificaciones no son un escáner aparte. Son el lado de salida de cada colector que ya está corriendo dentro del Monitor — el <link>Monitor de salud</link>, el journal watcher, el task watcher de Proxmox, el hook del webhook de PVE, el polling collector y los eventos in-process emitidos por scripts de ProxMenux. Cada evento corre por la misma pipeline de despacho antes de llegar a un móvil o a un buzón de correo."
},
"howItWorks": {
"heading": "Cómo funciona",
"intro": "Cada notificación sigue el mismo camino por el proceso del Monitor. Los eventos los producen un puñado de colectores independientes, se normalizan en un payload estructurado, pasan por una pipeline de despacho que decide si enviar y en qué forma, opcionalmente se reescriben por un LLM, y finalmente se reparten a los canales que el usuario haya configurado.",
"arrowLabel": "evento",
"caption": "Flujo de alto nivel. Cada intento real de despacho — exitoso, agregado o fallido — se registra en la tabla de historial SQLite para inspección retrospectiva. Los eventos suprimidos por la etapa de cooldown no se loguean.",
"nodes": {
"sourcesLabel": "Fuentes",
"sourcesDetail": "Monitor de salud\nJournal watcher\nTask watcher\nPVE webhook hook\nPolling collector\nEmisores in-process",
"dispatchLabel": "Pipeline de despacho",
"dispatchDetail": "Toggle por evento\nDedup fingerprint\nCooldown\nAgregación de ráfaga",
"aiLabel": "Reescritura IA (opc.)",
"aiDetail": "OpenAI / Anthropic\nGemini / Groq\nOpenRouter / Ollama\n(off por defecto)",
"channelsLabel": "Canales",
"channelsDetail": "Telegram\nDiscord\nEmail (SMTP)\nGotify\nApprise (~80 servicios)"
}
},
"enabling": {
"heading": "Activar el panel",
"intro": "En una instalación recién hecha la tarjeta Notifications en la pestaña Settings muestra un badge <em>Disabled</em> y un único botón <em>Enable Notifications</em>. Nada se despacha y ninguna config de PVE se toca hasta que lo pulsas.",
"disabledAlt": "Tarjeta Notifications en una instalación recién hecha mostrando badge Disabled y un único botón Enable Notifications",
"disabledCaption": "El primer estado — un clic para activar.",
"stepsIntro": "Pulsar el botón hace tres cosas en secuencia:",
"steps": [
"Cambia el panel a su estado <em>Active</em> y despliega el formulario de canal debajo.",
"Registra un destino webhook de Proxmox VE en <code>/etc/pve/notifications.cfg</code> apuntando a <code>POST http://127.0.0.1:8008/api/notifications/webhook</code>. Desde este momento, todo lo que Proxmox VE emite por sí mismo (HA, replicación, vzdump desde la GUI) fluye a la misma pipeline que los eventos propios del Monitor. Mira <pvelink>Integración del webhook de PVE</pvelink> más abajo para la mecánica completa.",
"Arranca el hilo de fondo de despacho. El hilo hace polling de la cola de eventos y camina cada evento por la pipeline diagramada arriba."
],
"activeAlt": "Tarjeta Notifications tras activar — badge Active, pestañas de canal (Telegram, Gotify, Discord, Email), campo Display Name y sección colapsable Advanced AI Enhancement",
"activeCaption": "Estado Active — pestañas de canal arriba (Telegram / Gotify / Discord / Email), el campo Display Name, la lista de categorías por canal y la sección colapsable <em>Advanced: AI Enhancement</em>."
},
"sources": {
"heading": "Fuentes de eventos",
"intro": "Seis colectores independientes alimentan el motor de notificaciones. Corren como hilos de fondo dentro del proceso del Monitor y emiten un <code>NotificationEvent</code> estructurado cada vez que algo pasa.",
"headerCollector": "Colector",
"headerWatches": "Vigila",
"headerEvents": "Eventos típicos",
"rows": [
{
"collector": "Monitor de salud",
"watches": "Diez categorías, cada 5 minutos",
"events": "<code>new_error</code>, <code>error_resolved</code>, <code>error_escalated</code>, <code>health_degraded</code>, <code>health_persistent</code>."
},
{
"collector": "Journal watcher",
"watches": "<code>journalctl --follow</code> con pattern matching para fallos de autenticación SSH / web, bans de Fail2Ban (cuando el jail opcional está instalado), errores I/O del kernel, OOM, eventos de smartd.",
"events": "<code>auth_fail</code>, <code>ip_block</code>, <code>oom_kill</code>, <code>disk_io_error</code>, <code>service_fail</code>."
},
{
"collector": "Task watcher",
"watches": "Hace polling de <code>/var/log/pve/tasks/index</code> para nuevos UPIDs de tareas y sigue sus logs por archivo.",
"events": "<code>backup_start</code>, <code>backup_complete</code>, <code>backup_warning</code>, <code>backup_fail</code>, <code>migration_*</code>, <code>snapshot_complete</code>."
},
{
"collector": "Hook de webhook Proxmox",
"watches": "Escucha en <code>POST /api/notifications/webhook</code>. Proxmox VE 8.1+ empuja sus propias notificaciones aquí una vez configurada la integración (mira <pvelink>abajo</pvelink>).",
"events": "Cualquier cosa que PVE emita — incluyendo eventos que el Monitor de otro modo perdería (HA, replicación, vzdump desde la GUI)."
},
{
"collector": "Polling collector",
"watches": "Comparaciones periódicas (nodos del cluster online, caducidad de certificado, estado de passthrough de GPU, disponibilidad de actualización PVE / ProxMenux).",
"events": "<code>node_disconnect</code>, <code>node_reconnect</code>, <code>pve_update</code>, <code>proxmenux_update</code>, <code>gpu_mode_switch</code>, <code>pci_passthrough_conflict</code>."
},
{
"collector": "Emisores in-process",
"watches": "Llamadas directas desde scripts de ProxMenux y desde el propio Monitor (<code>notification_manager.emit_event(...)</code>).",
"events": "<code>system_startup</code>, <code>system_shutdown</code>, <code>system_reboot</code>, <code>ai_model_migrated</code>, eventos de prueba personalizados."
}
],
"after1": "Cada evento lleva un <code>event_type</code> estable (el catálogo está abajo), una <code>severity</code> (<code>INFO</code>, <code>WARNING</code>, <code>CRITICAL</code>), una <code>category</code> (usada para enriquecimiento de emoji y filtros por grupo) y un payload <code>data</code> con lo que la template necesite (<code>vmid</code>, <code>device</code>, <code>source_ip</code>, <code>reason</code>…).",
"after2": "Cada <code>event_type</code> tiene una template coincidente en <code>notification_templates.py</code> que renderiza el evento estructurado en un cuerpo de texto plano antes de que cualquier otra cosa pase. Ese cuerpo templated es lo que viaja por la pipeline de despacho, y lo que la capa opcional de IA reescribe si está activada. Mira la <ailink>página del Asistente de IA</ailink> para cómo la capa de reescritura interactúa con este cuerpo templated."
},
"channels": {
"heading": "Walkthroughs de canales",
"intro": "Cinco canales están actualmente soportados: Telegram, Discord, Gotify, Email (SMTP) y Apprise. Los primeros cuatro son nativos — cada uno tiene su propia pestaña dentro del panel Notifications con un enlace <em>+ setup guide</em> que abre un modal in-app. Apprise es un hub genérico que añade ~80 servicios adicionales (ntfy, Matrix, Pushover, Slack, Teams, Pushbullet, AWS SNS, Mattermost…) a través de un único campo de URL. Están todos documentados paso a paso abajo.",
"credsTitle": "Dónde viven las credenciales",
"credsBody": "Los tokens, URLs de webhook y contraseñas SMTP se guardan localmente en la base de datos SQLite del Monitor bajo <code>/usr/local/share/proxmenux/</code>. Nunca salen del host excepto para llegar a sus respectivos servicios. Un backup de ese directorio basta para recuperar los canales configurados."
},
"telegram": {
"heading": "Telegram",
"intro": "Se requieren dos piezas de información: un <strong>Bot Token</strong> (uno por bot, reutilizable entre chats) y un <strong>Chat ID</strong> (donde el bot debe publicar — tu chat privado, un grupo o un tema dentro de un supergrupo). La guía in-app de abajo contiene el paso a paso completo; el resto de esta sección lo repite como texto más las dos formas que puede tomar el Chat ID.",
"guideAlt": "Modal Telegram Bot Setup Guide con cuatro secciones numeradas: Crear un Bot con BotFather, Obtener el Bot Token, Obtener tu Chat ID y Para Grupos o Canales",
"guideCaption": "El enlace <em>+ setup guide</em> dentro de la pestaña Telegram abre este modal — los cuatro pasos numerados van de sin bot a un canal funcionando en unos dos minutos.",
"step1Title": "1 · Crea un bot con BotFather",
"step1Items": [
"Abre Telegram y empieza un chat con <a>@BotFather</a> (el que tiene el tick azul de verificación — las copias son comunes).",
"Envía <code>/newbot</code>.",
"Elige un nombre visible (p. ej. <em>ProxMenux Lab</em>). Se puede cambiar después.",
"Elige un username terminado en <code>bot</code> (p. ej. <em>proxmenux_lab_bot</em>). Debe ser único en Telegram.",
"BotFather responde con un token de la forma <code>123456789:ABCdef…</code> — ese es el Bot Token. Trátalo como una contraseña."
],
"step2Title": "2 · Obtén el Chat ID",
"step2Intro": "El Chat ID identifica <em>dónde</em> publica el bot. Toma una de dos formas según el destino.",
"privateLabel": "Chat privado (recibes las alertas en tu propia cuenta):",
"privateItems": [
"Empieza un chat con tu nuevo bot y envía cualquier mensaje (p. ej. <code>/start</code>).",
"Abre un chat con <a1>@userinfobot</a1> (o <a2>@myidbot</a2>) y envía <code>/start</code>. Te responde con tu ID numérico de usuario — ese es el Chat ID. Es un número positivo."
],
"privateAlt": "Formulario de canal Telegram rellenado con Bot Token (enmascarado), Chat ID positivo para un chat privado y un campo opcional Topic ID vacío",
"privateCaption": "Chat privado con el bot — el Chat ID es un número positivo (tu ID de usuario personal).",
"groupLabel": "Grupo o supergrupo con temas:",
"groupItems": [
"Añade el bot al grupo como miembro (y hazlo admin si el grupo lo requiere para publicar).",
"Envía cualquier mensaje en el grupo.",
"Abre <code>https://api.telegram.org/bot&lt;TU_TOKEN&gt;/getUpdates</code> en un navegador. Busca <code>chat.id</code> en la respuesta JSON — para grupos es un número negativo, para supergrupos empieza con <code>-100</code>.",
"Para supergrupos con <em>Topics</em> activado, anota también el <code>message_thread_id</code> del tema al que quieres apuntar — eso va en el campo opcional <em>Topic ID</em>."
],
"groupAlt": "Formulario de canal Telegram con Bot Token (enmascarado), Chat ID negativo prefijado con -100 indicando un supergrupo, y Topic ID 3 configurado para entregar a un tema específico",
"groupCaption": "Supergrupo — el Chat ID empieza con <code>-100…</code> y el <em>Topic ID</em> opcional apunta a un hilo específico.",
"step3Title": "3 · Guarda y prueba",
"step3Body": "Pega el Bot Token y el Chat ID en la pestaña Telegram, guarda y pulsa <em>Send Test</em> al final del panel. Un mensaje de prueba debería llegar en un segundo; si no llega, la sección History registra el fallo con el motivo exacto (token inválido, bot no en el grupo, bloqueado por el usuario, etc.)."
},
"discord": {
"heading": "Discord",
"intro": "Los canales de Discord aceptan mensajes entrantes a través de una <em>Webhook URL</em> ligada a un único canal. El Monitor necesita esa URL y nada más.",
"items": [
"En Discord, abre el servidor donde quieres que aterricen las notificaciones y ve a <em>Server Settings → Integrations → Webhooks</em>.",
"Pulsa <em>New Webhook</em>. Dale un nombre (p. ej. <em>ProxMenux</em>) y elige el canal donde debe publicar. Un avatar es opcional.",
"Pulsa <em>Copy Webhook URL</em> — tiene aspecto de <code>https://discord.com/api/webhooks/&lt;id&gt;/&lt;token&gt;</code>.",
"Pégalo en el campo Webhook URL de la pestaña Discord en el panel Notifications y guarda."
],
"imageAlt": "Formulario de canal Discord con campo Webhook URL empezando por https://discord.com/api/webhooks/",
"imageCaption": "Discord — pega la Webhook URL de <em>Server Settings → Integrations → Webhooks</em>."
},
"gotify": {
"heading": "Gotify",
"intro": "Gotify es un servidor push autoalojado. Necesitas su URL base y un <em>Application Token</em> generado desde la UI de admin de Gotify.",
"items": [
"Si aún no tienes una instancia de Gotify, instala una — mira la <a>guía oficial de instalación</a>.",
"Abre la UI web de Gotify, loguéate como admin, ve a <em>Apps</em> → <em>Create Application</em>. Dale un nombre (p. ej. <em>ProxMenux</em>). Gotify genera un token — cópialo.",
"En la pestaña Gotify del panel Notifications, configura <em>Server URL</em> a la URL base de tu instancia (p. ej. <code>https://gotify.example.com</code>) y pega el App Token.",
"Guarda y pulsa <em>Send Test</em>."
],
"imageAlt": "Formulario de canal Gotify con campo Server URL configurado a https://gotify.example.com y un campo App Token con placeholder A_valid_gotify_token",
"imageCaption": "Gotify — URL del servidor de tu instancia autoalojada más el App Token de la UI de admin de Gotify."
},
"email": {
"heading": "Email (SMTP)",
"intro": "Email es el canal más flexible — y el que tiene más campos. Necesitas un servidor SMTP, un puerto, un modo TLS, opcionalmente un usuario y contraseña, una dirección de remitente y al menos un destinatario.",
"imageAlt": "Formulario de canal Email con SMTP Host, Port, dropdown TLS Mode, Username, Password, From Address, To Addresses separadas por coma y campos Subject Prefix",
"imageCaption": "Email — host / puerto / modo TLS de SMTP, usuario + contraseña opcionales, dirección de remitente, destinatarios separados por coma y un prefijo de asunto para hacer las alertas fáciles de filtrar en el lado del inbox.",
"appNote": "Si usas una cuenta personal de Gmail o Microsoft 365, el campo password no puede ser tu contraseña normal de cuenta — ambos proveedores requieren una <strong>app password</strong> generada específicamente para clientes de terceros. Los dos flujos están abajo.",
"gmailTitle": "App password de Gmail",
"gmailIntro": "Las app passwords de Gmail requieren que la <strong>verificación en 2 pasos</strong> esté activa en la cuenta de Google. Si no lo está, la página <em>App passwords</em> no existirá.",
"gmailItems": [
"Abre <a>myaccount.google.com/security</a> y activa <em>Verificación en 2 pasos</em> si no está activada.",
"Ve a <a>myaccount.google.com/apppasswords</a>.",
"Escribe un nombre (p. ej. <em>ProxMenux</em>) y pulsa <em>Create</em>. Google muestra una contraseña de 16 caracteres — cópiala.",
"Rellena la pestaña Email con: <em>Host</em> <code>smtp.gmail.com</code>, <em>Port</em> <code>587</code>, <em>TLS Mode</em> <code>STARTTLS</code>, <em>Username</em> tu dirección de Gmail, <em>Password</em> la app password de 16 caracteres."
],
"outlookTitle": "App password de Microsoft / Outlook",
"outlookIntro": "Microsoft ahora requiere <strong>verificación en dos pasos</strong> en la cuenta personal antes de que se pueda crear una app password. Los tenants empresariales donde el admin ha deshabilitado SMTP basic auth necesitan un camino distinto (OAuth2) que el Monitor no soporta actualmente — apunta esos a un relay SMTP que controles en su lugar.",
"outlookItems": [
"Abre <a>account.microsoft.com/security</a> y activa la verificación en dos pasos.",
"Abre <em>Advanced security options</em>, baja a <em>App passwords</em> y pulsa <em>Create a new app password</em>.",
"Microsoft muestra una contraseña aleatoria larga — cópiala.",
"Rellena la pestaña Email con: <em>Host</em> <code>smtp-mail.outlook.com</code>, <em>Port</em> <code>587</code>, <em>TLS Mode</em> <code>STARTTLS</code>, <em>Username</em> tu dirección de Outlook / Microsoft 365, <em>Password</em> la app password generada."
],
"relayTitle": "Relay SMTP autoalojado",
"relayBody": "Si corres tu propio relay SMTP (Postfix, msmtp, etc.) en la LAN, apunta el Monitor a él y saltea el baile de app-password por completo. El relay maneja la auth upstream y el Monitor envía en cleartext sobre una red de confianza."
},
"apprise": {
"heading": "Apprise (hub genérico para ~80 servicios)",
"intro": "Apprise es una librería de notificaciones de código abierto que habla el protocolo de unos 80 servicios distintos a través de un único formato de URL. Añadirlo como un canal más dentro del Monitor significa que puedes entregar alertas a servicios que no tienen una pestaña dedicada — ntfy, Matrix, Pushover, Slack, Microsoft Teams, Mattermost, Pushbullet, AWS SNS, Pushsafer, Rocket.Chat, Signal API y muchos otros — sin que ProxMenux tenga que implementar cada integración por separado.",
"listIntro": "La lista completa de servicios soportados y el formato exacto de URL para cada uno vive en la wiki oficial de Apprise:",
"listItems": [
"<a>github.com/caronc/apprise/wiki</a> — índice completo de servicios soportados.",
"<a>URL basics</a> — cómo se estructuran las URLs de Apprise."
],
"stepsTitle": "Pasos",
"steps": [
"Elige el servicio destino en la <a>wiki de Apprise</a> y copia la plantilla de URL para él. Cada página de servicio muestra el esquema exacto a usar (<code>ntfy://</code>, <code>matrix://</code>, <code>pover://</code>, <code>slack://</code>…) más cualquier token, canal u hostname requerido.",
"Rellena los placeholders con tus propias credenciales. Por ejemplo, un topic de ntfy.sh tiene aspecto de <code>ntfy://ntfy.sh/mi-topic</code>; una URL de Pushover tiene aspecto de <code>pover://user@token</code>; una URL de Matrix tiene aspecto de <code>matrix://user:pass@host:port/#room</code>.",
"Pega la URL final en el campo <em>Apprise URL</em> en la pestaña Apprise del panel Notifications y guarda.",
"Pulsa <em>Send Test</em> para verificar que la URL es alcanzable y las credenciales se aceptan."
],
"deliveredTitle": "Qué se entrega",
"deliveredBody": "Apprise recibe el mismo payload que los otros canales — título, cuerpo y una severidad (info / success / warning / failure). La severidad se mapea a lo que el servicio destino exponga (icono, prioridad, color). El formato de mensajes ricos y la capa de reescritura con IA corren todos antes de que se invoque la URL, exactamente como para Telegram o Email.",
"fanoutTitle": "Una URL por canal Apprise",
"fanoutBody": "El Monitor expone un único slot de URL por canal Apprise. Si necesitas hacer fan-out a varios servicios Apprise a la vez (p. ej. ntfy.sh más una sala de Matrix), el enfoque más limpio es alojar un pequeño <a>servidor Apprise API</a> con una config etiquetada y apuntar el Monitor a su endpoint — el servidor luego difunde a cada URL detrás de esa etiqueta."
},
"rich": {
"heading": "Mensajes ricos, categorías y filtrado por canal",
"intro": "Bajo el formulario del canal cada canal expone los mismos tres controles: un toggle <em>Rich messages</em> arriba (destacado con la flecha en la captura), once <em>Notification Categories</em> colapsables con toggles por evento y un botón <em>Send Test</em> abajo.",
"imageAlt": "Panel Notification Categories con toggle maestro Rich messages destacado arriba, secciones colapsables para VM/CT, Backups, Resources, Storage, Network, Security, Cluster, Services, Health Monitor, Updates cada una con toggle y contador de eventos, y un botón Send Test",
"imageCaption": "Flecha de arriba — el toggle <em>Rich messages</em> por canal. Abajo — las once categorías colapsables con toggles por evento. <em>Send Test</em> está al final del canal.",
"richTitle": "Mensajes ricos",
"richIntro": "Con <em>Rich messages</em> activado, la cabecera de cada evento se prefija con un emoji de categoría y el cuerpo se renderiza usando el formato nativo del canal (HTML de Telegram, embed de Discord con color de severidad). Con él desactivado, el Monitor envía una versión de texto plano con la misma información menos las pistas visuales. Mismo contenido, distinta presentación:",
"plainHeader": "Plano — Rich messages off",
"richHeader": "Rico — Rich messages on",
"richOutro": "El toggle es por canal: deja Email plano para legibilidad de reglas de inbox dejando que Telegram y Discord rendericen la versión rica. Los canales que no soportan formato inline (email texto plano, Gotify) ignoran el formato y caen a texto de todas formas.",
"togglesTitle": "Categorías por evento",
"togglesIntro": "Unos setenta tipos de evento están agrupados en once categorías de UI. Cada evento tiene un toggle maestro y un override por canal — dos capas que deciden si un evento dado llega a un canal dado:",
"togglesItems": [
"<strong>Toggle maestro por evento.</strong> Si <code>vm_start</code> está off en todas partes, ningún canal ve nunca un <code>vm_start</code>. Los toggles persisten como <code>event_toggles[event_type] = true | false</code>.",
"<strong>Overrides por canal.</strong> Un tipo de evento también se puede silenciar para un canal específico (<em>\"enviar <code>backup_complete</code> a Discord pero no a Telegram\"</em>). Estos viven en <code>channel_overrides[channel_name][event_type]</code> y solo aplican si el evento pasó el toggle maestro."
],
"togglesOutro": "Cada cabecera de categoría en la captura también muestra el conteo de eventos <em>actualmente activados</em> / <em>total</em> para ese grupo, y un toggle a nivel de categoría que pone cada evento dentro a on o off en un clic — el atajo para silenciar un grupo entero (p. ej. todos los backups <code>info</code>, todos los eventos relacionados con actualizaciones) sin expandir la sección."
},
"quiet": {
"heading": "Quiet Hours",
"intro": "Quiet Hours es una ventana temporal por canal durante la cual el dispatcher solo deja pasar eventos <strong>CRITICAL</strong>. Todo lo demás — INFO, WARNING, eventos de acción — se retiene, se persiste a disco y se entrega como un único resumen agrupado en el momento en que la ventana cierra. El canal sigue recibiendo las cosas urgentes en tiempo real; el ruido espera hasta que probablemente lo quieras.",
"imageAlt": "Ajustes de canal mostrando ambos knobs lado a lado: tarjeta Quiet Hours con toggle activado, Start 22:00 y End 07:00 más una preview en vivo de la siguiente transición, y justo debajo la tarjeta Daily digest con su propio toggle, un selector de hora de entrega configurado a 09:00 y la nota de que CRITICAL y WARNING nunca se retrasan",
"imageCaption": "Ambos knobs viven lado a lado dentro de la tarjeta de ajustes de cada canal — Quiet Hours arriba, Daily digest debajo. Independientes por canal.",
"purposeTitle": "Para qué sirve",
"purposeItems": [
"<strong>No me despiertes a las 03:00 por un aviso de actualización.</strong> Backups, actualizaciones de apps, optimizaciones post-instalación y otros eventos de nivel INFO dejan de avisar a tu móvil por la noche.",
"<strong>Pero aun así despiértame por un fuego.</strong> Fallos de disco, OOM kills, shutdowns del host, bans de fail2ban — cualquier cosa clasificada como CRITICAL — saltea la ventana y llega inmediatamente.",
"<strong>Tampoco pierdas nada.</strong> Los eventos suprimidos durante la ventana no se descartan silenciosamente — se sientan en un buffer SQLite hasta que vuelves al reloj."
],
"howTitle": "Cómo funciona",
"howItems": [
"<strong>Toggle por canal.</strong> Cada canal tiene su propia configuración de Quiet Hours — Telegram puede estar silencioso 22:00-07:00 mientras email sigue recibiendo todo 24/7.",
"<strong>Hora de inicio y fin</strong> en tu zona horaria local, intervalo semi-abierto (inicio inclusivo, fin exclusivo). La ventana puede cruzar medianoche (p. ej. 22:00-07:00 significa esta noche hasta mañana por la mañana).",
"<strong>Línea de preview en vivo</strong> justo debajo de los inputs muestra si la ventana está actualmente activa y cuándo ocurre la siguiente transición. Ahorra abrir un reloj.",
"<strong>Durante la ventana:</strong> los eventos CRITICAL siguen disparando por la pipeline de despacho normal. Los eventos INFO y WARNING se enrutan a un buffer persistente (tabla <code>quiet_pending</code> en la DB SQLite del Monitor).",
"<strong>Cuando la ventana cierra:</strong> se envía una única notificación agrupada con todo lo que se acumuló — una línea por evento bufferizado, en orden cronológico. El buffer se limpia solo después de que el canal confirme la entrega, para que un fallo transitorio de Telegram / SMTP no pierda el contexto de la noche.",
"<strong>A través de reinicios.</strong> Si el Monitor reinicia a mitad de ventana, el buffer está intacto en disco. Si el reinicio ocurre justo después de que la ventana cierre, el siguiente ciclo de despacho detecta las filas pendientes y las descarga con un único resumen \"recovery\" — no se pierden notificaciones por un deploy o un reboot."
],
"criticalTitle": "Qué cuenta como CRITICAL",
"criticalBody": "La severidad se fija en la creación del evento, no en el momento del despacho. Los fallos de disco, OOM kills, split-brain de cluster, shutdowns del host y el nivel \"duro\" de errores I/O de disco se envían como CRITICAL por diseño. Todo lo demás (backups OK, actualizaciones disponibles, logs INFO, hits de rate-limit) cae por defecto a INFO o WARNING y por tanto es silenciable. Puedes verificar la severidad por defecto de un evento dado en el <link>Catálogo de eventos</link> más abajo en esta página."
},
"digest": {
"heading": "Resumen diario de eventos INFO",
"intro1": "El Daily Digest es el knob opuesto: un ajuste <strong>opt-in</strong> que dice \"no me envíes cada backup exitoso o aviso de actualización según ocurre — recoléctalos y envíame un resumen al día a las 09:00 (o la hora que elija)\". Mismo objetivo que Quiet Hours (menos ruido) pero un mecanismo distinto (resumen basado en tiempo en vez de una ventana diaria).",
"intro2": "Vive en la misma tarjeta de ajustes de canal que Quiet Hours (mira la figura bajo <link>Quiet Hours</link>), justo debajo. Cada uno se activa independientemente.",
"purposeTitle": "Para qué sirve",
"purposeItems": [
"<strong>El recap matutino de \"todo lo que pasó\".</strong> Si chequeas el host una vez al día con un café, un digest a las 09:00 lleva la misma información que 20 pings individuales a lo largo del día anterior, sin que leas 20 burbujas de Telegram.",
"<strong>Separa ruido de señal.</strong> Los eventos INFO responden a \"qué pasó\"; CRITICAL y WARNING responden a \"qué necesito hacer ahora mismo\". El digest maneja el primero; todo lo demás mantiene su entrega en vivo."
],
"howTitle": "Cómo funciona",
"howItems": [
"<strong>Opt-in por canal.</strong> Off por defecto — Telegram no batcheaiza silenciosamente tus alertas. Lo activas en los canales donde quieres un digest, dejando otros en entrega en vivo.",
"<strong>Hora de entrega</strong> en tu zona horaria local. Por defecto 09:00 pero puedes elegir cualquier hora; el dispatcher dispara el digest dentro de ~60 s de ese minuto.",
"<strong>Qué entra en el digest:</strong> cualquier evento que el canal habría recibido en vivo cuya severidad es <strong>INFO</strong>. Ejemplos — <em>vzdump complete</em>, <em>Tailscale update available</em>, <em>ProxMenux optimisation update available</em>, <em>APT security updates pending</em>, <em>rate-limit hit</em>.",
"<strong>Qué nunca se retrasa:</strong>",
"<strong>Persistencia.</strong> Los eventos pendientes se sientan en una tabla SQLite (<code>digest_pending</code>) hasta la hora configurada. El Monitor puede reiniciar libremente sin perder lo que el digest eventualmente contendrá.",
"<strong>Los días vacíos son silenciosos.</strong> Si nada de nivel INFO pasó, no se envía digest — el canal se mantiene quieto en vez de recibir un mensaje \"no hay eventos para reportar\"."
],
"neverDelayedSub": [
"Los eventos <strong>CRITICAL</strong> siempre pasan inmediatamente.",
"Los eventos <strong>WARNING</strong> siempre pasan inmediatamente.",
"Eventos de acción en vivo (VM/CT start / stop / shutdown / restart, vm_fail / ct_fail, backup start / fail, replication start / fail, host shutdown / reboot) saltean el digest incluso con severidad INFO — has hecho opt-in a verlos en vivo, el digest derrotaría ese opt-in."
],
"comboTitle": "Combinar Quiet Hours y Daily Digest",
"comboBody": "Los dos funcionan juntos. Un canal puede tener <em>ambos</em> activos — Quiet Hours de 22:00 a 07:00 más un Daily Digest a las 09:00. Los eventos INFO durante la ventana quiet van al buffer quiet y llegan a las 07:00 como el resumen de cierre de ventana; los eventos INFO durante el día van al buffer digest y llegan a las 09:00 a la mañana siguiente. CRITICAL y WARNING siempre atraviesan ambos. Elige Quiet Hours cuando el objetivo es una <em>ventana de silencio</em>, el Daily Digest cuando el objetivo es un <em>resumen a hora fija</em>; muchos setups quieren ambos."
},
"displayName": {
"heading": "Display Name",
"intro": "Cada notificación lleva un <em>Display Name</em> — la etiqueta que identifica qué host produjo la alerta. Es el valor que ves al final del ejemplo de mensajes ricos arriba (<code>🏠 home-lab</code>) y dentro del prefijo de asunto del email.",
"imageAlt": "Campo Display Name con el valor amd mostrado como ejemplo, etiqueta Name shown in notifications - edit to customize or leave empty to use the system hostname",
"imageCaption": "El campo Display Name — déjalo vacío para usar el hostname del sistema, o sobreescríbelo con lo que quieras.",
"outro": "Si el campo está vacío, el Monitor cae al hostname del sistema. El override es sobre todo útil cuando corres varios hosts ProxMenux que envían al mismo chat de Telegram o buzón — una etiqueta más amigable (<em>home-lab</em>, <em>office-pve</em>) es más fácil de leer que <code>pve01.lan</code> o <code>pmx-prod-01</code>."
},
"dispatch": {
"heading": "Pipeline de despacho",
"intro": "Entre que un evento se levanta y un mensaje sale del host, corren tres etapas en este orden:",
"headerStage": "Etapa",
"headerWhat": "Qué hace",
"headerTunable": "¿Ajustable?",
"rows": [
{
"stage": "1. Deduplicación por huella",
"what": "Cada evento genera una huella (<code>event_type + campos clave de data</code>). Las huellas idénticas dentro de una ventana corta se consideran duplicados del primero.",
"tunable": "No — lógica interna del dispatcher."
},
{
"stage": "2. Cooldown",
"what": "Cuando una huella ya se ha enviado, esa misma huella se silencia durante el cooldown propio de cada severidad. El estado se guarda en la tabla SQLite <code>notification_last_sent</code> para que sobreviva a reinicios. Valores por defecto: <code>CRITICAL</code> 60 s, <code>WARNING</code> 300 s, <code>INFO</code> 900 s, con posibilidad de override por categoría (por ejemplo <code>resources</code> 900 s, <code>updates</code> 86 400 s).",
"tunable": "No — valores por defecto integrados en el dispatcher."
},
{
"stage": "3. Agregación de ráfagas",
"what": "Cuando llegan N eventos del mismo tipo dentro de una ventana corta (por ejemplo un aluvión de intentos de fuerza bruta SSH), se agrupan en un único mensaje <code>burst_*</code> con un contador y una muestra.",
"tunable": "No — ventana y umbral están fijados por tipo de evento."
}
],
"calloutTitle": "El despacho ocurre en un hilo de fondo",
"calloutBody": "El bucle de despacho corre en su propio hilo. La petición HTTP que emite un evento devuelve en cuanto el evento se encola — no espera al RTT de Telegram, SMTP o el webhook. Cada resultado de envío se registra en la tabla de historial para revisarlo después."
},
"aiRewrite": {
"heading": "Reescritura con IA opcional",
"body1": "Cualquier evento se puede pasar por un LLM que reescribe su cuerpo en lenguaje natural y (opcionalmente) en el idioma del usuario destino antes del fan-out. El reescritor de IA está off por defecto. Cuando se activa corre en el hilo de despacho; si la llamada al proveedor falla o caduca, se usa el cuerpo templated original en su lugar.",
"body2": "Se soportan seis proveedores (OpenAI, Anthropic, Google Gemini, Groq, OpenRouter y Ollama local), con nivel de detalle por canal (<code>brief</code>, <code>standard</code>, <code>detailed</code>), idioma de salida, modo de prompt (<code>default</code> o <code>custom</code>) y un prompt personalizado opcional. El walkthrough de configuración completo, capturas y ejemplos de prompt viven en la página dedicada <link>Asistente de IA</link>.",
"privacyTitle": "Nota de privacidad",
"privacyBody": "La reescritura con IA envía el cuerpo del evento — que puede incluir hostnames, direcciones IP, usernames, mensajes de error y líneas de journal — al proveedor configurado. Ollama mantiene todo en el host; los otros cinco proveedores transmiten datos a sus respectivos endpoints. Desactiva el reescritor, o usa Ollama, si el host corre en un entorno donde el contenido de los eventos no puede salir de la red."
},
"pveWebhook": {
"heading": "Integración del webhook de PVE",
"intro1": "Proxmox VE 8.1+ tiene su propio sistema de notificaciones con <em>endpoints</em> integrados (sendmail, gotify, SMTP, webhook). Cuando activas Notifications en el Monitor, se registra como uno de esos endpoints — un destino <code>webhook</code> que apunta de vuelta a la propia API del Monitor. Desde ese momento, todo lo que Proxmox mismo emite (fencing HA, replicación, vzdump desde la GUI, renovación de certificado, etc.) fluye por la misma pipeline de despacho que los eventos propios del Monitor.",
"intro2": "El destino es visible desde la GUI de Proxmox en <em>Datacenter → Notifications → Notification Targets</em>:",
"imageAlt": "Diálogo Proxmox VE Edit Webhook mostrando el destino proxmenux-webhook autocreado con método POST, URL http://127.0.0.1:8008/api/notifications/webhook y una plantilla JSON usando escape title, escape message, escape severity, escape timestamp y campos json",
"imageCaption": "El destino webhook del lado PVE como Proxmox lo ve (la GUI está en el locale configurado del host — español en este ejemplo). Los mismos campos aplican en cualquier idioma.",
"registeredIntro": "Qué se registra:",
"registeredItems": [
"<strong>Método y URL.</strong> <code>POST http://127.0.0.1:8008/api/notifications/webhook</code>. Solo loopback — PVE habla con el proceso del Monitor corriendo en el mismo host.",
"<strong>Plantilla de body.</strong> Un body JSON usando los helpers Handlebars nativos de PVE — guardado base64-encoded en el archivo de config por PVE, pero se expande a:",
"<strong>Matcher.</strong> Un bloque compañero <code>matcher: proxmenux-matcher</code> con <code>mode all</code> para que cada notificación de PVE llegue al destino.",
"<strong>Bloque priv compañero.</strong> Una entrada vacía <code>webhook: proxmenux-webhook</code> se añade a <code>/etc/pve/priv/notifications.cfg</code>. PVE se niega a instanciar cualquier endpoint webhook sin un bloque privado coincidente, incluso cuando no se necesitan secrets — así que el Monitor escribe un stub solo de cabecera ahí. No se configuran tokens, cabeceras ni HMAC en el lado PVE."
],
"securityTitle": "Cómo se asegura el receptor",
"securityIntro": "El receptor webhook en <code>POST /api/notifications/webhook</code> aplica distintas capas de seguridad según de dónde venga la petición:",
"securityItems": [
"<strong>Loopback (<code>127.0.0.1</code> / <code>::1</code>).</strong> Solo rate-limit. El endpoint confía en la interfaz loopback — solo procesos corriendo en el host pueden alcanzarlo, y PVE mismo no puede enviar cabeceras de auth personalizadas en el body que genera. Este es el camino que viaja cada notificación emitida por PVE.",
"<strong>Llamadores remotos.</strong> Cinco capas se apilan encima del rate-limiting: un shared secret en la cabecera <code>X-Webhook-Secret</code>, un timestamp de frescura en <code>X-ProxMenux-Timestamp</code> (rechazado si se desvía más allá de la ventana configurada), una búsqueda de caché de replay y una allowlist de IP opcional. El shared secret vive en la tabla de ajustes SQLite del Monitor — no en <code>/etc/pve/priv/notifications.cfg</code> — y se genera en el primer setup. Este camino existe para integraciones personalizadas que hacen POST desde fuera del host; el destino configurado por PVE nunca lo ejercita."
],
"practiceTitle": "En la práctica",
"practiceBody": "El setup de PVE escribe el destino como <code>http://127.0.0.1:8008</code>, así que las notificaciones emitidas por PVE siempre pasan por el camino loopback con seguridad solo rate-limit. El camino de llamador remoto con shared secret es opt-in para integraciones personalizadas — apunta un servicio externo a <code>https://&lt;host-monitor&gt;:&lt;port&gt;/api/notifications/webhook</code> y suministra la cabecera <code>X-Webhook-Secret</code> para usarlo.",
"actionsIntro": "El Monitor gestiona este destino a través de tres acciones en la pestaña Settings:",
"actionsItems": [
"<strong>Setup</strong> — corre automáticamente cuando activas Notifications. Crea la entrada en <code>/etc/pve/notifications.cfg</code> tras hacer backup del archivo actual.",
"<strong>Cleanup</strong> — elimina la entrada. El backup previo del archivo se conserva.",
"<strong>Read config</strong> — muestra los destinos y matchers actuales como PVE los ve. Así es como confirmas que la entrada del Monitor es la que dispara cuando PVE tiene múltiples rutas de notificación configuradas."
],
"clusterTitle": "Nodos de cluster",
"clusterBody": "<code>/etc/pve/</code> se replica entre miembros del cluster, así que el destino webhook es visible en cada nodo. Cada nodo, sin embargo, hace POST a su <em>propio</em> <code>127.0.0.1:8008</code> — lo que significa que el Monitor corriendo en ese nodo recibe los eventos que PVE generó localmente. Ejecuta el Monitor en cada nodo que quieras ver en el historial de Notifications."
},
"catalogue": {
"heading": "Catálogo de eventos",
"intro": "Unos setenta tipos de evento están agrupados en once categorías de UI. El panel Notifications renderiza una sección colapsable por grupo con un toggle por cada evento dentro. Cada evento está on por defecto salvo que se marque explícitamente lo contrario.",
"headerGroup": "Grupo",
"headerEvents": "Eventos",
"rows": [
{
"group": "VM / CT",
"events": "<code>vm_start</code>, <code>vm_start_warning</code>, <code>vm_stop</code>, <code>vm_shutdown</code>, <code>vm_fail</code>, <code>vm_restart</code>, más los equivalentes <code>ct_*</code>, <code>migration_start</code>, <code>migration_complete</code>, <code>migration_warning</code>, <code>migration_fail</code>, <code>replication_complete</code>, <code>replication_fail</code>."
},
{
"group": "Backups",
"events": "<code>backup_start</code>, <code>backup_complete</code>, <code>backup_warning</code>, <code>backup_fail</code>, <code>snapshot_complete</code>, <code>snapshot_fail</code>."
},
{
"group": "Recursos",
"events": "<code>cpu_high</code>, <code>ram_high</code>, <code>temp_high</code>, <code>load_high</code>."
},
{
"group": "Almacenamiento",
"events": "<code>disk_space_low</code>, <code>disk_io_error</code>, <code>storage_unavailable</code>, <code>smart_test_complete</code>, <code>smart_test_failed</code>."
},
{
"group": "Red",
"events": "<code>network_down</code>, <code>network_latency</code>."
},
{
"group": "Seguridad",
"events": "<code>auth_fail</code>, <code>ip_block</code>, <code>firewall_issue</code>, <code>user_permission_change</code>."
},
{
"group": "Cluster",
"events": "<code>split_brain</code>, <code>node_disconnect</code>, <code>node_reconnect</code>."
},
{
"group": "Servicios",
"events": "<code>system_startup</code>, <code>system_shutdown</code>, <code>system_reboot</code>, <code>system_problem</code>, <code>service_fail</code>, <code>oom_kill</code>, <code>system_mail</code>."
},
{
"group": "Monitor de salud",
"events": "<code>new_error</code>, <code>error_resolved</code>, <code>error_escalated</code>, <code>health_degraded</code>, <code>health_persistent</code>, <code>health_issue_new</code>, <code>health_issue_resolved</code>."
},
{
"group": "Actualizaciones",
"events": "<code>update_summary</code>, <code>update_available</code>, <code>pve_update</code>, <code>update_complete</code>, <code>proxmenux_update</code>."
},
{
"group": "Hardware / GPU",
"events": "<code>gpu_mode_switch</code>, <code>gpu_passthrough_blocked</code>, <code>pci_passthrough_conflict</code>, <code>ai_model_migrated</code>."
}
],
"burstNote": "Un puñado de tipos de agregación <code>burst_*</code> (<code>burst_auth_fail</code>, <code>burst_ip_block</code>, <code>burst_disk_io</code>, etc.) existen solo en el dispatcher — reemplazan ráfagas de eventos individuales con un único mensaje de resumen y no se exponen como toggles en la UI. Heredan el estado on/off de su tipo de evento padre."
},
"history": {
"heading": "Historial",
"body1": "Cada <em>intento</em> de despacho que el dispatcher realmente ejecuta se registra en la tabla SQLite <code>notification_history</code>. Cada fila guarda el timestamp (<code>sent_at</code>), canal, tipo de evento, severidad, título, cuerpo de mensaje renderizado, un flag <code>success</code> y — cuando el envío falló — el error devuelto por el proveedor en <code>error_message</code>. Los eventos agregados en ráfaga aparecen como una única fila con el tipo de evento <code>burst_*</code>. Los eventos suprimidos por la etapa de cooldown no se loguean: nunca se convierten en un intento de despacho.",
"body2": "La pestaña History dentro de Settings → Notifications muestra las últimas 20 entradas y tiene un único botón <em>Clear</em> que borra la tabla.",
"body3": "Los mismos datos se exponen en <code>GET /api/notifications/history</code> con parámetros opcionales <code>limit</code>, <code>offset</code>, <code>severity</code> y <code>channel</code>, y se pueden borrar con <code>DELETE /api/notifications/history</code>."
},
"api": {
"heading": "Endpoints de API",
"headerEndpoint": "Endpoint",
"headerMethod": "Método",
"headerUse": "Uso",
"rows": [
{
"endpoint": "/api/notifications/settings",
"method": "GET / POST",
"use": "Lee o escribe la configuración completa (canales, toggles por evento, reescritor de IA, Display Name)."
},
{
"endpoint": "/api/notifications/test",
"method": "POST",
"use": "Envía una notificación de prueba a un canal: <code>'{'\"channel\":\"telegram\"'}'</code>."
},
{
"endpoint": "/api/notifications/test-ai",
"method": "POST",
"use": "Renderiza y reescribe un evento de muestra sin despacharlo."
},
{
"endpoint": "/api/notifications/provider-models",
"method": "POST",
"use": "Lista modelos disponibles para el proveedor de IA seleccionado."
},
{
"endpoint": "/api/notifications/send",
"method": "POST",
"use": "Emite un evento desde fuera (integraciones personalizadas)."
},
{
"endpoint": "/api/notifications/history",
"method": "GET / DELETE",
"use": "Lee el historial con filtros; bórralo."
},
{
"endpoint": "/api/notifications/webhook",
"method": "POST",
"use": "Recibe las notificaciones propias de Proxmox VE. Los llamadores loopback están solo rate-limited; los llamadores remotos deben pasar adicionalmente la cabecera <code>X-Webhook-Secret</code>, comprobación de frescura <code>X-ProxMenux-Timestamp</code>, caché de replay y allowlist de IP opcional."
},
{
"endpoint": "/api/notifications/proxmox/setup-webhook",
"method": "POST",
"use": "Registra el Monitor como destino en <code>/etc/pve/notifications.cfg</code>."
},
{
"endpoint": "/api/notifications/proxmox/cleanup-webhook",
"method": "POST",
"use": "Elimina el destino del Monitor de la config de notificaciones de PVE."
},
{
"endpoint": "/api/notifications/proxmox/read-cfg",
"method": "GET",
"use": "Muestra la config actual de notificaciones de PVE como PVE la ve."
}
]
},
"whereNext": {
"heading": "Por dónde seguir",
"items": [
{
"label": "Asistente de IA",
"href": "/docs/monitor/ai-assistant",
"tail": " — proveedores, modelos, modos de prompt, idiomas, niveles de detalle por canal."
},
{
"label": "Monitor de salud",
"href": "/docs/monitor/health-monitor",
"tail": " — el mayor productor individual de eventos, con sus propias duraciones de supresión por categoría."
},
{
"label": "Arquitectura",
"href": "/docs/monitor/architecture",
"tailRich": " — dónde encajan las tablas SQLite (<code>notification_last_sent</code>, <code>notification_history</code>) y el hilo de despacho en el proceso más amplio del Monitor."
},
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tailRich": " — cómo se emiten API tokens para scripts que llaman a <code>/api/notifications/send</code>."
},
{
"label": "Dashboard → Logs del sistema",
"href": "/docs/monitor/dashboard/system-logs",
"tail": " — la vista en vivo del mismo journal que alimenta el journal watcher."
}
]
}
}