Pular para o conteúdo principal

Arquitetura e integrações

Referência técnica baseada no código local revisado em 07/10/2026. Os caminhos citados são relativos à raiz que contém pepper-api, pepper-front e pepper-docs. A análise mapeia a arquitetura geral e aprofunda os contratos de CRM; não equivale a uma auditoria completa de todos os domínios ou da infraestrutura implantada.

Os três projetos​

ProjetoStack encontradaResponsabilidade
pepper-apiNode 20, Express 4, Mongoose 8, MongoDB, Agenda, Firebase AdminRegras de negócio, autenticação, permissões, persistência, integrações e jobs
pepper-frontAngular 18, Ionic 7, Capacitor 6, RxJS, AngularFireAplicação web e mobile, formulários, quadro, agenda, relatórios e áreas públicas
pepper-docsDocusaurus 3, React 19, TypeScript, MDX e MermaidDocumentação operacional e técnica

O frontend tem áreas por perfil (colaborador, administrador e cliente), área pública, catálogo de produtos, clientes, pedidos, assinaturas, fornecedores, cupons, contratos, feiras, eventos e equipe. O backend agrupa recursos em domínios com arquivos de modelo, controller, rotas, validações, permissões e políticas. Os módulos de feira, avaliação e presença suportam fluxos como ATLA Expo/Fitec; eles compartilham clientes, produtos e perfis com o restante da plataforma.

Fontes: pepper-front/src/app/app-routing.module.ts, home/home-routing.module.ts, app.module.ts; pepper-api/src/routes.js, src/models/index.js e os package.json dos três projetos.

O backend inicializa Firebase Admin, logging e GlitchTip, expõe /health, /api-docs e /api-docs.json e monta os domínios sob /api/v1. As chamadas do CRM usam API REST; a presença de AngularFire na aplicação não significa que o kanban grava oportunidades diretamente no Firestore.

Fluxo de uma requisição​

  1. CrmService obtém o identificador empresarial de BusinessService.id.
  2. O interceptador acrescenta x-access-token e requesting, conforme token e perfil guardados no navegador, e monta a URL da API configurada.
  3. src/routes.js instala parser JSON e middleware de transação antes das rotas de domínio.
  4. As rotas internas passam por validação, JWT e permissão do recurso.
  5. O controller consulta ou grava modelos, normalmente com req.session.
  6. A resposta segue o formato de mensagem, dados e, nas listas, metadados de paginação.

O cabeçalho requesting representa o perfil ativo, não o ID da empresa. O sistema verifica se o perfil pertence ao usuário e se possui a permissão exigida. As políticas complementam essa decisão com atributos do recurso. Filtros de empresa também precisam ser aplicados no servidor; não basta confiar no identificador enviado pelo frontend.

A camada transacional exige MongoDB compatível com transações, como um replica set. Os controllers frequentemente enviam a resposta antes de chamar next() para o commit. Há riscos registrados na análise sobre essa ordem e sobre requisições negadas que não chegam ao encerramento da sessão.

Modelo comercial​

EntidadeDados e vínculos principais
ProfileBusinessContexto empresarial; configurações de formulário, roteamento, webhook e cadências
PipelineEmpresa, padrão e estágios; cada etapa tem chave estável, ordem, probabilidade, prazo, roteiro e marcas de resultado
LeadEmpresa, responsável, contato, BANT, origem inicial/último toque, consentimento, score, situação e cliente convertido
CustomerCadastro da carteira; pode ser reaproveitado pela conversão do lead
DealEmpresa, pipeline, estágio, lead, cliente, responsável, valor, previsão, resultado, motivo e histórico de etapas
ActivityEmpresa e vínculos opcionais com negócio/lead/cliente; tipo, responsável, prazo, conclusão e resultado
CadenceEmpresa, passos, trigger, evento, estado ativo e limite diário
CadenceEnrollmentVínculos de inscrição, passo atual, próximo horário, estado e histórico dos toques
SegmentBase alvo, regras, modo de combinação, dinâmica ou snapshot de membros e último tamanho
Order / SubscriptionRegistro de venda/pagamento e base de cálculo para RFM e recuperação

O campo business do CRM referencia o contexto ProfileBusiness. Não troque por um ID genérico do cadastro Business sem conferir a relação.

