Aller au contenu principal

Boilerplate SaaS multi-tenant avec Next.js, Prisma et tRPC

Isolation multi-tenant · vérifiée par tests

Multi-tenant,
pas juste promis. Vérifié par tests.

La plupart des boilerplates ajoutent une colonne organizationId et vous laissent le filtre à vous. HeartCo automatise les lectures, cadre les écritures par une règle simple, et fournit les tests qui le prouvent.

6
opérations Prisma auto-scopées
12
fichiers de tests sécurité
8
rôles RBAC
160+
modèles Prisma

Comment l'isolation fonctionne

Une extension Prisma pour les lectures, une règle simple pour les écritures.

Lectures auto-filtrées

ctx.orgDb ajoute organizationId à findMany, findFirst, findFirstOrThrow, count, aggregate et groupBy. Rien à écrire, rien à oublier.

Écritures explicites, par design

create, update et delete ne sont pas couverts par le filtre automatique : organizationId doit apparaître dans le where, à la main, vérifiable en revue de code.

findFirst, jamais findUnique

findUnique n'accepte que des champs uniques dans son where : le filtre d'organisation ne peut pas s'y ajouter. La règle est simple et se grep.

Sous-entités via le parent

Une ligne de facture n'a pas d'organizationId direct : le filtre passe par la relation vers la facture, jamais par l'ID de la ligne seul.

IDOR : NOT_FOUND, jamais FORBIDDEN

Une ressource d'une autre organisation renvoie une absence, pas un refus. Un refus confirme qu'un ID valide existe ailleurs.

RBAC en matrice

L'isolation protège les frontières entre organisations. Une matrice de permissions par rôle protège les frontières à l'intérieur d'une organisation.

Ce que l'isolation couvre, ce qu'elle ne couvre pas

La plupart des pages produit s'arrêtent au premier tableau. Voici le second.

Automatique

Ce que ctx.orgDb filtre

  • Les lectures sur les modèles enregistrés comme scopés par organisation
  • findMany, findFirst, findFirstOrThrow, count, aggregate, groupBy
  • De façon identique dans tous les routers qui utilisent ctx.orgDb
Explicite

Ce qui reste à votre charge

  • Toutes les écritures : create, update, delete
  • findUnique, volontairement hors du filtre automatique
  • Enregistrer un nouveau modèle comme scopé par organisation
  • Les accès directs via ctx.db (webhooks, tâches planifiées, administration)

Les tests fournis, pas une promesse

Douze fichiers de tests de sécurité livrés avec le code, pas une checklist à écrire soi-même.

Isolation croisée

Deux organisations mockées, chaque lecture sensible (factures, devis, conversations) vérifiée séparément.

IDOR par domaine

Un fichier dédié par surface sensible : comptabilité, conversations, messages, notifications, événements d'intégration tierce.

Audit qui parcourt le schéma

Un test générique vérifie que chaque modèle scopé passe par le filtre automatique, pas seulement les modèles déjà couverts à la main.

Pour qui, et pour qui non

C'est pour vous si
  • Vous construisez un SaaS B2B où une organisation a plusieurs utilisateurs
  • Une fuite de données entre deux clients serait un incident, pas un détail
  • Vous voulez des tests fournis, pas une architecture à concevoir seul
Pas pour vous si
  • Votre produit est mono-tenant, sans notion d'organisation
  • Vous préférez une isolation par base de données séparée par client

Le code d'isolation, pas juste l'idée.

Prisma, tRPC, les tests de sécurité : tout est dans le repo, dès le premier jour.

Boilerplate SaaS multi-tenant Next.js | HeartCo