# API central de saúde das VPS O backend do painel de suporte consulta a **central**, que reúne os servidores já cadastrados no console. Não é necessário distribuir os tokens administrativos das VPS ao painel. Esta API é de leitura; não reinicia serviços nem altera instâncias, limites de chamadas ou webhooks. ## Endpoints e autenticação | Base | Endpoint | Credencial | |---|---|---| | Central, por exemplo `https://wpp.atendro.cloud` | `GET /api/v1/servers/status` | `Authorization: Bearer ` | | Central | `GET /api/v1/servers/{server}/status` | Mesmo token de monitoramento | | API de cada VPS | `GET /v1/system/status` | Header `admintoken`, usado internamente pela central | `server` é o nome cadastrado no console. O cadastro existente determina as VPS consultadas; esta API não aceita URLs arbitrárias. O token da central fica em `CONSOLE_MONITORING_TOKEN` ou, no Compose, `ATENDROZAP_CONSOLE_MONITORING_TOKEN`. Use um segredo aleatório de pelo menos 32 caracteres, distinto dos tokens das VPS. Ausente: HTTP 503 `monitoring_disabled`. Inválido: HTTP 401. Servidor não cadastrado: HTTP 404 `server_not_found`. O token é exclusivo destes GETs. Login do console, cookies, token de instância e query string não o substituem. Guarde-o no **backend** do suporte, nunca no bundle, localStorage ou parâmetros da URL. A API não habilita CORS público. Exemplo de consumo no backend Node, sem imprimir credenciais: ```js const response = await fetch( `${process.env.ATENDROZAP_CENTRAL_URL}/api/v1/servers/status`, { headers: { Authorization: `Bearer ${process.env.ATENDROZAP_MONITORING_TOKEN}` }, signal: AbortSignal.timeout(10_000), redirect: 'error', }, ); if (!response.ok) throw new Error(`monitoring_http_${response.status}`); const fleet = await response.json(); // Entregue fleet à rota autenticada do seu painel de suporte. ``` Contrato completo: [OpenAPI da central](https://wpp.atendro.cloud/monitoring-openapi.json). O endpoint de cada VPS está no [OpenAPI principal](https://wpp.atendro.cloud/openapi.json). ## Como ler a resposta `schemaVersion` começa em 1. `servers` inclui também servidores offline, sem suporte à nova versão ou com falhas parciais. A ordem é pelo nome cadastrado. | Campo | Significado | |---|---| | `generatedAt` | Momento da resposta da central, em UTC | | `cacheSeconds` | Reutilização interna por até 15 segundos | | `summary` | Contagem total, online, offline, indisponíveis e por saúde | | `servers[].server` | Nome da VPS no cadastro central | | `observedAt` | Momento da tentativa mais recente de consultar a VPS | | `lastSuccessAt` | Última resposta válida observada; `null` se ainda não houve | | `availability` | `online`, `offline`, `unauthorized`, `unsupported`, `invalid_configuration`, `invalid_response`, `stale`, `unavailable` ou `cancelled` | | `health` | `ok`, `warning`, `critical` ou `unknown` | | `latencyMilliseconds` | Tempo até os headers HTTP da VPS; `null` quando indisponível | | `dataStale` | A resposta de `data` é uma leitura anterior, não uma medição atual | | `data` | Snapshot tipado da VPS, ou `null` sem leitura válida | | `alerts[]` | Código estável e gravidade, sem erros brutos ou dados privados | HTTP 200 significa que a consulta central foi executada; **não significa que todas as VPS estão saudáveis**. Use `availability`, `health`, `dataStale` e os estados de cada seção. Um erro de autenticação da VPS não é ausência de carga. Falhas não propagam corpos, headers, endereços ou tokens do servidor remoto. As duas rotas compartilham cache. Há no máximo oito consultas simultâneas e cinco segundos por coleta, incluindo a espera por vaga. Muitas consultas de suporte ao mesmo servidor se unem em uma coleta. Novos cadastros aparecem na próxima consulta; alterações de URL/token invalidam o cache correspondente. Leituras anteriores ficam somente em memória e se perdem ao reiniciar a central. ## Métricas disponíveis em `data` | Seção | Medições e interpretação | |---|---| | `host.snapshot.cpu` | CPUs lógicas, uso, espera por I/O e steal, em porcentagem | | `host.snapshot.load` | Load de 1/5/15 minutos e load dividido por CPUs lógicas | | `host.snapshot.memory` | RAM total, disponível, usada e percentual; considera `MemAvailable` | | `host.snapshot.swap` | Total, livre, usada e percentual | | `host.snapshot.rootFilesystem` | Disco total, livre, disponível, reservado, ocupado; inodes livres e usados | | `host.snapshot.network` | Contadores e bytes/s de recepção/transmissão; inclui interfaces virtuais não loopback | | `host.snapshot.diskIO` | I/O e ocupação do dispositivo da raiz; evita somar disco e partição | | `host.snapshot.uptimeSeconds` | Tempo ligado da VPS | | `host.snapshot.operations.docker` | Por papel `api/db/backup/console/caddy`: containers, em execução, reiniciando, OOM, reinícios e healthcheck | | `host.snapshot.operations.storage` | Bytes lógicos, quantidade e idade de arquivos de WAL, backups, gravações e diagnóstico; WAL completo cru, gzip, incompleto e auxiliares separados | | `host.snapshot.operations.backupVerification` | Marcador da última execução de `pg_verifybackup`; estado e idade da verificação | | `database` | Disponibilidade, tamanho do banco e pool de conexões da API | | `database.archiver` | Estado do arquivamento, quantidade pendente, tamanho de `pg_wal`, sucessos/falhas e timestamps | | `workload.instances` | Contagens por tipo/estado, leases desta VPS, estados conectados sem lease, vagas de chamadas configuradas e limite de sessões do worker | | `workload.calls` | Chamadas persistidas abertas, ativas/tocando/conectando/vídeo, excluindo leases expirados ou transferidos do total `live` | | `workload.webhooks` | Fila pendente, idade do evento mais antigo, retentativas, eventos mortos e destinos falhando/pausados | | `process` | Uptime, goroutines e memória do runtime Go da API; não é a RAM da VPS | `host.status` pode ser `ok/degraded/stale/unavailable`. O snapshot traz a hora original de coleta e sua validade. Métricas sem base de comparação, inclusive CPU/rede no primeiro ciclo e após reset, são `null`. Coleta parcial não converte ausência em zero. Tamanhos dos diretórios são bytes lógicos; disco disponível vem do filesystem. Tráfego agregado inclui interfaces Docker: não serve como fatura de tráfego externo. Falta de healthcheck aparece como tal. Instâncias e webhooks usam `scope: database`. Chamadas usam `scope: worker` e `source: database_snapshot`; não são uma prova de mídia RTP nem de qualidade da chamada. Se duas VPS compartilham banco, **não some as contagens de escopo database**. `callSlotsConfigured` é configuração, não capacidade homologada. A central não estima quantas chamadas uma VPS aguenta a partir desses números. Um backup verificado não prova cópia fora da VPS nem uma cadeia PITR completa. Sem o marcador de verificação, a situação é desconhecida, mesmo que existam arquivos de backup no diretório. O histórico de falhas do archiver é cumulativo; `blocked` exige falha mais recente que o sucesso e segmentos pendentes. ## Alertas e painel O painel pode começar com cartões de VPS, barras de CPU/RAM/disco, estado dos serviços, arquivamento do WAL, idade do backup, instâncias e chamadas ativas. Atualize a cada 30 segundos. Preserve indicação de leitura antiga e exiba `—` para `null`, em vez de zero. Um erro global da central deve marcar o painel como desatualizado, sem limpar todos os servidores existentes. Limiares iniciais da central: | Medida | Aviso | Crítico | |---|---:|---:| | Disco e inodes ocupados | 85% | 95% | | RAM ocupada | 85% | 95% | | CPU ocupada | 85% | 98% | | CPU steal | 10% | 25% | | Verificação de backup antiga | — | Mais de 36 horas | Banco indisponível, WAL bloqueado e serviço parado/reiniciando/unhealthy/OOM geram alerta crítico. Dados incompletos, WAL parcial e fila de webhook com mais de cinco minutos geram aviso. Os limiares avaliam snapshots; para notificações, o suporte deve exigir persistência em várias amostras e deduplicar alertas. Esta implementação não envia mensagens nem instala um sistema de notificações. Para gráficos históricos, armazene as amostras no backend do suporte usando `server` e a hora original `sampledAt`; não duplique amostras vindas do cache. A API fornece estado atual e última leitura válida, não séries temporais. ## Instalação 1. Preparar a revisão pelo fluxo `deploy/ship.sh HOST REV`. O build exporta `host-health` e `wal-archive` estáticos para `/opt/atendrozap/releases/REV/ops`. Ative a revisão com `sh deploy/host-health/install-ops.sh REV` no host; o preparo do build por si só não troca os executáveis em uso. 2. Instalar os arquivos de `deploy/host-health` e executar `install.sh` no host. O serviço systemd coleta a cada 15 segundos e escreve arquivo privado 0600, dono UID/GID 65532, em `/opt/atendrozap/health/status.json`. 3. O Compose monta esse diretório somente para leitura na API. Configure `ATENDROZAP_SYSTEM_STATUS_HOST_FILE=/host-health/status.json` e, opcionalmente, `ATENDROZAP_SYSTEM_STATUS_HOST_MAX_AGE=3m` (15s a 15m). O prazo efetivo é o menor entre esse teto e `validForSeconds` do snapshot; com coleta a cada 15 segundos, o coletor declara validade de 45 segundos. 4. Configure o token de monitoramento privado na central. Publique API e console na janela autorizada; recriar a API afeta brevemente as sessões de mensagens e chamadas. Recriar PostgreSQL para usar o novo `archive_command` é um passo distinto e deve ser coordenado. 5. Confira cada VPS pelo novo endpoint e as ausências parciais antes de considerar o painel operacional. VPS antigas aparecem como `unsupported`. O coletor roda no **host Linux**, acessa `/proc` e consulta apenas campos permitidos do Docker. O socket Docker não é montado na API. Reinicie somente o coletor após mudar volumes/papéis para atualizar os diretórios descobertos. macOS e execução do coletor dentro de container são explicitamente indisponíveis.