Bloc jalon (progression Gitea, échéance FR, retard, ETA journal
avec signal après-échéance — mêmes définitions que le bandeau
du board) et point santé vert/orange/rouge dérivé de
_project_health, info-bulle et lien vers /health du projet.
Le bouton Recherche & commandes devient une icône 🔍 seule à
droite du titre (sous le logo en rail replié). Les groupes
deviennent des accordéons: chevron animé, transition douce,
sections fermées mémorisées (appliquées avant le rendu), section
de la page courante toujours ouverte; rail replié = icônes.
Retour de Bruno sur la 0.15.0 (disposition pas conviviale, trop
de place, mobile inchangé): la barre horizontale disparaît.
Barre latérale groupée (Principal/Rituels/Pilotage/Outils),
repliable en rail d'icônes mémorisé sur desktop, tiroir
hors-canvas sur mobile; topbar de 52px (fil d'Ariane + actions).
Partiel _header.html unique pour les 19 pages (fin des copies qui
dérivaient): desktop une ligne — primaires + menu Plus + Ctrl K,
page active déduite du gabarit dans render(); mobile ≤900px
burger + panneau ≥44px, Échap/clic extérieur; wallboard sans
header et triage sur le même partiel. nav.js partagé.
slugify + branch_name_for (issue-<n>-<slug>, reconnu par #1/#2);
client create_branch; POST /api/issues/{o}/{r}/{n}/branch (nom
libre validé, idempotent si existante); la carte passe en En
cours, journalisée source branch, étiquette synchronisée;
formulaire dans la section Code lié du panneau détail.
app/code_links.py: appariement pur (#n dans titres/corps/messages,
numéro en jeton de branche). Client: list_branches/list_pulls/
list_commits. Badge sur les cartes (board + fragments live),
section Code lié du panneau détail, /api/issues/{o}/{r}/{n}/code.
app/sprint.py + /sprint/{o}/{r} (rendu markdown, copier/télécharger)
+ /api/sprint en JSON: livré avec temps de cycle, plus lentes,
reporté, chiffres de période. Lien depuis le bandeau milestone.
Navigation: pilules Aujourd'hui/Prévisions et actions palette.
←/→ et contrôles à l'écran changent de projet; navigation manuelle
= pause de rotation 90 s; Espace = pause franche avec badge. La
position survit aux rechargements via sessionStorage (le cycle de
12 projets x 30 s dépassait le refresh de sécurité de 5 min: le
mur semblait figé). Fix: l'écoute SSE utilisait onmessage, inerte
pour les événements nommés 'gitea' du hub.
/triage (sélecteur par taille de backlog) + /triage/{o}/{r}
(session plein cadre, file embarquée): 1-5 colonnes, X fermer,
L étiquettes, A s'assigner (nouvel endpoint assign-self +
client.set_issue_assignees, idempotent), Entrée suivante, Z annuler.
Progression + résumé de session; décisions via /api/move et les
API existantes. Entrées: board + palette.
Rotation automatique entre projets actifs (30 s), compteurs des
six colonnes, cartes en vol avec âge, fermées du jour (journal),
horloge; rafraîchissement en direct par le flux SSE (rechargement,
aucune interaction à protéger) + filet de sécurité à 5 min.
?repo= fige un projet. Lien de navigation ajouté partout.
- modale Étiquettes: liste, création (nom + couleur + palette),
suppression via DELETE (CSRF par en-tête); panneau détail:
bascules d'étiquettes par issue avec mise à jour immédiate des
chips de la carte; _issue_payload expose les ids d'étiquettes
- API étiquettes dans main (routes repos + toggle issue)
- notes: bouton replier/déplier et largeur par glisser, persistés
par projet (localStorage), sauvegarde automatique débouncée
avec statut, formulaire repris par board.js (HTMX retiré du board)
- nouvelles pages search/my/briefing; navigation enrichie partout
(Mes issues, Briefing, Recherche); CSS associé
- en-tête vitré sticky, navigation en pastilles avec état actif,
logo en tuile dégradée, fil d'Ariane projet
- dashboard: hero + tuiles de synthèse (actifs, fermées/déplacements
30 j, cycle moyen), barre de progression par projet, états vides
guidés, raccourci clavier /
- board: sélecteur de milestones + bandeau de progression, colonnes
à défilement indépendant, placeholders de colonnes vides, hint
sur le panneau de notes, toast et drawer animés
- live.js: recharge douce conditionnelle (visible, pas de drawer,
pas de saisie, pas de drag) sinon pastille d'actualisation
- accessibilité: anneau de focus visible, prefers-reduced-motion,
responsive retravaillé; board.js: drapeau de drag partagé avec
live.js + raccourci / vers le filtre
- drawer de détail: corps markdown rendu (marked + DOMPurify
vendorés), commentaires, formulaire de commentaire vers Gitea;
clic distingué du drag par la distance du pointeur
- badges ⏳ N j au-delà du seuil d'âge (rouge au double)
- en-têtes de colonnes: n/limite, classe .over en rouge, toast
d'avertissement au dépôt dans une colonne saturée
- page activity.html, liens Activité dans dashboard et board
- vendor: HTMX/Alpine/SortableJS servis depuis /static/vendor (M3)
- board.js: jeton CSRF, ordres source/destination envoyés, carte
replacée + toast rouge en cas d'échec (M8), filtres texte/étiquette,
formulaire de création d'issue
- dashboard: 3 onglets Actifs/Inactifs/Archivés, recherche via
data-search échappé au lieu d'une interpolation JS (M9)
- board: cartes liées vers l'issue Gitea, méta CSRF, notes protégées
- nouvelles pages focus.html et error.html
- CSS: fond des badges en color-mix, l'ancien var(--accent)20 était
invalide (M1); styles toolbar/focus/erreur/toast erreur
- Dashboard with all Gitea projects (active/archived)
- Kanban board per project (Backlog → À faire → En cours → Révision → Terminé)
- Drag & drop issues between columns (SortableJS)
- Project notes panel
- Gitea API integration (read issues, repos)
- SQLite local state for board positions
- Dark theme design system
- Docker-ready (Dockerfile + docker-compose.yml)
- FastAPI + Jinja2 + HTMX + Alpine.js stack