# Proposta — Monitor de sistema (disco, memória, CPU)

## Contexto

Quando o servidor cai ou trava, precisamos de visibilidade sobre o estado de
**disco, memória e CPU** nos minutos anteriores à falha — caso contrário o
diagnóstico vira adivinhação. O monitor precisa:

1. Sobreviver a crash/hang do backend Node (senão não vale nada pós-mortem)
2. Ter pouca sobrecarga (não queremos o próprio monitor derrubar o servidor)
3. Ser simples de consultar depois do incidente

---

## Opções

### 🅰 Post-mortem via log rotativo (mínimo viável)

Script bash standalone + systemd timer coletando snapshot a cada 30–60s em
`/var/log/newwhats-health.log` (rotativo por `logrotate`).

**Campos coletados:**

- Uso de disco (`df -h /`)
- Memória (`free -m` — total, usado, livre, cache, swap)
- CPU / load average (`uptime`, `top -bn1 | head`)
- Processos do newwhats (PID, %CPU, %MEM, comando)
- Rede (`ss -s` — conexões TCP ativas)
- Uptime (`uptime -p`)

**Entregáveis:**

- `/opt/newwhats/scripts/collect-health.sh` — script bash idempotente
- `/etc/systemd/system/newwhats-health.service` — unit oneshot
- `/etc/systemd/system/newwhats-health.timer` — timer disparando a cada 30s
- `/etc/logrotate.d/newwhats-health` — rotação diária, retenção configurável

**Vantagem crítica:** roda fora do backend. Sobrevive a crash, hang, OOM
killer, e até a `kill -9` do processo Node. Quando o servidor cair, basta
`tail /var/log/newwhats-health.log` e aparece exatamente o estado nos
últimos minutos.

**Desvantagem:** sem dashboard — só via terminal.

---

### 🅱 Post-mortem + endpoint em tempo real

**Tudo do A, mais:**

Endpoint `/api/admin/system-health` no backend que retorna JSON com leitura
ao vivo:

```ts
{
  uptime:        number,    // os.uptime()
  loadAvg:       [n, n, n], // os.loadavg()
  memory: {
    total:       number,    // os.totalmem()
    free:        number,    // os.freemem()
    usedPct:     number,
    processRss:  number,    // process.memoryUsage().rss
    processHeap: number,    // process.memoryUsage().heapUsed
  },
  disk: {
    total:       number,    // fs.statfs('/')
    free:        number,
    usedPct:     number,
  },
  cpu: {
    cores:       number,
    model:       string,
  },
  node: {
    version:     string,
    pid:         number,
  },
}
```

Protegido por `adminMiddleware`.

**Vantagem:** permite montar dashboard no frontend depois sem re-arquitetar.
Útil também pra curl/monitoring externo (UptimeRobot, etc).

**Desvantagem:** endpoint depende do backend estar vivo. Se o processo
travou, só o log bash salva. Por isso sempre acompanha o A, nunca substitui.

---

### 🅲 A + B + dashboard frontend + alertas

**Tudo do B, mais:**

- Página admin no frontend (`/admin/system`) com gráficos das últimas 24h
- Polling do endpoint a cada 5s
- Histórico persistido em tabela Postgres (`system_health_samples`) ou
  stream no Dragonfly (mais leve, TTL de 24h automático)
- Emit de `system:alert` via socket.io quando threshold é ultrapassado:
  - Memória > 90%
  - Disco > 85%
  - Load > `numCores * 2`
- Toast no frontend mostrando o alerta

**Desvantagens:**

- Adiciona chart lib no frontend (recharts, apex, chart.js — ~50KB gzipped)
- Alertas via socket.io não chegam se o backend estiver morto — falsa
  sensação de segurança
- Alertas em tempo real geralmente são feitos com ferramenta externa
  (Grafana/Prometheus/Netdata) — reinventar dentro do app é trabalho sem
  ROI claro

---

## Recomendação: A+B

**Por quê:**

1. **A cobre o caso real** que você descreveu ("servidor caiu ou travou").
   Post-mortem via log é o que **sempre** funciona, mesmo no pior cenário.
2. **B dá um hook** pra construir dashboard depois sem refatorar — o
   endpoint é pequeno e vive debaixo do `adminMiddleware`.
3. **C adiciona complexidade** que pode ser feita em sprint futura se você
   decidir que o ganho vale. Começar sem gráficos é mais barato e mais
   rápido de entregar.
4. **Alertas em tempo real são complementares, não substitutos:** se você
   quiser notificações robustas, a resposta é integrar com Prometheus /
   Grafana / Netdata — que foram feitos pra isso — não reescrever a roda
   dentro do app.

---

## Decisões que precisam de resposta antes de aplicar

| # | Decisão | Opções | Default sugerido |
|---|---------|--------|------------------|
| 1 | Intervalo de coleta | 30s / 60s | **30s** (granularidade importa pra detectar spikes) |
| 2 | Retenção do log | 7 dias / 30 dias | **7 dias** (rotação diária, arquivo ~10MB/dia) |
| 3 | Notificações imediatas | email / webhook / nada | **nada** (começar simples) |
| 4 | Path do log | `/var/log/newwhats-health.log` (precisa root na criação) / `/home/deploy/projetos/newwhats.local/logs/health.log` (sem sudo) | **`/var/log/newwhats-health.log`** (padrão systemd, integra com logrotate global) |

---

## Escopo explicitamente fora

- ❌ Monitoramento distribuído (vários hosts)
- ❌ Alertas por SMS/WhatsApp/Slack
- ❌ Dashboard com gráficos históricos (fica na Opção C)
- ❌ Integração com Prometheus/Grafana/Netdata (trabalho separado, fora do
  scope do app)
- ❌ APM / tracing de requests (é outra categoria de ferramenta)
- ❌ Monitor de health do Postgres / Dragonfly (checar separadamente se
  houver sintomas — hoje não é gargalo)

---

## Estimativa de entrega (referência, não commitment)

**Opção A isolada:** script bash + 2 units systemd + logrotate config →
3 arquivos pequenos, baixa superfície.

**Opção A+B:** adiciona 1 endpoint no backend (~40 linhas TypeScript) e
uma chamada em `server.ts` pra montar a rota. Sem mudança no frontend.

**Opção C:** soma uma página React com gráficos + migration + lógica de
sample + lógica de alerta + toast handler. Bem mais trabalho.
