# 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 - [x] Criar tabela `tenants` — `id, slug, name, domain, active, created_at` - [x] Criar tabela `tenant_config` — `tenant_id, primary_color, secondary_color, logo_url, favicon_url, contact_email, contact_phone, app_url, asaas_key` - [x] Adicionar coluna `tenant_id` em `users` - [x] Adicionar coluna `tenant_id` em `raffles` - [x] Adicionar coluna `tenant_id` em `orders` - [x] Adicionar coluna `tenant_id` em `tickets` - [x] Adicionar coluna `tenant_id` em `promotions` - [x] Adicionar coluna `tenant_id` em `whatsapp_logs` - [x] Criar tabelas do clube já com `tenant_id`: `benefit_clubs`, `club_plans`, `club_members`, `club_dependents`, `club_payments`, `club_partners` - [x] Inserir tenant padrão `alemao` - [x] Popular `tenant_id = 1` em todos os registros existentes - [x] Criar índices em `tenant_id` em todas as tabelas ### Middleware de tenant - [x] Criar `middleware/tenant.js` — detecta por subdomínio e header `X-Tenant-Slug`; anexa `req.tenant` - [x] Fallback: hostname sem tenant → responde com `req.tenant` do slug `alemao` (ambiente local) - [x] Criar `middleware/tenantAdmin.js` — verifica que admin pertence ao tenant correto ### Isolamento de dados - [x] Atualizar models `User`, `Raffle`, `Order`, `Ticket`, `Promotion` para filtrar por `tenant_id` - [x] Atualizar `analyticsController` com filtro de tenant - [x] Atualizar `whatsappService` com `tenant_id` nos logs ### API pública - [x] `GET /api/tenant/config` — retorna branding do tenant detectado (público) --- ## Fase 9B — Autenticação do Cliente: Email + Senha ### Backend - [x] Adicionar colunas `email VARCHAR(255)`, `password_hash VARCHAR(255)` em `users` - [x] Atualizar `POST /api/register` — aceitar `nome, email, cpf, telefone, password` - [x] Atualizar `POST /api/login` — email+senha; fallback CPF+telefone para legados - [x] Criar `POST /api/auth/forgot-password` — token temporário, envia WhatsApp - [x] Criar `POST /api/auth/reset-password` — valida token, atualiza hash - [x] Criar tabela `password_reset_tokens` — `user_id, token, expires_at, used` - [x] Atualizar JWT payload — incluir `tenant_id` - [x] `verifyUserToken` — validar `tenant_id` do token ### Migração de legados - [x] Login CPF+telefone continua funcionando se `password_hash IS NULL` - [x] `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 - [x] Criar `models/BenefitClub.js` — CRUD clubes e planos - [x] Criar `models/ClubMember.js` — findByCpf, create, updateStatus, listByClub - [x] Criar `models/ClubPayment.js` — create, findByMember, listOverdue - [x] Criar `models/ClubPartner.js` — CRUD parceiros por clube ### Asaas — Assinaturas recorrentes - [x] Criar `services/clubAsaasService.js` - [x] `createCustomer(cpf, nome, email, telefone)` → `asaas_customer_id` - [x] `createSubscription(customerId, planPrice, description)` → `asaas_subscription_id` + primeiro PIX - [x] `cancelSubscription(subscriptionId)` - [x] `suspendSubscription(subscriptionId)` - [x] `listPayments(subscriptionId)` → histórico - [x] Webhook `POST /api/webhooks/asaas/club` — `PAYMENT_RECEIVED`, `PAYMENT_OVERDUE`, `PAYMENT_DELETED` ### API pública - [x] `GET /api/clubs` — clubes ativos do tenant com planos - [x] `GET /api/clubs/:slug` — detalhe + parceiros + benefícios - [x] `POST /api/clubs/:slug/subscribe` — adesão: cria membro + assinatura Asaas + retorna PIX - [x] `GET /api/clubs/card/:cpf` — carteirinha digital (dados não-sensíveis, público) - [x] `POST /api/clubs/member/cancel` — cancelamento pelo cliente --- ## Fase 10B — Clube Odonto ### Backend - [x] `GET /api/clubs/odonto/partners` — clínicas/dentistas parceiros - [x] `GET /api/clubs/odonto/validate/:cpf` — validação pública para recepções de clínicas - [x] Worker: membros com pagamento +5 dias em atraso → `status = suspended` - [x] Worker: reativar após pagamento de mensalidade em atraso ### WhatsApp — Templates - [x] `club_welcome` — boas-vindas + link carteirinha - [x] `club_payment_reminder` — lembrete 3 dias antes do vencimento - [x] `club_payment_confirmed` — confirmação + validade - [x] `club_payment_overdue` — inadimplência + link pagar - [x] `club_suspended` — plano suspenso - [x] `club_canceled` — confirmação de cancelamento - [x] Adicionar `club_payment_confirmed` e `club_suspended` em `CRITICAL_TYPES` - [x] Criar `services/clubNotificationService.js` ### Admin (admin-app) - [x] Criar `ClubOdonto.tsx` com KPIs: membros ativos, MRR, inadimplentes, cancelamentos - [x] Lista de membros com status, plano, próxima cobrança, botão detalhes - [x] Lista de inadimplentes com "Reenviar cobrança WhatsApp" - [x] Modal membro: histórico pagamentos, dependentes, ações suspender/cancelar/reativar - [x] CRUD parceiros (clínicas) - [x] Gráfico evolução de membros (Recharts AreaChart) - [x] Registrar rota `/clubs/odonto` no `App.tsx` --- ## Fase 10C — Clube Médico ### Backend - [x] Criar clube `medico` com planos Individual e Família - [x] `GET /api/clubs/medico/partners` — parceiros por especialidade - [x] `GET /api/clubs/medico/validate/:cpf` - [x] Template WhatsApp `club_medico_partner_new` — novo parceiro na rede ### Admin (admin-app) - [x] Criar `ClubMedico.tsx` (componentes reutilizados de `ClubOdonto.tsx`) - [x] Filtro de parceiros por especialidade (clínico geral, pediatria, ginecologia, etc.) - [x] Registrar rota `/clubs/medico` no `App.tsx` --- ## Fase 10F — Relatórios do Clube (admin-app) - [x] Criar `ClubReports.tsx` - [x] MRR (Monthly Recurring Revenue) — gráfico de linha por mês - [x] Churn rate mensal (cancelamentos / total início do mês) - [x] Inadimplência — % membros com pagamento em atraso - [x] Crescimento — novos vs cancelamentos por mês - [x] Distribuição de planos — Individual vs Família por clube (PieChart) - [x] Export CSV: membros ativos filtrado por clube/plano/status - [x] Registrar rota `/clubs/reports` no `App.tsx` --- ## Fase 9E — Super Admin (SPA React) ### Backend - [x] Criar tabela `super_admins` — `id, email, password_hash, name, created_at` - [x] Criar `middleware/superAuth.js` — JWT secret separado - [x] `POST /superadmin/api/login` - [x] `GET /superadmin/api/tenants` - [x] `POST /superadmin/api/tenants` - [x] `PUT /superadmin/api/tenants/:id` - [x] `DELETE /superadmin/api/tenants/:id` — soft delete - [x] `GET /superadmin/api/tenants/:id/stats` — receita, usuários, tickets, membros clube - [x] `POST /superadmin/api/tenants/:id/admins` - [x] Servir `superadmin-app` em `GET /superadmin*` ### superadmin-app (React + Tailwind) - [x] Setup: Vite + React 18 + TS + Tailwind, output → `public/superadmin/` - [x] `LoginPage` — email + senha - [x] `Dashboard` — totais globais por empresa - [x] `TenantsPage` — tabela empresas, status, receita, membros clube - [x] `TenantDetailPage` — stats + formulário branding (logo, cores, domínio) - [x] `BrandingEditor` — preview live das cores/logo - [x] `TenantAdminsPage` — cria/lista admins por empresa --- ## Fase 9F — Admin React Multi-tenant - [x] `tenant_id` no JWT do admin (`cloud_token`) - [x] Header do admin-app exibe nome e logo do tenant - [x] Settings: aba "Identidade Visual" — edita `tenant_config` - [x] 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 - [x] Criar `customer-app/` — Vite + React 18 + TS + Tailwind - [x] Build output → `sistema-nuvem/public/app/` - [x] Adicionar `lucide-react`, `axios`, `swiper` (para hero slider) - [x] Hook `useTenant()` — carrega `/api/tenant/config`, aplica CSS variables - [x] Componente `` wrappa o app ### Páginas - [x] `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 - [x] `LoginPage` — email+senha, tabs entrar/cadastrar, link "esqueci minha senha" - [x] `RafflePage` — grid de números multi-seleção, contador de selecionados + valor, modal checkout 3 etapas (resumo → login/cadastro inline → PIX) - [x] `DashboardPage` — meus tickets, opt-in WhatsApp, carteirinha clube - [x] `CarteirinhaPage` — `/carteirinha/:token` pública, exibe `` sem login - [x] `ClubSubscribePage` — modal de adesão ao clube (escolha plano → dados → PIX) - [x] `BlockedPage` — substitui `bloqueado.html` ### Remoção do Bootstrap - [x] Remover `bootstrap.min.css` e `bootstrap-icons.min.css` de `public/css/` - [x] 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) |