Pular para conteúdo

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.aprovada ou proposta.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 por proposta.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 por contrato-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.

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 (fila negocios.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.tsxpages/comercial/kanban/KanbanBoard.tsx; componentes em pages/comercial/kanban/components/; domínio em domains/comercial/negocios/{api,hooks,types}.
  • DB: supabase/migrations/ — tabelas negocio, negocio_movimentacao, negocio_nota, colunas prioridade/versao/pendenciado_em, RPC contar_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}.md não refletem o código atual — mesa-f1.md ainda descreve drag-and-drop, e STATUS.md diz "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".