440 lines
24 KiB
Markdown
440 lines
24 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** : 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 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 |
|
||
| `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.
|
||
|
||
### 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.
|
||
|
||
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).
|
||
- **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 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 — 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, 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.
|