ADR 0038 – Dashboards déclaratifs, accueil « Aujourd'hui », filtres de vue, regroupement par jour, tâches débloquées
Accepté (2026-10-16, mode autonome)
ADR 0038 – Dashboards déclaratifs, accueil « Aujourd’hui », filtres de vue, regroupement par jour, tâches débloquées
Statut : Accepté (2026-10-16, mode autonome)
Décisions prises en mode autonome (vague 1 validée par Aurélien le 2026-10-15 : « vue Aujourd’hui comme accueil par défaut (retards, échéance aujourd’hui, récemment débloquées, inbox), bouton Replanifier les retards (aujourd’hui ou demain) » ; « contexte de tâche en énumération et vue Maintenant (contexte choisi, estimation ≤ 15 min), pensée pour le mobile » ; « vue Terminées groupée par jour »). S’appuie sur le moteur de vues (ADR 0028) et ses modes (ADR 0029, 0030, 0035).
Contexte
config/dashboards/accueil.yaml n’était qu’un exemple, jamais chargé ; l’accueil était une page provisoire. Le moteur de vues ne savait ni filtrer à la demande (choisir un contexte), ni regrouper par jour, ni parler des dépendances (ADR 0027, calculées seulement pour la fiche et l’arbre). Le raccourci PWA « Aujourd’hui » ouvre déjà / (ADR 0034).
Décision
Dashboards (config/dashboards/, méta-schéma dashboard.schema.json)
name: aujourdhui
label: Aujourd'hui
icon: today
default: true # accueil ; s'il y en a plusieurs, le premier par nom
widgets: # dans l'ordre ; width 1 (défaut) ou 2 colonnes de la grille
- { kind: view, view: revue-retards, label: En retard, limit: 10, reschedule: tache.echeance }
- { kind: view, view: echeance-aujourdhui, limit: 10 }
- { kind: view, view: recemment-debloquees, limit: 10 }
- { kind: inbox, limit: 5 }
- { kind: counter, view: factures-a-payer, label: Factures à payer }
- { kind: templates, templates: [tache-semaine, facture-papier], label: Créer }
- Quatre widgets :
view(premières lignes d’une vue, nombre total, lien « Tout voir »),counter(nombre de lignes d’une vue, « 1000+ » au-delà de la limite de la vue),inbox(nombre et derniers éléments à trier),templates(boutons de création depuis un modèle, ADR 0016). Les actions déclaratives restent au jalon 3. - Contrôles au chargement : vues et modèles connus,
reschedule= champ date d’un aspect (format: date). Un dashboard invalide est ignoré et signalé comme les autres définitions (santé de la configuration) ; la version précédente reste en service. GET /api/definitions/dashboards. Page/= dashboard par défaut,/dashboards/:namepour les autres ; sans dashboard, l’accueil provisoire reste.- Pas de grille libre (
col,row) : l’ordre de la liste etwidthsuffisent, et la grille passe à une colonne sur mobile.
« Replanifier les retards »
reschedule: <aspect>.<champ> sur un widget view affiche un menu « Replanifier : aujourd’hui | demain ». Le front écrit la date, calculée dans le fuseau du navigateur, sur chaque ligne de la vue qui porte l’aspect, par l’endpoint existant PATCH /api/nodes/{id}/aspects/{aspect} (validation, workflow et node_event déjà en place), quatre requêtes à la fois, puis relit le widget et affiche un bilan (« 5 tâches replanifiées », erreurs par tâche). Pas d’endpoint de lot : le volume est petit et chaque écriture garde ses contrôles.
Filtres de vue choisis par l’utilisateur
display.filters: [tache.contexte]: champs à valeurs fermées (enum, type, booléen). La page de la vue affiche un groupe de puces « Tous / maison / ordinateur… » par filtre ; le choix est mémorisé par vue dans le navigateur.GET /api/views/{name}/results?filter=tache.contexte:maison(répétable). Champ hors dedisplay.filtersou valeur hors des valeurs admises : 400errors.filter. Le filtre s’ajoute à la requête de la vue : égalité, valeur absente exclue pour un enum ou un type, booléen absent lu comme faux (même sémantique quewhere).ViewResult.filtersdécrit les filtres (clé, libellé, valeurs) etViewResult.appliedceux appliqués.
Regroupement par jour
display.groupByaccepte aussi un champ date ou date-heure (createdAt,updatedAt, champ d’aspect) en modetableoulist(pas en kanban). Le groupe est le jour, dans le fuseauzonede la requête ; les groupes sont les jours présents, dans l’ordre des lignes ;groupKind = DAY, jamais modifiable par déplacement.- Le front titre les groupes « Aujourd’hui », « Hier », puis « jeudi 15 octobre » (année ajoutée si elle diffère).
Champ de nœud unblockedAt
- Nouveau champ de nœud, utilisable dans
whereetsort(pas en colonne) : date-heure à laquelle la dernière dépendance du nœud s’est terminée, nulle si le nœud n’a pas de dépendance avec état ou si l’une d’elles bloque encore. Mêmes règles que l’ADR 0027 : liensblocking, cibles hors corbeille, état du premier aspect à workflow (ordre des noms), une cible sans état ne compte pas. - L’instant de fin est le
updated_atde la cible terminée la plus récente : une modification ultérieure de cette cible le déplace. C’est une approximation assumée ; le journal (node_event) permettra une date exacte plus tard. - Calcul en SQL par sous-requête corrélée, construite depuis les définitions chargées (types de liens bloquants, champ et états finals de chaque workflow), valeurs liées.
Configuration livrée
tache.contextedevient une énumération :maison,ordinateur,telephone,courses,dehors,bureau(sans accent, comme les autres valeurs) ;version: 2. Une ancienne valeur libre reste lisible (« tolérer à la lecture »).- Règle du moteur : à l’écriture d’un aspect déjà porté, une violation de schéma sur un champ de premier niveau dont la valeur n’a pas changé est tolérée. Ainsi une ancienne valeur devenue invalide ne bloque ni la replanification, ni le kanban, ni le passage à « fait » ; la modifier impose une valeur valide. Pas de migration de données : elle coderait le domaine en SQL.
- Vues : le widget « En retard » réutilise
revue-retardsde la revue hebdomadaire (ADR 0037), pour un même périmètre (tout sauf fait, abandonné, plus tard, « en attente » compris) ; nouvelles vuesecheance-aujourdhui(même périmètre),recemment-debloquees(7 jours),maintenant(liste, filtretache.contexte, tâches à faire ou en cours — « en attente » et « plus tard » ne se font pas tout de suite —, estimation ≤ 15 min ; une tâche qui commence plus tard est masquée pardeferUntil, ADR 0039),terminees(liste groupée par jour de modification, 30 derniers jours). accueil.yaml(exemple jamais chargé, qui citait des actions du jalon 3) est remplacé paraujourdhui.yaml.
Alternatives écartées
- Paramètres libres de vue (
{{contexte}}danswhere) : demande un langage de gabarits dans lewhereet un formulaire ; les filtres sur valeurs fermées couvrent le besoin et se valident simplement. - Endpoint de replanification en lot : une transaction unique serait plus atomique, mais dupliquerait validation, workflow et événements ; le volume est faible.
- Date de fin exacte par le journal : requiert une requête plus lourde sur
node_event; reporté. - Grille libre (
col,row) : inutile pour quelques widgets et pénible sur mobile. - Une vue par contexte : multiplie les fichiers et ne permet pas de choisir à la volée.
Conséquences
- L’accueil devient « Aujourd’hui » ; la capture rapide et le dépôt de fichiers restent en tête de page.
- Le statut de santé de la configuration lit désormais
dashboards/: ses fichiers sont « chargés » ou « ignorés », plus « pas encore lus ». ViewResultgagnefiltersetapplied;groupKindgagneDAY. Le client est régénéré.