Files
mercado.clube67.com/docs/superAdmin.md
T

11 KiB

Super Admin, Multi-tenant & Clube de Benefícios — Plano de Implementação

Visão Geral

Transformar o sistema em uma plataforma multi-tenant SaaS. Cada empresa tem identidade visual, domínio, usuários e rifas isolados. Um Super Admin gerencia todas as empresas. As páginas públicas migram de Bootstrap/HTML para React + Tailwind em uma única entrega que inclui o Clube de Benefícios (Odonto + Médico).


Decisões de Arquitetura

  • Detecção de tenant: subdomínio (alemao.app.com, ariane.app.com) + fallback header X-Tenant-Slug
  • Branding: armazenado no DB (tenant_config), injetado via /api/tenant/config como CSS variables
  • Auth do cliente: CPF+telefone → email + senha (bcrypt). Legados mantêm fallback temporário.
  • Bootstrap removido: zero reescrita em Bootstrap — próxima versão das páginas públicas já é React
  • customer-app: SPA React unificada com landing, login, sorteio, clube e dashboard do cliente
  • Super Admin: SPA React separada em /superadmin
  • tenant_id: todas as tabelas (existentes e novas do clube) recebem tenant_id na mesma migration

Sequência de Execução

9A  → 9B  → 10A → 10B → 10C
 │                            └─► 10F (relatórios, após 10B+10C)
 ├─► 9E  (super admin, paralelo com 10A+10B+10C)
 └─► 9F  (admin multi-tenant, paralelo com 10A+10B+10C)

9D + 9C + 10D + 10E  ←  FUSÃO: customer-app React unificado
  (após 9B + 10B + 10C estarem com backend pronto)

10D (slides Bootstrap) REMOVIDA — Bootstrap não recebe mais desenvolvimento. 9C (multi-ticket) e 10E (carteirinha) são implementados dentro do customer-app React.


Fase 9A — Fundação Multi-tenant (Backend) ← ATUAL

Banco de dados

  • Criar tabela tenantsid, slug, name, domain, active, created_at
  • Criar tabela tenant_configtenant_id, primary_color, secondary_color, logo_url, favicon_url, contact_email, contact_phone, app_url, asaas_key
  • Adicionar coluna tenant_id em users
  • Adicionar coluna tenant_id em raffles
  • Adicionar coluna tenant_id em orders
  • Adicionar coluna tenant_id em tickets
  • Adicionar coluna tenant_id em promotions
  • Adicionar coluna tenant_id em whatsapp_logs
  • Criar tabelas do clube já com tenant_id: benefit_clubs, club_plans, club_members, club_dependents, club_payments, club_partners
  • Inserir tenant padrão alemao
  • Popular tenant_id = 1 em todos os registros existentes
  • Criar índices em tenant_id em todas as tabelas

Middleware de tenant

  • Criar middleware/tenant.js — detecta por subdomínio e header X-Tenant-Slug; anexa req.tenant
  • Fallback: hostname sem tenant → responde com req.tenant do slug alemao (ambiente local)
  • Criar middleware/tenantAdmin.js — verifica que admin pertence ao tenant correto

Isolamento de dados

  • Atualizar models User, Raffle, Order, Ticket, Promotion para filtrar por tenant_id
  • Atualizar analyticsController com filtro de tenant
  • Atualizar whatsappService com tenant_id nos logs

API pública

  • GET /api/tenant/config — retorna branding do tenant detectado (público)

Fase 9B — Autenticação do Cliente: Email + Senha

Backend

  • Adicionar colunas email VARCHAR(255), password_hash VARCHAR(255) em users
  • Atualizar POST /api/register — aceitar nome, email, cpf, telefone, password
  • Atualizar POST /api/login — email+senha; fallback CPF+telefone para legados
  • Criar POST /api/auth/forgot-password — token temporário, envia WhatsApp
  • Criar POST /api/auth/reset-password — valida token, atualiza hash
  • Criar tabela password_reset_tokensuser_id, token, expires_at, used
  • Atualizar JWT payload — incluir tenant_id
  • verifyUserToken — validar tenant_id do token

Migração de legados

  • Login CPF+telefone continua funcionando se password_hash IS NULL
  • POST /api/auth/migrate — legado informa CPF+telefone+novo email+senha

Fase 10A — Clube de Benefícios: Backend

Tabelas já criadas na 9A com tenant_id. Esta fase implementa a lógica de negócio.

Models

  • Criar models/BenefitClub.js — CRUD clubes e planos
  • Criar models/ClubMember.js — findByCpf, create, updateStatus, listByClub
  • Criar models/ClubPayment.js — create, findByMember, listOverdue
  • Criar models/ClubPartner.js — CRUD parceiros por clube

Asaas — Assinaturas recorrentes

  • Criar services/clubAsaasService.js
  • createCustomer(cpf, nome, email, telefone)asaas_customer_id
  • createSubscription(customerId, planPrice, description)asaas_subscription_id + primeiro PIX
  • cancelSubscription(subscriptionId)
  • suspendSubscription(subscriptionId)
  • listPayments(subscriptionId) → histórico
  • Webhook POST /api/webhooks/asaas/clubPAYMENT_RECEIVED, PAYMENT_OVERDUE, PAYMENT_DELETED

API pública

  • GET /api/clubs — clubes ativos do tenant com planos
  • GET /api/clubs/:slug — detalhe + parceiros + benefícios
  • POST /api/clubs/:slug/subscribe — adesão: cria membro + assinatura Asaas + retorna PIX
  • GET /api/clubs/card/:cpf — carteirinha digital (dados não-sensíveis, público)
  • POST /api/clubs/member/cancel — cancelamento pelo cliente

Fase 10B — Clube Odonto

