Files
gestion_projets/README.md
Bertrand Benjamin 3092be86ae Piloter la frise au clavier, à la vim
Les flèches décalaient déjà une phase, mais rien ne permettait de la choisir :
`selection` n'était posée qu'au clic, si bien qu'il fallait la souris pour
commencer. Elle devient `curseur`, désigne une ligne — celle d'un projet en est
une, d'où l'on plie, renomme et ajoute — et survit à Échap, sans quoi elle ne
pourrait servir de point de départ au déplacement suivant. `dessiner` le
normalise, la ligne du projet servant de refuge quand la sienne disparaît.

Deux couches qui ne se recouvrent pas : les flèches modifient, les lettres
déplacent et commandent. Aucun raccourci documenté ne change de sens. Les
touches se taisent dès que le clavier est à quelqu'un d'autre — une saisie, un
dialogue, le menu, un glisser —, faute de quoi `a` dans un nom créerait une
phase. AltGr est toléré : sur un clavier français `{` et `}` n'existent qu'avec
lui, et Windows le présente comme Ctrl+Alt.

Les phases étant triées par date, `o` et `O` insèrent dans le temps et non dans
un rang. `P` reste hors de cette famille : un projet naît sans position.

Le curseur se peint dans la colonne des libellés, seul endroit qui porte une
ligne pour chaque position atteignable — projet plié, projet masqué, ligne de
projet. Et `?` ouvre la table des raccourcis, qui ne se devinent pas.

Décision 26.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 10:36:07 +02:00

18 KiB

Frise multi-projets

Un outil de planification macro : voir sur une seule frise chronologique où en est chaque projet, quelles sont ses grandes phases, et comment les projets se situent les uns par rapport aux autres.

Ce n'est pas un outil de suivi quotidien : pas de sous-tâches, pas de tickets, pas de checklists. Une phase représente plusieurs semaines ou plusieurs mois de travail.

Démarrer

Récupérer le binaire de sa plateforme, le poser dans un dossier avec son planning, et le lancer — par un double-clic ou en ligne de commande :

./frise

Le navigateur s'ouvre tout seul. Rien à installer : l'interface est embarquée dans l'exécutable, qui ne dépend d'aucune bibliothèque système — pas même de la glibc. Il tourne tel quel sur n'importe quelle distribution, et sur une machine sans Python ni Node.

Par défaut, le planning est le fichier projets.json posé à côté de l'exécutable. C'est ce qui permet de déposer les deux dans un dossier synchronisé (Dropbox, Nextcloud, Syncthing) et de retrouver son outil et ses données sur n'importe quelle machine.

📁 Mon dossier synchronisé
   ├── frise            ← l'exécutable
   └── projets.json     ← le planning

Options :

./frise --port 9000                  # imposer un port (sinon : le premier libre à partir de 8000)
./frise --data ~/plannings/2027.json # ouvrir un autre fichier
./frise --no-browser                 # ne pas ouvrir le navigateur

Au premier lancement, le planning est vide et aucun fichier n'est créé tant qu'on n'a rien saisi. Pour découvrir l'outil sur des données réalistes, copier data/exemple.json en projets.json à côté de l'exécutable.

Compiler soi-même

./build.sh          # les cinq plateformes, dans dist/
./build.sh local    # seulement la machine courante

Il faut Go 1.22 ou plus récent, et rien d'autre : aucune dépendance externe, aucun vendor/. Les binaires des trois systèmes se produisent depuis une seule machine, sans intégration continue ni SDK tiers.

Développer

go run . --dev

Le mode --dev sert index.html, css/ et js/ depuis le disque plutôt que depuis le binaire : un simple rafraîchissement suffit à voir ses modifications, sans recompiler. Il lit alors data/projets.json, comme avant.

go test ./...       # le serveur
node --test tests/  # le modèle métier

Prise en main

Nouveau projet crée le projet aussitôt, sous un nom provisoire, et ouvre ses paramètres avec ce nom présélectionné : on tape simplement par-dessus. Il n'y a aucun formulaire à valider — ni ici, ni pour une phase. Tout s'applique au fil de la saisie, et un projet créé par erreur se supprime depuis son propre panneau.

Dans la colonne de gauche, le triangle plie et déplie le couloir d'un projet, et un clic sur son nom ouvre ses paramètres : nom, couleur, tags. Deux commandes apparaissent au survol de la ligne, sur son bord droit :

  • + ajoute une phase à la suite de la dernière, et ouvre son panneau de détail ;
  • ouvre le menu du projet : ajouter une phase, plier, masquer de la frise, renommer, figer la référence, supprimer. Un clic droit sur le libellé ouvre le même menu.

