Aller au contenu

API : Espaces de travail

GET /api/workspaces

Renvoie tous les espaces de travail dont tu es membre, avec ton rôle dans chacun.

[
{
"id": "019f7462-ac2a-73e3-ab40-be2e43f943f9",
"name": null,
"personal": true,
"ownerFirstName": "Greta",
"role": "OWNER"
},
{
"id": "019f7464-1617-7464-b8ef-7f34b631bdfa",
"name": "Lengl Family",
"personal": false,
"ownerFirstName": "Greta",
"role": "OWNER"
}
]
  • name vaut null pour les espaces de travail personnels — les clients affichent un libellé localisé à partir de ownerFirstName.
POST /api/workspaces
{ "name": "Renovation" }

Renvoie 201 avec { "id": "…" }. Erreurs : 409 si tu possèdes déjà un espace de travail portant ce nom (insensible à la casse), 403 si tu as atteint ta limite d’espaces de travail partagés.

DELETE /api/workspaces/{workspaceId}

Propriétaire uniquement. Renvoie 204. Supprime définitivement toutes les tâches, listes, adhésions et pièces jointes. Les espaces de travail personnels ne peuvent pas être supprimés.

Chaque espace de travail a une limite de membres qui compte tous les membres, propriétaire inclus ; c’est un droit lié au propriétaire de l’espace de travail (offre par défaut : 5).

GET /api/workspaces/{workspaceId}/members
[
{
"userId": "019f…",
"firstName": "Greta",
"lastName": "Lengl",
"avatarUrl": "/api/avatars/019f…?v=3",
"role": "OWNER"
}
]

Les nouveaux membres sont ajoutés exclusivement via les invitations par e-mail.

PUT /api/workspaces/{workspaceId}/members/{memberId}
{ "role": "ADMIN" }

Renvoie 204. Rôles : ADMIN ou MEMBER — la propriété n’est pas transférable via cet endpoint.

DELETE /api/workspaces/{workspaceId}/members/{memberId}

Renvoie 204. Les propriétaires ne peuvent pas être retirés.

POST /api/workspaces/{workspaceId}/leave

Renvoie 204. Quitte un espace de travail partagé que tu as rejoint : les tâches dont tu es l’auteur·e sont réattribuées à un « Utilisateur inactif » réservé et tes assignations sont effacées. Le propriétaire ne peut pas quitter l’espace de travail (400) — transfère d’abord la propriété. Les non-membres obtiennent 404.

POST /api/workspaces/{workspaceId}/transfer-ownership
{ "newOwnerId": "019f…" }

Propriétaire uniquement. Renvoie 204 : le destinataire devient propriétaire et l’appelant·e reste administrateur ; les limites de stockage et de membres de l’espace de travail suivent désormais le forfait du nouveau propriétaire. Erreurs : 404 quand le destinataire n’est pas membre, 400 pour un espace de travail personnel ou un transfert vers toi-même, 403 quand le destinataire a atteint la limite d’espaces de travail partagés de son forfait, 409 quand le destinataire possède déjà un espace de travail portant le même nom.

Les invitations sont personnelles : chacune est liée à une seule adresse e-mail, valable 7 jours et à usage unique. Les invitations expirées sont aussi supprimées par un nettoyage quotidien.

POST /api/workspaces/{workspaceId}/invites
{ "emails": ["person@example.com", "other@example.com"] }

Propriétaire/admin uniquement, espaces de travail partagés uniquement, au plus 20 adresses par requête. Chaque adresse invitée avec succès reçoit un e-mail avec un lien d’invitation personnel (jeton tdminv_…). Réinviter une adresse émet un nouveau lien et invalide le précédent. La réponse détaille le résultat par adresse :

{
"results": [
{ "email": "person@example.com", "outcome": "INVITED" },
{ "email": "other@example.com", "outcome": "ALREADY_MEMBER" }
]
}

Résultats : INVITED, ALREADY_MEMBER, INVALID_ADDRESS. Erreurs : 400 pour un lot vide ou trop grand, 403 pour les membres simples ou quand l’espace de travail a déjà atteint sa limite de membres, 404 pour les non-membres.

GET /api/workspaces/invites/{token}

Nécessite une authentification, et l’invitation doit être adressée à l’adresse e-mail du compte connecté. Renvoie qui t’a invité :

{
"workspaceName": "Lengl Family",
"personal": false,
"ownerFirstName": "Greta",
"ownerLastName": "Lengl",
"ownerAvatarUrl": null
}

Les jetons inconnus, expirés ou destinés à quelqu’un d’autre sont indiscernables : tous renvoient 404.

POST /api/workspaces/join
{ "token": "tdminv_…" }
{ "workspaceId": "019f…", "newlyJoined": true }

newlyJoined vaut false si tu étais déjà membre.

La même règle personnelle s’applique : le jeton ne fonctionne que pour le compte avec l’adresse e-mail invitée, et il est consommé en cas de succès. Les jetons inconnus, expirés ou destinés à quelqu’un d’autre renvoient tous 404. Renvoie 403 quand l’espace de travail a atteint sa limite de membres — l’invitation reste valable et peut être retentée tant qu’elle n’a pas expiré.

GET /api/workspaces/{workspaceId}/sync?since={cursor}

Récupère tout ce qui a changé après le curseur du client, pour les clients capables de fonctionner hors ligne : les entités modifiées sous forme d’objets complets dans leur état actuel, les suppressions sous forme de listes d’ids, et le curseur suivant. since=0 renvoie l’espace de travail complet (le miroir initial). Appliquer un lot est un upsert idempotent : répéter des récupérations ou les faire se chevaucher est sans danger.

{
"cursor": 812,
"tasks": [ { "id": "019f…", "title": "…", "subtasks": [], "attachments": [] } ],
"deletedTaskIds": ["019f…"],
"lists": [],
"deletedListIds": [],
"members": [],
"deletedMemberIds": []
}
  • Les objets tâche ont la même forme que GET /api/workspaces/{id}/tasks ; les changements de sous-tâches et de pièces jointes apparaissent comme des changements de leur tâche parente.
  • Quand une liste est supprimée, ses tâches ne sont pas renvoyées : les clients effacent ce listId localement, comme le fait le serveur.
  • Les changements plus récents qu’environ une seconde sont déjà inclus dans le lot, mais le curseur s’arrête avant eux — la récupération suivante les livre à nouveau, et l’upsert idempotent absorbe la répétition. Un client qui interroge juste après sa propre écriture la voit donc toujours.
GET /api/workspaces/{workspaceId}/events

Un flux server-sent events qui signale que le contenu de l’espace de travail a changé — une sonnette, pas un flux de données : quand elle retentit, recharge ce dont tu as besoin.