Fase 7: CDR/métricas/relatórios, reconciliação, dashboard e compliance

- Reconciliação de tentativas órfãs após restart (reconciliation.ts),
  rodando a cada 60s.
- Vínculo real agente<->chamada (agent-call-binding.ts): claim atômico de
  agente disponível via FOR UPDATE SKIP LOCKED, DialAttempt.agentId
  populado no connect, ciclo AVAILABLE -> IN_CALL -> WRAP_UP -> AVAILABLE.
- Corrige abandonRate (EWMA) nunca atualizado pelo campaign-worker real —
  agora o fluxo QUEUED -> connect-or-abandon atualiza as estatísticas de
  fato usadas pelo predictive engine.
- Novo módulo de relatórios: /api/reports/calls (+export CSV), /metrics
  (TME/TMA/abandono), /agents/:id.
- Novo módulo de dashboard: /api/dashboard, /calls-by-hour,
  /campaigns/:id (Postgres + snapshot EWMA do Redis).
- Novo módulo de compliance: ComplianceSettings configurável +
  /api/compliance/settings e /indicators com contadores reais.
- Validado end-to-end contra containers reais (campanha de teste em modo
  simulação): agentId no connect, ciclo de estado do agente e abandonRate
  todos confirmados corrigidos com dados reais, não só no harness isolado.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QoVkLx1KsvtT1C88dRS3QW
This commit is contained in:
2026-08-27 16:09:22 -03:00
parent 66cc2058fd
commit 0a8b830e2c
22 changed files with 1072 additions and 34 deletions

View File

@@ -159,23 +159,26 @@ chamadas em andamento (seção 76).
- **AMD**: campo `Campaign.amdEnabled` existe no schema/DTO, mas a
detecção de secretária eletrônica em si (app `AMD()` do Asterisk ou
ARI) ainda não está integrada ao fluxo de originação real. Pendente.
- **Wrap-up automático**: `Campaign.wrapUpTimeSeconds` existe, mas a
transição automática do agente para o estado `WRAP_UP` ao final de uma
chamada real (via eventos `AgentComplete` do Asterisk) ainda não está
implementada em `apps/asterisk-events` — hoje o agente só muda de estado
manualmente pela tela do agente (Fase 5). Isso significa que, em uma
campanha com chamadas REAIS (não simuladas), a contagem de
`availableAgents`/`agentsLikelyToFreeSoon` não reflete automaticamente
agentes que entraram em uma chamada real — só funciona corretamente hoje
no modo de simulação (que modela isso internamente) e para as
transições manuais já cobertas pela Fase 5 (login/disponível/pausa/
logout). Wiring de `AgentConnect`/`AgentComplete` -> transição de estado
fica para consolidação junto da Fase 7 (reconciliação de estados).
- **Wrap-up automático (simulação)**: desde a Fase 7, `claimAvailableAgent`/
`releaseAgentAfterCall` (`agent-call-binding.ts`) implementam o ciclo
completo `AVAILABLE → IN_CALL → WRAP_UP → AVAILABLE` (usando
`Campaign.wrapUpTimeSeconds`) e `DialAttempt.agentId` é populado
corretamente ao conectar — validado end-to-end em modo simulação (ver
TODO.md Fase 7). **Isso ainda só é acionado pelo fluxo simulado
(`tryConnectOrAbandon`/`connect` em `campaign-worker.ts`).** Para
campanhas com chamadas REAIS (`DIALER_SIMULATION=false`), a transição via
eventos `AgentConnect`/`AgentComplete` do Asterisk ainda não está
implementada em `apps/asterisk-events` — hoje o agente em chamada real só
muda de estado manualmente pela tela do agente (Fase 5). Pendente para
quando houver troncos/chamadas reais para testar (Fase 9/10).
- **Correlação de eventos reais**: quando `DIALER_SIMULATION=false`, a
chamada é originada de verdade via AMI, mas a resolução fina
(atendida/ocupada/sem resposta) depende de reconciliação com
CDR/CEL/queue_log — planejada explicitamente para a Fase 7 (seção 51).
Por ora, uma chamada real sem eventos correlacionados expira em
(atendida/ocupada/sem resposta) ainda depende de reconciliação fina com
CDR/CEL/queue_log, que não está implementada — a Fase 7 entregou apenas a
reconciliação de *estados órfãos* (`reconciliation.ts`, tentativas presas
por >10min são forçadas a `FAILED`/`RECONCILED_ORPHAN`), não a
correlação de eventos AMI em tempo real para o resultado exato da
chamada. Por ora, uma chamada real sem eventos correlacionados expira em
`FAILED` após o timeout de segurança, o que é seguro (nunca fica presa
para sempre) mas não tão preciso quanto a resolução via simulação.
- **Disposições/Callback**: adiados para consolidar junto da tela do