Pular para o conteúdo

Multi-tenancy e isolamento de dados

Arquitetura multi-tenant do Studeia: cada instituicao tem isolamento completo em nivel de banco com filtro por tenantId, RLS Supabase, per-tenant API keys, white-label total e SSO independente.

2026-05-23 7 min
Resposta curta

Multi-tenancy no Studeia significa que cada instituicao (Tenant) tem dados completamente isolados em nivel de banco. Filtro obrigatorio por tenantId em todas as queries Prisma, RLS Supabase como safety net, per-tenant API keys, configuracao de IA independente (pode usar proprias chaves Anthropic/OpenAI) e white-label total (dominio, branding, tema, email).

Modelo conceitual

Tenant (Instituicao)
  ├── Users (alunos, professores, coordenadores, admin institucional)
  ├── Courses → Modules → Lessons
  ├── ClassGroups (turmas)
  ├── MediaAssets (biblioteca de midia)
  ├── Automations
  ├── EmailTemplates
  ├── VideoProviderConfig (BBB/Zoom/Teams/Meet)
  ├── TenantApiKey (chaves proprias de IA)
  ├── TenantSubscription (billing)
  ├── ...todas as outras entidades

Usuarios sem tenantId sao B2C (plataforma direta). Usuarios com tenantId pertencem a uma instituicao.

Isolamento de dados — 3 camadas

Camada 1: Filtro obrigatorio em queries

Toda query Prisma em codigo de aplicacao filtra por tenantId:

const { tenantId } = requireTenant(user);
const courses = await prisma.course.findMany({
  where: { tenantId }, // OBRIGATORIO
});

requireTenant() em apps/web/lib/tenant.ts retorna NextResponse 403 se o usuario nao tem tenant. Sem essa chamada, e impossivel acessar dados B2B.

Camada 2: RLS no Supabase

Como safety net contra bugs, policies RLS no Supabase reforcam isolamento ate em queries diretas. Se um codigo esquecer o filtro tenantId, o banco recusa.

Camada 3: Auditoria de admin global

Quando um admin global precisa acessar dados de um tenant (suporte, debug), ele usa impersonacao via cookie HMAC com:

  • TTL fixo de 1h (nao prorrogavel)
  • Assinatura HMAC-SHA256 com IMPERSONATION_SECRET
  • Auditoria em AdminAuditLog (acao impersonate.start, IP, user-agent)
  • getUserProfile() retorna isImpersonating: true + overlay em memoria
  • Supabase auth NUNCA modificado (apenas overlay)
  • Banner sticky no /institution/ alerta o admin durante a sessao

Detalhes em painel admin SaaS.

Per-tenant API keys

Por padrao, todas as chamadas LLM usam chaves globais (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc) do Studeia. Custos vao para o tenant via metering.

Mas instituicoes que ja tem contas Anthropic/OpenAI/Google podem usar proprias chaves (TenantApiKey, criptografada AES-256-GCM no banco):

  1. Custos vao DIRETO para a conta do tenant na Anthropic/OpenAI
  2. Studeia nao cobra margem de IA — apenas a assinatura mensal
  3. Resolucao automatica: TenantApiKeyProviderApiKey global → process.env (cascata em apps/web/lib/api-key-resolver.ts)

NUNCA seta process.env em runtime (conflitaria entre tenants) — passa a key via options do SDK.

White-label completo

Cada tenant pode personalizar:

AspectoComo
Logo, faviconUpload no settings
Cores (primary, accent, background)Editor com preview
Fonte (Google Fonts)Dropdown
Tema visual (de 9 opcoes)Toggle por usuario ou padrao do tenant
Custom CSSSanitizado, max 10KB
Dominio customizadoDNS CNAME + TLS automatico Traefik
Logo no emailPor template
Sender email (SMTP/Resend/SendGrid)TenantEmailConfig
Esconder marca StudeiaSim (plano enterprise)

Roles e permissoes

RoleEscopoPode fazer
studentProprio progressoChat tutor, cursos, simulados, gamificacao
parentFilhos vinculadosVer progresso, alertas, relatorios
teacherProprias turmas/cursosCriar cursos, upload material, ver alunos das turmas
coordinatorTodas turmas do tenantGerenciar turmas, ver todos os alunos
pedagogueTodos alunos do tenantOrientacao educacional, relatorios
institution_adminTodo o tenantConfig IA, API keys, white-label, usuarios
adminGlobal (plataforma)Tudo + gerenciar tenants

Limites por plano

Limites enforceados via checkTenantResourceLimit(tenantId, resource) em apps/web/lib/plan-limits.ts:

PlanoAlunos maxProfessoresCursosIA
Demo111Haiku only, 10 msgs/dia
Mini10IlimitadoIlimitadoTodos providers
Crescimento50IlimitadoIlimitadoTodos providers
Escala100IlimitadoIlimitadoTodos providers
EnterpriseCustom (maxStudentsOverride)IlimitadoIlimitadoTodos providers

7 pontos de enforcement (todos auditados em 2026-04-11):

  1. POST /api/courses/[courseId]/enroll — self-enroll do aluno
  2. POST /api/institution/courses/[id]/clone — clone de curso
  3. POST /api/institution/courses/import — import IMS CC
  4. executeEnrollUser() em automacao
  5. POST /api/scim/v2/Users — provisionamento SCIM
  6. POST /api/institution/users — vincular usuario existente
  7. PATCH /api/institution/users/[id] — promover role

Como solicitar override enterprise

Tenants enterprise podem ter Tenant.maxStudentsOverride: Int? ajustado pelo admin global. Sem override (null), enterprise = ilimitado. Contato comercial via suporte@studeia.com.

Limitacoes

  • Um User pertence a UM tenant. Para professores que atendem multiplas escolas, criar usuarios separados.
  • Compartilhamento de cursos entre tenants nao e nativo (cada tenant tem seu CMS isolado). Roadmap: marketplace de cursos com licenciamento.
  • Migracao de tenant para outro plano e instantanea, mas downgrade que viola limites atuais e bloqueado ate o tenant ajustar os recursos.

Veja tambem

FAQ

Dados de tenants estao realmente isolados?

Sim. Tres camadas: (1) toda query Prisma filtra por tenantId obrigatoriamente (regra critica 30 do projeto); (2) RLS policies no Supabase como safety net; (3) auditoria automatizada de queries cross-tenant via testes. Impersonacao de admin global e auditada (AdminAuditLog) e usa cookie HMAC com TTL fixo de 1h.

Posso ter dominio proprio (white-label completo)?

Sim. Configure Tenant.customDomain no settings + aponte CNAME para o dominio Studeia. TLS automatico via Let's Encrypt no Traefik. Logo, favicon, cores, fontes, 9 temas visuais e ate mensagens de email customizaveis. Pode remover a marca Studeia totalmente.

Custos de IA sao por tenant?

Sim. Cada chamada LLM e logada em AiUsageLog com tenantId. Admin global ve breakdown de custo por tenant em /admin/finance/ai-cost (com calculo de margem vs MRR). Tenants podem usar proprias chaves de API (TenantApiKey) — nesse caso custos vao para o tenant, nao para Studeia.

Como sao gerenciados usuarios cross-tenant?

Por design, um User pertence a UM tenant (User.tenantId). Para casos B2B onde um pedagogo atende multiplas escolas, recomendamos criar usuarios separados por instituicao. Admin global pode reassign usuarios via /admin/tenants (auditado).

Veja tambem

Multi-tenancy e isolamento de dados | Studeia Docs