Nexo CRM
CRM multiempresa com WhatsApp (API oficial e QR Code), funil kanban em tempo real, mensagens rápidas, comandos por voz, painel de métricas, importação/exportação Excel e cobrança recorrente via Asaas — o acesso só é liberado com a assinatura paga.
Funcionalidades
- Painel: leads novos, valor em andamento, vendas ganhas, conversão, mensagens por dia, funil, origem, tags e ranking por responsável (7/30/90 dias ou mês).
- Funil (kanban): arrastar e soltar, tempo real entre a equipe, filtros, vários funis.
- Conversas: estilo WhatsApp Web, texto + foto, vídeo, áudio e documento (anexar, arrastar ou colar), mensagens rápidas com
/, status de entrega/leitura.
- Janela de 24h (API oficial): o chat avisa quando a janela fecha e oferece modelos aprovados da Meta com variáveis e prévia.
- Voz: mover etapa, adicionar/remover tags, criar lead, valor, responsável, anotação, editar nome/telefone/e-mail e enviar mensagem no WhatsApp falando — sempre com confirmação.
- Google Agenda: cada vendedor conecta a própria conta. Agendar por voz (“agendamento com o Yuri amanhã às 10 horas” → move para a etapa Agendamento e cria o evento), arrastando o lead para a coluna Agendamento ou pelo botão Agendar no lead; cancelar remove o evento do Google.
- Mensagens agendadas: escolha dia, hora e texto (ou modelo aprovado) e o sistema envia sozinho no WhatsApp do lead — pelo chat, pelo lead, pela tela Agendadas ou por voz (“entrar em contato com o Yuri dia 31 de outubro: e aí, meu patrão, tudo certo?”). Falha temporária tenta de novo (até 3 vezes); falha que exige ação aparece com o motivo e botão de reenviar.
- Relatórios: envie um relatório de exemplo (PDF ou Word) e a IA aprende a estrutura. Todo último dia do mês (30/31; 28/29 em fevereiro) o sistema gera o relatório de cada cliente nesse formato — leads recebidos, ligações, follow-ups, agendamentos, vendas, conversão, metas batidas ou não e o porquê — e envia o PDF no grupo do WhatsApp do cliente (ou num número). O mesmo modelo serve para todos os seus clientes (“Usar em todos os clientes”). Metas e comentários do mês por empresa, prévia em PDF, envio manual e histórico com download.
- Time comercial (mesmo fluxo do playbook): a pessoa toca na função (SDR / Closer), depois no nome, e preenche o checklist do dia com + e − (ou digita o número); salva sozinho e zera a cada dia. Cada meta mostra CONCLUÍDO / EM ANDAMENTO, meta do dia, semana e mês/ciclo. Resultados ligados a cada atividade (ex.: contatos efetivos de ligações) mostram a conversão. Closer registra OS fechada com valor, nº e SDR de origem; vê OS do dia, faturamento e a meta da loja com quanto falta por dia útil. SDR vê as OS da loja e quantas OS vieram dele. Bloco de notas do dia (o closer lê as notas dos SDRs da loja). Painel do gestor: ranking, lojas, conversão por pessoa, origem das OS, atividade de cada dia, observações (copiar para o WhatsApp) e antes x depois com marco zero. Ciclos de 30 dias a partir do início da consultoria (ou meses do calendário). Excel completo. Metas padrão por função e individuais por pessoa (dia/semana/mês). Entra no relatório mensal.
- Ligar pelo WhatsApp (número da API oficial): botão Ligar na conversa, como no WhatsApp. A ligação sai do navegador (microfone do computador) e toca no WhatsApp do cliente; clientes que ligam para a empresa tocam no CRM com Atender / Recusar. A barra da ligação continua aberta enquanto você navega pelo sistema. Toda ligação é gravada: pelo WhatsApp (o cliente ouve um aviso em português antes) e o navegador ainda guarda uma cópia de segurança. Ao encerrar, a ligação vai para a aba Ligações (filtros, ouvir, baixar, Excel) e fica salva para sempre — apagar o lead, a conversa ou o número não apaga a ligação nem o áudio. Também aparece no chat e no histórico do lead, e conta em Ligações do time e do relatório.
- Ligações: botão Registrar ligação no lead (atendeu, não atendeu, caixa postal…) ou por voz (“liguei pro Yuri e ele não atendeu”) — entra no relatório.
- Leads: tabela com busca, ações em massa, importação/exportação Excel.
- Limite de uso por usuário em todas as rotas sensíveis (voz, envio, importação, convites).
"Nexo CRM" é um nome provisório. Para trocar, edite src/components/logo.tsx e o title em src/app/layout.tsx.
Stack
| Camada | Tecnologia |
|---|
| App | Next.js 16 (App Router), React 19, TypeScript estrito, Tailwind |
| Banco, login, tempo real | Supabase (Postgres + RLS + Auth + Realtime) |
| Cobrança | Asaas (assinatura mensal, Pix/boleto/cartão) |
| WhatsApp oficial | Meta Cloud API (com coexistência para histórico) |
| WhatsApp QR Code | Evolution API v2 (self-hosted) |
| Voz | OpenAI (transcrição) + Claude (interpretação do comando) |
Segurança (como foi pensada)
- Isolamento por empresa no próprio banco: toda tabela tem Row Level Security. Um usuário só lê/escreve dados das empresas das quais é membro. Mesmo com um bug no front-end, o banco recusa.
- Bloqueio por falta de pagamento também no banco: sem assinatura ativa e dentro da vigência, as consultas a leads, conversas etc. retornam vazio. A tela de cobrança continua acessível.
- Ninguém se auto-ativa: só o webhook do Asaas (com token secreto) altera a assinatura.
- Segredos isolados: tokens da Meta ficam numa tabela sem nenhuma política de leitura — só o servidor acessa. Nunca chegam ao navegador.
- Webhooks autenticados: Meta por assinatura HMAC-SHA256, Asaas por token, Evolution por segredo único por número. Todos com comparação em tempo constante e idempotência (reenvios não duplicam nada).
- Permissões por função: Proprietário, Administrador e Atendente. Atendente não exclui leads nem altera configurações.
- Anti-adulteração: gatilhos impedem vincular lead a etapa/tag/responsável de outra empresa.
- Cabeçalhos HTTP de segurança (HSTS, X-Frame-Options, nosniff, Permissions-Policy).
Testes incluídos
npm test # roda tudo
npm run test:unit # 29 testes: webhooks, modelos, mídia, fuso horário/agenda, mensagens agendadas, relatórios (metas, último dia do mês, PDF), telefone, CPF/CNPJ, dinheiro, voz
npm run test:db # 121 testes: migrations reais num Postgres embutido — isolamento, bloqueio, permissões, deduplicação, 9º dígito, limites, painel, agendamentos, mensagens agendadas (sem envio duplicado)
npm run typecheck
npm run build
Passo a passo para colocar no ar
1. Supabase
- Crie um projeto em supabase.com (região São Paulo).
- Em SQL Editor, rode, na ordem do nome, todos os arquivos de
supabase/migrations/
(ou use a CLI: supabase link e supabase db push).
O projeto nexo-crm já está criado e com todas as migrations aplicadas.
- Em Authentication → URL Configuration:
- Site URL:
https://seu-dominio.com.br
- Redirect URLs:
https://seu-dominio.com.br/auth/callback
- Em Authentication → Emails, personalize os textos em português (confirmação, convite, redefinição de senha) e configure um SMTP próprio (Resend, SES…) — o SMTP padrão do Supabase tem limite baixo.
- Copie de Project Settings → API: URL,
anon key e service_role key.
2. Variáveis de ambiente
Copie .env.example para .env.local (ou cadastre na Vercel) e preencha. Nunca coloque a SUPABASE_SERVICE_ROLE_KEY em variável NEXT_PUBLIC_*.
3. Asaas (cobrança)
- Crie a chave de API em Integrações → Chave de API. Comece pelo sandbox (
ASAAS_API_URL=https://api-sandbox.asaas.com/v3).
- Em Integrações → Webhooks, crie um webhook:
- URL:
https://seu-dominio.com.br/api/webhooks/asaas
- Token de autenticação: o mesmo valor de
ASAAS_WEBHOOK_TOKEN
- Eventos: todos de Cobrança e todos de Assinatura
- Defina
PLAN_PRICE_CENTS (ex.: 19700 = R$ 197,00) e PLAN_NAME.
Fluxo: cadastro → cria empresa → tela de assinatura → paga a fatura → o Asaas avisa o webhook → acesso liberado sozinho (a tela verifica a cada 8s). Vencida sem pagamento → acesso pausado; pagou → volta tudo, sem perder dados.
4. WhatsApp — API oficial (Meta)
- No Meta for Developers, crie um app do tipo Business com o produto WhatsApp.
- Em WhatsApp → Configuração → Webhook:
- URL de callback:
https://seu-dominio.com.br/api/webhooks/meta
- Token de verificação: o valor de
META_WEBHOOK_VERIFY_TOKEN
- Assine os campos:
messages, history, smb_message_echoes
META_APP_SECRET = Configurações do app → Básico → Chave secreta do app.
- Assine também o campo
calls no webhook (ligações).
Conexão em 1 clique para os clientes (Cadastro Incorporado / Embedded Signup) — o app é criado uma vez só; cada cliente conecta o próprio número sozinho:
- No app da Meta: Login do Facebook para Empresas → Configurações → Criar configuração. Escolha a variação WhatsApp Embedded Signup, marque os produtos WhatsApp Cloud API (e Marketing Messages, se quiser) e as permissões
whatsapp_business_management e whatsapp_business_messaging. Copie o ID da configuração.
- Em Login do Facebook para Empresas → Configurações, adicione o seu domínio em Domínios permitidos para o SDK JavaScript e URIs de redirecionamento OAuth válidos (ex.:
https://seu-dominio.com.br/).
- Variáveis:
NEXT_PUBLIC_META_APP_ID (ID do app), NEXT_PUBLIC_META_ES_CONFIG_ID (ID da configuração), META_APP_SECRET.
- Para clientes de fora do seu Business: verificação da empresa (Configurações do Business → Central de segurança), virar Tech Provider e passar pela Análise do app com as permissões acima no acesso avançado.
O cliente clica em Configurações → WhatsApp → API oficial → Continuar com o Facebook, entra, escolhe/cria a conta e confirma o número por SMS. O sistema troca o código pelo token, assina os webhooks, registra o número (PIN gerado e guardado) e ativa as ligações. Opção "mesmo número do app do celular" usa a coexistência (sem ligações pela API — limite da Meta).
Conexão manual (sem Embedded Signup): informe Phone Number ID, WABA ID e um token permanente de usuário do sistema pelo link "Conectar manualmente".
Histórico na API oficial: só existe via coexistência (número que já usa o app WhatsApp Business, conectado pelo Embedded Signup). A Meta envia até ~6 meses de conversas, e a solicitação precisa ser feita em até 24h após conectar — o sistema já pede isso automaticamente ao cadastrar o número.
5. WhatsApp — QR Code (Evolution API v2)
- Suba a Evolution API v2 num servidor seu (Docker; Railway, VPS etc.) com Postgres/Redis conforme a documentação dela.
- Preencha
EVOLUTION_API_URL e EVOLUTION_API_KEY (a global API key).
- No sistema, Configurações → WhatsApp → QR Code gera a instância, configura o webhook sozinho e mostra o QR. Ao conectar, o histórico completo é sincronizado automaticamente; o botão Importar histórico faz uma varredura completa e pode ser repetido sem duplicar nada.
Conexão por QR Code é não oficial (protocolo do WhatsApp Web). Existe risco de bloqueio do número pela Meta, principalmente com disparos em massa. Para operação crítica, prefira a API oficial.
6. Comandos por voz
OPENAI_API_KEY — transcrição do áudio (gpt-4o-mini-transcribe, barato e bom em PT-BR).
ANTHROPIC_API_KEY — interpreta a frase e transforma em ações.
Clique em Comando de voz (ou Ctrl+Shift+M), fale, por exemplo: "mova o lead Yuri para Negociação e coloque a tag Anúncio". O sistema mostra o que entendeu e só executa depois da sua confirmação; se houver dois "Yuri", ele pergunta qual. Também dá para digitar o comando (ícone de teclado).
Ações suportadas: mover de etapa, adicionar/remover tags (cria a tag se não existir), criar lead, definir valor, definir responsável, adicionar anotação, registrar ligação, enviar e agendar mensagem, agendar reunião — várias na mesma frase.
7. Google Agenda
- Em Google Cloud Console: crie um projeto e ative a Google Calendar API.
- Tela de consentimento OAuth: tipo Externo, adicione o escopo
.../auth/calendar.events. Enquanto o app estiver em Teste, só os e-mails cadastrados como testadores conseguem conectar; para todos os clientes, envie para verificação do Google.
- Credenciais → Criar ID do cliente OAuth (Aplicativo da Web) com o URI de redirecionamento
https://seu-dominio.com.br/api/google/callback.
- Preencha
GOOGLE_CLIENT_ID e GOOGLE_CLIENT_SECRET.
- No sistema: Configurações → Integrações → Conectar Google Agenda (cada pessoa da equipe conecta a sua).
Empresas criadas a partir de agora já nascem com a etapa Agendamento no funil. Em empresas antigas, crie uma etapa com "Agendamento" no nome (Configurações → Funil).
8. Mensagens agendadas (disparador)
O disparador já está criado no Supabase (pg_cron, a cada minuto, só chama o app quando há mensagem vencida). Depois do deploy, ative-o uma vez:
- Gere um segredo:
openssl rand -hex 32 e coloque em CRON_SECRET (Vercel/.env.local).
- No SQL Editor do Supabase, rode (com os seus valores):
select vault.create_secret('https://seu-dominio.com.br', 'app_url');
select vault.create_secret('<o mesmo CRON_SECRET>', 'cron_secret');
- Pronto. Para conferir: Integrations → Cron no painel do Supabase mostra as execuções do job
nexo-scheduled-messages.
Regra da Meta: na API oficial, texto livre só é entregue se o cliente falou nas 24h anteriores; para retomar contato, agende um modelo aprovado (o sistema avisa e oferece). Pelo QR Code não há essa restrição.
8b. Ligações pelo WhatsApp (Calling API da Meta)
- Só funciona no número conectado pela API oficial. Pelo QR Code o WhatsApp não permite ligação de voz por sistema (o botão mostra o número para ligar pelo celular).
- No painel da Meta (seu app → WhatsApp → Configuração → Webhooks), marque o campo calls (além de messages).
- No CRM: Configurações → WhatsApp → Ligações no número oficial → ative e escolha a gravação:
- Pelo WhatsApp (recomendado): a Meta toca um aviso em português ("O áudio desta ligação será gravado para: …") e manda o arquivo; o CRM guarda no bucket privado
calls. O navegador grava uma cópia de segurança ao mesmo tempo.
- Só no navegador: grava as duas vozes no computador de quem ligou, sem aviso automático (avise o cliente).
- Não existe opção "não gravar". Os arquivos não expiram (o bucket não tem regra de exclusão); cada minuto ocupa ~0,25 MB.
- Regras da Meta: o cliente precisa permitir ligações antes (botão "Pedir permissão" na conversa; só dentro de 24h da última mensagem dele; vale 7 dias ou para sempre). Limites: 1 pedido por dia e 2 por semana; até 100 ligações conectadas por dia por número; 4 ligações seguidas sem atender cancelam a permissão.
- Precisa de HTTPS (já é assim na Vercel) e microfone liberado no navegador.
8c. Telefonia VoIP (ligações gravadas para o celular do lead)
Funciona com qualquer WhatsApp (coexistência ou QR Code), porque é uma ligação telefônica comum, feita pelo navegador.
- Crie a conta na Api4Com, coloque créditos (paga por minuto) e gere um token de API sem validade no portal.
- No CRM: Configurações → Integrações → Telefonia → Conectar central, cole o token (e o domínio SIP, ex.:
suaempresa.api4com.com, se já souber). O CRM cadastra sozinho o webhook de fim de ligação com a gravação.
- Na mesma tela, clique Criar ramal para cada pessoa que vai ligar (ou Já tenho ramal para vincular um existente).
- A pessoa recarrega o CRM: o telefone embutido conecta na central e aparece o botão verde Ligar no lead e na conversa.
Como funciona: o CRM pede a ligação à central → a central chama o ramal (o navegador atende sozinho) → disca para o lead. A central grava; ao terminar, o CRM baixa a gravação e guarda para sempre em Ligações (o navegador também guarda uma cópia de segurança).
Ligação pelo WhatsApp (Calling API) só existe em número 100% API oficial. Em coexistência a Meta não libera ligação pela API, e pelo QR Code o WhatsApp não permite — por isso a telefonia VoIP.
9. Relatórios mensais
- Usa a mesma
ANTHROPIC_API_KEY. O modelo que escreve o relatório é ANTHROPIC_REPORT_MODEL (padrão claude-sonnet-5-5).
- O disparador mensal já está criado no Supabase (job
nexo-monthly-reports, de hora em hora) e usa os mesmos segredos do Vault do item 8 — se você já fez o item 8, não precisa fazer nada.
- Em cada empresa: Relatórios → envie o relatório de exemplo → defina metas → em Envio automático escolha o WhatsApp, o grupo do cliente e o horário → ative.
- Envio para grupo exige o número conectado por QR Code (a API oficial da Meta não envia para grupos). Pela API oficial dá para enviar a um número.
- Proteções: um único envio automático por empresa e mês (não duplica no grupo); se falhar, tenta de novo na hora seguinte, até 3 vezes; só envia para empresas com assinatura em dia. Os PDFs ficam no bucket privado
reports do Supabase.
10. Deploy (Vercel)
- Suba o código para um repositório GitHub e importe na Vercel.
- Cadastre as variáveis de ambiente.
- Plano Pro recomendado: a importação de histórico e os webhooks usam até 300s por execução.
- Aponte o domínio e atualize
NEXT_PUBLIC_APP_URL e as URLs no Supabase, Asaas e Meta.
Escala (muitos usuários simultâneos)
- Banco: índices em todas as chaves de busca e de empresa; políticas RLS no padrão recomendado pelo Supabase (
(select auth.uid()), funções security definer estáveis) para não recalcular por linha. Comece no plano Pro do Supabase e suba o compute conforme o volume.
- Kanban: carrega 50 leads por coluna com "carregar mais" e contagem real — funciona com dezenas de milhares de leads.
- Conversas e mensagens: paginadas (rolagem infinita); mídia baixada sob demanda pelo servidor, sem lotar o armazenamento.
- Tempo real: assinaturas filtradas por empresa e por conversa.
- Webhooks: idempotentes e atômicos (uma função no banco grava conversa + mensagem + lead + contadores de uma vez); reenvios do provedor não duplicam.
- Importação de histórico: em etapas com cursor, sem estourar tempo limite, retomável.
- Planilhas: até 20.000 linhas por importação, em lotes de 500; atualiza pelo telefone em vez de duplicar.
Estrutura
supabase/migrations/ schema, RLS, gatilhos e funções
src/proxy.ts protege rotas (sessão Supabase)
src/lib/ auth, Asaas, WhatsApp (meta/evolution), voz, planilhas
src/app/api/ rotas: cobrança, canais, mensagens, mídia, voz, leads, equipe, webhooks
src/app/(app)/ telas: funil, conversas, leads, configurações
src/components/ kanban, inbox, painel do lead, voz, configurações, UI
tests/ testes unitários e de banco
Próximos passos sugeridos
- Cadastro pelo Embedded Signup da Meta (conexão do número oficial em 1 clique, com coexistência) — exige o app aprovado como Tech Provider.
- Gravação de áudio direto no chat (nota de voz).
- Monitoramento de erros (Sentry) e alertas de webhook.