tipo: funcionalidade contexto: comercial fontes: [código atual apps/api-menos-juros/src/v2/comercial/negocios, apps/crm-menos-juros/client/src/pages/comercial/kanban-comercial, specs/kanban-comercial/ARQUITETURA.md, PR #90] atualizado_em: 2026-07-14 status: ativo
Kanban / Pipeline Comercial¶
O que é¶
Board Kanban para o time Comercial acompanhar a posição de cada contato no funil de crédito,
em https://crm.menosjuros.com/comercial/kanban-comercial. Resolve o problema de dar
visibilidade de funil (análise → proposta → formalização → pagamento) sem exigir que ninguém
mova cards manualmente e sem duplicar a fonte de verdade das telas legadas.
Como funciona¶
Princípio central: board read-only orientado a eventos¶
O usuário não arrasta card. Ver board-read-only-orientado-a-eventos. Cada ação real feita nas telas legadas (análise, propostas, bancarização) ou um webhook externo emite um evento de domínio (BullMQ) que reposiciona o agregado negocio; o Supabase Realtime reflete a mudança no board. Os "botões" do card são atalhos que disparam a ação real (que por sua vez emite o evento) — eles não movem o card diretamente.
Fluxo do evento:
use-case emite → fila mesa-analise.eventos
→ MesaAnaliseEventosDispatcher (fan-out)
→ fila negocios.eventos
→ NegocioEventosProcessor aplica a transição no agregado
→ persiste
→ Supabase Realtime
→ board invalida (debounce ~500ms, cirúrgico por pipe)
O agregado Negocio¶
Ver negocio para o detalhe. Em resumo: representa a posição de 1 contato (CPF) no funil —
1 análise, 1 (pipe, etapa), 1 status, 1 responsável, N propostas associadas pela mesma
análise. Vocabulário oficial: "Negócio" (não Card/Oportunidade/Lead), "Pendência" (não
Travado/Parado).
2 pipes, 3 boards¶
O mesmo componente KanbanBoard genérico serve três boards, diferenciados pelo pipe (e, no
caso da Mesa, também a etapa):
| Board | Rota | Etapas |
|---|---|---|
| Comercial | /comercial/kanban-comercial |
6 etapas comerciais + colunas virtuais |
| Mesa F1 (análise) | /comercial/kanban-mesa |
Nova Análise · Em Análise · Criação de Propostas |
| Mesa F2 (formalização) | /comercial/kanban-mesa-f2 |
Cadastrar CCB · Enviar Documentos |
Ver pipe-e-etapa para o vocabulário de etapas e a máquina de estados completa. Para o aprofundamento coluna a coluna (responsabilidade + features + movimentações de cada coluna dos 3 boards, incluindo as virtuais), ver referencia-de-colunas-do-pipe.
Regras por coluna (pipe Comercial)¶
- Aguardando Apresentação — entra por
analise.aprovadaouproposta.criada; botões Chat - Pegar; sai para Em Negociação ao clicar Pegar.
- Em Negociação — entra ao Pegar (
proposta.atribuida, vira responsável); botões Chat + ✓ Aceito; sai para Coleta de Documentos ao aceitar uma proposta. - Coleta de Documentos — entra por
proposta.aceita(forward-only); botões Chat + Docs OK (confirma); sai para Mesa F2/Cadastrar CCB porproposta.docs-coletados. - Pendências/Bloqueados (VIRTUAL) — qualquer negócio pendenciado, de qualquer pipe; botão Resolver; ao resolver, volta à mesma etapa onde estava. Ver pendencia.
- Em formalização (Mesa) (VIRTUAL) — ghost: negócio do Comercial fisicamente em Mesa F2 com
responsável já atribuído. Sem prioridade e sem mover de etapa (não arrasta, sem "Mover
para…"/"Pendenciar…"); o nome abre o drill (
CardDetalheSheet) igual aos demais cards.⚠️ Antes (até PR #90): totalmente sem menu/ações — só visibilidade. Desde PR #90: tem o menu ⋮ em modo enxuto (
soAtribuicaoEArquivar), com Reatribuir (admin)/Desatribuir e Arquivar — só quando o card estáativo. Ver atribuicao-de-negocio e arquivar-negocio. - Aguardando Assinatura — entra por
proposta.efetivada(volta da F2); botões Chat + Assinado; sai para Aguardando Pagamento porcontrato-assinado. - Aguardando Pagamento — botão Chat; sai para Concluído pelo webhook
PropostaPaga(FIDEM). - Concluído — pagamento confirmado,
status='concluido'; libera o contato para refin; terminal. - Arquivado/Reprovado (VIRTUAL) — arquivamento manual (motivo obrigatório) ou recusa da análise; terminal.
Etapas da Mesa: Nova Análise (▶ inicia) → Em Análise (👁 ver) → Criação de Propostas (+ criar) → Cadastrar CCB (F2, dialog de bancarização FIDEM/FIDUCIA) → Enviar Documentos (F2, botões Enviar Docs + Efetivar).
Regras de domínio sempre válidas¶
- Aceite de proposta é forward-only.
- Concluir é terminal em qualquer pipe.
- Trocar de pipe zera o responsável — exceto o round-trip Comercial ↔ Mesa F2, que preserva o responsável.
- 1 negócio ativo por CPF (
UNIQUE(contato_id) WHERE status='ativo'). - Pendência "congela" o card: ignora eventos de posição não-terminais; recusa e pagamento vencem a pausa.
- Handlers de evento são idempotentes.
Mapa evento → destino do card¶
| Evento | Destino |
|---|---|
contatos-mesa.criado |
cria card Mesa/Nova Análise (automático, mesa aberta) |
contatos-mesa.reaberta |
Mesa/Nova Análise |
analise.iniciada |
Mesa/Em Análise (+ analista vira responsável) |
analise.aprovada |
Comercial/Aguardando Apresentação |
proposta.criada |
Comercial/Aguardando Apresentação |
contatos-mesa.recusado |
Arquivado |
analise.ccb |
Mesa/Cadastrar CCB |
proposta.atribuida (Pegar) |
Em Negociação + responsável |
proposta.liberada (Desatribuir) |
limpa responsável (não move de coluna) |
proposta.aceita (✓ Aceito) |
Coleta de Documentos (forward-only) |
proposta.docs-coletados (Docs OK) |
Mesa F2/Cadastrar CCB |
proposta.ccb-cadastrada (bancarização) |
Mesa F2/Enviar Documentos |
proposta.efetivada (Efetivar) |
Comercial/Aguardando Assinatura |
proposta.contrato-assinado (Assinado) |
Aguardando Pagamento |
PropostaPaga (webhook FIDEM compra-liberação) |
Concluído + status=concluido |
O agregado também emite eventos comercial.negocio.* na fila comercial-eventos — hoje
sem consumidor, é um seam preparado para notificações/métricas futuras.
Funcionalidades do card¶
Mostra: nome (abre detalhe), CPF, Valor do Negócio (verde quando há proposta aceita, senão o maior valor), badges Pré-Aprovado/Cliente/Pendenciado, produtos, origem, motivo (se arquivado), ocupação·banco, "enviado por" (com ♻️ se reprocessado), responsável, nº de propostas (clicável), tempo parado (semáforo verde <24h / amarelo 24-72h / vermelho >72h), toggle Urgente (P0).
Menu ⋮ do card: - Mover para… — override manual, qualquer usuário logado. Ver mover-negocio. - Reatribuir… — só admin/super admin. Ver atribuicao-de-negocio. - Pendenciar… — nota obrigatória. Ver pendencia. - Arquivar… — motivo obrigatório (lista fixa + Outro). Ver arquivar-negocio. - Desatribuir de mim. Ver atribuicao-de-negocio.
No card-fantasma da coluna virtual "Em formalização (Mesa)" o menu ⋮ é enxuto (prop
soAtribuicaoEArquivar do CardMenu, desde PR #90): só Reatribuir/Desatribuir e Arquivar —
"Mover para…" e "Pendenciar…" ficam ocultos ali, porque o negócio está no fluxo da Mesa.
Dialogs: Propostas (lista + Imprimir — abre PropostaPrintModal, um dialog de impressão
embutido no próprio card, não a rota legada /propostas/imprimir/:id, que existe no
código mas não é referenciada por nenhuma tela; no Comercial também "Simular outros valores"),
Aceitar Proposta (escolha única exclusiva, ver avanco-do-negocio-comercial), Cadastrar CCB
(só a proposta aceita é bancarizável; escolhe FIDEM/FIDUCIA — ver cadastrar-ccb), Enviar
Documentos (Enviar Docs + Efetivar — mesmo dialog e mesma lógica da tela
aguardando-documentacao, embutidos no card), Detalhe do card (drawer com abas
Detalhe/Histórico/Notas — ver notas-e-historico-do-negocio —, de onde "Abrir perfil do
contato" leva à ficha-do-contato). Ver proposta.
Botão Chat: abre a conversa (ou, na falta dela, o perfil do contato) no Chatwoot — app
externo (chat.menosjuros.com), fora do CRM. Não há tela própria no wiki para isso; ver
chatwootUrl() em KanbanCard.tsx.
Filtros são server-side e persistidos por board: busca por nome/CPF (debounce 350ms), data de criação (presets Hoje/Ontem/7d/30d + custom, sem default), origem, e no popover Filtros: banco, produto, tempo parado (+24h/+72h), responsável; toggles Urgentes/Clientes/Meus negócios. Ordenação: Mais parados (default), Urgentes primeiro, Mais recentes, Mais antigos, Nome A-Z. Paginação por coluna: 25/página (15 em Arquivado/Concluído). Header da coluna mostra contagem e Total (Σ Valor do Negócio). Aprofundamento de todos esses controles (incluindo o realtime e o semáforo de tempo parado) em board-comercial-controles.
Atribuição e RBAC¶
- Pegar — self-assign, só no pipe Comercial, avança em Aguardando Apresentação.
- Desatribuir — só o próprio responsável.
- Reatribuir — só admin/super admin (RPC
is_super_admin). - Herança de dono: ao entrar no Comercial, se as propostas já tinham um responsável comercial único, ele é herdado.
Aprofundamento dos 4 mecanismos (Pegar/Desatribuir/Reatribuir/herança) em atribuicao-de-negocio.
RBAC via KanbanPermissaoGuard: recursos kanban_comercial/kanban_mesa em
system_resources, grants read/update em user_permissions. O board pede read, ações
por id pedem update, mover pede só login, reatribuir pede admin. A UI só esconde os
controles — o backend recusa com 403 independentemente disso.
Resiliência¶
Dual-write best-effort: o evento é emitido após o commit; se falhar, logger.error com o
payload (replayable) — evolução planejada é um padrão outbox. Optimistic lock via versao:
conflito lança ConflictException retryável. Um cron
(ReconciliarNegociosCronService) materializa cards faltantes, cobrindo o go-live sem
backfill.
Navegação — telas que o Kanban abre¶
Mapa explícito de cada clique/ação do card para o destino correspondente. Só as duas primeiras linhas navegam para outra tela — o resto é dialog embutido no próprio card (já descrito acima, em "Funcionalidades do card") ou abre um app externo.
| Clique no Kanban | Vai para |
|---|---|
| Nome do card / drawer "Abrir perfil do contato" | ficha-do-contato (/contatos/:id) |
| Botões da Mesa ▶ Iniciar / 👁 Ver / + Criar proposta | analise-de-credito (aba da ficha, ?tab=analise-credito) |
| Aba "Negociações" da ficha → "Abrir no Pipeline" | volta aos boards (kanban-comercial / Mesa F1 / Mesa F2) |
| Botão "Enviar Docs" / "Efetivar" (Mesa F2) | mesma lógica da tela aguardando-documentacao (dialog embutido no card) |
| Botão "Chat" | Chatwoot — app EXTERNO, sem página no wiki |
| "N propostas" → "Imprimir" | dialog PropostaPrintModal embutido (sem página; ver conceito proposta) |
| "Cadastrar CCB" | dialog de bancarização FIDEM/FIDUCIA embutido (sem página própria) |
Regras de negócio¶
⚠️ A documentar. Esta tela ainda não tem as regras de negócio levantadas do código.
O que entra aqui: invariante (o que nunca pode acontecer), permissão (quem pode fazer o quê), bloqueio (o que impede a ação e a mensagem que o usuário vê), cálculo (fórmula e arredondamento) e efeito colateral (o que mais muda quando isso acontece).
Regra só entra aqui com origem no código — arquivo e linha. Regra que alguém "acha que é assim" é pior que seção vazia, porque vira decisão de produto baseada em memória.
Onde vive no código¶
- API (DDD V2):
apps/api-menos-juros/src/v2/comercial/negocios/ - controller:
presentation/controllers/negocios.controller.ts(base/v2/comercial/negocios) - agregado:
domain/entities/negocio.entity.ts - VOs:
domain/value-objects/pipe.vo.ts - processor:
infrastructure/processors/negocio-eventos.processor.ts(filanegocios.eventos) - dispatcher:
apps/api-menos-juros/src/v2/mesa-analise/infrastructure/processors/mesa-analise-eventos.dispatcher.ts - CRM:
apps/crm-menos-juros/client/src/pages/comercial/kanban-comercial/index.tsx→pages/comercial/kanban/KanbanBoard.tsx; componentes empages/comercial/kanban/components/; domínio emdomains/comercial/negocios/{api,hooks,types}. - DB:
supabase/migrations/— tabelasnegocio,negocio_movimentacao,negocio_nota, colunasprioridade/versao/pendenciado_em, RPCcontar_negocios_por_coluna, recursos RBAC do Kanban. - Specs:
specs/kanban-comercial/(ARQUITETURA.mdé a referência técnica).
⚠️ Specs defasados:
specs/kanban-comercial/{STATUS,mesa-f1,eventos-movimentacao}.mdnão refletem o código atual —mesa-f1.mdainda descreve drag-and-drop, eSTATUS.mddiz "nada em produção". A verdade é o código: o board é read-only orientado a eventos, e as features PROD-01 (ghost "Em formalização"), PROD-04 (prioridade Urgente), FEAT-01 (timeline), FEAT-02 (drawer), FEAT-03/04 (override de movimentação / reatribuir admin), FEAT-05 (busca) e FEAT-08 (notas) já estão entregues em produção. Em aberto: PROD-03 (vocabulário/labels das etapas).
Relacionado¶
comercial · negocio · pipe-e-etapa · board-read-only-orientado-a-eventos · pendencia · proposta · ficha-do-contato · aguardando-documentacao · mesa · analise-de-credito · referencia-de-colunas-do-pipe · atribuicao-de-negocio · avanco-do-negocio-comercial · cadastrar-ccb · arquivar-negocio · mover-negocio · notas-e-historico-do-negocio · board-comercial-controles
Histórico¶
- 2026-07-10: primeira ingestão da funcionalidade no wiki, a partir do mapeamento verificado no código atual (API v2 comercial/negocios + CRM kanban-comercial + specs).
- 2026-07-10: documentadas as telas alcançadas por clique a partir do board — cross-link com
ficha-do-contato e aguardando-documentacao; esclarecido que "Imprimir" abre um dialog
embutido (
PropostaPrintModal), não a rota legada/propostas/imprimir/:id; e que "Chat" abre o Chatwoot (app externo). - 2026-07-10: adicionada seção "Navegação — telas que o Kanban abre", com tabela mapeando cada clique/ação do card ao destino correspondente (tela do wiki, dialog embutido ou app externo).
- 2026-07-10: ingestão das features do card/board (Eixo 1) e do aprofundamento por coluna (Eixo 2) em páginas próprias — cross-links adicionados nas seções "Menu ⋮ do card", "Atribuição e RBAC", dialogs do card e filtros/ordenação; ver referencia-de-colunas-do-pipe e as páginas listadas em Relacionado.
- 2026-07-14 (PR #90): o card-fantasma "Em formalização (Mesa)" deixou de ser totalmente
read-only — ganhou o menu ⋮ em modo enxuto (Reatribuir/Desatribuir + Arquivar, sem "Mover
para…"/"Pendenciar…"), visível só quando
ativo. Marcado antes/depois na coluna virtual e na seção "Menu ⋮ do card".