Options de modèle de données multi-tenant pour un backend no-code
Les choix de modèle de données multi-tenant pour un SaaS influencent sécurité, reporting et performances. Comparez tenant_id, schémas séparés et bases séparées avec leurs compromis clairs.

Le problème : séparer les locataires sans ralentir\n\nLa multi-tenancy signifie qu'un même logiciel sert plusieurs clients (locataires), et chaque locataire ne doit voir que ses propres données. Le défi est de garantir cela de façon cohérente : pas seulement sur un écran, mais sur chaque appel d'API, panneau d'administration, export et job en arrière-plan.\n\nVotre modèle de données influence les opérations quotidiennes bien plus que beaucoup d'équipes ne le pensent. Il façonne les permissions, le reporting, la vitesse des requêtes en croissance, et le danger qu'un « petit » bug devienne critique. Oublier un filtre peut entraîner une fuite de données. Isoler trop fortement complique le reporting.\n\nIl existe trois façons courantes d'organiser un modèle de données multi-tenant :\n\n- Une base de données où chaque table inclut un tenant_id\n- Schémas séparés par locataire à l'intérieur d'une même base\n- Bases de données séparées par locataire\n\nMême si vous construisez visuellement dans un backend no-code, les mêmes compromis s'appliquent. Des outils comme AppMaster génèrent du code backend réel et des structures de base de données à partir de votre design, donc les décisions de modélisation apparaissent vite en production, tant en comportement qu'en performance.\n\nImaginez un outil de helpdesk. Si chaque ligne de ticket a un tenant_id, il est facile d'interroger « tous les tickets ouverts », mais il faut appliquer la vérification du locataire partout. Si chaque locataire a son propre schéma ou sa propre base, l'isolation est plus forte par défaut, mais le reporting inter-locataires (par exemple « temps moyen de fermeture ») demande plus de travail.\n\nL'objectif est d'obtenir une séparation fiable sans ajouter de friction au reporting, au support et à la croissance.\n\n## Façon rapide de choisir : 4 questions qui réduisent l'incertitude\n\nNe commencez pas par la théorie des bases de données. Commencez par l'usage du produit et ce dont vous aurez besoin pour opérer chaque semaine.\n\n### Quatre questions qui rendent la réponse souvent évidente\n\n1) À quel point les données sont-elles sensibles, et êtes-vous soumis à des règles strictes ? Le secteur médical, financier et certains contrats clients poussent souvent vers une isolation plus forte (schéma séparé ou base séparée). Cela réduit le risque et facilite les audits.\n\n2) Avez-vous souvent besoin de reporting cross-locataire ? Si vous avez régulièrement des métriques « tous clients » (usage, revenus, performance), une base unique avec tenant_id est généralement la plus simple. Les bases séparées compliquent l'agrégation car il faut interroger plusieurs emplacements et combiner les résultats.\n\n3) Dans quelle mesure les locataires seront-ils différents les uns des autres ? Si les locataires exigent des champs personnalisés, des workflows propres ou des intégrations uniques, les schémas ou bases séparés réduisent le risque de fuites lors de modifications. Si la plupart partagent la même structure, tenant_id reste propre et simple.\n\n4) Que peut raisonnablement gérer votre équipe en production ? Plus d'isolation signifie souvent plus de travail : plus de backups, plus de migrations, plus de pièces en mouvement et plus d'endroits où les pannes peuvent se cacher.\n\nUne approche pratique consiste à prototyper vos deux meilleures options, puis tester les vrais points douloureux : règles de permission, requêtes de reporting et déroulé des changements au fil de l'évolution du modèle.\n\n## Approche 1 : une base unique avec tenant_id sur chaque ligne\n\nC'est le setup le plus courant : tous les clients partagent les mêmes tables, et chaque enregistrement appartenant à un locataire porte un tenant_id. C'est simple opérationnellement car vous gérez une seule base et un seul jeu de migrations.\n\nLa règle est stricte : si une ligne appartient à un locataire, elle doit inclure tenant_id, et chaque requête doit le filtrer. Les tables typiquement scoped par locataire incluent utilisateurs, rôles, projets, tickets, factures, messages, métadonnées de fichiers, et les tables de jointure qui relient les données du locataire.\n\nPour réduire les fuites, traitez tenant_id comme non négociable :\n\n- Rendre tenant_id obligatoire (NOT NULL) sur les tables appartenant aux locataires\n- Ajouter des index commençant par tenant_id (par exemple tenant_id, created_at)\n- Inclure tenant_id dans les règles d'unicité (comme email unique par locataire)\n- Propager tenant_id dans chaque API et flow métier, pas seulement dans les formulaires UI\n- L'appliquer côté backend, pas uniquement via des filtres client\n\nDans PostgreSQL, les policies de row-level security peuvent ajouter un filet de sécurité solide, surtout quand les requêtes sont générées dynamiquement.\n\nLes données de référence tombent généralement dans deux catégories : tables partagées (comme countries) sans tenant_id, et catalogues scoped par locataire (comme tags personnalisés ou pipelines) qui incluent tenant_id.\n\nSi vous construisez avec AppMaster, une bonne habitude évite la plupart des incidents : définir tenant_id à partir du locataire de l'utilisateur authentifié avant toute création ou lecture dans votre logique Business Process, et garder ce pattern cohérent.\n\n## Impact sur les permissions : ce qui change selon l'approche\n\nLes permissions sont le lieu où la multi-tenancy réussit ou échoue. Le layout des données que vous choisissez change la façon dont vous stockez les utilisateurs, scopez les requêtes, et évitez les moments « oups » dans les écrans admin.\n\nAvec une base unique et tenant_id sur chaque ligne, les équipes utilisent souvent une table Users partagée et relient chaque utilisateur à un locataire et à un ou plusieurs rôles. La grande règle reste la même : chaque lecture et écriture doit inclure le scope du locataire, même pour des tables « petites » comme settings, tags ou logs.\n\nAvec des schémas séparés, on conserve souvent une couche d'identité partagée (login, mot de passe, MFA) à un endroit, tandis que les données des locataires résident dans un schéma par locataire. Les permissions deviennent en partie un problème de routage : l'application doit pointer les requêtes vers le bon schéma avant que la logique métier ne s'exécute.\n\nAvec des bases séparées, l'isolation est plus forte, mais la logique des permissions glisse vers l'infra : choisir la bonne connexion, gérer les identifiants et traiter les comptes « globaux » du personnel.\n\nSur les trois approches, quelques patterns réduisent systématiquement le risque inter-locataires :\n\n- Mettre tenant_id dans la session ou dans les claims du token d'auth et le traiter comme requis.\n- Centraliser les vérifications de locataire en un seul endroit (middleware ou Business Process partagé), pas dispersées sur tous les endpoints.\n- Dans les outils admins, afficher clairement le contexte de locataire et exiger un changement explicite.\n- Pour l'accès support, utiliser l'usurpation (impersonation) avec un journal d'audit.\n\nDans AppMaster, cela signifie typiquement stocker le contexte de locataire juste après l'authentification et le réutiliser dans les endpoints API et Business Processes afin que chaque requête reste scoped. Un agent support ne doit voir des commandes que si l'app a défini le contexte du locataire, pas parce que l'UI a filtré par hasard.\n\n## Reporting et performance avec un modèle tenant_id\n\nAvec l'approche base unique tenant_id, le reporting est généralement simple. Les tableaux de bord globaux (MRR, inscriptions, usage) peuvent s'exécuter avec une seule requête sur tous les clients, et les rapports par locataire sont la même requête avec un filtre.\n\nLe compromis est la performance avec le temps. À mesure que les tables grossissent, un locataire très actif peut devenir un voisin bruyant en produisant plus de lignes, plus d'écritures, et ralentir des requêtes communes si la base doit scanner trop d'enregistrements.\n\nL'indexation maintient ce modèle en bonne santé. La plupart des lectures scoped par locataire doivent pouvoir utiliser un index commençant par tenant_id, pour que la base puisse se déplacer directement vers la tranche de données de ce locataire.\n\nUn bon socle :\n\n- Ajouter des index composites où tenant_id est la première colonne (par exemple tenant_id + created_at, tenant_id + status, tenant_id + user_id)\n- Conserver des index véritablement globaux uniquement quand des requêtes cross-locataire les nécessitent\n- Surveiller les jointures et filtres qui « oublient » tenant_id, car elles provoquent des scans lents\n\nLa rétention et les suppressions nécessitent aussi un plan car l'historique d'un locataire peut gonfler les tables pour tout le monde. Si les locataires ont des politiques de rétention différentes, envisagez des suppressions douces plus archivage programmé par locataire, ou déplacer les vieilles lignes dans une table d'archive cléée par tenant_id.\n\n## Approche 2 : schémas séparés par locataire\n\nAvec des schémas séparés, vous utilisez toujours une base PostgreSQL, mais chaque locataire obtient son propre schéma (par exemple tenant_42). Les tables à l'intérieur de ce schéma appartiennent uniquement à ce locataire. C'est un peu comme donner à chaque client une « mini-base », sans l'overhead de gérer de nombreuses bases.\n\nUne configuration courante conserve des services globaux dans un schéma partagé et les données locataires dans des schémas dédiés. La séparation porte généralement sur ce qui doit être partagé entre tous les clients contre ce qui ne doit jamais se mélanger.\n\nRépartition typique :\n\n- Schéma partagé : table tenants, plans, enregistrements de facturation, feature flags, paramètres d'audit\n- Schéma locataire : tables métier comme orders, tickets, inventaire, projets, champs personnalisés\n- Selon le produit : users et rôles peuvent être d'un côté ou de l'autre, surtout si des utilisateurs accèdent à plusieurs locataires\n\nCe modèle réduit le risque de jointures inter-locataires parce que les tables vivent dans des namespaces différents. Il peut aussi faciliter la sauvegarde ou la restauration d'un locataire en ciblant un schéma.\n\nLes migrations surprennent souvent les équipes. Quand vous ajoutez une table ou une colonne, il faut appliquer le changement à chaque schéma locataire. Avec 10 locataires c'est gérable. Avec 1 000, il vous faut un processus : suivre les versions de schéma, exécuter les migrations par lots, et échouer en sécurité pour qu'un locataire cassé ne bloque pas les autres.\n\nLes services partagés comme l'auth et la facturation vivent habituellement en dehors des schémas locataires. Un pattern pratique est l'auth partagée (une table user avec une table d'appartenance aux locataires) et la facturation partagée (IDs client Stripe, factures), tandis que les schémas locataires stockent les données métier propres à chaque client.\n\nSi vous utilisez AppMaster, planifiez tôt comment les modèles du Data Designer se mappent aux schémas partagés vs locataires, et gardez les services globaux stables pour que les schémas locataires puissent évoluer sans casser la connexion ou les paiements.\n\n## Reporting et performance avec des schémas séparés\n\nLes schémas séparés offrent une séparation par défaut plus forte qu'un simple filtre tenant_id parce que les tables sont physiquement distinctes et les permissions peuvent être appliquées par schéma.\n\nLe reporting est excellent quand la plupart des rapports sont par locataire. Les requêtes restent simples car vous lisez les tables d'un seul locataire sans filtrer constamment des tables partagées. Ce modèle permet aussi des « locataires spéciaux » qui nécessitent des tables ou colonnes supplémentaires sans imposer ces changements à tout le monde.\n\nL'agrégation across tenants est là où les schémas commencent à poser problème. Vous devez soit disposer d'une couche de reporting capable d'interroger plusieurs schémas, soit maintenir des tables de récapitulatif partagées dans un schéma commun.\n\nPatterns courants :\n\n- Dashboards par locataire qui interrogent uniquement le schéma du locataire\n- Un schéma d'analytics central avec des rollups nocturnes depuis chaque locataire\n- Jobs d'export qui copient les données locataires dans un format adapté à un entrepôt\n\nLa performance est généralement solide pour les charges par locataire. Les index sont plus petits par locataire, et les écritures lourdes dans un schéma impactent moins les autres. Le compromis est l'overhead opérationnel : provisionner un nouveau locataire signifie créer un schéma, exécuter les migrations et maintenir l'alignement des schémas quand le modèle évolue.\n\nLes schémas conviennent quand vous voulez une isolation stricte sans le coût de multiples bases, ou quand vous prévoyez de la personnalisation par locataire.\n\n## Approche 3 : base de données séparée par locataire\n\nAvec une base par locataire, chaque client obtient sa propre base (ou sa propre base sur le même serveur). C'est l'option la plus isolée : si les données d'un locataire sont corrompues, mal configurées ou très sollicitées, elles impactent moins les autres.\n\nC'est adapté aux environnements réglementés (santé, finance, gouvernement) ou aux clients entreprise qui exigent une séparation stricte, des règles de rétention personnalisées ou des performances dédiées.\n\nL'onboarding devient un workflow de provisioning. Lorsqu'un nouveau locataire s'inscrit, le système doit créer ou cloner une base, appliquer le schéma de base (tables, index, contraintes), créer et stocker les identifiants en sécurité, et router les requêtes API vers la bonne base.\n\nSi vous construisez avec AppMaster, le choix clé est où garder l'annuaire des locataires (une cartographie centrale locataire → connexion DB) et comment garantir que chaque requête utilise la bonne connexion.\n\nLes mises à jour et migrations sont le principal compromis. Un changement de schéma n'est plus « exécuter une fois », c'est « exécuter pour chaque locataire ». Cela augmente le travail opérationnel et le risque, donc les équipes versionnent souvent les schémas et lancent les migrations comme des jobs contrôlés qui suivent la progression par locataire.\n\nL'avantage est le contrôle. Vous pouvez migrer d'abord les gros locataires, surveiller la performance, puis déployer progressivement.\n\n## Reporting et performance avec des bases séparées\n\nLes bases séparées sont les plus simples à raisonner. Les lectures cross-locataires accidentelles sont beaucoup moins probables, et une erreur de permission affecte généralement un seul locataire.\n\nLa performance est aussi un point fort. Requêtes lourdes, imports massifs ou rapports incontrôlés chez le Locataire A ne ralentiront pas le Locataire B. C'est une forte protection contre les voisins bruyants et cela permet d'ajuster les ressources par locataire.\n\nLe compromis apparaît dans le reporting. L'analytique globale devient la plus difficile car les données sont physiquement dispersées. Les patterns pratiques incluent la copie d'événements clés ou de tables vers une base de reporting centrale, l'envoi d'événements vers un entrepôt, l'exécution de rapports par locataire puis l'agrégation des résultats (quand le nombre de locataires est faible), et la séparation des métriques produit des données clients.\n\nLe coût opérationnel est l'autre facteur majeur. Plus de bases signifie plus de sauvegardes, mises à jour, monitoring et réponses incidents. Vous pouvez aussi atteindre plus vite les limites de connexions car chaque locataire peut nécessiter son propre pool de connexions.\n\n## Erreurs fréquentes qui causent des fuites de données ou des douleurs ultérieures\n\nLa plupart des problèmes multi-tenant ne sont pas des échecs de conception majeurs. Ce sont de petites omissions qui deviennent des bugs de sécurité, du reporting chahuté et des nettoyages coûteux. La multi-tenancy fonctionne quand la séparation des locataires est une habitude, pas une fonctionnalité ajoutée après coup.\n\nUne fuite courante est d'oublier le champ locataire sur une table, particulièrement les tables de jointure comme user_roles, invoice_items ou les tags. Tout semble correct jusqu'à ce qu'un rapport ou une recherche joigne cette table et tire des lignes d'un autre locataire.\n\nUn autre problème fréquent est des dashboards admin qui contournent les filtres de locataire. Cela commence souvent par « juste pour le support », puis se réutilise. Les outils no-code ne changent pas ce risque : chaque requête, business process et endpoint qui lit des données locataires doit avoir le même scope.\n\nLes IDs peuvent aussi poser problème. Si vous partagez des IDs lisibles par l'humain entre locataires (comme order_number = 1001) et supposez qu'ils sont globalement uniques, les outils de support et intégrations mélangeront les enregistrements. Gardez les identifiants scoped par locataire séparés des clés primaires internes, et incluez le contexte du locataire dans les recherches.\n\nEnfin, les équipes sous-estiment migrations et sauvegardes à l'échelle. Ce qui est simple avec 10 locataires peut devenir lent et risqué avec 1 000.\n\nVérifications rapides qui évitent la plupart des problèmes :\n\n- Rendre la propriété par locataire explicite sur chaque table, y compris les tables de jointure.\n- Utiliser un seul pattern de scoping et le réutiliser partout.\n- S'assurer que les rapports et exports ne peuvent s'exécuter sans scope de locataire (sauf s'ils sont vraiment globaux).\n- Éviter les identifiants ambigus par locataire dans les APIs et outils support.\n- Pratiquer les étapes de restauration et de migration tôt, pas après la montée en charge.\n\nExemple : un agent support cherche « facture 1001 » et remonte le mauvais locataire parce que la recherche a sauté le scope. C'est un petit bug avec un gros impact.\n\n## Checklist rapide avant de vous engager\n\nAvant de verrouiller un modèle multi-tenant, faites quelques tests. L'objectif est de détecter les fuites tôt et de confirmer que votre choix tient quand les tables grossissent.\n\n### Vérifications rapides réalisables en une journée\n\n- Preuve d'isolation des données : créez deux locataires (A et B), ajoutez des enregistrements similaires, puis vérifiez que chaque lecture et mise à jour est scoped au locataire actif. Ne vous fiez pas seulement aux filtres UI.\n- Test de rupture permissions : connectez-vous en tant qu'utilisateur du locataire A et essayez d'ouvrir, modifier ou supprimer un enregistrement du locataire B en ne changeant que l'ID. Si quelque chose réussit, bloquez la release.\n- Sécurité du chemin d'écriture : confirmez que les nouveaux enregistrements reçoivent toujours la bonne valeur de locataire (ou atterrissent dans le bon schéma/base), même via jobs en arrière-plan, imports ou automatisations.\n- Essai reporting : confirmez que vous pouvez exécuter un reporting par locataire et un reporting « tous locataires » (pour le staff interne), avec des règles claires sur qui peut voir la vue globale.\n- Test performance : ajoutez une stratégie d'index maintenant (notamment (tenant_id, created_at) et autres filtres courants), et mesurez au moins une requête lente volontairement pour savoir à quoi ressemble « mauvais ».\n\nPour rendre le test de reporting concret, choisissez deux questions dont vous savez qu'elles seront nécessaires (une scoped par locataire, une globale) et exécutez-les sur des données d'exemple.\n\nsql\n-- Tenant-only: last 30 days, one tenant\nSELECT count(*)\nFROM tickets\nWHERE tenant_id = :tenant_id\n AND created_at \u003e= now() - interval '30 days';\n\n-- Global (admin): compare tenants\nSELECT tenant_id, count(*)\nFROM tickets\nWHERE created_at \u003e= now() - interval '30 days'\nGROUP BY tenant_id;\n\n\nSi vous prototypez dans AppMaster, intégrez ces vérifications dans vos Business Processes (read, write, delete), et semez deux locataires dans le Data Designer. Quand ces tests passent avec un volume réaliste, vous pouvez vous engager avec confiance.\n\n## Scénario d'exemple : des premiers clients à la montée en charge\n\nUne société de 20 personnes lance un portail client : factures, tickets et un tableau de bord simple. Ils prévoient 10 locataires le premier mois, puis viser 1 000 sur l'année suivante.\n\nAu début, le modèle le plus simple est souvent une base unique où chaque table stockant des données clients inclut un tenant_id. C'est rapide à construire, simple pour le reporting et évite des setups dupliqués.\n\nAvec 10 locataires, le risque principal n'est pas la performance mais les permissions. Un filtre oublié (par exemple une requête « lister les factures » qui oublie tenant_id) peut provoquer une fuite. L'équipe doit appliquer les vérifications de locataire en un endroit cohérent (logique métier partagée ou patterns d'API réutilisables) et traiter le scoping comme non négociable.\n\nEn passant de 10 à 1 000 locataires, les besoins changent. Le reporting devient plus lourd, le support demande des « exports complets » pour un locataire, et quelques gros locataires commencent à dominer le trafic et ralentir les tables partagées.\n\nUne trajectoire d'évolution pratique :\n\n1) Conserver la logique applicative et les règles de permission, mais déplacer les locataires à fort volume vers des schémas séparés.\n2) Pour les plus gros ou les clients compliance, migrer vers des bases séparées.\n3) Garder une couche de reporting partagée qui lit depuis tous les locataires, et planifier les rapports lourds hors-peak.\n\nChoisissez le modèle le plus simple qui protège aujourd'hui, puis planifiez une migration pour le problème des « quelques très gros locataires » plutôt que d'optimiser pour ça dès le jour 1.\n\n## Étapes suivantes : choisissez un modèle et prototypez-le dans un backend no-code\n\nChoisissez selon ce que vous devez protéger en priorité : isolation des données, simplicité opérationnelle ou montée en charge par locataire. La confiance vient de la construction d'un petit prototype et de la tentative de le casser avec de vrais cas de permission et de reporting.\n\nUn guide de démarrage simple :\n\n- Si la plupart des locataires sont petits et que vous avez besoin d'un reporting cross-locataire simple, commencez par une base unique et un tenant_id sur chaque ligne.\n- Si vous avez besoin d'une séparation plus forte tout en gardant une seule base à gérer, envisagez des schémas séparés par locataire.\n- Si les locataires exigent une isolation stricte (conformité, sauvegardes dédiées, risque de voisin bruyant), envisagez une base séparée par locataire.\n\nAvant de construire, décrivez les frontières de locataire en langage clair. Définissez les rôles (owner, admin, agent, viewer), ce que chacun peut faire, et ce que signifie « global » (plans, templates, logs d'audit). Décidez comment le reporting doit fonctionner : uniquement par locataire, ou « tous locataires » pour le staff interne.\n\nSi vous utilisez AppMaster, vous pouvez prototyper rapidement ces patterns : modélisez les tables dans le Data Designer (y compris tenant_id, contraintes uniques et index nécessaires), puis appliquez les règles dans le Business Process Editor pour que chaque lecture et écriture reste scoped. Si vous voulez un point de référence pour la plateforme, AppMaster est disponible à appmaster.io.\n\nUn test final pratique : créez deux locataires (A et B), ajoutez des utilisateurs et commandes similaires, puis exécutez les mêmes flows pour les deux. Essayez d'exporter un rapport pour le locataire A, puis passez volontairement des IDs du locataire B dans les mêmes endpoints. Votre prototype est « suffisamment sûr » quand ces tentatives échouent systématiquement et que vos rapports clés restent rapides sur des volumes réalistes.
FAQ
Par défaut, choisissez une base de données unique avec un tenant_id sur chaque table appartenant à un locataire si vous souhaitez des opérations simples et des analyses inter-locataires fréquentes. Passez aux schémas séparés quand vous avez besoin d'une isolation plus forte ou de personnalisation par locataire sans gérer de nombreuses bases. Optez pour des bases de données séparées lorsque la conformité ou les exigences entreprise demandent une séparation stricte et un contrôle des performances par locataire.
Traitez le scoping de locataire comme obligatoire côté backend, pas comme un filtre UI. Rendez tenant_id obligatoire sur les tables appartenant aux locataires, et dérivez-le toujours du contexte de l'utilisateur authentifié plutôt que de faire confiance à l'entrée client. Ajoutez un filet de sécurité comme les politiques RLS de PostgreSQL si votre stack le permet, et créez des tests qui essaient d'accéder aux enregistrements d'un autre locataire en ne changeant que l'ID.
Placez tenant_id en premier dans les index qui correspondent à vos filtres courants, pour que la base de données puisse cibler la tranche de données d'un locataire. Une base est d'indexer (tenant_id, created_at) pour les vues temporelles, et d'ajouter (tenant_id, status) ou (tenant_id, user_id) pour les filtres fréquents des tableaux de bord. De plus, assurez-vous que les contraintes d'unicité sont scoped par locataire, par exemple « email unique par locataire ».
Les schémas séparés réduisent les jointures croisées accidentelles parce que les tables résident dans des espaces de noms différents, et vous pouvez appliquer des permissions au niveau du schéma. L'inconvénient principal est la gestion des migrations : chaque schéma doit recevoir la même modification, ce qui devient un problème opérationnel quand le nombre de locataires augmente. C'est un bon compromis quand vous voulez une isolation plus forte que tenant_id sans gérer de multiples bases de données.
Les bases de données séparées minimisent la blast radius : un pic de charge, une mauvaise configuration ou une corruption affecte plus probablement un seul locataire. Le coût est l'augmentation de la charge opérationnelle, car la provision, les sauvegardes, la surveillance et les migrations se multiplient par locataire. Vous aurez aussi besoin d'un annuaire fiable liant locataires et connexions, et d'un routage des requêtes pour que chaque appel API utilise la bonne connexion.
Le reporting inter-locataires est le plus simple avec une base unique et tenant_id, car les tableaux de bord globaux sont simplement des requêtes sans filtre de locataire. Avec des schémas ou des bases séparées, l'analyse globale fonctionne généralement mieux en copiant les événements clés ou des résumés dans un store de reporting partagé selon un planning. Règle simple : les métriques produit vont dans la couche de reporting, les données clients restent isolées.
Affichez explicitement le contexte de locataire dans les outils support et exigez un basculement intentionnel avant d'afficher des enregistrements. Si vous utilisez l'usurpation (impersonation), conservez un journal d'audit indiquant qui a accédé à quoi et quand, et limitez la durée. Évitez les workflows support qui acceptent uniquement un ID d'enregistrement sans contexte de locataire — c'est précisément ce qui transforme un bug comme « facture 1001 » en fuite réelle.
Si des locataires ont besoin de champs ou workflows différents, les schémas ou bases séparées réduisent le risque qu'une modification fasse effet chez les autres. Si la plupart des locataires sont similaires, conservez un modèle partagé avec tenant_id et gérez les différences via des options configurables comme des feature flags ou des champs optionnels. L'essentiel est d'éviter les tables « presque globales » qui mélangent des données partagées et spécifiques sans propriété claire.
Définissez tôt la frontière de locataire : décidez où le contexte de locataire est stocké après authentification et garantissez que chaque lecture/écriture l'utilise. Dans AppMaster, cela revient généralement à définir tenant_id à partir de l'utilisateur authentifié dans la logique Business Process avant de créer ou d'interroger des enregistrements appartenant au locataire, pour éviter tout oubli. Traitez ce schéma comme un pattern réutilisable applicable partout.
Créez deux locataires avec des données similaires et tentez de casser l'isolation en ne changeant que les IDs lors des lectures, mises à jour et suppressions. Vérifiez que les jobs en arrière-plan, imports et exports écrivent bien dans le bon scope de locataire, car ces chemins sont faciles à oublier. Exécutez aussi un rapport par locataire et un rapport admin global sur un volume d'échantillon réaliste pour confirmer que performances et règles d'accès tiennent la route.