O quadro pede resumo agregado e páginas de negócios por estágio, com result=open. Ganho e perda são endpoints próprios. stageHistory registra entradas, saídas e duração das passagens. Renomear o estágio preservando sua chave mantém a relação; remover uma chave usada no histórico pode prejudicar a interpretação futura.

Fontes: modelos em pepper-api/src/domains/{Pipeline,Lead,Deal,Activity,Cadence,Segment}, pepper-front/src/app/crm/crm.service.ts e src/utils/Garbage.ts.

A raiz comercial é /home-profilecollaborator/crm. As rotas são board, pipelines, leads, lead, new, view, activities, cadences, import, segments, dashboard e reports.

CrmService é compartilhado. O ID do negócio é guardado por Garbage em sessionStorage; o ID do lead fica em memória no serviço. O funil ativo é persistido em localStorage por empresa (crm.pipeline.<businessId>). A ficha sem ID na URL depende da seleção anterior ou do estado da sessão; não é um permalink autossuficiente.

O quadro realiza movimentação otimista com rollback em erro. Os relatórios selecionam períodos; a agenda envia limites do dia no fuso do aparelho. O calendário combina atividades, previsões e cadências e permite que uma fonte falhe sem apagar os dados das demais.

Contratos internos do CRM​

Todos os caminhos abaixo são relativos a /api/v1. As operações internas exigem x-access-token e requesting, além da permissão correspondente.

RecursoOperações principais
PipelineGET/POST /pipeline, POST /pipeline/ensure-default, GET/PUT/DELETE /pipeline/:pipelineId, PUT /pipeline/:pipelineId/stages/reorder
LeadGET/POST /lead, GET/PUT/DELETE /lead/:leadId, PUT /lead/:leadId/convert
Captação técnicaPOST /lead/form, POST /lead/import/preview, POST /lead/import, POST /lead/webhook-secret
DistribuiçãoGET /lead/unattended, POST /lead/assign-owners
DealGET/POST /deal, GET /deal/summary, GET/PUT/DELETE /deal/:dealId, GET /deal/:dealId/timeline
Decisão do negócioPUT /deal/:dealId/stage, /win, /lose, /reopen
ActivityGET/POST /activity, GET /activity/agenda, GET/PUT/DELETE /activity/:activityId, PUT /activity/:activityId/complete
CadenceGET/POST /cadence, GET/PUT/DELETE /cadence/:cadenceId, PUT /cadence/:cadenceId/toggle
Inscrições e A/BGET /cadence/enrollments, POST /cadence/:cadenceId/enroll, /enroll-segment, PUT /cadence/enrollment/:enrollmentId/unenroll, GET /cadence/:cadenceId/ab-report
SegmentGET/POST /segment, GET/PUT/DELETE /segment/:segmentId, GET /segment/fields, POST /segment/preview, GET /segment/rfm, GET /segment/:segmentId/members, /export
RelatóriosGET /deal/report/funnel, /deal/report/win-loss, /lead/report/attribution, /lead/report/referral

Não existe PUT /deal/:dealId/pipeline nas rotas revisadas, embora o frontend o chame. A atualização comum de Deal também não aceita order no schema atual, apesar de um comentário do controller sugerir vínculo posterior de pedido. Confira schemas e rotas, não apenas comentários ou Swagger.

Exemplo: conversão​

{
"createDeal": true,
"pipeline": "ID_DO_FUNIL",
"dealTitle": "Implantação — Empresa Exemplo",
"dealValue": 12000
}

Envie em PUT /lead/ID_DO_LEAD/convert, substituindo IDs por ObjectIds reais de 24 caracteres hexadecimais da empresa correta. A resposta contém data.lead, data.customer e data.deal. O telefone do lead é obrigatório; a API recusa reconversão de um lead convertido. Título e valor não entram no pagamento automaticamente.

Exemplo: registrar uma resposta estruturada​

{
"business": "ID_DO_PERFIL_EMPRESARIAL",
"lead": "ID_DO_LEAD",
"deal": "ID_DO_NEGOCIO",
"type": "call",
"subject": "Cliente confirmou interesse e pediu reunião",
"outcome": "connected"
}

Envie em POST /activity. O encerramento de cadências reconhece tipos call, whatsapp, email, meeting com resultados connected, rescheduled, refused. Vínculos corretos são necessários para localizar as inscrições. Se ambos forem informados, a função atual prioriza a busca pelo lead.

