All checks were successful
Build / build (push) Successful in 1m2s
Statut : quatre boutons peints de leur texture, si bien que le panneau sert enfin de légende. « En cours » se raye et « terminé » redevient vif — la trame les distingue, la teinte n'a plus à le faire. Date imposée : un cadre tireté cerne la forme entière. Les taquets tombaient sous les poignées de redimensionnement et disparaissaient sur une barre courte. Son libellé passe dans le modèle, ce qui la fait apparaître dans la vue par mois, qui la taisait. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
487 lines
28 KiB
Markdown
487 lines
28 KiB
Markdown
# 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 :
|
||
|
||
```sh
|
||
./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 :
|
||
|
||
```sh
|
||
./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
|
||
|
||
```sh
|
||
./build.sh # les cinq plateformes, dans dist/
|
||
./build.sh local # seulement la machine courante
|
||
```
|
||
|
||
Il faut [Go](https://go.dev) 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
|
||
SDK tiers.
|
||
|
||
Une pipeline Gitea rejoue les mêmes commandes à chaque poussée sur `main` — `node --test`, puis
|
||
`./build.sh` — et dépose les cinq binaires en artefacts de l'exécution, à récupérer depuis
|
||
l'onglet **Actions**. Elle ne remplace pas la compilation locale, elle la vérifie : rien
|
||
n'oblige à passer par elle pour produire un exécutable.
|
||
|
||
### Développer
|
||
|
||
```sh
|
||
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.
|
||
|
||
```sh
|
||
go test ./... # le serveur
|
||
node --test # 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.
|
||
|
||
Il naît **envisagé** : sans phase, avec pour seul ancrage un horizon d'un mois, celui où on le
|
||
crée. On le repousse à sa place, et on l'engage le jour où on lui donne des dates fermes — voir
|
||
[le cycle de vie](#le-cycle-de-vie-dun-projet) juste en dessous.
|
||
|
||
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, horizon. 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,
|
||
déclarer terminé, écarter, 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** ni pour marquer une **date imposée** : ce
|
||
sont deux cases du panneau de la phase, indépendantes l'une de l'autre comme du statut. Cocher
|
||
« Jalon » ramène la fin sur le début, cocher « Date imposée » encadre les deux champs de date d'un
|
||
trait tireté — le même qu'on verra sur la barre. Les deux bascules jouent dans les deux sens à tout
|
||
moment.
|
||
|
||
Le **statut** se choisit sur quatre boutons, chacun peint de la texture qu'il donne à la barre. Deux
|
||
traits suffisent à les lire : c'est **plein** quand rien ne bouge et **rayé** quand quelque chose se
|
||
passe ; c'est la **couleur pleine** du projet dès qu'une phase a commencé, et une teinte **diluée**
|
||
tant qu'elle n'a pas commencé. D'où : à venir pâle et bordé, en cours plein et rayé, terminé plein et
|
||
nu, bloqué rayé de rouge — seule teinte étrangère, parce que c'est la seule chose qui ne parle pas
|
||
d'avancement. La couleur reste celle du projet : elle distingue les couloirs, jamais l'avancement. Le
|
||
panneau sert ainsi de légende — il n'y en a pas d'autre, et il n'y a rien à apprendre avant de s'en
|
||
servir.
|
||
|
||
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 la barre résumé d'un projet | Repousse le projet entier, écarts conservés |
|
||
| Glisser la barre pâle d'un envisagé | Décale son horizon, au mois |
|
||
| 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 — ou tout le projet, sur sa ligne |
|
||
| `Maj` + `←` `→` | Allonge ou raccourcit la phase 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.
|
||
|
||
### Repousser un projet en bloc
|
||
|
||
Un projet engagé glisse dans le temps — c'est même ce qui arrive le plus souvent. Plutôt que de
|
||
reprendre ses phases une à une, on **glisse sa barre résumé** : le même nombre de jours s'applique à
|
||
toutes, jalons compris, et les écarts entre elles sont conservés au jour près. Le projet est
|
||
repoussé, il n'est pas replanifié. Les flèches `←` `→` font la même chose au jour près, curseur posé
|
||
sur la ligne du projet.
|
||
|
||
**Ce qui est terminé ne bouge pas.** Les phases finies restent où elles sont : décaler un projet,
|
||
c'est reconnaître qu'il prendra plus de temps, pas réécrire ce qu'on a déjà vécu. Sur un projet à
|
||
moitié fait, la barre s'étire donc au lieu de se déplacer — son bord gauche tient et le reste s'en
|
||
va. Un projet dont tout est terminé n'offre aucune prise, et son infobulle le dit.
|
||
|
||
**Ce dont on ne décide pas non plus.** Une phase peut porter une **date imposée** : elle est
|
||
déléguée à quelqu'un d'autre, ou tenue par un contrat, un créneau, une échéance réglementaire. La
|
||
case se coche dans son panneau, sous « Jalon », et sa forme se cerne alors d'un **trait tireté** —
|
||
une barre comme un losange, et jusqu'aux deux champs de date du panneau. À ne pas confondre avec le
|
||
contour plein de la phase sélectionnée : celui-ci est dedans et discontinu, celui-là dehors et
|
||
franc. Repousser le projet ne la repousse pas : si tout le reste
|
||
glisse, c'est le créneau qu'on rate, et le chevauchement qui apparaît est justement ce qu'on voulait
|
||
voir. Elle reste glissable seule, elle : « imposée » veut dire *indépendante du projet*, pas
|
||
*immuable*.
|
||
|
||
À ne pas confondre avec le statut **bloqué**, son voisin dans le panneau : bloqué dit que ça
|
||
n'avance pas, date imposée que l'échéance ne vous appartient pas. Une phase peut être les deux.
|
||
|
||
Le **planning de référence ne suit pas** : repousser de trois semaines affiche aussitôt une dérive
|
||
de trois semaines. C'est voulu — le geste inscrit ce qu'il coûte.
|
||
|
||
### Le cycle de vie d'un projet
|
||
|
||
On a presque toujours plus de projets imaginables que de temps pour les mener, et l'enjeu n'est pas
|
||
de les oublier en attendant. Un projet traverse donc quatre états, dont **deux se déduisent tout
|
||
seuls** — il n'y a rien à tenir à jour :
|
||
|
||
| État | Comment on le sait |
|
||
|---|---|
|
||
| **Envisagé** | il n'a qu'un horizon, pas encore de phase |
|
||
| **Engagé** | on lui a donné au moins une phase datée |
|
||
| **Terminé** | toutes ses phases sont finies **et** on l'a acté |
|
||
| **Écarté** | on a décidé de ne pas le faire |
|
||
|
||
Le flux tient en une phrase : **une idée entre avec un horizon, on la situe, on l'engage en lui
|
||
donnant des dates, elle vit sur la frise, elle s'achève ou on l'écarte.**
|
||
|
||
Engager n'est donc pas un bouton, c'est un geste : ajouter la première phase. Terminer et écarter,
|
||
eux, s'actent — livré n'est pas clos, et abandonner est une décision. Leurs deux commandes sont au
|
||
bas du **panneau du projet**, sous le champ qui dit où il en est, et aussi dans son menu **`⋯`**.
|
||
|
||
**Déclarer un projet terminé termine aussi toutes ses phases**, jalons compris : sans quoi la frise
|
||
se contredirait, avec des tâches « à venir » dans un projet fini. C'est la seule opération du cycle
|
||
qui écrase quelque chose — le statut d'une phase bloquée est perdu, et rouvrir le projet ne le
|
||
rendra pas. Elle demande donc confirmation, mais seulement s'il reste des phases à changer.
|
||
|
||
#### L'horizon
|
||
|
||
Un projet envisagé n'est jamais hors du temps : il porte un **horizon en mois** — « mars 2027 »,
|
||
« de mars à septembre 2027 », « courant 2028 » — et il se pose **sur la frise**, à cet horizon.
|
||
C'est là que l'arbitrage devient concret : quand le printemps 2027 est déjà chargé et que six
|
||
barres pâles s'y superposent, on décide devant l'évidence.
|
||
|
||
Sa barre est hachurée et ses bords sont fondus, parce que ces dates ne sont pas fermes. Elle se
|
||
glisse et se redimensionne comme une barre de phase, mais **accrochée au mois** là où celle d'une
|
||
phase l'est au lundi : le geste est possible, il ne permet simplement pas de poser une date qu'on
|
||
n'a pas. Le panneau du projet offre en plus trois crans — `−3 mois`, `+3 mois`, `+1 an` — et les
|
||
deux mois au clavier.
|
||
|
||
La largeur de la barre *est* l'incertitude, et elle se resserre à mesure que le projet mûrit :
|
||
d'abord une plage large, puis un mois, puis les dates fermes de l'engagement.
|
||
|
||
**Engager démarre à l'horizon** : la première phase d'un projet envisagé naît au premier jour de son
|
||
horizon, là où la barre pâle commençait. On précise ensuite ses dates comme n'importe quelle phase.
|
||
|
||
Un projet dont l'**horizon est passé** — ou qui n'en a jamais eu — le dit sur sa ligne, par une
|
||
pastille **« à dater »**. C'est ce qui empêche la liste des envisagés de devenir une décharge : on
|
||
repousse, ou on écarte, mais on ne laisse rien dormir.
|
||
|
||
#### Écarter n'est pas supprimer
|
||
|
||
Un projet écarté quitte la frise, mais il garde tout — notes comprises, où l'on aura écrit
|
||
pourquoi on a dit non. Les mêmes idées reviennent tous les deux ans, portées par d'autres, et
|
||
savoir qu'on les a déjà examinées vaut mieux que de refaire le débat.
|
||
|
||
On le retrouve en cochant **Écartés** dans la barre *Afficher*, et **Remettre en jeu** l'en sort. Il
|
||
n'y a alors aucune destination à choisir : le projet retrouve seul l'état que ses données
|
||
commandent — engagé s'il a des phases, envisagé sinon. Son horizon étant resté celui d'avant, il
|
||
réclamera aussitôt une date, et c'est voulu.
|
||
|
||
### 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 barre** — `Entré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.
|
||
|
||
Les **projets sans phase** y figurent aussi, au premier mois de leur horizon : un projet visé pour
|
||
mars 2027 arrive bel et bien en mars 2027, et la liste répond à « qu'est-ce qui arrive », pas à
|
||
« qu'est-ce qui est déjà décidé ». Leur ligne occupe les mêmes colonnes, en italique, et porte
|
||
« Envisagé » là où les autres portent leur statut. Un projet **écarté** avant d'avoir jamais été
|
||
engagé s'y retrouve de la même façon — barré, et seulement si l'on a coché *Écartés*.
|
||
|
||
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.
|
||
|
||
La petite marque en tête de ligne reprend les formes de la frise — barre pour une tâche, losange pour
|
||
un jalon, texture du statut, cadre tireté pour une **date imposée**. C'est ici qu'elle compte le
|
||
plus : une liste d'échéances doit dire lesquelles ne vous appartiennent pas.
|
||
|
||
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 **tags** — `client`, `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.
|
||
|
||
### Afficher par état
|
||
|
||
Une seconde barre, **Afficher**, paraît au-dessus dès que le planning compte plus d'un état. Elle
|
||
montre chacun avec son compte — *Envisagés (4)*, *Écartés (7)* — et un clic l'affiche ou le masque.
|
||
Les écartés en sont décochés au départ : le cimetière ne s'ouvre que si on le demande.
|
||
|
||
Elle ne joue **pas** dans le même sens que le filtre par tags, et c'est pourquoi elle ne lui
|
||
ressemble pas : un projet porte plusieurs tags mais un seul état, si bien que cocher un tag de plus
|
||
resserre la sélection quand cocher un état de plus l'élargit. D'où « Filtrer » d'un côté, « Afficher »
|
||
de l'autre, et des boutons carrés plutôt que des pastilles. Comme le filtre par tags, celui-ci vaut
|
||
pour les deux vues et n'est pas enregistré.
|
||
|
||
## 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), et
|
||
porter une **date imposée** quand elle est déléguée ou tenue du dehors — le décalage du projet ne
|
||
l'emporte alors pas.
|
||
- **Un cycle de vie** — envisagé, engagé, terminé, écarté — dont deux états se déduisent des
|
||
données. Ce qu'on envisage sans pouvoir encore le mener vit sur la même frise que le reste, et
|
||
ne s'y perd pas.
|
||
- **Un horizon en mois** pour les projets envisagés, rendu en barre hachurée aux bords fondus : la
|
||
largeur dit l'incertitude, et un horizon dépassé réclame de lui-même qu'on tranche.
|
||
- **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 se
|
||
glisse pour repousser le projet entier.
|
||
- **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 — doublé d'un affichage par état, qui joue lui en sens inverse.
|
||
- **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.
|
||
|
||
**Pas de note de priorité non plus, ni de matrice.** L'arbitrage passe par l'horizon : dire « celui-ci
|
||
au printemps, celui-là on verra en 2028 » *est* la décision, et un score posé à côté des dates se
|
||
périmerait en silence. Ce qui manque encore, c'est le départage fin entre deux projets visant le même
|
||
trimestre — il attend d'avoir un endroit où ranger, la frise sachant situer mais pas ordonner.
|
||
|
||
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](docs/decisions.md).
|
||
|
||
## Où vivent les données
|
||
|
||
Tout tient dans un fichier JSON, `data/projets.json`, décrit dans
|
||
[docs/modele-donnees.md](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.
|
||
|
||
```sh
|
||
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
|
||
|
||
```sh
|
||
node --test # la logique métier
|
||
go test ./... # le serveur
|
||
```
|
||
|
||
Côté navigateur : validation des dates et des horizons, bornes et emprise d'un projet, calcul de
|
||
dérive, génération des identifiants, normalisation et filtrage des tags, regroupement des phases par
|
||
mois, dérivation de l'état d'un projet et transitions de son cycle de vie. 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/` |
|
||
| `.gitea/workflows/build.yml` | Pipeline Gitea : tests puis `build.sh`, binaires déposés en artefacts |
|
||
| `js/model.js` | Données et règles métier : CRUD, validation, bornes, cycle de vie et horizon, 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 de phase et de projet envisagé, 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 — au lundi pour une phase ou un projet, au mois pour un horizon |
|
||
| `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.
|