Il n'y a pas de commande séparée pour créer un jalon : c'est une phase dont on coche la case « Jalon » dans le panneau, ce qui ramène sa fin sur son début. La bascule joue dans les deux sens à tout moment.

La colonne se redimensionne en glissant la ligne qui la sépare de la frise, en haut à gauche : un double-clic revient à la largeur d'origine. Cette largeur est propre au navigateur, elle n'est pas enregistrée dans le planning.

Une fois un projet en place :

Geste Effet
Glisser le corps d'une barre Décale la phase, durée conservée
Glisser le bord d'une barre Change la date de début ou de fin
Glisser le bord gauche du panneau Change sa largeur (double-clic : d'origine)
Clic sur une barre ou son nom Ouvre le panneau de détail
Clic sur une autre barre, panneau ouvert Bascule le panneau sur cette phase
Clic sur un nom de phase hors écran Ramène la frise sur elle
Décale d'un jour la phase du curseur
Maj + Allonge ou raccourcit d'un jour
Échap Annule le glisser en cours, ou ferme le panneau
Clic dans une zone vide Ferme le panneau ouvert
Maj + molette Fait défiler la frise horizontalement
dans un menu Parcourt les entrées

Faire défiler jusqu'au bord droit élargit la frise vers le futur, et jusqu'au bord gauche vers le passé. Le bouton Aujourd'hui ramène la vue sur la date du jour.

Au clavier, à la vim

La frise a un curseur : la ligne sur laquelle portent les raccourcis. Il se pose en cliquant une barre ou un nom, ou à la première frappe de j, et il se voit à la ligne bleutée dans la colonne de gauche. Il tient aussi sur la ligne d'un projet, position d'où l'on plie, renomme et ajoute.

Le bouton ? de la barre d'outils, ou la touche ?, ouvre la liste complète. En résumé :

Touche Effet
j k Ligne suivante, précédente — projets traversés
h l Phase précédente, suivante du même projet, sans déborder sur le voisin
{ } Projet précédent, suivant
gg G Première, dernière ligne
Entrée e Ouvre le volet sur la ligne du curseur et saisit le nom
Espace Statut suivant : à venir, en cours, terminé, bloqué
A a Ajoute une phase à la fin, au début du projet
o O En ajoute une juste après, juste avant celle du curseur
P Ajoute un projet
dd Supprime la phase — ou le projet depuis sa ligne
za Plie ou déplie le projet
zR zM Déplie tout, plie tout
zz Recentre la frise sur le curseur
w b Un mois plus tard, plus tôt
W B Un an plus tard, plus tôt
ga Revient à aujourd'hui
gm Bascule entre la frise et la vue par mois

Les phases étant rangées par date, o et O insèrent dans le temps et non dans une liste : la nouvelle phase se pose bord à bord avec sa voisine. P, lui, ne dépend pas du curseur : un projet naît hors de toute ligne, et la vue revient à la frise si on était dans la liste par mois.

Deux garde-fous. Ces touches se taisent pendant une saisie — dans un champ, une note, un dialogue ou le menu contextuel, elles écrivent la lettre qu'elles portent. Et dd demande toujours confirmation, comme le bouton Supprimer.

Le volet ouvert suit le curseur : j et k font alors défiler les phases une à une dans le panneau de détail, ce qui est le moyen le plus rapide de relire tout un projet. Pour cela, ouvrir le volet d'un clic sur une barreEntrée et e, eux, placent la frappe dans le champ « Nom », où les raccourcis se taisent.

Échap referme le volet sans déplacer le curseur, et la frappe suivante repart de là.

Les notes

Un projet et une phase portent chacun des notes, en bas de leur panneau. Elles y prennent toute la hauteur restante : les autres champs ont une taille dictée par leur contenu, une note fait ce qu'on a à dire.

Le texte s'écrit en markdown — titres, **gras**, *italique*, listes, - [ ] cases à cocher, liens, citations, blocs de code. Le bloc s'ouvre sur l'aperçu quand la note existe déjà, sur la saisie quand elle est vide ; le crayon en haut à droite bascule d'un état à l'autre, et une barre de six boutons paraît en saisie (Ctrl+B et Ctrl+I marchent aussi). Rien n'est converti à l'enregistrement : le fichier contient le markdown tel quel, lisible et modifiable à la main.

Les cases à cocher se cliquent directement dans l'aperçu — c'est le seul geste de l'aperçu qui change les données. Cocher une ligne ne touche à rien d'autre : votre mise en forme n'est jamais réécrite.

Les notes d'un projet sont ce que la frise ne sait pas dire — qui pilote, sur quel budget, quelle décision à quelle date. Elles se lisent aussi au survol du nom du projet dans la colonne de gauche, et celles d'une phase au survol de sa barre : l'infobulle les affiche sans les marques de mise en forme, puces et cases dessinées comprises.

Le panneau se redimensionne en glissant son bord gauche, comme la colonne des projets ; un double-clic revient à la largeur d'origine. Cette largeur est propre au navigateur, elle n'est pas enregistrée dans le planning.

La vue par mois

Les deux boutons Frise et Par mois, en haut à gauche, changent de regard sur les mêmes données. La vue par mois déroule toutes les tâches et tous les jalons du planning en une seule liste, projets mêlés, groupés par mois — celui où chaque phase commence. C'est la réponse à « qu'est-ce qui arrive le mois prochain », que la frise donne mal parce qu'elle sépare les projets en couloirs.

Chaque ligne se lit dans cet ordre : quand — la période, 31 → 13 nov. quand la phase déborde du mois —, chez qui — le projet et ses tags —, puis quoi — l'intitulé de la tâche ou du jalon — et enfin son statut. Une phase longue n'est pas répétée dans les mois qu'elle traverse : elle n'apparaît qu'à son mois de départ, avec sa date de fin écrite en clair.

Les phases qui portent des notes le signalent par un triangle en tête de ligne, le même que celui qui plie un projet sur la frise. Un clic n'importe où sur la ligne déplie la note en dessous, un second la referme. Elle s'y affiche rendue, comme dans le panneau. Rien n'est affiché d'office — trois lignes de notes sous chaque intitulé étaleraient un mois sur deux écrans.

Cette liste se lit — elle ne s'édite pas. Déplacer une phase demande de voir ce qu'elle chevauche, donc la frise ; c'est là que les dates et les notes se modifient. Seuls les tags et les notes y sont cliquables, et ni filtrer ni déplier ne touche aux données — les cases à cocher d'une note y sont d'ailleurs inertes, elles ne se cochent que depuis le panneau. Le bouton Aujourd'hui ramène ici sur le mois en cours, et la vue affichée n'est pas mémorisée : l'outil s'ouvre toujours sur la frise.

Filtrer par tag

Un projet peut porter des tagsclient, interne, R&D —, saisis séparés par des virgules dans le dialogue « Renommer, changer la couleur… ». Il n'y a pas de liste à tenir : les tags existants sont proposés en un clic, et un tag disparaît dès que plus aucun projet ne le porte.

Ils s'affichent en petites pastilles colorées dans la colonne de gauche, et une barre de filtres apparaît sous la barre d'outils dès qu'un tag existe. Cliquer un tag — dans la barre de filtres ou directement sur la pastille d'un projet — restreint la frise à ceux qui le portent ; recliquer le retire. Le filtre vaut pour les deux vues : il ne change pas quand on passe de la frise à la liste par mois.

Cocher plusieurs tags cumule les conditions : client + urgent ne montre que les projets portant les deux. Le filtre n'est pas enregistré, il ne vaut que pour la session en cours. Le bouton Tout afficher le vide d'un coup.

Les barres s'accrochent au lundi pendant le glisser. Pour une date au jour près, passer par les champs du panneau de détail.

Ce que fait l'outil

  • Plusieurs projets, chacun décomposé en phases ayant un nom, des dates de début et de fin, un statut, des notes. Une phase peut être un jalon (une date unique, rendue en losange).
  • Des notes en markdown, sur un projet comme sur une phase : titres, listes, cases à cocher, liens. Elles occupent toute la hauteur restante du panneau, et se cochent d'un clic dans l'aperçu.
  • Une frise commune, les projets empilés en couloirs, pour les comparer d'un coup d'œil.
  • Une barre cumulative par projet, segmentée en teintes selon le statut de chaque phase : la forme d'ensemble, toujours visible sur la ligne du projet et toujours rendue pareil. Elle ne se glisse pas.
  • Couloirs pliables : déplié, chaque phase occupe sa ligne sous la barre cumulative ; plié, il ne reste que celle-ci.
  • Manipulation directe : glisser une barre pour la décaler, tirer ses bords pour changer sa durée. Les barres s'accrochent au lundi ; pour une date exacte, on passe par le panneau de détail.
  • Planning de référence : une fois le planning validé, on le fige. La frise affiche alors une barre fantôme sous la barre réelle et la dérive en semaines — de quoi répondre à « ce projet a-t-il glissé, et de combien ? ».
  • Un en-tête à trois niveaux — année, mois, numéro de semaine ISO — qui donne le repère temporel sans jamais descendre au jour : à cette échelle, la semaine suffit. Il n'y a qu'une seule échelle, donc aucun réglage de zoom à comprendre.
  • Une frise sans fin : elle s'élargit d'elle-même quand le défilement approche d'un bord, ce qui permet d'aller planifier dans un futur qu'aucune phase n'occupe encore.
  • Une vue par mois : toutes les tâches et tous les jalons en une liste, projets mêlés, groupés par mois de début. Elle se lit, elle ne s'édite pas.
  • Des tags sur les projets, et un filtre qui restreint les deux vues à ceux qui les portent tous.
  • Repère « aujourd'hui » et masquage d'un projet.

Ce que l'outil ne fait pas

Volontairement : pas de dépendances entre phases, pas de sous-tâches, pas de collaboration temps réel, pas d'authentification, pas de gestion de charge par personne, pas de notifications.

Les durées se comptent en jours calendaires : ni week-ends ni jours fériés ne sont gérés. À l'échelle de phases de plusieurs semaines, la distinction n'apporte rien.

Les raisons derrière ces choix sont détaillées dans docs/decisions.md.

Où vivent les données

Tout tient dans un fichier JSON, data/projets.json, décrit dans docs/modele-donnees.md. Il est indenté et utilise des identifiants parlants (site-web, cadrage) plutôt que des UUID : il reste éditable à la main et lisible dans un diff git.

À l'ouverture, le serveur copie le planning dans un dossier backups/ voisin, horodaté : c'est l'état d'avant la séance, celui qu'on veut retrouver si elle tourne mal. Si le serveur reste allumé plusieurs jours, une copie est reprise au plus une fois par jour. Rouvrir l'outil sans avoir rien modifié ne laisse pas de trace.

Cinquante sauvegardes sont conservées, les plus anciennes étant supprimées au fil de l'eau. Comme elles valent une par séance et non une par modification, cela représente des mois d'historique plutôt que la dernière demi-heure.

Pour restaurer, arrêter frise et fermer l'onglet d'abord : l'application garde son planning en mémoire et sa prochaine sauvegarde écraserait ce qu'on vient de remettre en place.

ls -lt backups/                          # repérer la version voulue
cp backups/projets-20260801-170352.json projets.json

Le planning n'est pas versionné : .gitignore exclut projets.json, ce dépôt ne contenant que le code. Seul data/exemple.json y figure, comme jeu de démonstration.

Pour synchroniser plusieurs machines, déposer l'exécutable et son projets.json dans un espace synchronisé. L'option --data accepte n'importe quel chemin, le planning peut donc aussi vivre ailleurs que le binaire.

Deux frictions propres à ce mode de distribution, qui touchent tout exécutable et pas seulement celui-ci : le bit d'exécution n'est pas toujours préservé par la synchronisation (chmod +x frise une fois par machine), et un binaire non signé déclenche un avertissement au premier lancement — SmartScreen sous Windows, Gatekeeper sous macOS.

L'outil ne gère pas les conflits — si deux machines modifient le planning en même temps, la dernière écriture l'emporte. Les sauvegardes horodatées de data/backups/ sont le filet de sécurité.

Tests

node --test    # la logique métier
go test ./...  # le serveur

Côté navigateur : validation des dates, bornes d'un projet, calcul de dérive, génération des identifiants, normalisation et filtrage des tags, regroupement des phases par mois. Côté serveur : lecture et écriture du planning, refus des corps invalides, rotation des sauvegardes, écriture atomique, résolution du chemin de données. Aucune dépendance de part ni d'autre, les lanceurs intégrés à Node et à Go suffisent.

Organisation du code

Fichier Rôle
main.go Sert l'interface embarquée, expose GET/PUT sur /api/data, écrit les sauvegardes
build.sh Compile les binaires des cinq plateformes dans dist/
js/model.js Données et règles métier : CRUD, validation, bornes, référence, dérive, tags, regroupement par mois
js/storage.js Dialogue avec le serveur, sauvegarde debouncée, indicateur d'état
js/timeline.js Rendu de la frise : échelle, couloirs, barres, jalons, pli/dépli, curseur
js/mois.js Rendu de la vue par mois : groupes, lignes, ancrage sur le mois courant
js/tags.js Pastilles de tags, partagées par les deux vues
js/drag.js Glisser et redimensionner les barres
js/clavier.js Table des raccourcis à la vim, préfixes g z d, garde-fou de saisie
js/markdown.js Analyse du markdown des notes, aplatissement pour les infobulles. Sans DOM, donc testable sous Node
js/notes.js Rendu du markdown en DOM et bloc de notes — aperçu, barre d'outils, saisie — partagé par les deux panneaux
js/detail.js Panneau de détail d'une phase
js/projet.js Panneau des paramètres d'un projet : nom, couleur, tags, notes
js/menu.js Menu contextuel et dialogue de confirmation
js/app.js Amorçage, état en mémoire, câblage des événements

Le rendu utilise des éléments DOM positionnés en absolu, pas de SVG ni de bibliothèque Gantt.

Les identifiants de code et les clés JSON sont en anglais ; l'interface, les commentaires et la documentation sont en français.