📄 Documento de Execução — Card 30: [M6] CRM — Funil de Leads
| Campo |
Valor |
| Card Trello |
[30] [M6] CRM — Funil de Leads & Matrículas |
| URL Trello |
https://trello.com/c/z9izj6iZ |
| Marco |
M6 (IA + WhatsApp + CRM) |
| Data execução |
09/08/2026 |
| Responsável |
Wellington Santiago (via ZCode) |
| Doc anterior |
Card 29: Bot OpenAI |
| Próximo card |
Card 31: E-mail Workflows |
| Commits |
1eb4da2 |
🎯 1. O que foi implementado
CRM visual com funil Kanban drag-and-drop (@dnd-kit). 8 colunas (LeadStatus: NEW → CONTACTED → QUALIFIED → VISIT_SCHEDULED → VISITED → PROPOSAL_SENT → ENROLLED | LOST). Atendentes arrastam leads entre estágios. Origem principal Instagram (default); WhatsApp alimenta via Bot (Card 29).
Decisões do cliente aplicadas:
- Distribuição manual (cada atendente pega o que chegar).
- Conversão sem aprovação prévia (atendente converte direto em matrícula).
- Lead perdido exige motivo OBRIGATÓRIO (modal bloqueia se vazio).
- Follow-up automático após 3 dias sem contato (job
lead-followup marca isStale + notifica).
✅ Critérios de aceite validados
| # |
Critério |
Status |
| 1 |
Kanban arrasta entre estágios (LeadStatus) |
✅ |
| 2 |
Origem Instagram é default; WhatsApp (Bot) cria lead |
✅ |
| 3 |
Conversão para matrícula SEM aprovação (atendente direto) |
✅ |
| 4 |
Mover para LOST exige motivo (bloqueia se vazio) |
✅ |
| 5 |
Follow-up dispara após 3 dias sem contato (isStale) |
✅ |
| 6 |
Atribuição de atendente é manual |
✅ |
| 7 |
Conversão marca convertedToEnrollment |
✅ |
| 8 |
Build passa + lint OK |
✅ |
📁 2. Arquivos criados/modificados
Criados
| Arquivo |
Função |
src/app/(dashboard)/atendimento/crm/page.tsx |
Kanban @dnd-kit (8 colunas + LostReasonModal + NovoLeadModal) |
src/styles/crm-kanban.module.css |
Estilos do Kanban + modais |
src/server/queues/workers/lead-followup.ts |
Job diário 09:00: marca leads stale + notifica atendente |
Modificados
| Arquivo |
Mudança |
src/server/trpc/routers/attendant.ts |
+sub-router crm (board/create/update/move/lose/convert/detail/stats) |
src/server/queues/index.ts |
+QUEUE_NAMES.LEAD_FOLLOWUP + leadFollowupQueue |
src/server/queues/bootstrap.ts |
+worker lead-followup +cron check-stale (diário 09:00) |
prisma/schema.prisma |
Lead: +columnOrder (ordenação kanban) |
src/components/layout/nav-config.ts |
+item "CRM Kanban" no menu Atendimento |
package.json |
+deps @dnd-kit/{core,sortable,utilities} |
🗄️ 3. Schema do banco (mudanças)
leads: +columnOrder (INT default 0 — ordenação dentro da coluna kanban)
- Migration aplicada via
prisma db push na VPS
🔌 4. Handoff para o próximo card (31 — E-mail Workflows)
Procedures tRPC disponíveis (attendant.crm.*)
board({ onlyMine }) → leads agrupados por status
create({ name, phone, email?, courseInterest?, source?, branchId?, notes? })
update({ id, ...campos }) + adiciona interação ao interactionHistory
move({ id, status, columnOrder? }) — validação: LOST exige lose
lose({ id, lostReason }) — motivo OBRIGATÓRIO (min 3 chars)
convert({ id, classId?, courseId?, monthlyFee, notes? }) — marca ENROLLED
detail({ id }) → lead + branch
stats → conversão por origem
Job lead-followup
- Cron diário 09:00 (America/Sao_Paulo)
- Marca
isStale=true em leads ativos sem lastContactAt há 3+ dias
- Notifica atendentes responsáveis (Notification)
📋 5. Deploy DEV
🧠 6. Contexto gerado para próximas etapas
- Card 31 (E-mail): Lead LOST pode disparar reengajamento (LEAD_LOST_REENGAGE).
- Card 27 (Relatórios):
crm.stats alimenta captação por origem.
- Lead-follup: já ativo — leads sem contato há 3 dias ficam amarelos (⚠️) no Kanban.
🎯 7. Próximo card
Card 31 [M6] Automações de E-mail — Workflows. Motor de automação com 7 gatilhos + gatilhos push M2.