Quem consome o canônico
Quando um sistema externo puxa dados do SFA (GET /integrations/entities/{key}/records, autenticado
por x-api-key), a leitura fica registrada em consumer_reads — entidade, quantidade de
registros, duração, página e IP.
Onde ver
Aba Consumo externo em Execuções (/dashboard/executions), ao lado de
Conectores — vizinhas de propósito, porque a confusão entre as duas é justamente o que a seção
abaixo desfaz.
Por que não aparece na aba "Conectores"
Esta é a confusão mais comum, e ela tem uma razão de ser:
Conectores (SyncRun) | Consumo externo (ConsumerRead) | |
|---|---|---|
| O que registra | o SFA escrevendo o canônico a partir da fonte | um consumidor lendo o que já está gravado |
| Quem dispara | cron, botão Executar, API | o sistema externo |
| Tem de-para? | sim (é onde ele roda) | não, só leitura |
São sentidos opostos do fluxo. Se um consumidor puxar dados e você olhar a aba Conectores, não vai ver nada — e est á correto: nenhuma sincronização com a fonte aconteceu.
Antes do ADR-035, um consumidor lendo e um consumidor que nunca chamou produziam exatamente a
mesma tela vazia. É justamente essa distinção que consumer_reads resolve.
O que é registrado
Somente chamadas autenticadas por API key. Sessão humana é ignorada de propósito: o próprio painel de Integrações lê essa mesma rota para exibir os registros, e logar navegação de admin afogaria o dado útil.
{
"consumer": "Api principal", // nome da key, desnormalizado
"entityKey": "client",
"route": "/api/integrations/entities/client/records?page=1&pageSize=200",
"recordCount": 200,
"durationMs": 84,
"page": 1, "pageSize": 200,
"ip": "127.0.0.1",
"at": "2026-07-18T03:39:02.114Z"
}
Uma requisição = uma linha. Um consumidor que pagina 815 registros em páginas de 200 gera 5
linhas — o summary agrega isso.
Consultar
# leituras, mais recentes primeiro
GET /api/integrations/consumer-reads?entityKey=client&days=7
# agregado por consumidor x entidade
GET /api/integrations/consumer-reads/summary?days=7
Exige integration:read. Não aceita x-api-key — é trilha de auditoria, e um consumidor não
precisa enxergar o consumo dos outros.
Retenção: 60 dias
O Postgres não tem TTL nativo, então a expiração é um job (ConsumerReadPrunerService), que varre de
hora em hora.
| Variável | Default | O que faz |
|---|---|---|
CONSUMER_READ_RETENTION_DAYS | 60 | Dias de retenção. Valor inválido cai no default. |
CONSUMER_READ_PRUNE_ENABLED | ligado | false desliga o prune. |
O mesmo job expira api_key_usages, que era unbounded desde o ADR-028. É o mesmo tipo de dado —
log de acesso que cresce para sempre — e não faria sentido expirar um e deixar o outro.
Perguntas que isso responde
- O consumidor está mesmo puxando, ou caiu no fallback dele? → há linhas recentes?
- Quanto ele leva por sincronização? →
summary, colunarecords - Alguém está paginando demais? → muitas
readspara poucosrecords - Quem ainda consome a entidade X antes de eu renomear um campo? → filtro por
entityKey