Aller au contenu
Me contacter
Tous les articles
Mis à jour le 5 min de lecture

Développer une DXP multi-tenants

Retour d’expérience sur Goodbizz, une DXP multi-tenants développée chez Ikomobi : architecture en microservices, données isolées par tenant, permissions définies module par module et action par action, bibliothèque de médias et consentement RGPD.

  • Node.js
  • Next.js
  • DXP
  • MongoDB
  • MySQL
  • Express
  • Microservices

Un CMS gère des pages ; une DXP (Digital Experience Platform) structure des contenus et des ressources pour les diffuser sur plusieurs canaux et à plusieurs équipes. Chez Ikomobi, nous avons développé en interne Goodbizz, une DXP multi-tenants. Le projet reposait sur une première base écrite par d’anciens collègues, mise en pause tant que les projets clients passaient en priorité, et c’est sur elle que nous l’avons relancé. L’équipe comptait un lead dev, deux développeurs fullstack et un intégrateur, épaulés par un chef de projet et un designer. Chacun avait ses modules, sans s’interdire d’intervenir sur le reste. Voici les principaux choix d’architecture, et ce que j’y ai développé.

À quoi sert cette DXP ?

Goodbizz répond à trois usages, pour plusieurs organisations à la fois, les tenants :

  • alimenter des sites web, construits à partir de templates et de blocs gérés dans le back-office ;
  • alimenter des e-mails, qu’ils soient automatiques, marketing ou de notification ;
  • servir de gestionnaire de ressources aux équipes métier, avec une bibliothèque de fichiers partagée.

Servir plusieurs canaux et plusieurs tenants pèse sur toute la conception. Les données doivent être pensées indépendamment de leur rendu, et ce qui appartient à chaque tenant doit rester strictement isolé.

Une architecture en microservices

La plateforme se répartit entre plusieurs services Node.js / Express, chacun responsable d’un domaine :

  • une API passerelle, point d’entrée unique du back-office React et des fronts ;
  • un service d’authentification, qui gère utilisateurs, rôles, tenants et sessions ;
  • un service de contenus, qui couvre les pages, les templates et les blocs, les menus, la FAQ, le blog, les formulaires, les URL, les langues et les aperçus ;
  • un service de bibliothèque de fichiers ;
  • un catalogue produits, socle du moteur e-commerce.

La passerelle relaie les requêtes aux services en HTTP, et les services s’authentifient entre eux grâce à un token de service. MySQL accueille les données relationnelles, MongoDB les structures plus souples, comme les templates et les blocs du page builder, les rôles ou la bibliothèque. Quant aux sites publics, ils sont rendus côté serveur avec Next.js.

Comment isoler les données de chaque tenant ?

J’ai développé la partie multi-tenant. Au lieu d’une base de données par tenant, la plateforme utilise une base partagée dont chaque enregistrement porte l’identifiant de son tenant. Ce choix répond d’abord à l’usage, puisque plusieurs fronts peuvent partager les mêmes données. Il offre aussi une seule base à faire évoluer et à déployer, avec une contrepartie de taille : aucune requête ne doit oublier ce filtre.

Le tenant est inscrit avant tout dans le token d’authentification de l’utilisateur. La passerelle le transmet à chaque service, qui l’applique à ses lectures comme à ses écritures. Les rôles eux-mêmes appartiennent à un tenant, si bien que deux organisations peuvent avoir un rôle du même nom avec des droits différents.

Comment définir des permissions à la tâche près ?

La gestion des rôles, que j’ai reprise, devait offrir une granularité fine. Un rôle énumère les modules de la plateforme et, pour chacun, les actions autorisées (lire, créer, modifier, supprimer et, selon le module, publier ou télécharger). Chaque tenant peut ajuster ses rôles, voire en créer de nouveaux. En voici la structure, simplifiée pour l’article :

// A role belongs to one tenant and grants rights module by module
const editorRole = {
  tenantId: 'tenant-a',
  name: 'Éditeur',
  modules: [
    {identifier: 'pages', rights: {read: true, create: true, update: true, remove: false, publish: false}},
    {identifier: 'library', rights: {read: true, create: true, update: true, remove: true, download: true}},
  ],
};

// The API maps each HTTP method to the right it requires
const requiredRight = {POST: 'create', PUT: 'update', PATCH: 'update', DELETE: 'remove'};

Côté API, un middleware associe chaque requête d’écriture au droit qu’elle exige sur le module visé, et la rejette si le rôle ne l’accorde pas. La plateforme collaborative SRS applique le même principe avec des rôles plus simples.

Comment sécuriser l’authentification ?

J’ai également repris le module d’authentification, qui distingue les administrateurs du back-office des utilisateurs des fronts, ainsi que la gestion de ces deux populations. Le tenant de chaque compte figure dans son token. Les mots de passe sont hachés, leur réinitialisation passe par e-mail, et l’option « rester connecté » s’appuie sur des sessions dont seule une empreinte du token est conservée.

La connexion exige une double authentification, et les tentatives échouées sont comptées. Passé un certain nombre, l’accès est bloqué temporairement, ce qui freine les attaques par force brute.

Une bibliothèque de type Google Drive

Cœur du gestionnaire de ressources, la bibliothèque de fichiers fait aussi partie des modules que j’ai repris. Chaque type de média y reçoit un traitement adapté dès l’import :

  • les images sont redimensionnées et optimisées, et leurs métadonnées lues ;
  • les vidéos et les fichiers audio sont analysés, et le texte des PDF est extrait ;
  • les doublons sont repérés grâce à une empreinte du contenu de chaque fichier, stockée et comparée en base ;
  • les fichiers se téléchargent en lot dans une archive zip, et l’espace disque occupé est suivi.

J’ai aussi repris les statistiques et les outils de suivi de la bibliothèque. Ils retracent l’utilisation des fichiers et des dossiers ainsi que l’historique des actions, et signalent les médias trop volumineux, les doublons, les fichiers mal nommés ou devenus inutiles. Les équipes disposent ainsi de quoi garder une bibliothèque propre et cohérente dans la durée.

Comment gérer le consentement et le RGPD ?

Une plateforme qui envoie des e-mails marketing pour le compte de plusieurs organisations doit pouvoir prouver chaque consentement. Un module dédié conserve donc les consentements des utilisateurs et leurs preuves, ainsi que les politiques de confidentialité qui s’y rapportent.

Que ferais-je autrement aujourd’hui ?

Je poserais plus tôt, avec l’équipe, les choix techniques structurants et le périmètre de chaque service, avant d’entrer dans l’implémentation. Fixés en amont, ces repères rendent les intégrations plus fluides et l’évolution du projet plus prévisible.

Pour les équipes métier, la réussite d’une DXP se mesure à la facilité avec laquelle elles se l’approprient. Les garanties essentielles leur restent invisibles, qu’il s’agisse de l’isolation des données de chaque tenant ou des permissions vérifiées à chaque action, dans chaque module. L’interface est visible sur la fiche du projet Goodbizz ; pour en discuter, écrivez-moi.