Visão Geral

Arquitetura — 4 Camadas

Sistema SaaS multiempresa white-label. Cada barbearia é um tenant isolado com slug próprio.

┌─────────────────────────────────────────────────────────────┐ │ barbearia.iasolux.com.br │ ├─────────────────────────────────────────────────────────────┤ │ │ │ CAMADA 1 ── Painel Master /master │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Visão Geral │ Empresas │ Cobranças │ Planos │ │ │ │ Modal Ativar Asaas │ Bloquear │ Reativar │ │ │ └─────────────────────────────────────────────────────┘ │ │ ▼ │ │ CAMADA 2 ── Painel da Barbearia /empresa/{slug}/ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Dashboard │ Agenda │ Agendamentos │ │ │ │ Clientes │ Barbeiros│ Serviços │ │ │ │ Financeiro│ Config │ Agente Interno (AI) │ │ │ └─────────────────────────────────────────────────────┘ │ │ ▼ │ │ CAMADA 3 ── Link Público /agendar/{slug} │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Step 1: Serviço → Step 2: Barbeiro │ │ │ │ Step 3: Data/Hora → Step 4: Dados Pessoais │ │ │ │ Step 5: Resumo → Step 6: Confirmação │ │ │ │ Widget: Agente AI público (chat flutuante) │ │ │ └─────────────────────────────────────────────────────┘ │ │ ▼ │ │ CAMADA 4 ── Integrações Externas │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Multi-Asaas │ │ Evolution API│ │ Claude AI │ │ │ │ (hub 209) │ │ WhatsApp │ │ Agentes │ │ │ │ Pagamentos │ │ Instâncias │ │ Público/Int │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────┘

Mapa de Rotas

/master                         → Painel master (protegido por MASTER_TOKEN)
/empresa/{slug}/dashboard       → Dashboard da barbearia
/empresa/{slug}/agenda          → Agenda visual por barbeiro
/empresa/{slug}/agendamentos    → Lista de agendamentos
/empresa/{slug}/clientes        → CRM de clientes
/empresa/{slug}/barbeiros       → Gestão de barbeiros e horários
/empresa/{slug}/servicos        → CRUD de serviços
/empresa/{slug}/financeiro      → Cobranças do tenant
/empresa/{slug}/configuracoes   → WhatsApp, dados da empresa
/empresa/{slug}/bloqueada       → Página de acesso bloqueado
/agendar/{slug}                 → Link público (sem login, mobile-first)
/confirmar/{token}              → Confirmar/cancelar presença via token
/api/webhooks/asaas             → Recebe fan-out do Multi-IaSolux

Middleware de Acesso

