ligbox-ops-platform/specs/035-ligbox-watchman/spec.md
Ligbox Spec Hub c1881f58e6 chore: sync Console SSO, DNS viewer, specs e infra docs pendentes
Inclui console handoff Desk↔Console (Spec 019), melhorias DNS Viewer (037),
OpenPanel/Nextcloud/VM116 deploy notes, contracts stack e sidebar actualizado.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 20:10:17 +00:00

8.9 KiB
Raw Permalink Blame History

Spec 035 — Ligbox Watchman (vigilância contínua + alertas)

Criado: 2026-06-22
Solicitado por: Roger
Status: 📋 Draft — aguarda implementação Fase 1
Prioridade: P0 (incidente Desk 502 sem alerta — 2026-06-22)
Sistema: VM122 (processo standalone) + monorepo ligbox-ops-platform
Relacionado: Spec 033 (stack health UI) · Spec 002 (Wazuh) · Spec 007 (push) · VM115 ntfy


Resumo

Ligbox Watchman é um processo leve, contínuo e independente do Desk API que monitoriza todos os serviços do stack Ligbox (VMs 112, 114, 122, 123, 130 e extensões), regista estado, e alerta quando um serviço deixa de responder — antes de um utilizador reportar “a página não abre”.

Motivação (incidente real): desk.ligbox.com.br devolveu HTTP 502 porque ligbox-ops-platform_frontend_1 e api_1 estavam Exited na VM122 após reboot. O Traefik estava OK; o INFRA CODE do Desk não alertou porque depende da própria API.

Princípio: Watchman não morre quando o Desk morre.


Problema

Lacuna actual Impacto
stack_health.py só via API Desk Sem alerta se API/UI caírem
Sem processo 24/7 dedicado Falhas após reboot passam despercebidas
Docker sem restart: unless-stopped Containers ficam parados (exit 255)
Wazuh (VM104) SIEM — não substitui uptime sintético por URL

Decisões de arquitectura

# Tema Decisão
1 Onde corre VM122 — host com LAN para 112/114/123/130; processo fora do container api
2 Catálogo Fonte única YAML contracts/stack-services.yaml; Desk importa o mesmo catálogo (refactor Spec 033)
3 Intervalo Tier crítico 30 s · tier standard 60 s · tier slow 120 s — não 1 s global (anti-ruído)
4 Anti-flap Alerta só após N falhas consecutivas (default 2)
5 Recovery Notificação RESOLVED quando serviço volta OK após alerta
6 Estado SQLite local watchman.db (~MB) — histórico 7 dias
7 Alertas ntfy (primário) + email Postfix (secundário) + webhook Desk (opcional)
8 Recursos 1 processo Python, asyncio + pool HTTP, RAM alvo < 64 MB
9 Deploy systemd ligbox-watchman.service + opcional container Docker dedicado
10 RBAC Sem UI própria v1 — leitura via ficheiro status JSON + integração futura Desk

Arquitectura

flowchart LR
  subgraph VM122
    W[watchman.py systemd]
    DB[(watchman.db SQLite)]
    W --> DB
  end

  subgraph LAN
    VM112[VM112]
    VM114[CT114]
    VM123[VM123]
    VM130[CT130]
  end

  W -->|HTTP/TCP probes| VM112
  W -->|HTTP/TCP probes| VM114
  W -->|HTTP/TCP probes| VM123
  W -->|HTTP/TCP probes| VM130
  W -->|HTTPS WAN| desk.ligbox.com.br

  W -->|POST| ntfy[VM115 ntfy]
  W -->|SMTP| postfix[Postfix Proxmox]
  W -.->|opcional| desk_hook[Desk webhook]

Catálogo de serviços (v1)

Herda Spec 033 (stack_health.py) — ~22 probes em 5 VMs:

VM Serviços
112 Onboard API, Wizard UI, Carbonio, Domain Admin API
114 Traefik API, Router Desk WAN, Router API Ops WAN
122 Desk API LAN, Desk UI :8091, Redis, integrações locais
123 FOSSBilling, Odoo, OpenPanel, OpenAdmin, Bridge :18087, Ops Console, phpMyAdmin, Ollama
130 Forgejo, Spec Portal LAN, Spec Hub WAN

Fase 2 (extensão catálogo): VM104 Wazuh, CT107 Fluxus, VM116 RustDesk, VM124 Nextcloud, pfSense, Proxmox host ping.

Schema: contracts/stack-services.yaml.


Tiers e intervalos

Tier Intervalo Exemplos
critical 30 s desk.ligbox.com.br, api.ops.ligbox.com.br, Traefik, Desk API/UI LAN
standard 60 s Onboard, OpenPanel, Forgejo, FOSSBilling
slow 120 s Ollama, phpMyAdmin, Carbonio HTTPS LAN

Cada ciclo do Watchman executa apenas probes due (scheduler por next_check_at), não todos de uma vez cada segundo.


Alertas

