- packages/telephony: cliente AMI proprio sobre TCP puro (sem dependencia de terceiros pouco mantida) + interface TelephonyProvider + AsteriskTelephonyProvider (Originate, Hangup, QueuePause/Add/Remove, QueueStatus, ExtensionState, DeviceState, PJSIPShowEndpoints/Contacts, Reload, runCommand, stream de eventos). Testado contra o Asterisk real — o formato de resposta do Command mudou entre versoes do Asterisk (headers 'Output:' repetidos em vez de 'Response: Follows'/'--END COMMAND--'), corrigido apos inspecionar os bytes crus do protocolo - apps/asterisk-events: worker dedicado a manter a conexao AMI viva, normalizar eventos (Newchannel, DialBegin/End, Hangup, DeviceStateChange, ContactStatus, eventos de fila/agente), persistir ExtensionState no Postgres e publicar em Redis pub/sub para consumo em tempo real. Containerizado, alcanca o Asterisk (host network) via host.docker.internal a partir da rede bridge. Heartbeat no Redis para health check - packages/database: novos modelos Trunk, Extension, ExtensionState (migration aplicada) - packages/shared: secret-crypto.ts (AES-256-GCM para credenciais de trunk e senha SIP em repouso, master key externa ao banco) Testado ponta a ponta: chamada real originada -> eventos normalizados recebidos via Redis SUBSCRIBE, heartbeat renovando no TTL correto.
11 KiB
11 KiB
B2BCall — TODO Operacional
Checklist vivo. Marcar [x] somente após testar. Não deixar item concluído sem
validação. Ver critérios de aceite completos em docs/ARCHITECTURE.md e no prompt
mestre original (agente.md, seções 90-93).
Fase 0 — Infraestrutura base
- Levantamento do servidor (SO, recursos, rede)
- docs/ARCHITECTURE.md
- TODO.md
- Git init + .gitignore + primeiro commit
- Instalar Docker Engine + Compose plugin (29.7.2 / Compose v5.5.0)
- Estrutura de diretórios do monorepo
- .env.example (+ scripts/generate-secrets.sh, .env real gerado localmente)
- nftables (firewall base, default-deny administrativo, sem bloquear SSH) — adiado para a Fase 9, quando houver serviços/portas reais a proteger
Fase 1 — Dados e cache
- docker-compose: serviço postgres 17-alpine (schemas application/asterisk) — testado, healthy
- docker-compose: serviço redis 7-alpine (auth, AOF, maxmemory 100mb) — testado, healthy
- Health checks postgres/redis
- packages/database: schema inicial + migrations tool
Fase 2 — Asterisk
- Dockerfile Asterisk 22.10.1 LTS compilado do fonte (host network) —
Debian trixie não tem mais o pacote
asterisknos repos oficiais - PJSIP (transport UDP:5060; chan_sip nem existe mais a partir do Ast 21)
- AMI habilitado — testado login via 127.0.0.1:5038, bloqueado na LAN via nftables
- ARI habilitado — testado GET /ari/asterisk/info via 127.0.0.1:8088, 401 sem auth
- Realtime ODBC -> Postgres schema
asterisk(sorcery.conf + extconfig.conf + res_odbc.conf) —pjsip show endpointsconsulta o Postgres sem erro - CDR via cdr_adaptive_odbc — testado, grava em asterisk.cdr (ANSWERED,
duration/billsec corretos). Nota: coluna
endrenomeada paraend_time(palavra reservada no Postgres, cdr_adaptive_odbc não quota identificadores) - CEL via cel_odbc — testado, grava em asterisk.cel (CHAN_START/ANSWER/ HANGUP/CHAN_END)
- queue_log habilitado (padrão do app_queue, arquivo em /var/log/asterisk)
- Dialplan inicial de teste (contexto
b2bcall-healthcheck, exten 600, Answer/Playback/Echo) — testado viachannel originate ... extension - nftables protegendo AMI/ARI/SIP na interface da LAN (ens18), trazido da
Fase 9 para já — não testado a partir de outra máquina na LAN (só
localmente, onde tráfego para o próprio IP vai por
loe não exercita a regra; revisar quando OpenSIPS/outro host estiver disponível)
Pendências conhecidas da Fase 2 (não bloqueiam, revisitar depois)
res_pjsip_outbound_registrationrecusa carregar no boot (mensagem "no existing documentation" para o tipo 'registration' do sorcery) — carregamento manual viamodule loadfunciona mas é desfeito por uma flag interna de "declined at boot". Só afeta troncos com registration outbound; endpoints/aors funcionam normalmente. Investigar na Fase 4 ao implementar cadastro de troncos com registration.res_config_ldapgera ERROR de log no boot (sem LDAP configurado, não usamos). Cosmético — considerarnoloadem modules.conf.cdr_pgsql/cel_pgsqlnão compilaram (falta libpq-dev na imagem); usamoscdr_adaptive_odbc/cel_odbccomo alternativa funcional via ODBC — decisão adequada, não precisa dos módulos pgsql nativos.
Fase 3 — Backend base
- apps/api (NestJS 11 + Fastify) bootstrap — containerizado, healthy
- packages/database (Prisma) + packages/shared (catálogo de permissões) — decisão de ORM documentada em docs/ARCHITECTURE.md 3.6.1
- Migration inicial aplicada (users/sessions/roles/permissions/ user_roles/role_permissions/audit_logs/password_reset_tokens)
- Seed (40 permissões, 4 perfis, bootstrap super_admin com senha aleatória em FIRST_LOGIN.txt chmod 600) — testado
- Autenticação (Argon2id, access JWT + refresh opaco com rotação, cookies HttpOnly/SameSite=Lax, refresh_token restrito a /api/auth) — testado: login, /me, refresh, change-password, revogação de sessão
- Rate limiting de login progressivo via Redis (5/60s, bloqueio 1min→2min→4min...até 1h por IP) — testado com 7 tentativas seguidas
- RBAC completo (users/roles/permissions/user_roles/role_permissions) reforçado no backend via PermissionsGuard — testado (nega sem permissão, permite com todas as permissões) + unit tests
- Proteção contra auto-elevação de privilégio (usuário não altera os próprios roleIds) — testado, HTTP 403
- Auditoria (audit_logs) chamada explicitamente em cada ação sensível (login/login_failed/logout/password_changed/user_created/ user_updated/role_*) com redação de campos sensíveis — testado via GET /api/audit (roles.manage/audit.view), paginação server-side
- Health checks /api/health, /api/health/live, /api/health/ready (Postgres + Redis reais, sem dado fake) — testado
- Swagger/OpenAPI em /api/docs, desabilitável via SWAGGER_ENABLED=false — testado (200 com flag default true)
- Logs estruturados JSON (nestjs-pino) com request_id de correlação e redação de senha/tokens/cookies
- Filtro global de exceções: nunca expõe erro cru, sempre requestId
- Lint (eslint --fix) e testes unitários (PermissionsGuard) passando
- Recuperação de senha por e-mail: lógica completa (token com expiração, hash, uso único), mas envio real via SMTP é um stub que só loga — falta credencial SMTP real (.env SMTP_*), meramente externo — trocar MailerService por nodemailer quando houver
Fase 4 — Telefonia (camada de aplicação)
- packages/telephony: cliente AMI próprio (TCP raw, sem dependência de terceiros) + TelephonyProvider + AsteriskTelephonyProvider — testado contra o Asterisk real: login, PJSIPShowEndpoints/QueueStatus (lista vazia tratada corretamente), Command (parsing do formato real do Asterisk 22: múltiplos headers "Output:", não mais "Follows"/"--END COMMAND--"), Originate, stream de eventos
- apps/asterisk-events (worker dedicado, containerizado) — conecta via host.docker.internal (rede bridge -> Asterisk em host network), normaliza eventos relevantes, persiste ExtensionState (Postgres), publica em Redis pub/sub (b2bcall:events:asterisk e :extensions), heartbeat para health check — testado ponta a ponta com chamada real
- Schema Prisma: Trunk, Extension, ExtensionState + criptografia de segredos AES-256-GCM (packages/shared/secret-crypto.ts)
- CRUD Troncos (com CPS máximo, ACL, teste de status)
- CRUD Ramais (senha SIP gerada, reset, status tempo real)
- Painel visual de Ramais (WebSocket, prioridade de cores) — backend (gateway WS) pendente; ExtensionState/pub-sub já prontos como base
- Dialplan estruturado (versionado, modo Advanced, validação+rollback)
- Administração do Asterisk (abas: geral, pjsip, rtp, filas, cdr, cel, logs, ami, ari, modules, diagnóstico com allowlist de comandos)
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)
Fase 6 — Campanhas e discador preditivo
- CRUD Campanhas (todos os campos da seção 24)
- Import CSV streaming (preview, mapeamento, validação, duplicados, rejeitados)
- Normalização de telefone (serviço dedicado, BR inicialmente)
- Lista de supressão (DNC) + checagem obrigatória pré-originação
- CPS limiter (token bucket, coordenado via Redis, multi-worker)
- Reserva concorrente de leads (FOR UPDATE SKIP LOCKED + timeout)
- Idempotência de originação (attempt_id/call_id/uniqueid/linkedid, state machine)
- PredictiveDialerEngine (EWMA, pacing, previsão de liberação de agentes)
- Controle de abandono (pacing cai / suspende originação)
- AMD opcional por campanha
- Wrap-up time
- Retry engine (regras por causa, limite de tentativas)
- Horário de campanha (timezone, dias/horários, WAITING_SCHEDULE)
- Lock distribuído por campanha (Redis)
- docs/PREDICTIVE_DIALER.md
Fase 7 — CDR, métricas e relatórios
- Modelo consolidado de chamadas (CDR+CEL+AMI+queue_log)
- Reconciliação de estados órfãos após restart
- TME / TMA (definições documentadas, cálculo correto)
- Relatório de Chamadas (filtros, paginação server-side, export CSV)
- Relatório de Agentes (tempos, pausas detalhadas)
- Dashboard geral (cards + gráficos reais)
- Dashboard do discador (por campanha, tempo real)
- Compliance de Chamadas (parâmetros configuráveis, alertas, contadores)
Fase 8 — Frontend completo
- Bootstrap Next.js + Tailwind + shadcn/ui + TanStack Query + WS client
- Logo processada (b2bcall.png) + tema light/dark
- Menu completo (seção 52)
- Todas as telas do checklist de aceite (seção 90)
Fase 9 — Segurança e produção
- Criptografia de segredos de trunk (AES-256-GCM)
- HTTP security headers, CORS, CSRF, Helmet
- nftables final revisado
- Logs estruturados JSON (sem segredos)
- Correlation IDs (request_id/attempt_id/call_id)
- Métricas Prometheus (/metrics)
- Bootstrap super_admin (senha aleatória, FIRST_LOGIN.txt, forçar troca)
- Seed (permissões, perfis, pausas, disposições) sem dados fake em produção
- Backup/restore (postgres, asterisk config, .env seguro)
- scripts/install.sh, update.sh, backup.sh, restore.sh, healthcheck.sh
- Nginx reverse proxy (80/443, WS, HTTPS documentado)
Fase 10 — Testes e aceite
- Unit tests (predictive engine, CPS limiter, permissions, phone norm, retry, state machines, TME/TMA, scheduling)
- Integration tests (postgres, redis, repositories, API, AMI mock)
- E2E (login → ... → RBAC, conforme seção 64)
- Modo simulação (DIALER_SIMULATION=true) + testes do predictive engine
- Prova de CPS respeitado / concorrência máxima / sem discagem dupla / pausa efetiva / recuperação após restart / pacing reage a abandono / supressão respeitada / horário respeitado
- Quality gate (lint, typecheck, unit, integration, e2e, compose config, compose ps, health checks) — tudo verde
- Aceite de segurança (seção 92)
- Aceite Asterisk (seção 93, comandos documentados)
- README final completo
- Relatório final da implementação
Nota de ambiente: VM atual com 1.9 GiB RAM / 2 vCPU — adequada para dev e simulação, não para carga real de produção. Ver docs/ARCHITECTURE.md seção 1.