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
| Arquivo | Funcao |
|---|---|
middleware.ts | Detecta hostname, chama API, seta cookie |
lib/nucleo.ts | autoDetectNucleoByDomain() — le cookie e seta localStorage |
auth/nucleo/page.tsx | Chama autoDetect na montagem, pula se ja detectou |
auth/login/page.tsx | Chama autoDetect para dominio direto no login |
nucleos.controller.ts | GET /nucleos/dominio/:dominio — endpoint publico |
nucleos.service.ts | getByDominio() — 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 → loginInfraestrutura: 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 headerX-Tenant-ID, nunca pelo dominio
Frontend (Web)
- Cloud Run servico
mbles-webaceita 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:
- DNS: No painel DNS do dominio, adicionar registro CNAME
Tipo: CNAME Nome: [subdominio] (ex: "app") Destino: mbles-web-541511987434.us-east1.run.app - Google Cloud Run: No console, ir em Cloud Run → mbles-web → Integracoes → Dominios personalizados → Adicionar o dominio. SSL e provisionado automaticamente.
- Supabase: Em Authentication → URL Configuration → Redirect URLs, adicionar
https://[dominio]/auth/callback. Sem isso, login/cadastro nao funcionam no dominio novo. - 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
| Cargo | Nucleo | Descricao |
|---|---|---|
| SUPER_ADMIN | Nenhum (acessa todos) | Cria nucleos, cria outros super admins. Dado apenas pelo banco ou por outro super admin. |
| ADMINISTRADOR | Vinculado a 1 | Admin do nucleo. Configura sistema, ajusta CC, altera cargos. |
| COORDENADOR | Vinculado a 1 | Cria projetos, eventos, comunicados. |
| LIDER_PROJETO | Vinculado a 1 | Gerencia tarefas no seu projeto. |
| MEMBRO | Vinculado a 1 | Participa 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, cargoSUPER_ADMIN - 00008:
nucleo_idnullable (SUPER_ADMIN nao pertence a nucleo)
API: Endpoints de Nucleos
| Metodo | Rota | Auth | Descricao |
|---|---|---|---|
| GET | /nucleos/publicos | Nao | Lista nucleos (nome, logo, estado, slug, cores) |
| GET | /nucleos/dominio/:dominio | Nao | Busca nucleo pelo dominio customizado |
| GET | /nucleos/:slug | Nao | Detalhes de um nucleo pelo slug |
| GET | /admin/nucleos | SUPER_ADMIN | Lista todos os nucleos (completo) |
| POST | /admin/nucleos | SUPER_ADMIN | Criar nucleo |
| PATCH | /admin/nucleos/:id | SUPER_ADMIN | Atualizar nucleo |