feat: add call center queues

- packages/database: Agent, AgentSession, AgentStateEvent, AgentPauseEvent,
  PauseReason, Queue, QueueMember (agente.md secao 53)
- apps/api/src/queues: CRUD de filas gerando queues.conf pelo mesmo padrao
  do dialplan (arquivo compartilhado + module reload app_queue.so), mas
  SEM membros estaticos no arquivo — membership eh 100% dinamica via AMI
  (evita duas fontes de verdade conflitantes)
- apps/api/src/pause-reasons: CRUD de motivos de pausa
- apps/api/src/agents: CRUD administrativo de agentes (1:1 com User)
- apps/api/src/agent-console: maquina de estados do agente
  (LOGGED_IN/AVAILABLE/PAUSED), 'tela do agente' via
  login/available/pause/unpause/logout, cada transicao aciona AMI
  QueueAdd/QueuePause/QueueRemove de verdade e registra
  agent_state_events/agent_pause_events com inicio/fim
- apps/api/src/monitoring: GET /api/monitoring/queues (chamadas
  aguardando, agentes logados/pausados/disponiveis via AMI QueueStatus ao
  vivo) — metricas historicas (TME/TMA/SLA) ficam para a Fase 7

Testado ponta a ponta contra o Asterisk real: fila criada aparece via
'queue show'; agente loga, fica disponivel (QueueAdd confirmado, membro
dinamico visivel), pausa com motivo (confirmado 'paused:Almoco' ao vivo),
despausa, desloga (QueueRemove confirmado, fila volta a 'No Members').

Disposicoes de chamada e Callback adiados para a Fase 6 (dependem de
haver chamadas de campanha reais para classificar).
This commit is contained in:
2026-08-27 13:38:19 -03:00
parent cf3fc4b3ef
commit 63103d4335
29 changed files with 1627 additions and 15 deletions

36
TODO.md
View File

@@ -137,14 +137,34 @@ mestre original (`agente.md`, seções 90-93).
status/diagnóstico, não tem tela de edição de asterisk.conf/rtp.conf
## Fase 5 — Call Center
- [ ] Agentes (agents, agent_sessions) separados de users
- [ ] Máquina de estados do agente (OFFLINE..PAUSED)
- [ ] Motivos de pausa (CRUD)
- [ ] Filas (CRUD + estratégias documentadas)
- [ ] Tela do agente (login dinâmico, pausa/retomada, disposição)
- [ ] Disposições de chamada (CRUD + ações: callback, DNC)
- [ ] Callback (agendamento + scheduler)
- [ ] Monitoramento de Filas (tempo real)
- [x] Agentes (agents, separado de users 1:1) + agent_sessions +
agent_state_events + agent_pause_events — schema Prisma completo
- [x] Máquina de estados do agente (LOGGED_IN→AVAILABLE→PAUSED→AVAILABLE,
logout) com histórico início/fim por estado — testado ponta a ponta
contra o Asterisk real: login cria sessão, "disponível" faz AMI
QueueAdd (confirmado via `queue show`: membro dinâmico aparece),
"pausar" faz QueuePause com motivo (confirmado: "paused:Almoco"
aparece ao vivo), "despausar" reverte, "logout" faz QueueRemove
(confirmado: fila volta a "No Members")
- [x] Motivos de pausa (CRUD) — sem permissão dedicada no catálogo da
seção 11, tratado sob settings.manage
- [x] Filas (CRUD + 8 estratégias do enum QueueStrategy) — gera
queues.conf via o mesmo padrão do dialplan (arquivo compartilhado +
reload), mas SEM membros estáticos: membership é 100% dinâmica via
AMI (login/logout do agente), evitando dessincronia entre duas
fontes de verdade
- [x] Tela do agente (backend completo: login/available/pause/unpause/
logout via /api/agent-console/*) — disposição de chamada fica para
quando existir uma chamada de verdade para dispor (Fase 6)
- [ ] Disposições de chamada (CRUD + ações: callback, DNC) — adiado para
Fase 6 junto com Campanhas/Leads, já que disposição só faz sentido
quando há chamadas de campanha reais para classificar
- [ ] Callback (agendamento + scheduler) — idem, depende de leads/campanhas
- [x] Monitoramento de Filas (tempo real): GET /api/monitoring/queues
(chamadas aguardando, maior espera, agentes logados/pausados/
disponíveis) via AMI QueueStatus ao vivo. TME/TMA/SLA/taxa de
abandono HISTÓRICOS ficam para a Fase 7 (dependem de consolidação
de CDR/CEL/queue_log) — não inventamos número aqui
## Fase 6 — Campanhas e discador preditivo
- [ ] CRUD Campanhas (todos os campos da seção 24)