Aller au contenu
Studeia Docs
AI-assisted translation — last updated 2026-06-03. For original (pt-BR or en-US), use the language switcher.

Multi-tenancy et isolation des données

Architecture multi-tenant de Studeia : chaque établissement bénéficie d'un isolement complet au niveau de la base de données avec filtrage par tenantId, RLS Supabase, clés API par tenant, white-label total et SSO indépendant.

2026-06-03 7 min
Resposta curta

Le multi-tenancy dans Studeia signifie que chaque établissement (Tenant) dispose de données complètement isolées au niveau de la base de données. Filtrage obligatoire par tenantId dans toutes les requêtes Prisma, RLS Supabase comme filet de sécurité, clés API par tenant, configuration IA indépendante (possibilité d'utiliser ses propres clés Anthropic/OpenAI) et white-label total (domaine, branding, thème, e-mail).

Modèle conceptuel

Tenant (Établissement)
  ├── Users (étudiants, professeurs, coordinateurs, admin institutionnel)
  ├── Courses → Modules → Lessons
  ├── ClassGroups (groupes de classe)
  ├── MediaAssets (bibliothèque de médias)
  ├── Automations
  ├── EmailTemplates
  ├── VideoProviderConfig (BBB/Zoom/Teams/Meet)
  ├── TenantApiKey (clés IA propres)
  ├── TenantSubscription (facturation)
  ├── ...toutes les autres entités

Les utilisateurs sans tenantId sont des utilisateurs B2C (plateforme directe). Les utilisateurs avec tenantId appartiennent à un établissement.

Isolation des données — 3 couches

Couche 1 : Filtrage obligatoire dans les requêtes

Toute requête Prisma dans le code applicatif filtre par tenantId :

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

requireTenant() dans apps/web/lib/tenant.ts retourne NextResponse 403 si l'utilisateur n'a pas de tenant. Sans cet appel, il est impossible d'accéder aux données B2B.

Couche 2 : RLS dans Supabase

En tant que filet de sécurité contre les bugs, les politiques RLS dans Supabase renforcent l'isolement même pour les requêtes directes. Si un code oublie le filtre tenantId, la base de données refuse.

Couche 3 : Audit de l'admin global

Lorsqu'un admin global doit accéder aux données d'un tenant (support, débogage), il utilise l'usurpation d'identité via un cookie HMAC avec :

  • TTL fixe de 1h (non prolongeable)
  • Signature HMAC-SHA256 avec IMPERSONATION_SECRET
  • Audit dans AdminAuditLog (action impersonate.start, IP, user-agent)
  • getUserProfile() retourne isImpersonating: true + overlay en mémoire
  • L'authentification Supabase n'est JAMAIS modifiée (overlay uniquement)
  • Une bannière persistante sur /institution/ avertit l'admin pendant la session

Le panneau admin SaaS global inclut l'impersonation pour le support.

Clés API par tenant

Par défaut, tous les appels LLM utilisent les clés globales (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) de Studeia. Les coûts sont imputés au tenant via le métering.

Mais les établissements qui disposent déjà de comptes Anthropic/OpenAI/Google peuvent utiliser leurs propres clés (TenantApiKey, chiffrée AES-256-GCM en base) :

  1. Les coûts vont DIRECTEMENT sur le compte du tenant chez Anthropic/OpenAI
  2. Studeia ne facture pas de marge IA — seulement l'abonnement mensuel
  3. Résolution automatique : TenantApiKeyProviderApiKey global → process.env (cascade dans apps/web/lib/api-key-resolver.ts)

Ne définit JAMAIS process.env en runtime (cela créerait des conflits entre tenants) — passe la clé via les options du SDK.

White-label complet

Chaque tenant peut personnaliser :

AspectComment
Logo, faviconUpload dans les paramètres
Couleurs (primaire, accent, arrière-plan)Éditeur avec prévisualisation
Police (Google Fonts)Liste déroulante
Thème visuel (parmi 9 options)Bascule par utilisateur ou valeur par défaut du tenant
CSS personnaliséAssaini, max 10 Ko
Domaine personnaliséDNS CNAME + TXT _studeia-verify + TLS automatique Caddy (on-demand)
Logo dans les e-mailsPar template
E-mail expéditeur (SMTP/Resend/SendGrid)TenantEmailConfig
Masquer la marque StudeiaOui (plan Enterprise)

Rôles et permissions

RôlePérimètrePeut faire
studentSa propre progressionChat tuteur, cours, simulations, gamification
parentEnfants associésVoir la progression, alertes, rapports
teacherSes propres classes/coursCréer des cours, uploader du contenu, voir les élèves de ses classes
coordinatorToutes les classes du tenantGérer les classes, voir tous les élèves
pedagogueTous les élèves du tenantAccompagnement pédagogique, rapports
institution_adminTout le tenantConfig IA, clés API, white-label, utilisateurs
adminGlobal (plateforme)Tout + gérer les tenants

Limites par plan

Limites appliquées via checkTenantResourceLimit(tenantId, resource) dans apps/web/lib/plan-limits.ts :

PlanÉtudiants maxProfesseursCoursIA
Demo111Haiku uniquement, 10 msgs/jour
Mini10IllimitéIllimitéTous les providers
Crescimento50IllimitéIllimitéTous les providers
Escala100IllimitéIllimitéTous les providers
EnterprisePersonnalisé (maxStudentsOverride)IllimitéIllimitéTous les providers

7 points d'application (tous audités le 2026-04-11) :

  1. POST /api/courses/[courseId]/enroll — auto-inscription de l'étudiant
  2. POST /api/institution/courses/[id]/clone — clonage de cours
  3. POST /api/institution/courses/import — import IMS CC
  4. executeEnrollUser() dans une automatisation
  5. POST /api/scim/v2/Users — provisionnement SCIM
  6. POST /api/institution/users — associer un utilisateur existant
  7. PATCH /api/institution/users/[id] — promouvoir un rôle

Comment demander un dépassement Enterprise

Les tenants Enterprise peuvent avoir Tenant.maxStudentsOverride: Int? ajusté par l'admin global. Sans dépassement (null), Enterprise = illimité. Contactez le service commercial via contact@studeia.com.

Limitations

  • Un User appartient à UN seul tenant. Pour les professeurs intervenant dans plusieurs établissements, créer des utilisateurs distincts.
  • Le partage de cours entre tenants n'est pas natif (chaque tenant dispose de son propre CMS isolé). Feuille de route : marketplace de cours avec licences.
  • La migration d'un tenant vers un autre plan est instantanée, mais le passage à un plan inférieur qui viole les limites actuelles est bloqué jusqu'à ce que le tenant ajuste ses ressources.

Voir aussi

FAQ

Les données des tenants sont-elles réellement isolées ?

Oui. Trois couches : (1) toute requête Prisma filtre obligatoirement par tenantId (règle critique 30 du projet) ; (2) les politiques RLS dans Supabase servent de filet de sécurité ; (3) audit automatisé des requêtes cross-tenant via les tests. L'usurpation d'identité par l'admin global est auditée (AdminAuditLog) et utilise un cookie HMAC avec une TTL fixe de 1h.

Puis-je avoir mon propre domaine (white-label complet) ?

Oui. Configurez Tenant.customDomain dans les paramètres + pointez un CNAME vers le domaine Studeia. TLS automatique via Let's Encrypt sur Caddy (on-demand TLS, après vérification du domaine par enregistrement TXT). Logo, favicon, couleurs, polices, 9 thèmes visuels et même les messages e-mail personnalisables. Vous pouvez supprimer totalement la marque Studeia.

Les coûts d'IA sont-ils par tenant ?

Oui. Chaque appel LLM est enregistré dans AiUsageLog avec le tenantId. L'admin global voit la répartition des coûts par tenant dans /admin/finance/ai-cost (avec calcul de marge vs MRR). Les tenants peuvent utiliser leurs propres clés API (TenantApiKey) — dans ce cas, les coûts sont imputés au tenant, pas à Studeia.

Comment les utilisateurs cross-tenant sont-ils gérés ?

Par conception, un User appartient à UN seul tenant (User.tenantId). Pour les cas B2B où un pédagogue intervient dans plusieurs établissements, nous recommandons de créer des utilisateurs distincts par établissement. L'admin global peut réaffecter des utilisateurs via /admin/tenants (audité).

Veja tambem

Multi-tenancy et isolation des données