Espaces de travail et membres
La frontière entre tenants — ce que contient un espace de travail, ce que permettent les quatre rôles, et pourquoi un inconnu reçoit 404 plutôt que 403.
Un espace de travail est l'unité d'isolation. Tout le reste vit dans un espace et un seul : listes, cartes, registre des propriétés, statuts, fichiers, clés API, webhooks et journal d'événements.
Rien ne le traverse. Aucune requête du produit ne lit deux espaces à la fois, et
c'est garanti sous l'application : chaque requête s'exécute sur une connexion
Postgres limitée à un seul tenant par la sécurité au niveau des lignes (RLS), et
l'API s'y connecte avec un rôle qui n'a aucun moyen de la contourner. Une clause
WHERE oubliée ne peut pas laisser fuir les lignes d'un autre tenant, parce que
ce n'est pas elle qui tient la barrière.
Une conséquence visible
Le sélecteur d'espaces n'affiche aucun compteur. Pas faute d'en avoir voulu : compter les cartes de tous vos espaces demanderait une transaction par espace, et l'isolation qui rend le produit sûr est celle-là même qui rend cet agrégat coûteux. Les compteurs vivent un niveau plus bas, sur l'écran d'accueil de chaque espace.
Membres et rôles
On entre dans un espace de travail en en devenant membre. Il existe quatre
rôles, et ils sont ordonnés — une route qui exige member accepte aussi admin
et owner :
| Rôle | Peut |
|---|---|
viewer | Lire le contenu et les vues |
member | Tout ce qui précède, plus créer et modifier des cartes |
admin | Tout ce qui précède, plus le registre, les statuts, les membres, les clés API et les invitations |
owner | Tout ce qui précède, plus l'espace de travail lui-même |
Les rôles sont vérifiés à chaque écriture, côté serveur. Un client connaît son propre rôle pour pouvoir masquer les boutons voués à l'échec, mais masquer un bouton est une politesse, pas un contrôle.
Pourquoi vous recevez 404, et non 403
Demandez un espace de travail dont vous n'êtes pas membre : l'API répond 404 Not Found, jamais 403 Forbidden.
C'est voulu. Un 403 confirmerait que l'espace existe — précisément ce que cherche à savoir quelqu'un qui énumère des identifiants. Il en va de même pour une section de réglages que votre rôle ne peut pas ouvrir : invisible, donc inexistante.
Un 404 de cette API veut donc dire l'une de deux choses — la ressource n'existe pas, ou elle n'est pas à vous — et l'API ne vous dira pas laquelle.
Le périmètre vient de l'appartenance, jamais de l'URL
Mettre l'identifiant d'un espace dans un chemin n'accorde rien. Toute requête
sous /workspaces/{workspaceId}/… franchit deux portes avant d'atteindre une
route : l'authentification (401 sans bearer valide) et l'appartenance (404 sans
elle).
Les deux sont montées sur le préfixe du chemin plutôt que route par route : une route ajoutée demain est protégée le jour même où elle est écrite. La sécurité au niveau des lignes forme un second plancher en dessous — elle empêche de traverser d'un tenant à l'autre, mais c'est la vérification d'appartenance qui décide si vous avez le droit de nommer celui-ci.
Deux sortes de porteurs
Deux types d'identifiants passent la porte d'entrée, et au-delà rien ne permet de les distinguer :
- une session, ouverte par un humain qui se connecte — elle porte l'accès de cette personne à tous ses espaces, et expire au bout de 30 jours ;
- une clé API (
spk_…), pour les logiciels — limitée à un espace de travail, avec un rôle fixé à l'émission, révocable seule.
Pour tout ce qui tourne sans surveillance, utilisez une clé. Une session est le mauvais identifiant pour un script : elle est plus large que ce que la tâche demande, on ne peut pas la révoquer sans déconnecter la personne partout, et elle finira par expirer en pleine nuit.
Il en existe un troisième : le jeton d'installation d'app (spa_…), émis
par OAuth pour les logiciels tiers. Celui-là porte en plus des
scopes.
Vue d'ensemble
Chaque espace de travail a un écran d'accueil servi par une seule route,
GET /workspaces/{workspaceId}/overview : le nombre de cartes dans chaque
catégorie de statut, l'activité des quatorze derniers jours et l'avancement par
liste.
C'est une route à part entière plutôt que l'effet de bord d'une autre lecture, parce que le comptage est ce qui casse en premier dans un système de contenu qui grossit. Le tenir à part rend son coût visible et assumé — trois requêtes, quel que soit le nombre de listes — au lieu de le cacher dans un chargement de page qui, autrefois, ne coûtait rien.
Relier GitHub à vos cartes
Le connecteur GitHub rattache pull requests et commits aux cartes qu'ils citent, fait suivre les statuts au code, et importe les issues d'un dépôt dans une liste — sans doublon au second passage.
Listes et cartes
Les listes, les cartes qu'elles contiennent, les deux identifiants de chaque carte, et la différence entre là où une carte vit et là où elle apparaît.