Multi-tenant : le workspace¶
Le workspace (espace de travail) est l'unité multi-tenant fondamentale d'ikloze. Un entrepreneur crée un workspace, y invite des membres, et toutes les données — formulaires, leads, projets, paiements — appartiennent à ce workspace.
Le workspace actif¶
L'utilisateur peut appartenir à plusieurs workspaces. La requête HTTP indique sur lequel elle opère via l'en-tête :
Jamais persisté
Le workspace actif est calculé à la volée par la garde d'authentification à partir de l'en-tête X-Workspace-Id. Il n'existe aucune colonne persistée « workspace actif » sur la table users. À chaque requête, user.activeWorkspaceId est résolu depuis l'en-tête.
Derrière une garde qui exige un workspace, user.activeWorkspaceId est positionné et user.hasPerm(...) est significatif (voir Permissions).
Sélection du workspace côté client¶
Quand un utilisateur a plusieurs workspaces et n'en sélectionne aucun, l'API renvoie 401 avec code: "workspace_header_required" et la liste des workspaces disponibles. Le client présente un sélecteur, puis rejoue la requête avec l'en-tête X-Workspace-Id. Voir Erreurs API.
Scoping et anti-énumération¶
Toute lecture/écriture est scopée au workspace actif. Pour ne pas divulguer l'existence d'une ressource appartenant à un autre workspace, le backend renvoie volontairement 404 (et non 403) quand une ressource existe mais n'est pas visible dans le workspace actif.
const record = await Forms.findOne({ where: { id, workspaceId: user.activeWorkspaceId } });
if (!record) throw new NotFoundError();
C'est une règle anti-énumération : du point de vue de l'appelant, la ressource « n'existe simplement pas ».
Routes hors-workspace¶
Quelques routes doivent être atteignables avant d'appartenir à un workspace (ex. POST /workspaces pour créer son premier espace). Elles utilisent AuthenticatedGuard au lieu de RequireWorkspaceGuard — voir Authentification & gardes. Derrière AuthenticatedGuard, il n'y a pas de workspace actif : un service qui suppose un workspace ou une permission scopée serait un bug.
Propriétaire vs membres¶
- Le propriétaire (
workspace.ownerId) court-circuite toutes les vérifications de permission dans son workspace. - Les membres rejoignent via une invitation et reçoivent des permissions par leurs groupes (rôles) dans ce workspace.
Voir Permissions pour l'ordre de résolution complet et le module Cœur pour les invitations et adhésions.
Configuration du workspace¶
La configuration au niveau workspace (intégrations, réglages futurs) vit dans une colonne JSON workspaces.parameters — par exemple parameters.integrations.* — plutôt que dans des colonnes discrètes.