Cadências de contatos¶
Sequências multicanal do CRM próprio do Cadência, com matrícula por gatilhos, execução idempotente e pausa automática após resposta do lead.
Por que foi construído assim¶
Cadência e funil são conceitos diferentes. pipelines e pipeline_stages continuam representando o kanban comercial; cadências apenas definem uma sequência de contatos e podem se associar a um pipeline ou estágio. O estado é dividido entre definição, passos, inscrições e checks para permitir edição segura, execução concorrente e auditoria.
Existe um único scheduler no cadencia-growth. O executor experimental que existia na Lara foi removido para evitar dupla matrícula e duplo envio. A Lara permanece como adaptador de WhatsApp, agenda e sinal de inbound/reply.
Stack¶
| Camada | Tecnologia |
|---|---|
| Construtor e APIs | Next.js, React, Supabase server client |
| Estado | PostgreSQL: cadences, cadence_steps, contact_cadences, cadence_step_checks |
| Scheduler | Python em cadencia-growth/pipeline/cadence_tick.py |
| Resend | |
| WhatsApp e agenda | Endpoints administrativos do cadencia-lara |
Como funciona¶
flowchart TD
classDef warning fill:#FEF9C3,stroke:#EAB308,color:#111
classDef component fill:#D1FAE5,stroke:#10B981,color:#111
classDef decision fill:#EDE9FE,stroke:#8B5CF6,color:#111
classDef flow fill:#DBEAFE,stroke:#3B82F6,color:#111
classDef core fill:#FEE2E2,stroke:#EF4444,color:#111
subgraph SG_component["Componentes"]
builder[("Projetos/Cadencia/Docs/cadencias-de-contatos.md")]
schema["CRM e estado"]
tick["Scheduler único"]
lara["Adaptador Lara"]
end
class builder,schema,tick,lara component
subgraph SG_flow["Fluxo do processo"]
configure["Usuário cria/clona e configura a cadência"]
enroll["Contato é matriculado manualmente ou por gatilho"]
due["Tick busca inscrição vencida e próximo passo"]
dispatch["Dispara email/WhatsApp ou cria tarefa manual"]
advance["Grava check, avança e calcula próximo horário"]
end
class configure,enroll,due,dispatch,advance flow
subgraph SG_decision["Decisões"]
trigger["Qual gatilho?"]
reply["Lead respondeu após o início?"]
condition["Condição do passo foi satisfeita?"]
channel["Canal automático ou tarefa humana?"]
end
class trigger,reply,condition,channel decision
title["Cadências de contatos"]
class title core
pause["Pausa/espera"]
class pause warning
configure --> enroll
enroll --> due
due --> dispatch
dispatch --> advance
enroll --> trigger
due --> reply
due --> condition
dispatch --> channel
reply -->|"sim"| pause
condition -->|"não"| pause Os gatilhos disponíveis são manual, instant, stage, inbound_whatsapp e outbound_no_reply. O campo since protege a base histórica ao ativar automações. Email e WhatsApp são automáticos; ligação, manual e Instagram geram ações humanas. offset_minutes prevalece sobre day_offset, sempre relativo ao início da inscrição.
Decisões técnicas¶
- Toda inscrição executada pelo scheduler atual recebe
driver='growth'. cadence_step_checkspossui unicidade por inscrição, passo e ciclo e é a âncora de idempotência.- A resposta WhatsApp posterior ao início pausa a inscrição antes de qualquer novo envio.
- Templates system são somente leitura para owner e podem ser clonados para customização.
- As cadências 10D Prospecção e FUP Pós-Proposta são semeadas com copy operacional e associação de pipeline.
- Instagram é canal manual, não automação de publicação.
- Migrações removeram
auto_enroll*somente depois de aposentar o leitor antigo.
Gotchas & armadilhas¶
- O cron atual roda uma vez ao dia (
10 14 * * *, 11:10 BRT). Offsets em minutos não implicam precisão de minutos enquanto a frequência não for aumentada. - O runtime usa estado
running; comentários antigos de schema que citamactivenão são contrato atual. - A migration
20260715190000_cadence_unify_dev1329.sqlapaga linhas de teste comdriver='lara'; não reaplicar sem verificar o banco. inbound_whatsappsó matricula contato já existente no CRM.- O match por oito dígitos finais tolera variações brasileiras, mas pode colidir em outros contextos.
slot_availabledepende da agenda do tenant e da saúde do endpoint da Lara.[a definir]é tratado defensivamente como placeholder e não deve existir em templates novos.
Como operar¶
- Abra
/app/cadenciase crie uma sequência ou clone um template system. - Associe o pipeline e, quando aplicável, o estágio do gatilho.
- Configure
since, atraso do gatilho e passos com canal, copy, offset e condição. - Ative a cadência e matricule manualmente ou aguarde o sweep de gatilhos.
- Acompanhe estado, passo atual,
next_send_ate checks no contato. - Para diagnosticar, confirme primeiro o cron, depois a inscrição vencida, o check e o adaptador do canal.
Validação técnica: pytest -q tests/test_cadence_tick.py tests/test_cadence_templates.py no cadencia-growth, testes DEV-757 no cadencia-lara e build do cadencia-app.
FAQ¶
Ativar uma cadência matricula toda a base antiga? Não. O since define a fronteira temporal do gatilho.
Um contato pode receber o mesmo passo duas vezes? O check idempotente impede repetição do mesmo passo/ciclo em condições normais.
O que acontece quando o lead responde no WhatsApp? A inscrição em andamento é pausada antes do próximo disparo.
Por que um passo de cinco minutos pode executar horas depois? Porque o scheduler atual é diário. O offset define vencimento, mas a frequência do cron define quando ele será observado.