Isolation multi-établissements
Vérifié contre le produit le .
Ce scénario est autonome. Il monte ses deux établissements lui-même et se joue sans avoir déroulé les seize autres. C’est celui qu’on rejoue devant un client qui demande à voir.
| Domaine | Isolation entre établissements — aucune donnée ne franchit la frontière |
| Durée | ~10 min |
| Niveau | critique |
| Étiquette | manuel — il exige deux sessions simultanées dans deux établissements distincts, et son intérêt est précisément d’être joué sous les yeux de quelqu’un |
Ce que ce scénario démontre
Section intitulée « Ce que ce scénario démontre »Chaque établissement est étanche. Un utilisateur d’un établissement ne peut voir, ni chercher, ni atteindre aucune donnée d’un autre — même en connaissant l’adresse exacte de la ressource, même avec les droits les plus élevés de son propre établissement.
La séparation ne repose pas sur un filtre appliqué par l’interface, qu’on pourrait contourner en tapant une adresse : elle est appliquée au niveau de la base de données, sous chaque requête.
Préparation
Section intitulée « Préparation »Aucun jeu de données préexistant. Le scénario part d’un environnement démarré :
docker compose up -d postgres rediscd packages/db && bun run db:migratecd ../.. && bun run devL’application répond sur http://localhost:3000.
Deux navigateurs, ou un navigateur et une fenêtre privée — jamais deux onglets du même profil, qui partageraient la session.
1. Monter les deux établissements
Section intitulée « 1. Monter les deux établissements »| # | Action | Résultat attendu |
|---|---|---|
| 1.1 | Navigateur 1 → « Créer un compte » : alice, avec le nom d’établissement « École A » | le compte est créé, l’accueil s’affiche |
| 1.2 | alice → Référentiel & parc → créer un campus « Campus Nord », un bâtiment « BAT-A », une salle A-101 de 40 places | les trois éléments apparaissent dans l’arborescence |
| 1.3 | alice → Réservation → réserver A-101 demain 09:00–10:00, motif « Réunion A » | « Réservation confirmée. » |
| 1.4 | Navigateur 2 → « Créer un compte » : carol, avec le nom d’établissement « École B » | le compte est créé, l’accueil s’affiche |
| 1.5 | carol → Référentiel & parc → créer un campus « Campus Sud », un bâtiment « BAT-B », une salle B-201 de 30 places | les trois éléments apparaissent |
À ce stade, deux établissements existent, chacun avec sa salle, et l’un d’eux avec une réservation.
2. Ce que carol ne voit pas
Section intitulée « 2. Ce que carol ne voit pas »Tout ce bloc se joue dans le navigateur 2, avec carol — qui est administratrice de son propre établissement, donc au maximum de ses droits.
| # | Action | Résultat attendu |
|---|---|---|
| 2.1 | Réservation → rechercher demain, plage large, aucun filtre | seule B-201 apparaît. A-101 est absente, alors qu’elle est libre à cette heure-là |
| 2.2 | Référentiel & parc → parcourir l’arborescence | « Campus Sud » seul. Ni « Campus Nord », ni « BAT-A », ni A-101 |
| 2.3 | Administration → Utilisateurs | carol seule. alice n’y figure pas |
| 2.4 | Administration → Journal d’audit, filtres à « Tous » | aucune entrée concernant l’École A — ni la création du campus Nord, ni la réservation d’alice |
| 2.5 | Pilotage | les indicateurs ne portent que sur B-201 |
3. Ce que carol ne peut pas atteindre, même en connaissant l’adresse
Section intitulée « 3. Ce que carol ne peut pas atteindre, même en connaissant l’adresse »C’est le bloc qui distingue une véritable étanchéité d’un simple filtrage d’affichage.
| # | Action | Résultat attendu |
|---|---|---|
| 3.1 | Dans le navigateur 1, ouvrir la fiche de A-101 et copier l’adresse complète de la page | l’adresse contient l’identifiant de la salle |
| 3.2 | Coller cette adresse dans le navigateur 2, connecté en carol | « Salle introuvable. » — pas un refus d’accès : la salle n’existe pas de son point de vue |
| 3.3 | Recommencer avec l’adresse d’un plan d’étage, d’une fiche d’enseignant ou d’un import de l’École A | même comportement : introuvable |
La nuance vaut d’être dite à voix haute : le produit ne répond pas « vous n’avez pas le droit », ce qui confirmerait l’existence de la ressource. Il répond qu’elle n’existe pas.
4. La réciproque
Section intitulée « 4. La réciproque »Il ne suffit pas que B ne voie pas A ; il faut aussi que A ne voie pas B, et que rien n’ait bougé pendant les manipulations.
| # | Action | Résultat attendu |
|---|---|---|
| 4.1 | Navigateur 1, alice → Référentiel & parc | « Campus Nord » seul ; ni « Campus Sud », ni B-201 |
| 4.2 | alice → Réservation, recherche large | seule A-101 apparaît |
| 4.3 | alice → « Mes réservations » | sa réservation de l’étape 1.3 est intacte, statut « Confirmée » |
| 4.4 | alice → Administration → Journal d’audit | ses propres gestes y figurent, et aucun de ceux de carol |
5. L’étanchéité côté interface de programmation
Section intitulée « 5. L’étanchéité côté interface de programmation »Le même contrôle, en dehors de l’application web — c’est la question que pose un responsable informatique.
Dans le navigateur 2, connecté en carol, ouvrir http://localhost:3001/docs : la session est
transmise automatiquement.
| # | Action | Résultat attendu |
|---|---|---|
| 5.1 | Lister les salles | B-201 seule |
| 5.2 | Demander la salle A-101 par son identifiant, relevé à l’étape 3.1 | 404 — la ressource n’existe pas pour cette session |
| 5.3 | Lister les réservations | aucune — celle d’alice n’apparaît pas |
Le résultat est le même que dans l’interface, et c’est le point : la séparation n’est pas faite par l’écran, elle est faite en dessous.
Pièges connus
Section intitulée « Pièges connus »- Créer deux comptes coup sur coup peut déclencher le limiteur d’authentification. Le message affiché est « Une erreur est survenue. Veuillez réessayer. », générique. Attendre une minute de silence complet, puis reprendre.
- Le nom d’établissement est demandé à l’inscription. Un compte créé sans nom d’établissement rejoint une invitation, il n’en crée pas — le scénario a besoin de deux créations, pas d’une création et d’une invitation.
- L’étape 3.1 exige de relever une adresse réelle. Un identifiant inventé donnerait le même résultat pour une raison différente, et ne prouverait rien.
Les pièges transverses — environnement, authentification, fraîcheur des données — sont rassemblés sur Les pièges connus.
Traçabilité
Section intitulée « Traçabilité »| Ce qui est couvert | Story |
|---|---|
| Isolation par établissement, appliquée sous chaque requête | STORY-002 |
| Occupation unifiée et recherche de disponibilité | STORY-013, STORY-015 |
| Journal d’audit cloisonné | STORY-010 |
| Rôles et permissions par établissement | STORY-004 |
Couvert par les tests automatisés : apps/api/src/auth/auth-tenant.e2e.spec.ts et
apps/api/src/rbac/rbac.e2e.spec.ts éprouvent l’isolation côté serveur, y compris sur des
identifiants croisés. Le parcours complet côté interface ne l’est pas — et c’est
précisément celui qu’un client demande à voir.
Checklist
Section intitulée « Checklist »- Deux navigateurs distincts, deux comptes, deux établissements créés
- École A : un campus, un bâtiment, une salle A-101, et une réservation confirmée
- École B : un campus, un bâtiment, une salle B-201
- carol cherche une salle → seule B-201, A-101 absente bien que libre
- carol ouvre le référentiel → son campus seul
- carol ouvre les utilisateurs → elle seule
- carol ouvre le journal d’audit, filtres à « Tous » → aucune entrée de l’École A
- carol ouvre l’adresse directe de la fiche A-101 → « Salle introuvable. »
- alice ne voit ni le campus, ni la salle de l’École B
- La réservation d’alice est intacte après toutes les manipulations
- Depuis l’interface de programmation, en carol : A-101 par identifiant → 404
Écrans concernés
Section intitulée « Écrans concernés »- Réservations, Patrimoine, Détail d'une salle — les écrans traversés.
- Utilisateurs et Journal d'audit — les deux vérifications d’administration.
- Inscription — la création d’un établissement.