# PROMPT MESTRE — B2BCall Você é o arquiteto principal, engenheiro de software sênior, DevOps, DBA PostgreSQL e especialista em telefonia VoIP/Call Center responsável por projetar e implementar **do zero** uma plataforma profissional de discagem preditiva chamada: # B2BCall Você está trabalhando diretamente em um servidor: * Debian 13 * Instalação limpa * Servidor dedicado à aplicação * Diretório principal: `/opt/b2bcall` * Logo existente em: `/opt/b2bcall/b2bcall.png` * Banco de dados: PostgreSQL * Telefonia: Asterisk * SIP: PJSIP * Frontend e backend preferencialmente em TypeScript * Toda a aplicação deve funcionar em containers Docker * O Asterisk não possuirá IP público * O Asterisk ficará atrás de um OpenSIPS * Os troncos SIP serão acessados através de IPs privados * Nenhuma porta SIP, AMI, ARI, PostgreSQL ou Redis deve ficar desnecessariamente exposta à Internet A aplicação deve ser moderna, segura, modular, escalável e adequada para ambiente de produção. --- # 1. REGRA PRINCIPAL DE EXECUÇÃO NÃO produza apenas documentação. NÃO faça apenas mockups. NÃO faça somente o frontend. NÃO pare depois de criar a estrutura inicial. NÃO deixe funções principais marcadas como TODO. Você deve efetivamente: 1. analisar o servidor; 2. preparar o ambiente; 3. instalar Docker e dependências necessárias; 4. criar a estrutura do projeto; 5. criar os containers; 6. configurar PostgreSQL; 7. configurar Redis se necessário; 8. instalar/configurar Asterisk; 9. construir backend; 10. construir frontend; 11. construir o motor do discador; 12. integrar o backend ao Asterisk; 13. implementar autenticação; 14. implementar RBAC/permissões; 15. implementar todas as telas solicitadas; 16. implementar métricas; 17. implementar relatórios; 18. implementar monitoramento em tempo real; 19. implementar auditoria; 20. implementar segurança; 21. criar migrations; 22. criar testes; 23. executar os testes; 24. corrigir os problemas encontrados; 25. subir o ambiente; 26. validar os health checks; 27. documentar; 28. continuar até que o sistema esteja operacional. Trabalhe de maneira AUTÔNOMA. Quando houver mais de uma abordagem tecnicamente válida, escolha a solução que considerar mais adequada para produção e documente a decisão. Não interrompa o desenvolvimento a cada decisão pequena para perguntar ao usuário. Somente pare por algo realmente impossível de resolver sem informação externa, como uma senha de uma operadora que não foi fornecida. --- # 2. OBJETIVO DO PRODUTO O B2BCall será uma plataforma profissional de Call Center e discagem preditiva. Deve possuir: * Asterisk integrado; * ramais; * agentes; * filas; * pausas; * troncos; * dialplans; * campanhas; * leads; * discador preditivo; * controle CPS; * monitoramento em tempo real; * dashboards; * TME; * TMA; * relatórios; * RBAC; * administração completa; * configuração do Asterisk; * auditoria; * segurança; * observabilidade. Não quero um simples sistema de “click to call”. Quero um verdadeiro: **Predictive Dialer / Automatic Call Distribution System.** --- # 3. ARQUITETURA TECNOLÓGICA Use preferencialmente um monorepo TypeScript. Uma arquitetura recomendada é: ```text /opt/b2bcall ├── apps │ ├── frontend │ ├── api │ ├── dialer-worker │ ├── asterisk-events │ └── scheduler ├── packages │ ├── database │ ├── shared │ ├── types │ ├── ui │ └── telephony ├── infrastructure │ ├── asterisk │ ├── nginx │ ├── postgres │ └── docker ├── scripts ├── docs ├── docker-compose.yml ├── .env.example ├── .gitignore └── README.md ``` Pode adaptar a estrutura se houver justificativa técnica. ## Stack sugerida ### Frontend * Next.js * React * TypeScript * Tailwind CSS * shadcn/ui ou componentes equivalentes * TanStack Query * WebSocket para dados em tempo real ### Backend Preferencialmente: * Node.js * TypeScript * NestJS Pode utilizar Fastify como HTTP adapter. ### Banco * PostgreSQL 17 ou versão estável compatível * migrations obrigatórias * índices corretamente planejados * transactions * constraints * foreign keys * JSONB apenas quando fizer sentido ### Cache/mensageria Redis pode ser utilizado para: * filas internas; * locks; * presença; * sessões em tempo real; * workers; * campanhas; * rate limit; * eventos. Pode utilizar BullMQ. ### Telefonia Use: **Asterisk 22 LTS** com: * PJSIP; * AMI; * ARI quando realmente necessário; * CDR; * CEL; * queue_log; * app_queue. Não utilize `chan_sip`. --- # 4. DOCKER Toda a solução deve ser containerizada. Criar no mínimo serviços equivalentes a: ```text b2bcall-frontend b2bcall-api b2bcall-worker b2bcall-asterisk-events b2bcall-scheduler b2bcall-asterisk b2bcall-postgres b2bcall-redis b2bcall-nginx ``` Avalie cuidadosamente a rede do Asterisk. Como RTP possui uma quantidade significativa de portas UDP, considere utilizar `network_mode: host` para o container do Asterisk caso isso simplifique e torne a operação mais confiável. Se utilizar host network, documente detalhadamente os impactos. Os outros containers devem permanecer em redes Docker privadas sempre que possível. PostgreSQL e Redis não devem ficar expostos publicamente. Adicionar: * restart policies; * health checks; * volumes persistentes; * logging; * dependency checks; * resource considerations. --- # 5. TOPOLOGIA SIP A arquitetura é: ```text INTERNET | [ OpenSIPS ] | rede SIP privada | [ Asterisk ] | [ B2BCall ] ``` E para operadoras: ```text Asterisk | rede privada | Troncos SIP ``` O Asterisk NÃO possui IP público. Nunca assuma que ele precisa registrar troncos pela Internet. Permitir troncos: * IP Authentication; * Username/password quando necessário; * PJSIP registration quando necessário. Permitir configuração de: * IP; * porta; * transporte; * codecs; * DTMF; * From User; * From Domain; * Contact User; * Outbound Proxy; * identificação por IP; * autenticação; * caller ID; * limites; * context; * qualify; * timers. Criar ACLs e configurações de segurança. AMI e ARI jamais deverão estar publicamente acessíveis. --- # 6. ASTERISK REALTIME Avalie utilizar Asterisk Realtime + ODBC/PostgreSQL para objetos PJSIP. Exemplos: * ps_endpoints * ps_auths * ps_aors * ps_contacts * ps_endpoint_id_ips * ps_registrations O banco de aplicação deve continuar possuindo seu próprio modelo de domínio. Não misture indiscriminadamente tabelas da aplicação com tabelas internas do Asterisk. Uma boa estratégia é utilizar schemas separados: ```text public/application asterisk ``` ou configuração equivalente. --- # 7. INTEGRAÇÃO ASTERISK O backend deve possuir uma camada: ```text TelephonyProvider ``` e implementação: ```text AsteriskTelephonyProvider ``` Não espalhe comandos AMI dentro de controllers da aplicação. Criar serviço central responsável por: * Originate; * Hangup; * QueuePause; * QueueAdd; * QueueRemove; * ExtensionState; * DeviceState; * QueueStatus; * PJSIPShowEndpoints; * PJSIPShowContacts; * reload; * eventos; * canais; * bridges; * chamadas. Utilize AMI principalmente para eventos administrativos e controle. Utilize ARI quando o controle de canais/bridges exigir ARI. --- # 8. EVENTOS EM TEMPO REAL Criar serviço dedicado que permaneça conectado ao AMI. Ele deve consumir eventos como: * Newchannel; * DialBegin; * DialEnd; * BridgeEnter; * BridgeLeave; * Hangup; * Newstate; * DeviceStateChange; * QueueMemberStatus; * QueueMemberPause; * AgentConnect; * AgentComplete; * QueueCallerJoin; * QueueCallerLeave; * QueueCallerAbandon; * ContactStatus; * PeerStatus/PJSIP equivalentes. Normalizar esses eventos. Persistir eventos importantes. Transmitir dados do estado atual para o frontend utilizando WebSocket. Nunca fazer o frontend executar polling a cada segundo no Asterisk. --- # 9. AUTENTICAÇÃO Criar autenticação profissional. Login: * e-mail; * senha. Implementar: * Argon2id para hash; * access token; * refresh token; * cookies HttpOnly quando aplicável; * Secure; * SameSite; * rotação de refresh token; * logout; * revogação de sessão; * recuperação de senha; * token de recuperação com validade; * auditoria; * proteção contra enumeração de usuários. Nunca armazenar senha em texto puro. Nunca armazenar JWT em localStorage se puder ser evitado. --- # 10. RATE LIMIT É obrigatório implementar proteção contra força bruta. Exemplo: ```text 5 tentativas de login / minuto / IP ``` com bloqueio progressivo. Implementar também limites por: * IP; * usuário; * endpoint sensível. Registrar tentativas excessivas no audit log. Redis poderá ser utilizado para rate limiting distribuído. --- # 11. RBAC — PERMISSÕES Criar RBAC completo. Não faça simplesmente: ```text if user.role == admin ``` Criar: ```text users roles permissions user_roles role_permissions ``` Perfis iniciais: ```text super_admin admin supervisor agent ``` Porém os níveis NÃO devem ser fixos. O `super_admin` precisa possuir uma tela de: **Perfis e Permissões** onde possa definir exatamente o que cada perfil pode acessar. Exemplos: ```text dashboard.view trunks.view trunks.create trunks.update trunks.delete extensions.view extensions.create extensions.update extensions.delete dialplans.view dialplans.create dialplans.update dialplans.delete queues.view queues.create queues.update queues.delete agents.view agents.create agents.update agents.delete campaigns.view campaigns.create campaigns.start campaigns.pause campaigns.stop campaigns.update campaigns.delete reports.view reports.export monitoring.view asterisk.view asterisk.configure asterisk.reload users.view users.create users.update roles.manage audit.view settings.manage ``` O frontend deve esconder funcionalidades sem permissão. MAS: **a segurança sempre deve ser validada novamente pelo backend.** Nunca confie apenas no frontend. --- # 12. AUDITORIA Criar `audit_logs`. Registrar no mínimo: * login; * logout; * login inválido; * criação; * edição; * exclusão; * início de campanha; * pausa de campanha; * encerramento de campanha; * alteração de trunk; * alteração de ramal; * alteração de fila; * alteração de agente; * alteração do Asterisk; * reload; * alteração de permissões. Guardar: ```text user_id action entity_type entity_id before after ip_address user_agent created_at ``` Para campos sensíveis, nunca salvar segredos abertos no `before/after`. --- # 13. TELA DE TRONCOS Criar menu: **Telefonia → Troncos** Permitir: * adicionar; * editar; * ativar; * desativar; * duplicar; * excluir; * testar. Campos: * Nome * Tecnologia: PJSIP * Tipo: * IP * autenticação * registration * Host * Porta * Transporte * Username * Password * From User * From Domain * Contact User * Outbound Proxy * Context * Caller ID * Codecs * DTMF mode * Qualify * Max Channels * CPS máximo * ACL * IPs permitidos * Enabled Mostrar status: ```text ONLINE OFFLINE UNREACHABLE UNKNOWN ``` Nunca mostrar a senha completa depois de salva. --- # 14. TELA DE RAMAIS Criar: **Telefonia → Ramais** Campos: * número; * nome; * senha SIP; * caller ID; * contexto; * codecs; * transporte; * max contacts; * qualify; * enabled. Gerar senha SIP segura automaticamente. Permitir resetar a senha. Mostrar status em tempo real. --- # 15. PAINEL VISUAL DE RAMAIS Criar uma tela específica: **Monitoramento → Ramais** Cada ramal deverá aparecer em um card/quadrado. Exemplo: ```text ┌──────────────────┐ │ RAMAL 1001 │ │ João Silva │ │ DISPONÍVEL │ │ 00:04:32 │ └──────────────────┘ ``` Utilizar EXATAMENTE esta convenção principal: ```text CINZA = ramal offline VERDE = ramal disponível LARANJA = ramal ocupado AZUL = agente logado VERMELHO = agente em pausa ``` Como alguns estados podem coexistir, implementar a seguinte prioridade visual: ```text PAUSA ↓ EM CHAMADA ↓ AGENTE LOGADO ↓ REGISTRADO/DISPONÍVEL ↓ OFFLINE ``` Ou seja: ```text pausa -> vermelho ocupado -> laranja agente -> azul disponível -> verde offline -> cinza ``` Mostrar opcionalmente: * agente; * ramal; * fila; * duração do estado; * duração da chamada; * campanha atual. Atualização via WebSocket. --- # 16. AGENTES Separar claramente: **usuário da aplicação** de: **agente de Call Center** Uma pessoa pode possuir usuário e agente associados. Criar: ```text agents agent_sessions ``` Campos do agente: * código; * nome; * usuário associado; * ativo; * filas; * campanhas permitidas; * ramal atual. Permitir login dinâmico de agente. --- # 17. TELA DO AGENTE Após login, o agente deve possuir uma interface simplificada. Mostrar: ```text Agente Ramal Fila Campanha Estado Tempo no estado Chamada atual Telefone Nome do lead ``` Botões: ```text DISPONÍVEL PAUSA FINALIZAR PAUSA ``` Quando clicar em PAUSA, abrir os motivos cadastrados. Exemplo: ```text Banheiro Almoço Lanche Reunião Treinamento Suporte Particular ``` Registrar: * início; * fim; * duração; * motivo; * usuário; * agente; * ramal. O agente deve conseguir logar e deslogar das filas conforme suas permissões. --- # 18. CADASTRO DE PAUSAS Criar: **Call Center → Motivos de Pausa** Campos: ```text Nome Código Descrição Tempo máximo opcional Remunerada SIM/NÃO Ativa SIM/NÃO ``` Permitir relatórios de pausas posteriormente. --- # 19. FILAS Criar: **Call Center → Filas** Configurar: * Nome * Número * Strategy * Timeout * Retry * Wrap-up time * Max length * Music on Hold * Announce * Service Level * Auto Fill * Ring in use * Weight * Members Strategies: ```text ringall leastrecent fewestcalls random rrmemory rrordered linear wrandom ``` Mostrar explicação amigável de cada strategy na interface. --- # 20. MONITORAMENTO DE FILAS Criar: **Monitoramento → Filas** Cada fila deve mostrar em tempo real: * chamadas aguardando; * agentes logados; * agentes disponíveis; * agentes ocupados; * agentes pausados; * agentes offline; * maior tempo de espera atual; * TME; * TMA; * abandonos; * chamadas atendidas; * service level; * taxa de abandono. Permitir expandir uma fila e visualizar agentes individualmente. --- # 21. DIALPLAN Criar: **Telefonia → Dialplan** Não criar somente um textarea. Criar editor estruturado permitindo: ```text Context Extension Priority Application Arguments Enabled Order ``` Por exemplo: ```text Context: outbound Extension: _X. Application: Dial Arguments: PJSIP/${EXTEN}@trunk01 ``` Também disponibilizar um modo: **Advanced** somente para `super_admin` ou permissão equivalente. Antes de aplicar um dialplan: 1. gerar nova configuração; 2. validar; 3. manter backup; 4. tentar reload seguro; 5. verificar resultado; 6. caso inválido, não ativar; 7. permitir rollback. Versionar alterações. Criar: ```text dialplan_versions ``` --- # 22. ADMINISTRAÇÃO DO ASTERISK Criar menu: **Sistema → Asterisk** Quero uma interface de administração suficientemente completa para gerenciar os parâmetros necessários ao B2BCall. Separar por abas. ## Geral * system name; * language; * default context; * timezone; * sounds; * MOH. ## PJSIP * transports; * UDP/TCP/TLS; * bind; * local_net; * external signaling; * external media; * timers; * codecs; * endpoint defaults. ## RTP * RTP start; * RTP end; * ICE se necessário; * symmetric RTP; * configurações relevantes. ## Filas Parâmetros globais. ## CDR Configuração. ## CEL Configuração. ## Logs Configuração e nível de log. ## AMI Exibir STATUS da integração. Não mostrar senha AMI aberta. ## ARI Exibir STATUS da integração. ## Modules Listar módulos carregados. ## Diagnóstico Permitir executar comandos seguros e previamente permitidos como: ```text core show uptime core show channels pjsip show endpoints pjsip show contacts queue show module show ``` NÃO implemente uma shell Linux arbitrária pela interface web. Isso seria uma vulnerabilidade crítica. --- # 23. VERSIONAMENTO DAS CONFIGURAÇÕES DO ASTERISK Toda alteração gerada pela aplicação deve possuir versão. Criar algo como: ```text asterisk_config_versions ``` Guardar: * usuário; * data; * tipo; * configuração anterior; * nova configuração; * status; * resultado do reload. Disponibilizar: **Rollback** para versões anteriores. --- # 24. CAMPANHAS Criar: **Discador → Campanhas** Campos mínimos: ```text Nome Descrição Fila Tronco Caller ID Dialplan/context Status Data inicial Data final Dias da semana Horário inicial Horário final Timezone CPS Máximo de chamadas simultâneas Pacing inicial Pacing mínimo Pacing máximo Taxa alvo de abandono Tempo máximo aguardando agente Tempo de ring Número máximo de tentativas Intervalo entre tentativas Retry BUSY Retry NO ANSWER Retry CONGESTION AMD ligado/desligado ``` Status: ```text DRAFT READY RUNNING PAUSED DRAINING STOPPED COMPLETED ``` Botões: ```text INICIAR PAUSAR RETOMAR PARAR DRENAR ``` `DRAINING` significa: * não originar novas chamadas; * deixar as existentes terminarem. --- # 25. CPS — CALLS PER SECOND CPS é requisito obrigatório. Cada campanha deve possuir: ```text campaign.max_cps ``` Cada trunk também: ```text trunk.max_cps ``` O limite real deve ser: ```text min(campaign.max_cps, trunk.available_cps) ``` Implementar token bucket ou algoritmo equivalente. Não pode simplesmente executar um loop com `sleep`. Tem que funcionar de maneira correta mesmo com múltiplos workers. Utilize Redis para coordenação distribuída se necessário. --- # 26. LEADS Cada campanha possuirá leads. Criar tabela `leads`. Campos mínimos: ```text id campaign_id name phone normalized_phone status attempt_count last_attempt_at next_attempt_at last_result created_at updated_at ``` Permitir dados adicionais: ```text custom_fields JSONB ``` Status possíveis: ```text NEW READY RESERVED DIALING RINGING ANSWERED CONNECTED_AGENT BUSY NO_ANSWER FAILED INVALID VOICEMAIL CALLBACK COMPLETED DO_NOT_CALL MAX_ATTEMPTS ``` --- # 27. IMPORTAÇÃO CSV Criar na campanha: **Importar Leads** Formato mínimo: ```csv nome,telefone Joao Silva,48999999999 Maria Souza,11999999999 ``` Interface deve permitir: 1. upload; 2. detectar delimitador; 3. preview; 4. mapear colunas; 5. validar; 6. normalizar telefones; 7. detectar duplicados; 8. importar. Mostrar: ```text Total: 10.000 Válidos: 9.850 Inválidos: 100 Duplicados: 50 ``` Permitir baixar CSV dos registros rejeitados. Não carregar arquivo gigantesco inteiro na memória. Faça processamento streaming/batch. x --- # 28. NORMALIZAÇÃO DE TELEFONE Criar serviço dedicado de normalização. Não espalhar regexes pelo código. Preparar inicialmente para números brasileiros. Guardar: ```text phone_original phone_normalized ``` Arquitetura deve permitir suporte futuro a E.164 internacional. --- # 29. LISTA DE SUPRESSÃO Implementar: **Do Not Call / Lista de Bloqueio** Uma campanha não deve discar um número presente nessa lista. Criar: ```text suppression_list ``` Permitir: * adicionar manualmente; * importar CSV; * pesquisar; * remover com permissão; * informar motivo; * auditoria. Antes de originar: ```text CHECK SUPPRESSION ``` obrigatoriamente. --- # 30. MOTOR DO DISCADOR PREDITIVO Este é um dos componentes MAIS IMPORTANTES do projeto. NÃO implemente simplesmente: ```text for lead: originate() ``` Isso NÃO é discador preditivo. Criar um serviço: ```text PredictiveDialerEngine ``` responsável por decidir continuamente quantas chamadas devem ser originadas. Deve considerar: * agentes logados; * agentes disponíveis; * agentes ocupados; * agentes em wrap-up; * agentes pausados; * chamadas atualmente discando; * chamadas tocando; * chamadas atendidas aguardando agente; * answer rate histórico; * taxa de chamadas ocupadas; * taxa de não atendimento; * tempo médio até atendimento; * TMA; * agentes que provavelmente ficarão disponíveis; * abandono recente; * CPS disponível; * limite de concorrência; * pacing configurado. --- # 31. ALGORITMO PREDITIVO Implementar inicialmente um algoritmo conservador e adaptativo. Mantenha estatísticas por campanha. Exemplo: ```text answer_probability average_answer_delay average_talk_time abandon_rate available_agents busy_agents dialing_calls ringing_calls ``` Utilize EWMA ou método estatístico equivalente para evitar variações violentas. Calcular aproximadamente: ```text expected_agent_supply = agentes_disponiveis + agentes_com_probabilidade_de_liberacao_no_horizonte ``` Depois estimar: ```text expected_answers = calls_to_dial * answer_probability ``` e ajustar para que: ```text expected_answers ~= capacidade prevista de agentes ``` Adicionar multiplicador: ```text pacing_factor ``` Porém sempre respeitando: ```text CPS max_concurrent_calls max_pacing max_abandon_rate available_agents trunk capacity campaign schedule ``` --- # 32. PREVISÃO DE LIBERAÇÃO DE AGENTES Para tornar o discador realmente preditivo, utilize: ```text TMA histórico tempo atual da chamada distribuição histórica de duração ``` para estimar quais agentes podem ficar disponíveis dentro de um horizonte curto. Não precisa construir machine learning. Uma abordagem estatística eficiente, explicável e determinística é preferível inicialmente. Documentar detalhadamente o algoritmo em: ```text docs/PREDICTIVE_DIALER.md ``` --- # 33. CONTROLE DE ABANDONO O motor deve possuir proteção contra abandono excessivo. Se: ```text abandon_rate > target_abandon_rate ``` o pacing deve cair automaticamente. Se subir muito: ```text pacing -> modo conservador ``` Se necessário: ```text suspender novas originações ``` Nunca desenhar o sistema para originar milhares de chamadas sem agentes com o objetivo de verificar se números atendem. A intenção do discador é estabelecer comunicação real entre lead e agente. --- # 34. PROTEÇÃO REGULATÓRIA / COMPLIANCE Criar uma área: **Sistema → Compliance de Chamadas** Não hardcode regras de uma única legislação dentro do motor. Criar parâmetros configuráveis. Registrar: ```text total_calls answered_calls short_calls abandoned_calls calls_per_number calls_per_day calls_per_month ``` Criar alertas relacionados a: * volume excessivo; * chamadas curtas; * abandono; * excesso de tentativas; * horário permitido; * supressão; * caller ID. Para operação brasileira, preparar indicadores considerando que chamadas de curta duração são particularmente relevantes para fiscalização. Adicionar suporte de configuração de identificação/caller ID apropriado para campanhas de telemarketing, inclusive numeração 0303 quando aplicável ao caso de uso. Adicionar contador mensal para identificar operações de alto volume que possam exigir mecanismos adicionais de autenticação de chamadas pela rede. O sistema deve AJUDAR a cumprir regras. Nunca implementar funcionalidades destinadas a burlar mecanismos antispam, autenticação, identificação de origem ou bloqueios das operadoras. --- # 35. RESERVA CONCORRENTE DE LEADS É obrigatório evitar que dois workers disquem para o mesmo lead. Utilizar mecanismo transacional como: ```sql SELECT ... FOR UPDATE SKIP LOCKED ``` ou solução equivalente. Transição: ```text READY ↓ RESERVED ↓ DIALING ``` Tem que ser atômica. Implementar timeout de reservation para recuperar leads caso um worker morra. --- # 36. IDEMPOTÊNCIA Originação deve possuir: ```text attempt_id call_id uniqueid linkedid ``` Nunca originar novamente uma tentativa já confirmada simplesmente porque houve timeout da API. Construir chamadas como state machine. Exemplo: ```text CREATED RESERVED ORIGINATING RINGING ANSWERED QUEUED AGENT_CONNECTED COMPLETED FAILED ``` Persistir as transições relevantes. --- # 37. CALL FLOW PREDITIVO Fluxo esperado: ```text Lead ↓ PredictiveDialer ↓ CPS limiter ↓ Asterisk Originate ↓ Trunk ↓ Destino ``` Quando a chamada atende: ```text ANSWER ↓ opcional AMD ↓ humano ↓ Fila Asterisk ↓ Agente disponível ↓ Bridge ``` Persistir todos os timestamps. --- # 38. AMD Adicionar Answering Machine Detection como recurso OPCIONAL. Nunca deixar AMD obrigatório. Configurar por campanha. Possíveis resultados: ```text HUMAN MACHINE NOT_SURE HANGUP ``` Criar parâmetros avançados apenas para administrador. Registrar resultado para posterior otimização. --- # 39. AFTER CALL / WRAP-UP Implementar: ```text wrap_up_time ``` Durante wrap-up o agente não deve ser tratado pelo predictive engine como imediatamente disponível. Mostrar estado: ```text WRAP UP ``` e tempo restante. --- # 40. DISPOSIÇÃO DA CHAMADA Após atendimento, permitir ao agente classificar a ligação. Exemplos: ```text VENDA SEM INTERESSE CALLBACK NÚMERO ERRADO NÃO LIGAR NOVAMENTE CAIXA POSTAL OUTRO ``` Criar tela administrativa para configurar disposições. Uma disposição pode possuir ações. Exemplo: ```text CALLBACK -> solicitar data/hora ``` ```text DO_NOT_CALL -> adicionar automaticamente à suppression_list ``` --- # 41. CALLBACK Permitir agendar retorno. Campos: ```text lead agent campaign scheduled_at timezone notes ``` O scheduler deve colocar o lead novamente em condição de discagem no horário correto. Permitir callback: ```text para qualquer agente ``` ou: ```text preferencialmente para o mesmo agente ``` --- # 42. CDR / HISTÓRICO DE CHAMADAS Criar modelo consolidado próprio. Capturar: ```text call_id asterisk_uniqueid linkedid campaign lead queue agent extension trunk caller called start_at ring_at answer_at queue_enter_at agent_answer_at end_at duration billsec talk_time wait_time disposition hangup_cause amd_result ``` Nunca depender exclusivamente do CDR nativo para reconstruir toda a jornada do Call Center. Utilizar: * CDR; * CEL; * AMI Events; * queue_log. --- # 43. RELATÓRIO DE CHAMADAS Criar: **Relatórios → Chamadas** Filtros: * data inicial; * data final; * ramal; * agente; * fila; * campanha; * tronco; * telefone; * status; * disposição. Colunas: ```text Data Origem Destino Campanha Fila Agente Ramal Tronco Espera Conversação Duração Resultado Hangup Cause ``` Permitir exportar CSV. Paginação obrigatoriamente server-side. Não carregar milhões de registros de uma vez no browser. --- # 44. TME Implementar TME — Tempo Médio de Espera. Calcular principalmente: ```text agent_answer_at - queue_enter_at ``` para chamadas atendidas. Separadamente mostrar: ```text tempo médio antes do abandono ``` Não misturar as duas métricas silenciosamente. Documentar a definição utilizada. --- # 45. TMA Implementar: **TMA — Tempo Médio de Atendimento** Calcular principalmente: ```text SUM(talk_time) / answered_calls ``` Permitir futuramente visualizar: ```text Talk Time Talk + Wrap-Up ``` como indicadores separados. --- # 46. DASHBOARD Criar um dashboard moderno. Cards principais: ```text Chamadas hoje Chamadas atendidas Chamadas em andamento Chamadas aguardando Agentes disponíveis Agentes ocupados Agentes pausados TME TMA Taxa de atendimento Taxa de abandono ``` Gráficos: ### Chamadas por hora Line/area chart. ### Atendidas x abandonadas ### TME ao longo do dia ### TMA ao longo do dia ### Agentes por estado ### Campanhas Mostrar: ```text Discando Ringing Atendidas Conectadas CPS atual Pacing Answer Rate Abandono ``` Não criar gráficos falsos. Todos devem utilizar informações reais do banco/Asterisk. --- # 47. DASHBOARD DO DISCADOR Criar painel específico por campanha mostrando em tempo real: ```text CPS configurado CPS atual Chamadas discando Chamadas tocando Atendidas Na fila Conectadas em agente Agentes disponíveis Pacing atual Answer rate Abandon rate TME TMA Leads restantes Leads processados ``` Isso será extremamente importante para operação. --- # 48. STATUS DOS AGENTES Estados canônicos: ```text OFFLINE LOGGED_IN AVAILABLE RINGING IN_CALL WRAP_UP PAUSED ``` Não inferir tudo diretamente de uma única variável do Asterisk. Criar máquina de estados consistente. Registrar início/fim de cada estado. Isso permitirá calcular produtividade posteriormente. --- # 49. RELATÓRIO DE AGENTES Criar: **Relatórios → Agentes** Exibir: ```text Tempo logado Tempo disponível Tempo em chamada Tempo pausado Tempo wrap-up Chamadas atendidas TMA ``` Detalhar pausas: ```text motivo início fim duração ``` --- # 50. QUEUE_LOG Utilizar os dados do `queue_log` porque ele contém eventos específicos de ACD que um CDR tradicional não representa corretamente. Capturar eventos relevantes como: * ENTERQUEUE; * CONNECT; * COMPLETEAGENT; * COMPLETECALLER; * ABANDON; * RINGNOANSWER; * TRANSFER; * PAUSE; * UNPAUSE. Normalizar no PostgreSQL. Não basear TME/TMA exclusivamente em parsing periódico de arquivo. Preferencialmente capturar eventos em tempo real e utilizar queue_log também para reconciliação/auditoria. --- # 51. RECONCILIAÇÃO Eventos podem eventualmente ser perdidos por restart de algum worker. Criar rotina de reconciliação. Ela deve comparar informações recentes com: * CDR; * CEL; * queue_log; * estados persistidos. Corrigir chamadas que ficaram indevidamente em: ```text RINGING IN_PROGRESS CONNECTED ``` após falha/restart. --- # 52. INTERFACE Quero uma aplicação: * bonita; * moderna; * clean; * corporativa; * rápida; * responsiva; * com excelente UX. Utilizar a logo: ```text /opt/b2bcall/b2bcall.png ``` Copiar/processar para o diretório apropriado do frontend. Não modificar a logo original. Menu sugerido: ```text Dashboard Discador ├─ Campanhas ├─ Leads ├─ Importações ├─ Callbacks └─ Lista de Bloqueio Call Center ├─ Agentes ├─ Filas ├─ Motivos de Pausa └─ Disposições Telefonia ├─ Ramais ├─ Troncos └─ Dialplan Monitoramento ├─ Filas ├─ Agentes ├─ Ramais └─ Campanhas Relatórios ├─ Chamadas ├─ Agentes ├─ Filas └─ Campanhas Sistema ├─ Usuários ├─ Perfis e Permissões ├─ Asterisk ├─ Compliance ├─ Auditoria └─ Configurações ``` --- # 53. BANCO DE DADOS Planejar pelo menos entidades equivalentes a: ```text users sessions roles permissions user_roles role_permissions agents agent_sessions agent_state_events pause_reasons agent_pause_events extensions trunks queues queue_members dialplans dialplan_versions campaigns campaign_schedules campaign_agents lead_imports leads dial_attempts calls call_events queue_events call_dispositions call_callbacks suppression_list asterisk_config_versions audit_logs application_settings ``` Adicionar tabelas auxiliares necessárias. Criar índices para consultas de alto volume. Especial atenção para índices envolvendo: ```text campaign_id status next_attempt_at created_at phone_normalized call_id linkedid queue_id agent_id extension_id ``` --- # 54. VOLUME DE DADOS Projetar desde o início considerando milhões de registros de chamadas. Não criar relatórios que façam: ```sql SELECT * FROM calls; ``` Implementar: * paginação; * índices; * filtros; * agregações; * query plans razoáveis. Avaliar particionamento temporal posteriormente para: ```text calls call_events queue_events audit_logs ``` Não precisa particionar prematuramente se não houver necessidade, mas documentar estratégia de crescimento. --- # 55. SEGURANÇA DE SEGREDOS Criar: ```text .env .env.example ``` `.env` obrigatoriamente em `.gitignore`. Segredos: * PostgreSQL; * Redis; * JWT; * encryption key; * AMI; * ARI; * SIP; * SMTP. Nunca commitar. Nunca imprimir em logs. Credenciais de trunk devem ser criptografadas em repouso quando forem mantidas pelo aplicativo. Utilizar AES-256-GCM ou mecanismo equivalente com master key externa ao banco. --- # 56. FIREWALL Configurar firewall utilizando nftables ou abordagem adequada ao Debian 13. Princípio: **default deny para serviços administrativos/telefônicos sensíveis.** Permitir SIP no Asterisk somente de: * OpenSIPS autorizado; * operadoras privadas; * redes explicitamente configuradas. AMI: somente aplicação. ARI: somente aplicação. PostgreSQL: somente containers/localhost necessário. Redis: somente containers. Não bloquear SSH durante a instalação. --- # 57. HTTP SECURITY Implementar: * Content Security Policy; * X-Content-Type-Options; * Referrer-Policy; * HSTS quando HTTPS; * CORS restritivo; * CSRF quando necessário; * Helmet ou equivalente; * input validation; * DTO validation. Não confiar em entrada do usuário. --- # 58. SQL SECURITY Nunca concatenar SQL manualmente com dados fornecidos pelo usuário. Utilizar queries parametrizadas/ORM. Importação de CSV também deve ser tratada como entrada não confiável. --- # 59. ASTERISK CONFIG SECURITY O editor avançado de configuração é uma área sensível. Antes de gravar: * validar seção; * validar formato; * impedir path traversal; * nunca aceitar caminho arbitrário; * nunca permitir gravar fora de diretórios permitidos; * criar backup; * versionar; * validar; * reload controlado. Nunca transformar a interface do Asterisk em uma execução remota de comandos Linux. --- # 60. LOGS Utilizar logs estruturados JSON no backend. Campos úteis: ```text timestamp level service request_id user_id campaign_id call_id attempt_id message ``` Nunca registrar: * senha; * SIP password; * JWT; * refresh token; * credencial AMI; * credencial ARI. --- # 61. CORRELATION ID Cada request HTTP deve possuir: ```text request_id ``` Cada tentativa: ```text attempt_id ``` Cada chamada: ```text call_id ``` Relacionar com: ```text Asterisk UNIQUEID Asterisk LINKEDID ``` Isso será fundamental para troubleshooting. --- # 62. HEALTH CHECKS Criar: ```text /api/health /api/health/live /api/health/ready ``` Verificar: * API; * PostgreSQL; * Redis; * AMI; * Asterisk. Dashboard administrativo deve mostrar: ```text API OK Postgres OK Redis OK Asterisk OK AMI OK ``` --- # 63. BACKUP Criar scripts/documentação para backup de: * PostgreSQL; * configurações Asterisk; * `.env` de maneira segura; * uploads relevantes. Adicionar procedimento de restore. --- # 64. TESTES Criar testes reais. ## Unit tests Principalmente: * predictive engine; * CPS limiter; * permissions; * phone normalization; * retry strategy; * state machines; * TME/TMA; * scheduling. ## Integration * PostgreSQL; * Redis; * repositories; * API; * AMI adapter mockado. ## E2E Pelo menos: ```text login criar agente criar ramal criar fila criar trunk criar campanha importar CSV iniciar campanha em modo simulado pausar campanha relatórios RBAC ``` --- # 65. MODO DE SIMULAÇÃO Criar um recurso muito importante: ```text DIALER_SIMULATION=true ``` Neste modo: **NÃO realizar chamadas externas.** Simular: ```text ANSWER BUSY NO ANSWER ANSWER DELAY TALK TIME ``` Isso permitirá testar o predictive engine sem gerar milhares de chamadas reais. Criar testes utilizando esse modo. --- # 66. TESTE DO PREDICTIVE ENGINE Criar simulador com, por exemplo: ```text 20 agentes 10 CPS 30% answer rate 10 segundos answer delay 180 segundos TMA ``` Verificar: * pacing; * disponibilidade; * abandono; * CPS; * estabilização. Gerar logs/estatísticas. O motor não pode oscilar violentamente. --- # 67. GIT Inicializar Git em: ```text /opt/b2bcall ``` Criar `.gitignore`. Commits organizados por etapas. Exemplos: ```text feat: bootstrap b2bcall architecture feat: add authentication and RBAC feat: add asterisk pjsip integration feat: add call center queues feat: add campaign management feat: implement predictive dialing engine feat: add realtime monitoring feat: add call reports feat: add security hardening test: add predictive dialer simulation ``` Nunca versionar segredos. --- # 68. DOCUMENTAÇÃO Criar: ```text README.md docs/ARCHITECTURE.md docs/INSTALL.md docs/ASTERISK.md docs/OPENSIPS.md docs/PREDICTIVE_DIALER.md docs/DATABASE.md docs/SECURITY.md docs/OPERATIONS.md docs/BACKUP_RESTORE.md docs/API.md docs/TROUBLESHOOTING.md CHANGELOG.md ``` --- # 69. TODO OPERACIONAL Durante o desenvolvimento mantenha: ```text TODO.md ``` Exemplo: ```text [x] Docker [x] PostgreSQL [x] Redis [x] Authentication [x] RBAC [x] Asterisk [x] Extensions [x] Trunks [ ] Queues [ ] Agents [ ] Campaigns [ ] Predictive Engine ``` Quando terminar um item: * testar; * marcar `[x]`; * continuar para o próximo. Não utilize o TODO como desculpa para deixar funcionalidades incompletas. No final, nenhum requisito principal deste documento deve permanecer pendente. --- # 70. BOOTSTRAP DO SUPER ADMIN Na primeira instalação criar um usuário `super_admin`. Nunca utilizar senha padrão como: ```text admin 123456 password ``` Gerar senha aleatória forte. Mostrar apenas uma vez ao final da instalação. Idealmente criar: ```text /opt/b2bcall/FIRST_LOGIN.txt ``` com: ```bash chmod 600 ``` Orientar que o arquivo seja removido após primeiro acesso. Forçar troca da senha no primeiro login. --- # 71. SEED Criar seed inicial contendo: * permissões; * perfil super_admin; * admin; * supervisor; * agent; * motivos básicos de pausa; * disposições padrão. Mas tudo deve poder ser alterado posteriormente. --- # 72. NÃO CRIAR DADOS FAKE EM PRODUÇÃO Dados demonstrativos somente quando: ```text SEED_DEMO_DATA=true ``` Por padrão: ```text false ``` Dashboard de produção nunca deve apresentar números inventados. --- # 73. UX DE ERROS Não mostrar ao usuário: ```text 500 Internal Server Error ``` sem contexto. Mostrar mensagem amigável e gerar: ```text request_id ``` para suporte técnico. No log técnico, manter detalhes. --- # 74. PERFORMANCE Evitar: * N+1 queries; * polling desnecessário; * carregamento completo de tabelas; * processamento pesado dentro de HTTP request; * bloqueio do event loop; * originação síncrona de milhares de chamadas. Utilizar workers. --- # 75. CONTROLE DE CAMPANHA DISTRIBUÍDO O motor deve impedir dois workers de controlarem simultaneamente a mesma campanha. Criar distributed lock. Exemplo conceitual: ```text dialer:campaign:{id}:lock ``` com: * TTL; * renewal; * ownership token. Se worker morrer, outro poderá assumir posteriormente. --- # 76. PAUSA IMEDIATA Quando administrador clicar: ```text PAUSAR CAMPANHA ``` não originar nenhuma nova chamada. As chamadas já existentes podem continuar. Em: ```text STOP ``` definir comportamento de maneira clara e segura. Não derrubar ligações de clientes/agentes sem confirmação explícita. --- # 77. MONITORAMENTO DO TRONCO Monitorar: * status; * chamadas atuais; * CPS atual; * CPS limite; * channels limit; * tentativas; * falhas; * congestion; * SIP response codes quando disponíveis. Mostrar no dashboard. --- # 78. HANGUP CAUSE Guardar informações de encerramento. Normalizar resultados como: ```text ANSWERED BUSY NO_ANSWER REJECTED CONGESTION INVALID_NUMBER NETWORK_FAILURE CANCELLED ``` Mas preservar também o código original recebido do Asterisk/rede. --- # 79. RETRY ENGINE Criar regras por campanha. Exemplo: ```text BUSY -> 15 minutos NO ANSWER -> 60 minutos CONGESTION -> 5 minutos FAILED -> 30 minutos ``` Limitar quantidade máxima de tentativas. Permitir personalização. Nunca rediscagem infinita. --- # 80. HORÁRIO DE CAMPANHA Scheduler deve impedir discagem fora do período configurado. Considerar timezone. Por exemplo: ```text America/Sao_Paulo ``` Configurar: * segunda; * terça; * quarta; * quinta; * sexta; * sábado; * domingo. Campanha fora do horário: ```text WAITING_SCHEDULE ``` --- # 81. ARQUITETURA DE FRONTEND Criar componentes reutilizáveis. Evitar páginas gigantes com milhares de linhas. Separar: ```text components features hooks services schemas types ``` Usar tabelas com: * busca; * filtros; * paginação; * ordenação; * loading; * empty state; * error state. --- # 82. DESIGN A aparência deve lembrar sistemas SaaS/Contact Center modernos. Utilizar: * sidebar; * topbar; * cards; * tabelas profissionais; * badges; * tooltips; * gráficos; * skeleton loading; * dialogs; * toast notifications. Evitar aparência de: * sistema antigo; * FreePBX clone; * formulário HTML cru; * bootstrap antigo. A identidade visual deve utilizar a logo do B2BCall. Criar light/dark mode se não prejudicar o desenvolvimento. --- # 83. API Utilizar REST bem estruturada inicialmente. Exemplos: ```text /api/auth /api/users /api/roles /api/permissions /api/extensions /api/trunks /api/dialplans /api/agents /api/queues /api/pause-reasons /api/campaigns /api/campaigns/:id/leads /api/campaigns/:id/start /api/campaigns/:id/pause /api/campaigns/:id/stop /api/reports/calls /api/reports/agents /api/monitoring/extensions /api/monitoring/queues /api/monitoring/campaigns /api/asterisk /api/compliance /api/audit ``` Gerar OpenAPI/Swagger. Swagger administrativo deve poder ser desabilitado em produção. --- # 84. VALIDATION Usar validação forte de schemas/DTO. Exemplo: CPS: ```text >= 1 ``` Telefone: validar e normalizar. Datas: validar timezone. UUID: validar. IDs fornecidos pelo usuário nunca devem ser confiados sem validação. --- # 85. MIGRATIONS Nenhuma alteração de banco manual sem migration. Criar comandos: ```bash npm run db:migrate npm run db:seed ``` ou equivalentes. --- # 86. DEPLOYMENT Criar script: ```text scripts/install.sh ``` para servidor Debian 13 limpo. Ele deve: 1. verificar permissões; 2. instalar dependências; 3. instalar Docker; 4. instalar Compose plugin; 5. criar diretórios; 6. gerar secrets; 7. preparar `.env`; 8. buildar containers; 9. iniciar PostgreSQL/Redis; 10. executar migrations; 11. iniciar Asterisk; 12. iniciar API/workers/frontend; 13. executar health checks; 14. mostrar resultado. Também criar: ```text scripts/update.sh scripts/backup.sh scripts/restore.sh scripts/healthcheck.sh ``` --- # 87. NGINX / REVERSE PROXY Criar reverse proxy. Expor para a LAN preferencialmente apenas: ```text 80 443 ``` WebSocket precisa funcionar corretamente. Preparar suporte HTTPS. Se nenhum domínio/certificado estiver disponível inicialmente, documentar como ativar certificado posteriormente. Não inventar domínio. --- # 88. RESTART SEGURO Restart da API não deve destruir campanhas. Estado importante sempre no: * PostgreSQL; * Redis quando apropriado. Ao reiniciar worker: * recuperar campanhas RUNNING; * reconciliar chamadas; * limpar reservations expiradas; * reassumir locks; * continuar operação corretamente. --- # 89. OBSERVABILIDADE Criar no mínimo: * logs estruturados; * health checks; * métricas internas. Preparar endpoint Prometheus: ```text /metrics ``` Métricas úteis: ```text b2bcall_calls_total b2bcall_calls_answered_total b2bcall_calls_abandoned_total b2bcall_campaign_cps b2bcall_agents_available b2bcall_agents_busy b2bcall_agents_paused b2bcall_queue_waiting b2bcall_dialer_active_calls ``` Pode adicionar outras. --- # 90. REQUISITOS DE ACEITE O projeto NÃO está terminado enquanto eu não conseguir realizar, pela interface: 1. fazer login; 2. cadastrar usuário; 3. cadastrar perfil; 4. alterar permissões; 5. cadastrar ramal; 6. visualizar seu status; 7. cadastrar trunk; 8. cadastrar dialplan; 9. cadastrar fila; 10. cadastrar agente; 11. associar agente a fila; 12. cadastrar pausa; 13. logar como agente; 14. colocar agente em pausa; 15. retirar pausa; 16. cadastrar campanha; 17. configurar CPS; 18. importar CSV; 19. iniciar campanha; 20. pausar campanha; 21. visualizar discagem; 22. visualizar agentes; 23. visualizar fila; 24. visualizar TME; 25. visualizar TMA; 26. pesquisar chamadas; 27. filtrar por ramal; 28. filtrar por fila; 29. exportar relatório; 30. administrar configurações necessárias do Asterisk; 31. consultar audit log. --- # 91. ACEITE DO DIALER Além da interface, provar através de teste/simulação que: ```text configured CPS = 5 ``` não origina mais de 5 novas chamadas em qualquer janela apropriada de 1 segundo. Provar que: ```text campaign max concurrent = 20 ``` não ultrapassa 20 chamadas simultâneas. Provar que: * lead não é discado duas vezes simultaneamente; * campanha pausada não gera novas chamadas; * worker reiniciado recupera operação; * pacing cai quando abandono sobe; * lead bloqueado não é chamado; * campanha fora do horário não chama. --- # 92. ACEITE DE SEGURANÇA Verificar: * nenhuma senha no Git; * nenhum `.env` commitado; * PostgreSQL não público; * Redis não público; * AMI não público; * ARI não público; * rate limit funcionando; * RBAC funcionando no backend; * usuário agent não acessa configuração Asterisk; * agent não consegue elevar a própria permissão; * SQL injection protegida; * path traversal protegido; * logs sem credenciais. --- # 93. ACEITE ASTERISK Executar e documentar resultado de: ```text asterisk -rx "core show version" asterisk -rx "core show uptime" asterisk -rx "pjsip show endpoints" asterisk -rx "pjsip show contacts" asterisk -rx "queue show" ``` Validar comunicação: ```text API -> AMI -> Asterisk ``` --- # 94. QUALITY GATE Antes de declarar terminado: Executar: ```text lint typecheck unit tests integration tests e2e tests docker compose config docker compose ps health checks ``` Corrigir erros. Não simplesmente informar que existem erros conhecidos. --- # 95. README FINAL No final atualizar README com: ## B2BCall ### Architecture ### Requirements ### Installation ### First Login ### Configuration ### OpenSIPS Integration ### Trunks ### Agents ### Queues ### Campaigns ### Predictive Dialer ### Reports ### Backup ### Update ### Troubleshooting --- # 96. RELATÓRIO FINAL DA IMPLEMENTAÇÃO Somente depois de efetivamente terminar, apresentar um resumo contendo: ```text B2BCall version: Asterisk version: Node version: PostgreSQL version: Docker version: Containers: ... URLs: ... Super admin: ... Health: ... Tests: ... Pending: ... ``` Se existir algo pendente, explicar claramente. --- # 97. DECISÕES TÉCNICAS IMPORTANTES Tenha especialmente em mente: ### Asterisk não é banco de negócio O estado de campanhas/leads/agentes deve estar no PostgreSQL. ### Redis não é fonte permanente Informações importantes devem sobreviver à perda do Redis. ### AMI events são assíncronos Não presuma que Originate HTTP concluído significa chamada completada. ### LINKEDID é importante Uma chamada poderá possuir múltiplos canais Asterisk. ### Calls devem possuir ID próprio Não utilize `UNIQUEID` do Asterisk como primary key de negócio. ### WebSocket é para visualização O banco continua sendo fonte persistente. ### O predictive dialer precisa ser controlável Sempre permitir: ```text PAUSE DRAIN STOP ``` ### Segurança deve existir desde a arquitetura Não adicionar segurança apenas no final. --- # 98. PRIMEIRA TAREFA Comece AGORA. Primeiro: ```bash cd /opt/b2bcall ``` Analise: ```bash pwd ls -lah cat /etc/os-release uname -a ip addr df -h free -h ``` Verifique a existência: ```text /opt/b2bcall/b2bcall.png ``` Depois crie: ```text docs/ARCHITECTURE.md TODO.md ``` Defina a arquitetura inicial. Em seguida inicialize o Git e comece efetivamente a implantação. NÃO pare após criar os documentos. Continue imediatamente para: ```text Docker ↓ PostgreSQL ↓ Redis ↓ Asterisk ↓ Backend ↓ Authentication ↓ RBAC ↓ Telefonia ↓ Call Center ↓ Campanhas ↓ Predictive Dialer ↓ Frontend ↓ Monitoring ↓ Reports ↓ Security ↓ Tests ↓ Production validation ``` Trabalhe até alcançar os critérios de aceite. --- # 99. PRINCÍPIO FINAL Este projeto será usado como uma plataforma real de Call Center. Portanto, sempre prefira: ```text correto > rápido seguro > conveniente transacional > improvisado observável > caixa-preta configurável > hardcoded testado > presumido ``` Não entregue apenas uma demonstração. Construa o **B2BCall** como uma aplicação que possa realmente evoluir para produção.