Análise técnica do CRM
Revisão do código local em 07/10/2026, com leitura da arquitetura geral e análise detalhada do CRM. O fluxo principal tem modelos e endpoints para captação, qualificação, conversão, oportunidades, atividades, automações e relatórios. As maiores lacunas estão na conexão entre contratos da interface, validação HTTP e acionamentos de automação.
Escopo da validação: leitura de rotas, schemas, controllers, políticas, jobs, serviços e templates; execução dos testes unitários existentes dos domínios de CRM; compilação dos componentes reais para capturas locais. Não foram usadas contas, bancos ou provedores de produção. Os cenários dos prints retornam dados fictícios e não exercitam middlewares da API.
Prioridades de correção
As prioridades abaixo são propostas desta análise. “Bloqueio” indica incompatibilidade objetiva no código; “risco” exige validação adicional com ambiente e dados controlados.
| Prioridade | Achado e evidência | Impacto | Correção sugerida |
|---|---|---|---|
| Alta — bloqueio | LeadsPage.saveLead() envia consent; Lead/validations.js:add() não o aceita | Cadastro manual pode falhar por campo desconhecido, mesmo com checkbox desmarcado | Unificar schema/controller e registrar consentimento com prova, como na captura pública |
| Alta — bloqueio | CrmService.moveDealToPipeline() chama /deal/:id/pipeline; Deal/routes.js não monta essa rota | O botão de transferência não completa o fluxo | Implementar rota com validação de empresa, etapa, permissão e histórico, ou ocultar a ação até estar disponível |
| Alta — bloqueio | LeadPage permite salvar dados de convertido; Lead/controller.js:update() recusa qualquer convertido | Mensagem da tela promete uma edição que o backend impede | Definir campos editáveis pós-conversão e alinhar tela, schema e controller |
| Alta — risco de envio | deal_stalled e lead_created existem em editor/schema; só cart_abandoned tem acionador localizado | Eventos selecionáveis podem nunca inscrever contatos | Implementar acionamento idempotente ou retirar as opções até completar o fluxo |
| Alta — risco de envio | Cadence/reply.js exige outcome; registro rápido em crm.page.ts não o envia | Uma conversa registrada não encerra a cadência nem alimenta a resposta A/B | Capturar resultado estruturado e vincular lead/negócio na atividade |
| Alta — risco de envio | Deal/controller.js:win/lose não chama encerramento de inscrições; executor não testa resultado fechado | Mensagens podem continuar após decisão comercial | Encerrar inscrições por lead/negócio no fechamento e adicionar defesa no executor |
| Alta — bloqueio de integração | src/routes.js consome JSON antes do parser verify em Lead/webhook.js | req.rawBody ausente pode invalidar assinaturas legítimas | Preservar bytes antes de parsear e testar a rota HTTP completa |
| Alta — risco de consentimento | Inscrição via negócio sem lead e carrinho com cliente sem lead não têm a mesma verificação de aceite do caminho de lead | Canais automáticos podem escapar da regra de consentimento aplicada aos leads | Definir fonte de consentimento para todos os alvos e bloquear na inscrição e execução |
| Alta — risco de isolamento | Políticas customizadas de Lead/Deal/Pipeline/Cadence/Segment/Activity retornam permitido quando não resolvem ID da entidade; várias listas aceitam business opcional | Autorização de leitura não comprova isolamento da empresa nas consultas | Derivar escopo do perfil no servidor e validar listas, relatório e vínculos com duas empresas em testes de integração |
| Alta — risco de vínculo | Deal.add() verifica cliente/funil, mas não consulta o lead recebido; Lead.convert() carrega pipeline por ID sem comparação explícita da empresa | IDs de outra empresa podem criar relações comerciais incoerentes | Validar empresa de cada referência antes da gravação, incluindo lead, dono e produto |
| Alta — risco transacional | Transação começa antes dos guards; respostas de negação retornam sem alcançar commit/abort; controllers enviam sucesso antes do commit | Sessões podem ficar sem encerramento e o cliente pode ver sucesso antes de confirmar persistência | Gerenciar sessão em bloco com finalização garantida e enviar sucesso após commit |
| Média — consistência | ActivitiesPage.complete() classifica contador por horário vencido, enquanto a API define buckets por início/fim do dia | Contadores errados ao concluir item de hoje já vencido ou futuro | Usar o bucket selecionado ou consultar os contadores de novo |
| Média — histórico | Editor envia etapas sem playbook; controller substitui pipeline.stages | Salvar o funil pela interface pode apagar roteiros existentes | Preservar campos não editados ou expor editor para eles |
| Média — histórico | Proteção de remoção de etapa conta só negócios abertos | Etapas usadas apenas em registros fechados podem sumir do desenho do relatório | Manter etapas históricas ou permitir arquivamento com referência preservada |
| Média — projeção | shiftSummary() ajusta só quantidade e valor, não estagnação e ausência de ação | Resumo do quadro pode ficar desatualizado após arraste | Reconsultar o resumo ou ajustar todas as métricas retornadas |
| Média — entrega | Cadence/schedule.js avança currentStep também com resultado failed ou skipped | Falha não é reenviada automaticamente; fim da sequência pode incluir toques não entregues | Política explícita de retry, idempotência e exibição de falhas |
| Média — atribuição | Relatório lê source.lastTouch atual do lead, sem snapshot de fechamento | Recaptura posterior pode alterar o crédito de uma venda antiga | Guardar origem atribuída no fechamento ou trilha temporal de toques |
| Média — escala | Recálculo ordena por score.updatedAt e só grava quando números mudam | Lote estável de até 500 pode voltar sempre e atrasar leads fora dele | Persistir momento de avaliação ou usar cursor de lotes |
| Média — consistência | Deduplicação busca antes de criar; índices de contato não são únicos | Capturas simultâneas podem duplicar contatos | Resolver concorrência com chave normalizada/idempotência e estratégia de merge |
As políticas e autorização do projeto são mecanismos reais, mas os riscos de escopo acima não foram explorados contra dados de outras empresas. Devem ser verificados em homologação isolada antes de afirmar o alcance de exposição.
Comportamentos que a documentação anterior superestimava
| Afirmação anterior | O que o código revisado sustenta |
|---|---|
| Lead qualificado vira negócio e ganho vira cliente | Qualificação, conversão, criação de negócio e ganho são operações separadas |
| Qualquer resposta encerra cadência | Só atividade com tipo e outcome reconhecidos; a UI rápida não informa esse resultado |
| Ganho, perda e opt-out encerram tudo imediatamente | Ganho/perda não encerram inscrições gerais; opt-out atualiza aceite e o executor reage nos próximos passos automáticos |
| A/B alterna variantes e mede conversão de venda | Executor usa sorteio ponderado; relatório mede respostas por envio |
| Importação cola conteúdo de CSV | A interface lê arquivo de até 2 MB e envia seu texto à API |
| Congelamento e exportação são ações da tela de segmentos | Endpoints existem, mas faltam controles correspondentes na interface |
| Push automático alcança o lead consumidor | dispatch.sendPush() escolhe o responsável do lead ou negócio |
| Vincular pedido depois do ganho por atualização comum | Deal/validations.js:update() não aceita order; o vínculo é aceito no endpoint de ganho |
| Um estágio removido está sempre protegido se tem negócio | A proteção consulta apenas negócios abertos |
Essas diferenças foram incorporadas aos guias para não orientar o usuário a depender de um comportamento que ainda precisa ser implementado.
Outros pontos que merecem acompanhamento
O botão toggle de cadência pausa/retoma inscrições; update apenas altera campos da cadência. Para automações e integrações, use o endpoint apropriado. A função de resposta prioriza filtro por lead se ambos os vínculos forem informados; inscrições apenas por negócio podem precisar de tratamento complementar.
O job de estagnação não limpa uma marca antiga de um estágio cujo SLA foi desabilitado com zero, pois varre etapas com prazo positivo. O frontend limpa a marca local após registrar interação, mas a resposta do servidor pode mantê-la até a varredura.
O modelo linear de atribuição divide só primeiro e último toque. Datas de leads e de vendas têm recortes diferentes, e múltiplas vendas do mesmo lead também podem elevar a taxa acima de 100%. A conversão entre estágios compara contagens deduplicadas de visitas, não pares de transições obrigatórias. Ganho e Perdido ficam na mesma sequência ordenada: não interprete uma divisão entre essas etapas terminais como progressão de uma para outra.
O cron RFM e o teto diário de cadências usam o fuso do processo, enquanto a agenda utiliza o aparelho. No celular de 390 px, os valores do resumo podem quebrar em duas linhas; o quadro exige rolagem horizontal. Os prints preservam essas condições reais de layout.
O guard do frontend verifica login, e a central controla atalhos por features; a proteção efetiva de dados precisa continuar na API. Tokens e perfil usam armazenamento do navegador. A presença de configuração Firebase e integrações locais deve ser avaliada pelos responsáveis pelo ambiente sem incorporar segredos à documentação.
Validação desta entrega
Os 24 arquivos de teste e 244 testes unitários existentes dos domínios lead, deal, activity, cadence e segment passaram. O comando usado foi:
npm test -- --runInBand --testPathPattern='unit/domains/(lead|deal|activity|cadence|segment)/' --reporters=default
Também foram reproduzidas duas incompatibilidades localmente: o middleware real de criação rejeitou o payload da tela com "consent" is not allowed, e a sequência de parsers Express consumiu o JSON sem executar o verify local do webhook. Essas verificações não utilizaram rede externa nem banco.
Esses testes exercitam funções e controllers isolados. Eles não passam necessariamente pela combinação real de validação, parser, autenticação, transação e controller. Por isso, testes de domínio aprovados podem coexistir com os bloqueios de contrato identificados.
O npm run typecheck e o npm run build do pepper-docs passaram, sem links internos quebrados. A visão geral e o diagrama de arquitetura foram conferidos no navegador.
A compilação Angular das capturas usa componentes e estilos reais, com serviços substituídos por dados fictícios. Foram capturadas telas desktop e mobile e revisadas visualmente. A manutenção e os requisitos desse processo estão em Arquitetura e integrações.
Critérios propostos para homologação após correções
- Cadastrar lead pela tela com e sem aceite e conferir prova de consentimento.
- Capturar em landing e importar CSV; repetir contato e testar duas capturas simultâneas.
- Converter com e sem telefone, reaproveitar cliente e abrir negócio no funil correto.
- Criar oportunidade com lead vinculado e testar referências de outra empresa em ambiente isolado.
- Mover entre etapas e funis, preservar histórico e verificar rollback diante de erro.
- Registrar resposta e confirmar encerramento da inscrição e crédito de variante.
- Ganhar/perder, garantir ausência de novos toques e conferir relatório versus pagamento.
- Pausar/retomar, retirar inscrição, revogar aceite e testar carrinho sem lead associado.
- Repetir chamadas negadas e falhas de commit, conferindo fechamento das sessões.
- Conferir múltiplos funis, reabertura, salto de etapas, atribuição e recálculo com mais de 500 leads.
São critérios de validação futura, não testes já executados nesta entrega. As alterações desta revisão se concentram no pepper-docs; os problemas de aplicação estão documentados para correção.