Canais (ordem de envio)

  1. ntfyhttps://ntfy.ligbox.com.br/ligbox-watchman (tópico configurável; auth opcional)
  2. Emailadmin@ligbox.com.br via SMTP LAN (Postfix host ou VM122)
  3. Desk (opcional) — POST evento interno para tab Eventos

Formato ntfy (DOWN)

Title: 🔴 DOWN vm122-desk-ui
Body: Desk Frontend — HTTP timeout (3 failures)
Tags: warning,skull
Priority: high

Formato ntfy (RESOLVED)

Title: 🟢 OK vm122-desk-ui
Body: Desk Frontend — recovered after 19m down
Tags: white_check_mark
Priority: default

Anti-spam

  • Máximo 1 alerta DOWN por serviço por janela de 15 min (repeat throttle)
  • RESOLVED sempre enviado uma vez por incidente

Complemento Docker (VM122)

Independentemente do Watchman, aplicar na produção Desk:

restart: unless-stopped

em frontend, api, worker, redis no docker-compose.mvp.yml — previne classe de incidente 2026-06-22.


Estrutura no monorepo

projects/integrations/watchman/
  watchman.py              # daemon principal
  probes.py                # HTTP, TCP, Redis, Docker (opcional)
  catalog.py               # load YAML
  alerts.py                # ntfy, email, desk webhook
  store.py                 # SQLite state
  requirements.txt
  README.md

contracts/stack-services.yaml   # catálogo partilhado (fonte de verdade)

deploy/watchman/
  install.sh                 # systemd + venv
  ligbox-watchman.service
  watchman.env.example
  docker-compose.watchman.yml  # alternativa container

specs/035-ligbox-watchman/
  spec.md
  tasks.md
  quickstart.md
  contracts/

Refactor Spec 033: stack_health.py passa a ler contracts/stack-services.yaml + registry de probe handlers (evita duplicação).


API / ficheiros de status (v1)

Artefacto Path Descrição
Status JSON /var/lib/ligbox-watchman/status.json Snapshot último ciclo (para Desk/nginx)
SQLite /var/lib/ligbox-watchman/watchman.db Histórico incidentes
Log journalctl -u ligbox-watchman stdout estruturado

Formato status.json: ver contracts/status-snapshot.md.

Fase 2: GET /api/v1/watchman/status no Desk (read-only proxy do JSON).


RBAC e segurança

Item Regra
Credenciais ntfy/SMTP watchman.env — não commitar
Probes WAN só URLs públicas; LAN sem secrets em logs
OPENPANEL_BRIDGE_TOKEN herdado de env VM122 (mesmo que Desk)
Acesso status.json root:ligbox-watchman ou leitura Desk via grupo

Fases de implementação

Fase 0 — Mitigação imediata (sem Watchman)

  • restart: unless-stopped em docker-compose.mvp.yml produção VM122
  • Documentar no quickstart

Fase 1 — Watchman MVP

  • contracts/stack-services.yaml extraído de stack_health.py
  • watchman.py + systemd na VM122
  • Alertas ntfy
  • SQLite + anti-flap
  • status.json para consulta

Fase 2 — Integração Desk + email

  • Refactor stack_health.py → YAML
  • Email Postfix
  • Card “Watchman” em INFRA CODE (último alerta)
  • Catálogo VM104, 107, 116, 124

Fase 3 — Auto-remediação (opcional)

  • Probe docker local: se frontend/api down → docker start (com confirmação Roger)
  • Integração Agentic Ops (Spec 029) — ticket automático

Critérios de aceitação (Fase 1)

  1. Parar ligbox-ops-platform_frontend_1 → alerta ntfy em < 2 min (2×30 s critical).
  2. Subir frontend → alerta RESOLVED em < 2 min.
  3. Parar Desk API → Watchman continua a alertar (processo systemd independente).
  4. status.json actualizado a cada ciclo; summary.degraded correcto.
  5. RAM do processo < 64 MB em steady state (medido 1 h).
  6. Catálogo YAML versionado no Forgejo; alteração de URL = PR no repo.

Fora de escopo (v1)

  • UI web própria do Watchman (usar ntfy + Desk INFRA)
  • Prometheus/Grafana (peso excessivo para P0)
  • Monitorização Proxmox host metrics (Fase 2+)
  • Substituição do Wazuh

Documentos relacionados

Documento Conteúdo
quickstart.md Instalação VM122
tasks.md Checklist
contracts/stack-services.yaml Catálogo probes
contracts/status-snapshot.md Schema JSON
specs/033-desk-infra-console-ui/spec.md UI stack health
projects/ops-desk/api/app/stack_health.py Implementação actual (a migrar)

Incidente de referência

2026-06-22: https://desk.ligbox.com.br/ → HTTP 502 (Traefik OK, backend VM122:8091 down). Containers Exited (255) ~19 h. Causa provável: reboot VM sem restart Docker. Watchman teria alertado em < 1 min (tier critical).