Repository navigation
FR Bridge Multi Tenant
English · Type : procédure · Public : administrateur · Contexte : Reality Bridge · Statut : prête · S'applique depuis : 4.2.5
Le Reality Bridge, profil
distributed(Postgres) · contrat : expérimental · vérifié par la CI (matrice de support de la 4.4.0, 2026-10-23) : Postgres 16 en CI ; Le profil de qualification : HTTPS, trois instances (ops/qualify/) · vérifications automatiques : jobsbridge-postgres,deployment-smoke; plan de CIreality; 1 fichier de tests · passes humaines :bridge-postgres-httpspas faite (#77) · limites connues :bridge-tenants-demo-webhooks,bridge-tenants-shared-process
Comment servir plusieurs jeux, ou un même jeu dans plusieurs environnements, depuis un seul déploiement du Bridge, et comment faire tourner plusieurs instances sur un même stockage. Un tenant est le jeu d’un opérateur dans un environnement : son propre dossier, sa propre racine Biscuit, sa clé d’événements, son jeton d’opérateur, ses quotas, sa rotation et ses révocations. Ce qui les isole, et où cela s’arrête : Garanties.
Un serve (ou plusieurs identiques) qui tient plusieurs tenants sur un stockage SQL, chacun atteint par son propre
nom d’hôte, chacun signant des signaux WorldSignalV2 qui nomment leur tenant, avec des jetons de connecteur liés à
leur tenant.
- Un Bridge, depuis la 4.1.10 (« Constellation », ADR 0009, ADR 0010) ; cette page s’applique à partir de la 4.2.5
(les noms
quest-n-click-bridge). - Plusieurs tenants demandent un stockage SQL : SQLite pour une machine, Postgres pour plusieurs instances (le profil
distributed, expérimental). -
Vérifié sur : non rejoué pour cette page. La même disposition (deux tenants, trois instances, un Postgres) est
celle que
npm run ops:qualifymonte et vérifie (Le déploiement de référence).
- Comprendre d’abord un Bridge seul en marche : Installer et lancer le Bridge.
- Un nom d’hôte par tenant (
bridge.a.example,bridge.b.example) qui pointe vers le déploiement, ou un proxy qui poseX-Web-Scumm-Tenant. - Pour plusieurs instances : Postgres, et
pginstallé à côté du Bridge.
Sur la machine du déploiement (ou celle de chaque instance), avec un dossier par tenant, par exemple /srv/bridge/a
et /srv/bridge/b. npm run bridge -- … dans le dépôt du moteur, npx quest-n-click-bridge … avec le paquet
(passez alors --manifest= à init).
-
Créez le dossier de chaque tenant, avec son identifiant, son environnement et ses noms d’hôte :
# sur la machine du déploiement, dans le dépôt du moteur npm run bridge -- init --dir=/srv/bridge/a --tenant=a --environment=prod --hosts=bridge.a.example --no-demo-webhooks --origin=https://game-a.example npm run bridge -- init --dir=/srv/bridge/b --tenant=b --environment=staging --hosts=bridge.b.example --no-demo-webhooks --origin=https://game-b.example--environmentvautprod,stagingoudev(prodpar défaut) ; il est nommé dans chaque signal et dans les clés que liste le tenant.
-
Servez-les ensemble sur un stockage SQL :
# sur la machine du déploiement, dans le dépôt du moteur BRIDGE_STORE=postgres://… npm run bridge -- serve --tenants=/srv/bridge/a,/srv/bridge/b [--tenant-header]Une requête est routée par son
Host(leshostsde chaque tenant), ou parX-Web-Scumm-Tenantavec--tenant-header, avant toute lecture ; aucun tenant : une 404. Deux dossiers qui configurent le même tenant sont refusés au démarrage, tout comme un journal (plusieurs tenants partagent un stockage SQL :--store=sqlite:<fichier>,BRIDGE_STORE=postgres://…ouBRIDGE_STORE_FILE).
-
Donnez leurs jetons aux connecteurs de chaque tenant depuis le dossier de ce tenant :
grantajoute le tenant au jeton, si bien qu’aucun autre tenant ne l’accepte.# sur la machine du déploiement, dans le dépôt du moteur npm run bridge -- grant --dir=/srv/bridge/a --connector=mail-a --source=mail --signals=mail.answer.correct --pair > mail-a.token
- Pour plus de capacité, lancez autant de
serveidentiques qu’il faut sur le même stockage, sans affinité de session, derrière un répartiteur de charge. Les instances sont sans état.
-
GET /healthzsur n’importe quelle instance dit"tenants": 2et le type de stockage. -
npm run bridge -- doctor --dir=/srv/bridge/a(avec le mêmeBRIDGE_STORE) liste chaque tenant du stockage, avec ses joueurs, ses signaux, ses trous et ses lignes en quarantaine. - Une requête avec un
Hostinconnu reçoit 404{"error": "tenant"}.
- Les séquences, la déduplication et les accusés de réception se décident dans une seule transaction de la base ; la livraison est au moins une fois et appliquée une fois (D20).
- Un signal accepté par une instance atteint un flux tenu par une autre, qui lit le stockage quand on la réveille :
NOTIFYde Postgres, une lecture toutes les 250 ms sur SQLite, et un passage toutes les 5 s au cas où un réveil se perdrait. - Chaque ligne du stockage porte son tenant et chaque requête SQL filtre dessus. Un tenant d’un déploiement partagé
signe des
WorldSignalV2(le signal nomme son tenant, son environnement, son origine, son lien et sa clé), si bien que ni un jeton ni un signal d’un tenant n’est accepté par un autre, même quand deux d’entre eux ont reçu (à tort) la même clé. - Chaque instance borne ses flux ouverts (
streamsPerInstance, 10 000 ; au-delà, 429) et sa minute par connecteur : avec N instances, un connecteur peut proposer N fois son quota. - Une ligne gardée qui ne se vérifie plus est mise en quarantaine, jamais livrée, et
doctorla liste.
Limite ·
bridge-tenants-demo-webhooksUn serveur garde une seule table des webhooks de démonstration, par source, pour tous ses tenants : deux tenants avec un webhook de la même source entrent en collision. Donnez aux tenants d’un serveur partagé--no-demo-webhookset ungrantpar connecteur.
Limite ·
bridge-tenants-shared-processLes tenants d’un serveur partagent son processus, sa liste CORS (les--originde tous les tenants ensemble) et sa base. L’isolation est le code du Bridge ; il n’y a pas de sécurité par ligne et par tenant dans Postgres, et une instance compromise détient les clés de tous les tenants.
| Message | Cause | Correction |
|---|---|---|
✖ two directories configure the same tenant (a, a) |
Deux dossiers avec le même --tenant
|
Un dossier par tenant |
✖ several tenants share a SQL store: --store=sqlite:<file>, BRIDGE_STORE=postgres://… or BRIDGE_STORE_FILE |
La configuration du premier tenant nomme le journal | Nommer un stockage SQL |
404 {"error":"tenant","message":"no tenant here"}
|
Le Host n’est dans les hosts d’aucun tenant, et pas d’en-tête autorisé |
Ajouter l’hôte aux hosts du tenant dans config.json, ou --tenant-header derrière un proxy qui le pose |
403 sur POST /v1/signals
|
Le jeton du connecteur appartient à un autre tenant |
grant depuis le dossier du bon tenant |
BRIDGE_STORE_FILE: … does not exist / … is empty
|
Le fichier secret manque ou est vide | Le monter ; un fichier vide est refusé plutôt que de retomber sur un journal |
Un dossier par tenant (config.json, root.key, admin-token) ; le stockage partagé, où chaque ligne porte son
tenant.
- Sortir les lignes d’un tenant d’un stockage partagé :
tenant export --tenant=<id> --out=<fichier>; les supprimer :tenant delete --tenant=<id> --yes(Sauvegarde et restauration). - La clé ou la racine d’un tenant compromise, ou une instance : Sécurité. La rotation d’un tenant ne touche pas les autres.
- Le routage :
bridge/src/server.ts; la configuration d’un tenant :bridge/src/config.ts; les stockages :bridge/src/store-async.ts. -
ADR 0009, ADR 0010, le modèle de
menace
docs/dev/threat-models/constellation.md. - Testé par
tests/bridge-tenancy.test.tsettests/bridge-fanout.test.ts.
Generated publication · publication générée — current documentation · documentation courante: quest'n'click 4.4.0 r1, documentation revision · révision de la documentation 8dc717c69acb62c4742b69c54a7e7dfb620f75d8.
Earlier versions and permalinks · versions précédentes et liens permanents: https://wanoo.github.io/quest-n-click/docs/
An edit made in this wiki is overwritten at the next publication · une modification faite dans ce wiki est écrasée à la publication suivante.
Edit the source · Modifier la source · Report an error · Signaler une erreur
Index (6)
Démarrer (6)
Jouer (9)
Installer (17)
- Prérequis
- Installer depuis l'archive de la release
- Installer depuis npm, une fois publié
- Installer depuis le dépôt pour travailler sur le moteur
- doctor : vérifier sa machine
- Outils pour les images
- Outils audio : ffmpeg, fluidsynth, Furnace, uv
- Mettre à jour
- Notes de mise à jour : 4.4
- Notes de mise à jour : 4.3
- Notes de mise à jour : 4.2
- Notes de mise à jour : 4.1
- Notes de mise à jour : v3
- Notes de mise à jour : v2 vers v3
- Venir de web-scumm
- Référence du paquet
- Dépannage de l'installation
Créer un jeu (55)
- Votre premier jeu
- Organisation d'un projet créé et du dépôt du moteur
- La boucle de travail
- Principes du contenu et contrat d'identité
- Salles
- Géométrie : placement, zones de marche, masques, calques, caméra
- Un objet est visible mais inaccessible
- Réactions
- Commandes du jeu
- Conditions
- Drapeaux, variables et événements : lequel choisir
- Code sur mesure
- Personnages
- Objets et inventaire
- Carte du monde
- Dialogues
- Scripts et événements
- Faire bouger les personnages : patrouilles et marches
- Sorties
- Chapitres et objectifs
- État et sauvegardes : persistant ou temporaire, renommer un id, migrations
- Mise en scène : salles larges et animations
- La scène : lumières, particules, sols
- Habillage et polices
- Titre et générique
- Héros : plusieurs personnages et choix du héros
- Mini-jeux intégrés
- Un mini-jeu sur mesure
- Traductions
- Musique en stems
- Bruitages
- Voix : par langue et par héros
- Images : prompts, découpe des planches, transparence, échelle
- Provenance des assets
- Le storyboard, source de vérité
- Concevoir des énigmes
- Mécaniques classiques
- Pages de relecture
- Référence du DSL
- Vérifier son jeu
- Ce que prouve le solveur
- Options du solveur
- Playtests
- Remix
- Speedrun pour les auteurs
- La fin scellée
- Modèle de production
- Jeux d'exemple
- Travailler avec une IA
- Construire et publier un jeu
- Publier sur GitHub Pages
- Le jeu statique sur Clever Cloud
- Autres hébergeurs statiques
- Sous-chemin, cache et service worker, déploiement incomplet, retour arrière
- Tester sur un téléphone en réseau local
Studio local (24)
- Le Studio local : présentation et lancement
- Modifier une salle
- Placement et scène
- Aperçu, application, annulation
- Storyboard
- Assets et découpe
- Vérifier : validateur, solveur, chemin critique, chaleur, santé, couverture
- Captures avant et après
- Diff sémantique
- Jouer et rejouer une session
- Explication des règles
- Langue et objectifs
- Voix et matrice héros × langues
- Carte
- Notes
- Remix dans le Studio
- Musique
- L'Assistant : votre propre clé
- Mode démo et studio-apply
- Sécurité en local et en réseau local
- API du Studio
- MCP local : configurer chaque client
- Outils MCP
- Dépannage du Studio
Studio d'équipe (21)
- Ce qui tourne où
- Concepts : révision, transaction, pan, bail, aperçu, build
- Débuter comme dev invité
- Travailler ensemble au quotidien
- Rôles et actions : la matrice complète
- Invitations
- Gérer les membres
- Écriture refusée sur le Studio hébergé : révision de base périmée (409)
- Écriture refusée sur le Studio hébergé : pan verrouillé (423)
- Reprendre après un bail perdu, une déconnexion ou un aperçu périmé
- Commentaires
- Carte et diff sémantique
- Publier des builds
- MCP distant
- Le jeu dans Git
- Mettre à jour le moteur d'un jeu hébergé
- Assets hébergés
- La ligne de commande du serveur
- Routes de santé et de métriques
- L'essayer en local avec compose.yml
- Limites connues
Clever Cloud (23)
- Clever Cloud : vue d'ensemble, coût et prérequis
- Applications et add-ons
- Domaines et TLS
- Keycloak
- OIDC générique et GitLab
- Configuration
- Premier déploiement
- Sauvegardes
- RPO et RTO
- Exercice de restauration sur une installation vierge
- Redéploiements
- Mettre à jour le serveur et vérifier l'état après une migration
- Limites du retour arrière
- Supervision
- Sécurité
- Renouveler les clés
- Récupérer l'accès administrateur
- Changer de domaine ou de fournisseur OIDC
- Worker, PostgreSQL ou Cellar en panne
- Exporter le jeu et quitter l'installation
- Rétention
- Dépannage sur Clever Cloud
- Coûts et démontage
Reality Bridge et connecteurs (16)
- Le Reality Bridge : ce que c'est
- Démarrage rapide
- Garanties
- Installer et lancer le Bridge
- Sauvegarde et restauration
- Plusieurs tenants
- Signaux et manifeste
- La ligne de commande du Bridge
- Vue d'ensemble des connecteurs
- Connecteur email
- Connecteur Telnet
- Connecteur SSH
- Connecteur Open Badges
- Le SDK des connecteurs
- Sécurité : Biscuit et signatures
- Dépannage du Bridge et des connecteurs
Contribuer (25)
- Bienvenue
- Préparer son poste de développement
- La boucle de développement
- Avant une pull request
- Conventions
- Écrire la documentation
- Architecture
- Visite du code
- Frontières d'import
- Quels tests tournent quand
- Tests de mutation
- Le cliquet de couverture
- La référence de qualité
- La CI expliquée
- Passes de terrain
- Mesures de performance
- Publier une release
- Paquets npm
- Décisions et ADR
- Gouvernance
- Pull requests des bots
- Contribuer avec des agents IA
- Politique de sécurité
- Code de conduite
- Licences et crédits