Captação pública e webhook​

Endpoint públicoUso
GET /public/business/:businessId/lead-formFormulário e perguntas publicados pela empresa
POST /public/leadCaptura da landing ou embed
POST /public/fair/:fairId/leadCaptura contextualizada pela feira
POST /lead-webhook/:businessIdIntegração externa assinada por HMAC
GET/POST /public/opt-out/:tokenRevogar marketing pelo token de descadastro

A landing está em /public/campaign/:businessId e o embed em /public/embed/:businessId. A captura pública inclui limite de taxa e honeypot. A API permite salvar perguntas com tipos texto, nota, múltipla escolha e checkbox, associando respostas aos campos BANT quando configurado.

Para o webhook, gere o segredo em POST /lead/webhook-secret com a empresa no corpo. Ele é devolvido na geração; guarde-o fora do código. A rotação substitui o anterior. O contrato espera HMAC-SHA256 dos bytes exatos do corpo, em x-pepper-signature: sha256=<hex> ou x-hub-signature-256. O endpoint aceita corpo simples e field_data no formato de captura de anúncios; esse suporte não equivale a uma configuração completa da integração do provedor.

Parser do webhook

O parser JSON global é instalado antes do parser que deveria preservar req.rawBody no webhook. Com uma requisição JSON padrão, o corpo já foi consumido e o verify local não é executado. A assinatura pode ser recusada mesmo correta. Corrija a ordem do parser ou preserve o corpo cru no parser global antes de usar essa integração. O consumo do corpo antes do verify foi reproduzido localmente com os parsers Express reais; não foi testado contra produção.

Jobs e dependências de operação​

src/server.js habilita scheduler e watchers conforme variáveis/configuração. src/scheduler/index.js carrega schedule.js dos domínios. As strings de ambiente são convertidas com Boolean: a string "false" é verdadeira, e o fallback de configuração pode continuar habilitando o recurso. Confira a inicialização real do ambiente.

JobPeriodicidadeResponsabilidade
assignLeadOwners10 minutosDistribuir leads abertos sem dono, por regras de etiquetas e menor carga
recalculateLeadScores1 horaRecalcular até 500 leads abertos por rodada
sweepStalledDeals30 minutosMarcar/recuperar estagnação e notificar responsáveis
remindDueActivities15 minutosLembrar tarefas pendentes até os próximos 30 minutos
runCadenceEnrollments5 minutosExecutar até 200 inscrições vencidas
recoverAbandonedCarts30 minutosInscrever recuperações e interromper quando não há pedido elegível aberto
syncRfmSegmentsCron 0 3 * * *Recalcular empresas que já têm públicos automáticos RFM

O cron e os limites diários do scheduler dependem do fuso do processo/Agenda. A agenda visual usa o fuso do aparelho. Não suponha que os dois têm sempre o mesmo limite de dia.

O score total é 40% perfil e 60% engajamento. A distribuição por menor carga usa colaboradores aceitos da empresa e pode priorizar regras de etiquetas. Formulário, roteamento, teto geral de toques e espera de carrinho são configurações técnicas sem editores completos no CRM atual.

Fontes: src/domains/Lead/{routing,scoring,schedule}.js, Deal/schedule.js, Activity/schedule.js, Cadence/{schedule,dispatch,cartRecovery}.js, Segment/{schedule,rfm}.js.

Manter os prints​

Execute, na pasta pepper-docs:

npm run capture:crm

O script usa os componentes e estilos reais do pepper-front irmão, em um workspace temporário; fornece respostas fictícias de HttpClient e não inicia a aplicação principal, API, autenticação ou Firebase. Cria um servidor restrito a 127.0.0.1, abre Chrome headless e salva os PNGs em static/img/crm.

Requer dependências instaladas em ambos os projetos e Chrome. PEPPER_FRONT define outro caminho do frontend, e CHROME_PATH permite indicar outro executável Chromium. O caminho padrão do Chrome é o de macOS. Os scripts encerram navegador e servidor ao terminar normalmente.

Os dados, cenários e data fixa estão em scripts/crm-preview/main.ts.template; o driver está em scripts/capture-crm.cjs. Não substitua dados fictícios por tokens ou registros de clientes. Valide visualmente as imagens e rode npm run build antes de publicar.