ADR 0049 – Annuler partout
Accepté (2026-10-16, mode autonome)
ADR 0049 – Annuler partout
Statut : Accepté (2026-10-16, mode autonome)
Item 18 du jalon 3 (vague 2 du document d’idées) : toute écriture faite en un geste peut être défaite tout de suite, sans boîte de confirmation.
Contexte
- Les actions en lot (ADR 0041) proposent déjà « Annuler » pendant 10 secondes. Le serveur garde ce qu’il faut pour les défaire : données de l’aspect, tags, parent, inbox. Un jeton à usage unique vit 30 minutes en mémoire.
- « Classé » dans l’inbox propose aussi « Annuler ».
- Les autres gestes écrivent sans retour possible :
- action rapide d’une ligne de vue, ou d’une fiche (« Demain », « Payée aujourd’hui ») ;
- édition d’une cellule ;
- déplacement d’une carte du kanban ;
- déplacement d’un nœud ;
- mise à la corbeille.
- Il n’existe aucun moyen de sortir un nœud de la corbeille.
Décision
-
Un seul chemin : ces gestes passent par l’API des lots, avec un seul nœud (
POST /api/nodes/bulk).- Le serveur garde ainsi de quoi les défaire, avec la même règle que les lots : retour sans contrôle du workflow, puisqu’on revient à un état qui a existé.
- Seuls les champs écrits reviennent : ceux de la demande pour une modification, ceux que l’action a changés pour une action rapide. Les autres champs de l’aspect gardent leur valeur du moment. Annuler le statut d’une ligne ne défait donc pas la priorité modifiée juste avant, ni une échéance écrite ensuite. Cette règle vaut aussi pour les lots (amendement de l’ADR 0041).
- Pas de second mécanisme d’annulation, pas d’endpoint dupliqué. Les endpoints d’origine (
PATCH …/aspects/{a},…/actions/{i},PUT …/parent,DELETE) restent pour les autres clients.
-
Corbeille : nouvelle opération de lot
TRASH.- Son annulation appelle
NodeService.restore: le nœud sort de la corbeille avec ses aspects, liens, fichiers et sa place, qui n’avaient pas bougé. L’événementnode.restoredest journalisé. - Un nœud qui n’est plus en corbeille n’est pas « rétabli » : l’annulation le compte dans ses refus (« Ce nœud n’est plus dans la corbeille »).
- Son annulation appelle
-
Front :
UndoableWrites.apply(id, opération, { done, afterUndo })écrit, puis affichedoneavec « Annuler » pendant 10 secondes.- « Annuler » défait l’écriture et appelle
afterUndo: la vue se relit, la carte revient, la fiche se rouvre ou relit sa place. - Un refus du serveur (transition, condition, nœud introuvable) devient une erreur
WriteRefused, affichée là où l’était l’erreur d’avant. - Une annulation impossible le dit : « Annulation impossible : … ».
- Une écriture sans effet (« Demain » déjà à demain) est confirmée sans « Annuler ».
- « Annuler » défait l’écriture et appelle
-
Fiche : après une action rapide ou un déplacement, la fiche relit le nœud, que l’API des lots ne renvoie pas. Après « Annuler » d’une action rapide :
- sans saisie en cours, toute la fiche est relue ;
- avec une saisie en cours, seule la section de l’aspect touché est remplacée, et l’état enregistré mis à jour : l’enregistrement suivant ne réécrit pas la valeur annulée ;
- si cette section a elle-même été modifiée, la saisie est gardée et un message demande de la vérifier avant d’enregistrer.
Après « Annuler » d’un déplacement, seuls le parent et le fil d’Ariane sont relus.
Ce qui reste sans « Annuler »
- L’enregistrement de la fiche : plusieurs aspects, titre, corps. Il peut toucher beaucoup de choses à la fois. L’historique du nœud garde chaque champ avant et après ; Ctrl+Z reste disponible dans l’éditeur tant que la page n’est pas quittée.
- Changer le type / « Classer comme… » : des aspects peuvent être ajoutés ou retirés. Un retour fidèle demanderait une opération dédiée.
- Liens et fichiers : le retrait d’un fichier est déjà confirmé. Les liens se recréent en un geste.
- La suite d’une tâche récurrente : terminer une tâche récurrente crée l’occurrence suivante (ADR 0046). « Annuler » rouvre la tâche, mais l’occurrence créée reste ; si on termine à nouveau, elle n’est pas recréée. L’annonce « Occurrence suivante créée » remplace la notification « Annuler », car une seule notification est visible à la fois. On rouvre alors la tâche par son statut.
Alternatives écartées
- Un jeton d’annulation renvoyé par chaque endpoint : il faudrait changer six contrats et dupliquer la garde de l’état d’avant.
- Une pile d’annulation côté front (rejouer l’inverse) : le front ne connaît pas toujours l’état d’avant (valeurs calculées, actions rapides à variables). Le retour passerait de plus par le workflow, qui peut refuser le chemin inverse (annuler « abandonnée »).
- Une page Corbeille : utile, mais c’est une autre fonctionnalité.
restoreen sera la base.
Conséquences
- « Annuler » vaut 10 secondes à l’écran, et le jeton 30 minutes en mémoire du serveur. Un redémarrage le perd (ADR 0041).
- Une seule notification est visible à la fois : un nouveau geste remplace le « Annuler » du précédent, lot ou inbox compris. Dans une vue, terminer une tâche récurrente garde son « Annuler » (l’occurrence suivante n’y est pas annoncée), contrairement à la fiche.
- Les messages de refus d’une écriture unique perdent le libellé du champ que donnait
describeApiError. Les messages de règle métier et de workflow sont déjà des phrases complètes.