ADR 0037 – Revue hebdomadaire guidée, prochaine action et fréquence de revue
Accepté (2026-10-16, mode autonome)
ADR 0037 – Revue hebdomadaire guidée, prochaine action et fréquence de revue
Statut : Accepté (2026-10-16, mode autonome)
La ligne « Revue hebdomadaire » du jalon 2 demandait une vue dédiée : en retard, sans échéance, projets sans prochaine action, inbox. La vague 1 (validée par Aurélien le 2026-10-15) y ajoute :
- un champ
revueTousLessurprojet(7 jours par défaut) et un bouton « Marquer revu » ; - une revue qui ne montre que les projets dus ;
- la prochaine action du projet (la première tâche ouverte par échéance, ou un champ) en haut de la fiche ;
- une revue guidée en étapes (inbox, retards, sans échéance, projets à revoir ou sans prochaine action, en attente), avec un compteur par étape et un résumé final.
Tout reste dans config/, et le moteur de vues (ADR 0028) porte chaque étape. Le code ne nomme ni projet, ni tache, ni echeance.
Décision
Prochaine action : clé nextAction d’un aspect
nextAction:
label: Prochaine action # défaut
field: prochaineAction # facultatif : référence forcée
from: tache.projet # candidats : nœuds dont ce champ référence pointe vers ce nœud
states: [a-faire, en-cours] # facultatif : états de workflow d'un candidat
sort: [tache.echeance asc, tache.priorite desc]
- Règle de choix. La prochaine action est le nœud du champ forcé, s’il existe, est hors corbeille et candidat. Sinon, c’est le premier candidat hors corbeille, trié par
sort(valeurs absentes en dernier, un texte sans casse, un enum dans l’ordre du schéma), puis par date de création et par id. - Candidat. Son état de workflow (aspect de
from) est l’un destates. Sansstates, il suffit qu’il soit absent ou non final (workflow.final, ADR 0026). Le projet déclarestates: [a-faire, en-cours]: une tâche en attente ou mise de côté n’est pas une prochaine action, et un projet qui n’a qu’elle reste « sans prochaine action » dans la revue (relevé en revue). - Champ calculé
<aspect>.nextAction. Le calcul est une sous-requête SQL corrélée, construite parViewSql. Elle a deux usages :- dans les vues : on peut filtrer (
projet.nextAction == null) et afficher le champ en colonne (typeREF, avec le titre de la cible dansViewResult.nodes). Il n’est ni triable ni modifiable. Le nomnextActionest réservé dans le schéma d’un aspect qui déclare la clé ; - sur la fiche :
NodeView.nextActionsdonne, pour chaque aspect porté qui déclare la clé, son libellé et son nœud (nul s’il n’y en a pas). La fiche l’affiche en bandeau sous le titre : un lien, ou « aucune · ajoutez une tâche ouverte ou choisissez-en une ».
- dans les vues : on peut filtrer (
- Contrôles au chargement, après la lecture de tous les aspects, puisque la clé en cite un autre :
fromest un champ référence d’un aspect chargé ;fieldest un champ référence de l’aspect ;statessont des états du workflow de l’aspect defrom; chaque clé desortest un champ triable de l’aspect defrom; le nomnextActionest libre. Un aspect fautif est ignoré et signalé, comme tout fichier invalide. Le contrôle est répété tant qu’un aspect est écarté, puisqu’un aspect écarté peut invalider ceux qui le citent. - Traduction tolérante. Une version gardée au rechargement n’est pas recontrôlée contre les aspects frais : une clé de tri devenue inconnue est ignorée, et un aspect de
fromdisparu donne « pas de prochaine action ». Il n’y a donc jamais d’erreur 500. - Index. Les candidats sont cherchés par contenance (
data @> {"projet": "<id>"}), que sert l’index GIN denode_aspect.data. Le champ forcé est comparé à l’id typé (un texte qui n’est pas un UUID est ignoré), que sert la clé primaire. - Pourquoi calculer plutôt que stocker. Une prochaine action matérialisée devrait être recalculée à chaque écriture de tâche (état, échéance, projet, corbeille). C’est le terrain des règles du jalon 3. La sous-requête reste exacte et s’appuie sur les index existants.
Fréquence de revue et « Marquer revu »
- Champs de
projet:revueTousLes(entier, de 1 à 365, défaut 7),derniereRevueetprochaineRevue(dates), etprochaineAction(référence forcée vers une tâche). - « Marquer revu » est un bouton de report (ADR 0025). Il écrit
derniereRevue: {{today}}etprochaineRevue: {{today + revueTousLes d}}. - Décalage nommé. Un bouton de report peut donner comme décalage un champ entier de son aspect :
{{today + revueTousLes d}}. La valeur est lue dans les données de l’aspect, ou dans ledefaultdu schéma pour un projet antérieur au champ (ou dont la valeur est nulle). Elle est bornée à 9999 comme un littéral : une donnée ancienne démesurée laisse la variable non résolue, et la validation la refuse (400). Un modèle ne peut pas utiliser de décalage nommé : il n’a pas de données d’aspect, et la variable y reste inconnue. Le décalage nommé est contrôlé au chargement ; pour la validation, chaque champ entier vaut 1. - Projet dû. La revue montre un projet actif dont
prochaineRevueest absente ou passée, ou qui n’a pas de prochaine action. Stocker la date de la prochaine revue garde la condition dans le langage de vue existant, sans arithmétique entre champs. En contrepartie, changerrevueTousLesne déplace pas la revue déjà prévue : la nouvelle fréquence s’applique au « Marquer revu » suivant, et la date reste modifiable à la main.
État « en attente » des tâches
L’étape « En attente » a besoin d’un état. tache.statut gagne donc en-attente (GTD : en attente de quelqu’un ou de quelque chose), qui est atteignable depuis et vers les états non terminés. Il n’est pas final. Le kanban « Tâches ouvertes » (ADR 0035) gagne la colonne correspondante, et sa condition inclut l’état : une carte glissée dans cette colonne reste sur le plateau.
Revues guidées : config/reviews/<name>.yaml
name: hebdomadaire
label: Revue hebdomadaire
icon: fact_check
description: …
steps:
- { label: Inbox, inbox: true, help: … }
- { label: En retard, view: revue-retards, help: … }
- Définition. Un nouveau type de définition, avec son méta-schéma (
review.schema.json, 12 étapes au plus) : chaque étape a soitinbox: true, soit le nom d’une vue chargée.GET /api/definitions/reviewsles liste par libellé. Au rechargement, une revue gardée de la version précédente est revalidée contre les vues. - Quatre vues ordinaires portent la revue hebdomadaire :
revue-retards,revue-sans-echeance,revue-projetsetrevue-en-attente. - Page
/reviews/:name, accessible par le menu « Vue », section « Revues » :- en tête, la liste des étapes, chacune avec son compteur, puis « Résumé ». Tous les comptes sont lus à l’ouverture, et celui d’une étape est relu à chaque passage ;
- une étape affiche sa consigne puis :
- pour l’inbox, ses 50 derniers éléments et « Trier dans l’inbox » ;
- pour une vue, ses lignes : badge de type, titre en lien, valeurs des colonnes en métadonnées et boutons de report des aspects de la vue que la ligne porte (« Demain », « Marquer revu »…). Un bouton dont le workflow interdit la transition depuis l’état affiché est désactivé ;
- après une action, l’étape est relue et l’action est annoncée (
role=status). Elle est relue aussi au retour sur l’onglet ; - « Étape précédente » et « Étape suivante » permettent de naviguer, et la dernière étape mène au résumé. Le résumé compare, étape par étape, le compte au début et le compte actuel, et signale les étapes vidées ;
- l’état survit à une visite de fiche. L’étape est dans l’URL (
?etape=), et les comptes du début sont gardés pour la session du navigateur, par revue. Ouvrir une ligne puis revenir ramène donc à la même étape, et le résumé compare toujours au vrai début. « Recommencer la revue » relit les comptes du début ; - accessibilité : un bouton de report que le workflow interdit depuis l’état affiché n’est pas montré. Après une action, le focus revient au titre de l’étape, car la ligne a pu disparaître. « (vidée) » est dit en texte, pas seulement par une icône.
- Pourquoi des boutons de report sur les lignes. Ils couvrent les gestes de la revue (replanifier, mettre de côté, marquer revu) sans quitter l’étape, et ils sont déclarés dans
config/. Classer l’inbox ou choisir une prochaine action reste dans la page Inbox et dans la fiche.
Reporté
- Arithmétique entre champs dans
where(derniereRevue <= today - revueTousLes d) : le décalage nommé suffit ici. - Création d’une tâche rattachée au projet depuis le bandeau « aucune prochaine action » :
/nodes/newne sait pas encore préremplir un champ référence. - Historique des revues (date et résumé de chaque revue faite), rappel hebdomadaire.
- Compteur des revues dans
GET /api/definitions/status.
Conséquences
- Tout nouveau parcours en étapes se décrit dans
config/reviews/avec des vues, sans code. - Le moteur de vues connaît un champ calculé. Les champs calculés à venir (rollups, jalon 3) suivront le même chemin : résolution par
Fields, SQL parViewSql, ni tri ni édition par défaut.