Multi-tenant: Seletor de Nucleo + Dominio Customizado

Visao Geral

A plataforma suporta multiplos nucleos (ES, SP, RJ, etc.), cada um com configuracoes proprias (cores, logo, moeda, dominio). Um unico deploy serve todos os nucleos. Cada nucleo pode ter seu proprio dominio (ex: app.mblivres.com.br, app.mbl.org.br) — o servico Cloud Run aceita multiplos dominios mapeados.

Abordagem Hibrida

  • App mobile + URL padrao: Tela de selecao de nucleo (cards com logo/nome)
  • Dominio customizado: Detecta nucleo automaticamente, pula selecao
  • 1 unico app na Play Store / App Store
  • 1 unico deploy web no Google Cloud Run (servico mbles-web)
  • Cada nucleo pode ter um dominio completamente diferente (nao precisa ser subdominio)

Deteccao Automatica por Dominio

Quando um usuario acessa um dominio customizado, o sistema detecta automaticamente o nucleo:

1. Middleware (Next.js) le o hostname da request
2. Chama GET /api/nucleos/dominio/:hostname
3. Se encontra nucleo → seta cookie "mbles_nucleo_dominio" (30 dias, cache 5min)
4. Client-side le o cookie → auto-seta no localStorage
5. Pagina de selecao de nucleo e pulada → vai direto para login
6. Se dominio nao encontrado → fluxo normal (seletor de nucleo)

Arquivos envolvidos

ArquivoFuncao
middleware.tsDetecta hostname, chama API, seta cookie
lib/nucleo.tsautoDetectNucleoByDomain() — le cookie e seta localStorage
auth/nucleo/page.tsxChama autoDetect na montagem, pula se ja detectou
auth/login/page.tsxChama autoDetect para dominio direto no login
nucleos.controller.tsGET /nucleos/dominio/:dominio — endpoint publico
nucleos.service.tsgetByDominio() — busca nucleo pelo campo dominio

Fluxo Completo

Usuario abre app/site
  │
  ├── Dominio customizado? (ex: app.mblivres.com.br)
  │     SIM → middleware detecta nucleo via API
  │         → seta cookie mbles_nucleo_dominio
  │         → client-side le cookie e seta localStorage
  │         → pula selecao → login direto com branding do nucleo
  │
  ├── Nucleo salvo no localStorage?
  │     SIM → login daquele nucleo
  │     (botao "Trocar nucleo" disponivel)
  │
  └── NAO → tela de selecao de nucleo
            Cards: logo + nome + estado
            Click → salva → login

Infraestrutura: Multiplos Dominios

O frontend e o backend rodam no Google Cloud Run. Um unico servico aceita multiplos dominios:

Backend (API)

  • CORS configurado com origin: true — aceita qualquer origem
  • Seguranca garantida por JWT + RLS (nao por dominio)
  • Webhook Asaas: sempre a mesma URL fixa (/api/webhooks/asaas), independente do dominio do nucleo
  • TenantInterceptor: identifica nucleo pelo JWT do usuario ou header X-Tenant-ID, nunca pelo dominio

Frontend (Web)

  • Cloud Run servico mbles-web aceita multiplos dominios via Domain Mappings
  • Middleware detecta nucleo pelo hostname e seta cookie
  • Mesmo build serve todos os nucleos — branding aplicado dinamicamente

Checklist: Adicionar Novo Nucleo com Dominio

Quando o Super Admin cria um nucleo com dominio customizado, ele deve:

  1. DNS: No painel DNS do dominio, adicionar registro CNAME
    Tipo: CNAME
    Nome: [subdominio] (ex: "app")
    Destino: mbles-web-541511987434.us-east1.run.app
  2. Google Cloud Run: No console, ir em Cloud Run → mbles-web → Integracoes → Dominios personalizados → Adicionar o dominio. SSL e provisionado automaticamente.
  3. Supabase: Em Authentication → URL Configuration → Redirect URLs, adicionar https://[dominio]/auth/callback. Sem isso, login/cadastro nao funcionam no dominio novo.
  4. Asaas: Configurar API Key e Webhook nas configuracoes do nucleo. A URL do webhook e sempre a mesma (https://mbles-api-.../api/webhooks/asaas) — nao muda com o dominio.

O nucleo funciona imediatamente pelo seletor do app, mesmo antes do dominio propagar.

Cargos

CargoNucleoDescricao
SUPER_ADMINNenhum (acessa todos)Cria nucleos, cria outros super admins. Dado apenas pelo banco ou por outro super admin.
ADMINISTRADORVinculado a 1Admin do nucleo. Configura sistema, ajusta CC, altera cargos.
COORDENADORVinculado a 1Cria projetos, eventos, comunicados.
LIDER_PROJETOVinculado a 1Gerencia tarefas no seu projeto.
MEMBROVinculado a 1Participa de projetos e eventos.

SUPER_ADMIN e Multi-nucleo

O SUPER_ADMIN nao pertence a nenhum nucleo. Ele seleciona o nucleo ativo via dropdown no header. O frontend envia X-Tenant-ID em todas as requests via apiFetch(). O backend usa esse header no TenantInterceptor para injetar o nucleoId nos services.

Migrations

  • 00007: dominio (UNIQUE) + slug (UNIQUE) na tabela nucleos, cargo SUPER_ADMIN
  • 00008: nucleo_id nullable (SUPER_ADMIN nao pertence a nucleo)

API: Endpoints de Nucleos

MetodoRotaAuthDescricao
GET/nucleos/publicosNaoLista nucleos (nome, logo, estado, slug, cores)
GET/nucleos/dominio/:dominioNaoBusca nucleo pelo dominio customizado
GET/nucleos/:slugNaoDetalhes de um nucleo pelo slug
GET/admin/nucleosSUPER_ADMINLista todos os nucleos (completo)
POST/admin/nucleosSUPER_ADMINCriar nucleo
PATCH/admin/nucleos/:idSUPER_ADMINAtualizar nucleo