Roda em TODAS as rotas /empresa/{slug}/* e /agendar/{slug}:

// Status → Ação
trial        → trial_expira_em < NOW? → SET bloqueada → bloquear
               → senão: permitir + injetar BANNER_TRIAL
ativa        → permitir acesso completo
inadimplente → permitir + injetar BANNER_INADIMPLENTE
bloqueada    → redirect /empresa/{slug}/bloqueada
cancelada    → redirect /empresa/{slug}/bloqueada
Tecnologia

Stack & Convenções

⚙️Stack

Framework: Next.js 14 (App Router)

Linguagem: TypeScript strict

Banco: PostgreSQL + Prisma ORM

Estilo: Tailwind CSS

Ícones: Lucide React

Toasts: Sonner

🎨Paleta

#0D0D0D fundo

#1A1A1A cards

#C9A84C accent dourado

#22C55E sucesso/ativa

#EF4444 erro/bloqueada

#F97316 alerta/inadimplente

Estrutura de Diretórios

barbearia-saas/
├── prisma/
│   ├── schema.prisma         ← todas as 13 tabelas
│   └── seed.ts               ← dados de teste
├── src/
│   ├── app/
│   │   ├── master/           ← painel master
│   │   ├── empresa/[slug]/   ← painel tenant
│   │   ├── agendar/[slug]/   ← link público
│   │   ├── confirmar/[token]/← confirmação presença
│   │   └── api/
│   │       ├── webhooks/asaas/ ← recebe fan-out
│   │       └── agente/         ← chat AI
│   ├── components/
│   ├── lib/
│   │   ├── prisma.ts         ← client singleton
│   │   ├── asaas.ts          ← cliente thin para multi-iasolux
│   │   ├── evolution.ts      ← Evolution API client
│   │   └── notificacoes.ts   ← dispatch de notificações
│   └── middleware.ts         ← verificação de status
├── .env.example
└── package.json
Fases de Execução

Plano de Construção

Construir um módulo por vez. Não avançar sem o anterior funcionando.

1
Fundação
Banco de dados + Seed + Middleware de acesso
⬜ Pendente

Criar todas as 13 tabelas + 7 índices. Popular com dados de teste. Middleware de controle de acesso por status.

  • prisma/schema.prisma com todas as tabelas
  • prisma migrate dev sem erros
  • seed.ts: 3 planos, 1 empresa, 2 barbeiros, 5 serviços, 3 clientes, 8 agendamentos
  • middleware.ts intercepta /empresa/[slug]/* e /agendar/[slug]
  • Banner trial exibe (azul informativo)
  • Banner inadimplente exibe (laranja)
  • Página /bloqueada com botões Pagar e Suporte
  • Link público bloqueado para empresa bloqueada
  • Middleware não afeta rota /master
2
Integração Asaas
Via Multi-IaSolux (hub servidor 209)
⬜ Pendente

Registrar projeto barbearia no multi-iasolux. Criar cliente fino para criar customer e cobrança. Webhook receiver com fan-out. Job diário.

  • Projeto "barbearia" registrado no PROJETOS do multi (servidor 209)
  • Token gerado e salvo em BARBEARIA_WEBHOOK_TOKEN
  • Multi reiniciado, /health mostra "barbearia" em projetos_registrados
  • Migration: campos cpf_cnpj e tipo_pessoa em empresas
  • lib/asaas.ts com criarCustomer() e criarCobranca()
  • Modal de ativação no master chama e salva corretamente
  • POST /api/webhooks/asaas valida token e registra log
  • PAYMENT_RECEIVED: empresa ativa no banco
  • PAYMENT_OVERDUE: inadimplente/bloqueada conforme dias
  • SUBSCRIPTION_DELETED: empresa cancelada
  • Job diário: trials + inadimplentes + recalcular dias_atraso
3
Painel Master
Visão geral, empresas, cobranças, planos
⬜ Pendente
  • Rota /master protegida por env MASTER_TOKEN
  • Aba Visão Geral: MRR, métricas, gráfico 6 meses
  • Aba Empresas: tabela com filtros e badges coloridos
  • Ações por empresa: ver, editar, ativar, bloquear, reativar, cancelar
  • Aba Cobranças: histórico unificado com filtros
  • Aba Planos: CRUD completo
  • Modal Ativar Assinatura: 2 passos + integração multi-asaas
4
Painel da Barbearia
Barbeiros, Serviços, Agenda, Clientes, Dashboard
⬜ Pendente
  • Menu lateral responsivo (colapsa em mobile)
  • CRUD barbeiros com verificação de limite do plano
  • Horários por dia da semana (7 dias) salvos corretamente
  • CRUD serviços completo
  • Agenda visual por barbeiro (dia e semana)
  • Modal novo agendamento com slots calculados em tempo real
  • Ações no agendamento: concluir/cancelar/no-show
  • Lista clientes com busca por nome e telefone
  • Perfil cliente: histórico + resumo (total gasto, barbeiro favorito)
  • Dashboard com todos os dados vindos do banco real
  • Nenhum card com dado mocado
5
Link Público de Agendamento
Mobile-first, sem login, 6 steps
⬜ Pendente

Fluxo: Verificar empresa → Serviço → Barbeiro → Data/Hora (slots reais) → Dados → Resumo → Confirmação → Sucesso

  • Barra de progresso visível em todos os steps
  • Slots calculados corretamente (sem conflito, sem passado)
  • Opção "Sem preferência" agrupa por barbeiro disponível
  • Validações: nome 2 palavras, telefone 10-11 dígitos, email opcional
  • Não cria cliente duplicado (empresa_id + telefone)
  • Conflito final verificado antes do INSERT
  • Token de confirmação gerado e salvo
  • Tela de sucesso com número #8chars do agendamento
  • Link bloqueado para empresa bloqueada
6
AI + Notificações + Financeiro
Agentes, Evolution API, lembretes, confirmações
⬜ Pendente
  • Widget AI público: conduz agendamento completo por chat
  • Sessão salva em conversa_agente a cada etapa
  • Agente interno: 6 queries de gestão respondidas corretamente
  • Instância WhatsApp criada pela tela de configurações
  • QR Code exibido e polling a cada 5s funciona
  • Status "conectado" salvo no banco após leitura
  • Notificação 1: aviso ao barbeiro ao criar agendamento
  • Notificação 2: job a cada 5min envia lembrete 1h antes
  • Página /confirmar/{token}: confirmar e cancelar funcionam
  • Ambas as ações notificam o barbeiro
  • Financeiro tenant: histórico real de cobranças
  • Com NOTIFICATION_CHANNEL=none: log gerado, sem envio
Banco de Dados

Modelo de Dados — 13 Tabelas

📋planosPlanos de assinatura do SaaS
colunatipodescrição
idUUID PKgen_random_uuid()
nomeVARCHAR(100)Ex: Básico, Profissional, Premium
descricaoTEXTopcional
preco_mensalDECIMAL(10,2)Valor cobrado mensalmente
limite_barbeirosINTEGERDefault 3. NULL = ilimitado
limite_agendamentos_mesINTEGERNULL = ilimitado
funcionalidades_jsonJSONB{"agente_ai": true, "relatorios": true}
ativoBOOLEANDefault true
criado_emTIMESTAMPDefault NOW()
🏪empresasTenants — cada barbearia cadastrada
colunatipodescrição
idUUID PKgen_random_uuid()
nomeVARCHAR(200)Nome da barbearia
slugVARCHAR(100) UNIQUEEx: navalha-dourada — usado nas rotas
dono_nomeVARCHAR(200)opcional
telefoneVARCHAR(20)opcional
emailVARCHAR(200)opcional
cpf_cnpjVARCHAR(20)Obrigatório para Asaas
tipo_pessoaVARCHAR(10)fisica | juridica
cidadeVARCHAR(100)opcional
enderecoTEXTopcional
plano_idUUID → planosFK
statusVARCHAR(30)trial | ativa | inadimplente | bloqueada | cancelada
trial_expira_emTIMESTAMPNOW() + 7 dias ao criar
asaas_customer_idVARCHAR(100)ID do customer no Asaas (cus_XXX)
asaas_subscription_idVARCHAR(100)ID da assinatura (sub_XXX)
proximo_vencimentoDATEPróximo vencimento da cobrança
ultimo_pagamento_emTIMESTAMPopcional
dias_atrasoINTEGERDefault 0. Calculado pelo webhook
ativoBOOLEANDefault true
criado_em / atualizado_emTIMESTAMPDefault NOW()
💳cobrancasHistórico de cobranças por empresa
colunatipodescrição
idUUID PK
empresa_idUUID → empresasON DELETE CASCADE
asaas_payment_idVARCHAR(100) UNIQUEID do pagamento no Asaas
asaas_subscription_idVARCHAR(100)opcional
valorDECIMAL(10,2)
statusVARCHAR(30)pendente | pago | vencido | cancelado | estornado
vencimentoDATE
pago_emTIMESTAMPopcional
url_boletoTEXTopcional
url_pixTEXTopcional
descricaoTEXTopcional
📨asaas_webhooks_logLog de todos os webhooks recebidos do Asaas
colunatipodescrição
idUUID PK
eventoVARCHAR(100)PAYMENT_RECEIVED, PAYMENT_OVERDUE, etc.
asaas_payment_idVARCHAR(100)opcional
asaas_customer_idVARCHAR(100)opcional
payload_jsonJSONBPayload bruto do Asaas
processadoBOOLEANDefault false
erro_detalheTEXTopcional — se processado=false
recebido_emTIMESTAMPDefault NOW()
💈barbeirosProfissionais de cada barbearia
colunatipodescrição
idUUID PK
empresa_idUUID → empresasON DELETE CASCADE
nomeVARCHAR(200)
especialidadeVARCHAR(200)Ex: Corte + Barba
foto_urlTEXTopcional
telefoneVARCHAR(20)Para notificações WhatsApp
emailVARCHAR(200)Fallback se sem telefone
ativoBOOLEANDefault true
🕐horarios_trabalhoExpediente de cada barbeiro por dia da semana
colunatipodescrição
idUUID PK
barbeiro_idUUID → barbeirosON DELETE CASCADE
dia_semanaINTEGER0=dom, 1=seg, 2=ter, 3=qua, 4=qui, 5=sex, 6=sáb
hora_inicioTIMEEx: 09:00
hora_fimTIMEEx: 18:00. Deve ser > hora_inicio
✂️servicosServiços oferecidos por cada barbearia
colunatipodescrição
idUUID PK
empresa_idUUID → empresasON DELETE CASCADE
nomeVARCHAR(200)Ex: Corte Simples
descricaoTEXTopcional
duracao_minutosINTEGERBase para calcular slots
precoDECIMAL(10,2)Ex: 40.00
ativoBOOLEANDefault true
👥clientesClientes registrados por empresa (sem duplicação)
colunatipodescrição
idUUID PK
empresa_idUUID → empresasON DELETE CASCADE
nomeVARCHAR(200)
telefoneVARCHAR(20)Chave de deduplicação (empresa_id + telefone)
emailVARCHAR(200)opcional
📅agendamentosAgendamentos — tabela central do sistema
colunatipodescrição
idUUID PK
empresa_idUUID → empresasON DELETE CASCADE
cliente_idUUID → clientes
barbeiro_idUUID → barbeiros
servico_idUUID → servicos
data_hora_inicioTIMESTAMPInício do atendimento
data_hora_fimTIMESTAMPinicio + duracao_minutos
statusVARCHAR(30)confirmado | concluido | cancelado | no-show
lembrete_enviadoBOOLEANDefault false — flag do job
confirmado_pelo_clienteBOOLEANnull=sem resposta, true=confirmou
confirmado_emTIMESTAMPopcional
observacoesTEXTopcional
🔑confirmacao_tokensTokens para confirmação de presença via link
colunatipodescrição
idUUID PK
agendamento_idUUID → agendamentosON DELETE CASCADE
tokenUUID UNIQUEgen_random_uuid() — vai no link
usadoBOOLEANDefault false
respostaVARCHAR(10)sim | nao | null
expira_emTIMESTAMPNOW() + 24h ao criar
respondido_emTIMESTAMPopcional
🔔notificacoes_logLog de todas as notificações enviadas
colunatipodescrição
idUUID PK
agendamento_idUUID → agendamentosopcional
tipoVARCHAR(50)aviso_barbeiro | lembrete_cliente | resposta_processada
destinatarioVARCHAR(100)Telefone ou email
canalVARCHAR(20)whatsapp | email
statusVARCHAR(20)enviado | falhou | pendente
mensagem_textoTEXTopcional
erro_detalheTEXTopcional — se falhou
enviado_emTIMESTAMPDefault NOW()
📱whatsapp_instanciasInstâncias Evolution API por empresa
colunatipodescrição
idUUID PK
empresa_idUUID → empresasON DELETE CASCADE
instancia_nomeVARCHAR(100) UNIQUE= slug da empresa
statusVARCHAR(30)desconectado | aguardando_qr | conectado
numero_conectadoVARCHAR(30)opcional — número do WhatsApp
qr_code_base64TEXTopcional — atualizado no polling
ultima_verificacaoTIMESTAMPopcional
🤖conversa_agenteSessões do agente de atendimento IA
colunatipodescrição
idUUID PK
sessao_idUUID UNIQUEgen_random_uuid() — identifica a sessão
empresa_idUUID → empresasopcional
contextoVARCHAR(20)publico | interno
etapa_atualVARCHAR(50)inicio | servico | barbeiro | data | dados | resumo | confirmado
dados_sessao_jsonJSONBEstado completo da conversa
mensagens_jsonJSONBHistórico de mensagens
agendamento_confirmado_idUUID → agendamentospreenchido ao confirmar
iniciada_em / finalizada_emTIMESTAMP
Performance

Índices Obrigatórios

índicetabela / colunaspropósito
idx_agendamentos_empresa_dataagendamentos(empresa_id, data_hora_inicio)Queries de agenda por empresa e data
idx_agendamentos_barbeiro_dataagendamentos(barbeiro_id, data_hora_inicio)Verificação de conflito de horários
idx_clientes_empresa_telefoneclientes(empresa_id, telefone)Deduplicação de clientes no agendamento
idx_horarios_barbeirohorarios_trabalho(barbeiro_id, dia_semana)Busca de expediente por dia
idx_cobrancas_empresacobrancas(empresa_id, status)Histórico financeiro por empresa
idx_cobrancas_asaascobrancas(asaas_payment_id)Lookup rápido pelo ID do Asaas no webhook
idx_empresas_asaasempresas(asaas_customer_id)Identificar empresa pelo customer_id do Asaas
Integração

Evolution API — WhatsApp

Cada empresa tem instância própria com nome = slug da empresa.

⚙️Configuração
EVOLUTION_API_URL=https://sua-evolution-api.com
EVOLUTION_API_KEY=sua-chave-aqui

// Header em todas as chamadas:
{ "apikey": "{EVOLUTION_API_KEY}" }

Endpoints

POST
/instance/create
Criar instância para uma empresa. Chamar uma vez ao ativar o WhatsApp.
{ "instanceName": "{slug}", "qrcode": true }
GET
/instance/connect/{slug}
Buscar QR Code para escanear. Retorna base64 da imagem.
GET
/instance/connectionState/{slug}
Verificar status da conexão. Polling a cada 5s na tela de configurações.
state: "open" → conectado ✅
state: "close" → desconectado ❌
POST
/message/sendText/{slug}
Enviar mensagem WhatsApp. Verificar NOTIFICATION_CHANNEL antes de chamar.
{ "number": "5511999999999", "text": "mensagem" }

Formatação de Telefone

// Antes de enviar qualquer mensagem:
1. Remover caracteres não numéricos: replace(/\D/g, '')
2. Adicionar 55 se não começar com 55
3. Validar: deve ter 12 ou 13 dígitos
4. Se inválido: registrar em notificacoes_log (status='falhou') e NÃO enviar

// Exemplos:
"(11) 99999-9999" → "5511999999999" ✅
"11999990001"     → "5511999990001" ✅
"999"             → inválido, log + skip ❌

NOTIFICATION_CHANNEL

NOTIFICATION_CHANNEL=whatsapp  → envia via Evolution API
NOTIFICATION_CHANNEL=email     → envia via SMTP
NOTIFICATION_CHANNEL=both      → tenta ambos
NOTIFICATION_CHANNEL=none      → registra como pendente, NÃO envia — desenvolvimento
Integração

Multi-IaSolux — Hub Asaas

Conta Asaas centralizada no servidor 209 (209.50.240.142). O barbearia não tem chave Asaas própria.

🖧Configuração
MULTI_IASOLUX_URL=https://multi.iasolux.com.br
MULTI_INTERNAL_TOKEN=66efa8cfd3925f9efe67c565b971ad6c441ccb739960ff045f438ceb6481106f
BARBEARIA_WEBHOOK_TOKEN=<token-gerado-ao-registrar-projeto>

// Header em todas as chamadas ao multi:
{ "X-Internal-Token": "{MULTI_INTERNAL_TOKEN}" }

// externalReference — formato padrão do projeto:
"barbearia:{empresa.id}"

Endpoints do Multi

POST
/asaas/customer
Criar customer Asaas. Idempotente: busca por CPF antes de criar.
{ "nome": "...", "cpf": "00000000000", "email": "...", "telefone": "...",
"externalReference": "barbearia:cliente:{empresa_id}" }
POST
/asaas/payment
Criar cobrança. Retorna PIX QR code + copia-cola + boleto conforme método.
{ "projeto": "barbearia",
"customer_id": "cus_XXXXX",
"valor": 39.99,
"metodo": "BOLETO", // ou PIX
"dueDate": "2026-06-01",
"descricao": "BarbearIA — Plano Profissional — Navalha Dourada",
"externalReference": "barbearia:{empresa.id}" }
GET
/asaas/payment/:id
Consultar status de um pagamento.
POST
/webhook/asaas
Recebe eventos do Asaas e faz fan-out por externalReference. O barbearia recebe em /api/webhooks/asaas.

Setup Inicial (1x)

# No servidor 209:
ssh root@209.50.240.142

# Gerar token do projeto barbearia:
openssl rand -hex 32

# Editar /root/multi-iasolux/.env
# Adicionar no JSON de PROJETOS:
"barbearia": {
  "webhook": "https://barbearia.iasolux.com.br/api/webhooks/asaas",
  "token": "<token-gerado-acima>"
}

# Reiniciar:
pm2 restart multi-iasolux  # ou pm2 list pra ver o nome

# Verificar:
curl https://multi.iasolux.com.br/health
# Deve mostrar "barbearia" em projetos_registrados

Fluxo de Webhook

Asaas → POST multi.iasolux.com.br/webhook/asaas
       → multi extrai "barbearia" do externalReference
       → POST barbearia.iasolux.com.br/api/webhooks/asaas
         header: asaas-access-token: {BARBEARIA_WEBHOOK_TOKEN}

// Eventos tratados pelo barbearia:
PAYMENT_RECEIVED     → empresa.status = 'ativa', dias_atraso = 0
PAYMENT_CONFIRMED    → idem
PAYMENT_OVERDUE      → dias_atraso ≤ 5: 'inadimplente' / > 5: 'bloqueada'
PAYMENT_DELETED      → cobranca.status = 'cancelado'
PAYMENT_REFUNDED     → cobranca.status = 'estornado'
SUBSCRIPTION_DELETED → empresa.status = 'cancelada'
outros               → asaas_webhooks_log com processado=false
Restrições

Regras Absolutas de Negócio

🔴 Nunca violar — sem exceção

  • Nunca criar agendamento sem verificar conflito de horários no banco (race condition)
  • Nunca cadastrar cliente duplicado — sempre verificar empresa_id + telefone antes do INSERT
  • Nunca permitir acesso a empresa bloqueada ou cancelada (painel E link público)
  • Nunca processar webhook do Asaas sem validar o header asaas-access-token
  • Nunca deixar o agente AI inventar dados — sempre consultar o banco
  • Nunca avançar fase de construção sem a anterior integrada e funcionando
  • Nunca enviar notificação sem registrar em notificacoes_log
  • Se NOTIFICATION_CHANNEL=none: registrar como pendente, não tentar enviar
Continuidade

Como Qualquer Claude Retoma

🔄 Passo a passo para retomar o projeto

  • Ler /root/projeto/barbearia/00-ORGANOGRAMA.md — visão geral completa
  • Identificar qual fase está com status 🔄 (em andamento) ou ⬜ (pendente)
  • Ler o checkpoint da fase atual (ex: 01-FASE1-FUNDACAO.md) para saber o que falta
  • Verificar código existente em /root/barbearia-saas/
  • Continuar a partir do checklist — marcar [x] ao concluir cada item
  • Ao concluir a fase: atualizar status para ✅ e registrar no HISTÓRICO

📁 Arquivos de referência

  • /root/projeto/barbearia/00-ORGANOGRAMA.md — organograma e convenções
  • /root/projeto/barbearia/01-FASE1-FUNDACAO.md — DB + Seed + Middleware
  • /root/projeto/barbearia/02-FASE2-ASAAS.md — Integração Asaas via Multi
  • /root/projeto/barbearia/03-FASE3-MASTER.md — Painel Master
  • /root/projeto/barbearia/04-FASE4-PAINEL-TENANT.md — Painel da Barbearia
  • /root/projeto/barbearia/05-FASE5-LINK-PUBLICO.md — Link Público
  • /root/projeto/barbearia/06-FASE6-AI-NOTIFICACOES.md — AI + Notificações
  • /root/multi-iasolux/server.js (servidor 209) — hub Asaas
  • /root/iasolux-monitor/apps/api/src/services/payment-asaas.ts — referência de integração

Documentação gerada em 2026-05-05 · barbearia.iasolux.com.br · iasolux