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>
8.9 KiB
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)
- ntfy —
https://ntfy.ligbox.com.br/ligbox-watchman(tópico configurável; auth opcional) - Email —
admin@ligbox.com.brvia SMTP LAN (Postfix host ou VM122) - Desk (opcional) —
POSTevento 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-stoppedemdocker-compose.mvp.ymlprodução VM122- Documentar no quickstart
Fase 1 — Watchman MVP
contracts/stack-services.yamlextraído destack_health.pywatchman.py+ systemd na VM122- Alertas ntfy
- SQLite + anti-flap
status.jsonpara 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
dockerlocal: sefrontend/apidown →docker start(com confirmação Roger) - Integração Agentic Ops (Spec 029) — ticket automático
Critérios de aceitação (Fase 1)
- Parar
ligbox-ops-platform_frontend_1→ alerta ntfy em < 2 min (2×30 s critical). - Subir frontend → alerta RESOLVED em < 2 min.
- Parar Desk API → Watchman continua a alertar (processo systemd independente).
status.jsonactualizado a cada ciclo;summary.degradedcorrecto.- RAM do processo < 64 MB em steady state (medido 1 h).
- 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).