Backend

  • GET /api/clubs/odonto/partners — clínicas/dentistas parceiros
  • GET /api/clubs/odonto/validate/:cpf — validação pública para recepções de clínicas
  • Worker: membros com pagamento +5 dias em atraso → status = suspended
  • Worker: reativar após pagamento de mensalidade em atraso

WhatsApp — Templates

  • club_welcome — boas-vindas + link carteirinha
  • club_payment_reminder — lembrete 3 dias antes do vencimento
  • club_payment_confirmed — confirmação + validade
  • club_payment_overdue — inadimplência + link pagar
  • club_suspended — plano suspenso
  • club_canceled — confirmação de cancelamento
  • Adicionar club_payment_confirmed e club_suspended em CRITICAL_TYPES
  • Criar services/clubNotificationService.js

Admin (admin-app)

  • Criar ClubOdonto.tsx com KPIs: membros ativos, MRR, inadimplentes, cancelamentos
  • Lista de membros com status, plano, próxima cobrança, botão detalhes
  • Lista de inadimplentes com "Reenviar cobrança WhatsApp"
  • Modal membro: histórico pagamentos, dependentes, ações suspender/cancelar/reativar
  • CRUD parceiros (clínicas)
  • Gráfico evolução de membros (Recharts AreaChart)
  • Registrar rota /clubs/odonto no App.tsx

Fase 10C — Clube Médico

Backend

  • Criar clube medico com planos Individual e Família
  • GET /api/clubs/medico/partners — parceiros por especialidade
  • GET /api/clubs/medico/validate/:cpf
  • Template WhatsApp club_medico_partner_new — novo parceiro na rede

Admin (admin-app)

  • Criar ClubMedico.tsx (componentes reutilizados de ClubOdonto.tsx)
  • Filtro de parceiros por especialidade (clínico geral, pediatria, ginecologia, etc.)
  • Registrar rota /clubs/medico no App.tsx

Fase 10F — Relatórios do Clube (admin-app)

  • Criar ClubReports.tsx
  • MRR (Monthly Recurring Revenue) — gráfico de linha por mês
  • Churn rate mensal (cancelamentos / total início do mês)
  • Inadimplência — % membros com pagamento em atraso
  • Crescimento — novos vs cancelamentos por mês
  • Distribuição de planos — Individual vs Família por clube (PieChart)
  • Export CSV: membros ativos filtrado por clube/plano/status
  • Registrar rota /clubs/reports no App.tsx

Fase 9E — Super Admin (SPA React)

Backend

  • Criar tabela super_adminsid, email, password_hash, name, created_at
  • Criar middleware/superAuth.js — JWT secret separado
  • POST /superadmin/api/login
  • GET /superadmin/api/tenants
  • POST /superadmin/api/tenants
  • PUT /superadmin/api/tenants/:id
  • DELETE /superadmin/api/tenants/:id — soft delete
  • GET /superadmin/api/tenants/:id/stats — receita, usuários, tickets, membros clube
  • POST /superadmin/api/tenants/:id/admins
  • Servir superadmin-app em GET /superadmin*

superadmin-app (React + Tailwind)

  • Setup: Vite + React 18 + TS + Tailwind, output → public/superadmin/
  • LoginPage — email + senha
  • Dashboard — totais globais por empresa
  • TenantsPage — tabela empresas, status, receita, membros clube
  • TenantDetailPage — stats + formulário branding (logo, cores, domínio)
  • BrandingEditor — preview live das cores/logo
  • TenantAdminsPage — cria/lista admins por empresa

Fase 9F — Admin React Multi-tenant

  • tenant_id no JWT do admin (cloud_token)
  • Header do admin-app exibe nome e logo do tenant
  • Settings: aba "Identidade Visual" — edita tenant_config
  • Settings: APP_URL e asaas_key por tenant (não mais variáveis globais de ambiente)

Fase 9D+9C+10D+10E — customer-app React (Entrega Unificada)

Uma única SPA React substitui todas as páginas Bootstrap e entrega todas as funcionalidades do cliente de uma vez.

Setup

  • Criar customer-app/ — Vite + React 18 + TS + Tailwind
  • Build output → sistema-nuvem/public/app/
  • Adicionar lucide-react, axios, swiper (para hero slider)
  • Hook useTenant() — carrega /api/tenant/config, aplica CSS variables
  • Componente <TenantProvider> wrappa o app

Páginas

  • LandingPage — hero slider 3 slides (promoções, odonto, médico), seção promoções, seção sorteio, seção clube odonto, seção clube médico
  • LoginPage — email+senha, tabs entrar/cadastrar, link "esqueci minha senha"
  • RafflePage — grid de números multi-seleção, contador de selecionados + valor, modal checkout 3 etapas (resumo → login/cadastro inline → PIX)
  • DashboardPage — meus tickets, opt-in WhatsApp, carteirinha clube
  • CarteirinhaPage/carteirinha/:token pública, exibe <MemberCard> sem login
  • ClubSubscribePage — modal de adesão ao clube (escolha plano → dados → PIX)
  • BlockedPage — substitui bloqueado.html

Remoção do Bootstrap

  • Remover bootstrap.min.css e bootstrap-icons.min.css de public/css/
  • Remover todos os HTML de views/landing/ (rotas redirecionadas para /app/*)

Stack Final

Camada Tecnologia
Backend Node.js + Express
Admin React 18 + Tailwind + Recharts (existente)
Customer app React 18 + Tailwind (novo — substitui Bootstrap)
Super Admin React 18 + Tailwind (novo)
CSS Tailwind — zero Bootstrap
Ícones Lucide React — zero Bootstrap Icons
DB PostgreSQL + tabelas tenant + clube
Pagamentos recorrentes Asaas Subscriptions API
Notificações WhatsApp via BullMQ (existente + novos templates)