Projets & Kanban
Le module Projets est un outil générique de pilotage par tableau kanban. Il sert à organiser n’importe quelle liste de tâches structurée — chantier de modernisation, programme de certification, suivi du backlog dev, tickets de support — sans être lié au modèle maintenance. Chaque instance configure ses propres types de projet, ses propres colonnes et y déroule ses items en drag-and-drop.
Quatre objets de base
- Project
Le tableau lui-même : un chantier de haut niveau identifié par un code lisible unique dans l’instance (ex
PROJ-MOD-MOTUR-2026). Porte un titre, une description, une priorité, un responsable, un planning prévisionnel et une hiérarchie optionnelle (programme → projet → sous-projet).
- ProjectKind
Le « type » de projet, configurable par instance. Exemples : « Dev », « Certification », « Modernisation flotte », « Sales ». Sert à classer et filtrer les projets. Chaque kind a un code stable, un libellé, une couleur et une icône optionnelles.
- ProjectStatus
Une colonne du kanban — également configurable par instance. Exemples : « Backlog », « In progress », « Blocked », « Done ». Deux contraintes obligatoires par instance : au moins un statut marqué
isInitial(assigné automatiquement à la création) et au moins un statut marquéisFinal(figeactualEnd/completedAt).
- ProjectItem
Une carte du kanban, rattachée à un projet. Porte titre, description, priorité, assignee, effort estimé/réel, échéance et liens optionnels vers une entité métier ( aéronef, OT, Part Number).
Cloisonnement multi-tenant
Comme tous les modules d’Envergure, Projects est strictement cloisonné par instance. Toutes les
requêtes API exigent l’en-tête X-Instance-Id. Les Project, ProjectKind et
ProjectStatus d’une instance ne sont jamais visibles d’une autre — y compris quand deux instances
tournent sur le même cluster. Les FKs croisées (kindId, statusId,
parentProjectId) sont vérifiées côté service pour qu’un item ne puisse pas pointer vers
un référentiel d’une autre instance.
Liste des projets (vue tabulaire)
La page Projets est le point d’entrée du module : un tableau listant tous les projets de l’instance avec filtres, tri et pagination. C’est là qu’on retrouve un projet pour l’ouvrir, le supprimer, ou simplement suivre l’avancement global.
Filtrer et trier
- Recherche : champ libre en haut à gauche, applique un filtre insensible à la casse et aux accents sur le code et le titre.
- Type et Statut : deux selects à côté de la recherche, listent les ProjectKind et ProjectStatus de l’instance.
- Priorité : quatre boutons multi-sélection (
Basse,Moy.,Haute,Crit.). Cumulatif — cliquer plusieurs affiche les projets qui matchent au moins une priorité cochée. - Réinitialiser : bouton à droite des filtres, n’apparaît que si au moins un filtre est actif.
- Tri : cliquer sur l’en-tête d’une colonne (Code, Titre, Type, Statut, Priorité, Avancement,
Activité, Créé) trie sur cette colonne ; un second clic inverse l’ordre. Une flèche
↑/↓indique la colonne et l’ordre actifs.
Tous ces réglages sont persistés dans l’URL (search params q, kind, status, priority,
sort, order, page). Partager le lien partage exactement la vue filtrée ; revenir en arrière
restaure les filtres précédents.
Colonnes affichées
- Avancement : barre de progression compacte + compteur
n/total(sous-tâches done sur total).—italique si le projet ne contient aucun item. - Activité : date de la dernière modification d’un item du projet, format relatif (
hier,il y a 3 j,il y a 2 sem…) avec la date absolue en tooltip.—si aucun item. - Créé : date de création du projet (
YYYY-MM-DD). - Actions : bouton corbeille pour supprimer. Désactivé tant que
itemCount > 0— il faut d’abord supprimer ou réaffecter les items pour éviter une cascade soft accidentelle. Une confirmation est demandée avant la suppression définitive.
Pagination
50 projets par page. Si la liste filtrée dépasse 50 items, une barre « Précédent / Page X / Y / Suivant »
apparaît sous le tableau. Le numéro de page fait partie de l’URL et est aussi réinitialisé dès qu’un
filtre change (on revient page 1 pour éviter de tomber sur une page vide).
Affichage mobile
Sous le breakpoint md (~768 px), chaque ligne du tableau bascule automatiquement en card empilée,
avec un label inline devant chaque valeur (Type, Statut, Priorité, etc.). La barre de filtres
et la pagination s’adaptent en flex-wrap. Aucune action n’est masquée — le bouton corbeille reste
accessible en bas de chaque card.
Créer un projet
Création d'un projet
- Préparer les référentiels
Avant la première utilisation, l’instance doit posséder au moins un ProjectKind et un jeu de ProjectStatus couvrant initial + final (configurables dans l’admin). Le seed de démonstration en fournit déjà un jeu :
backlog,todo,in_progress,blocked,done,cancelled. - Ouvrir le formulaire
Depuis la liste des projets, cliquez sur « + Nouveau projet ». Le formulaire est servi par la route
/projects/new. - Saisir code, titre et type
Le code est un slug court unique dans l’instance (lettres, chiffres, point, tiret, underscore — non modifiable après création). Choisissez le type (ProjectKind) qui détermine la classification. La priorité par défaut est Moyenne.
- Valider
L’appel POST
/projectscrée le projet et lui assigne automatiquement le statutisInitialde l’instance. Vous êtes redirigé vers la vue kanban.
Utiliser le kanban
Travail au quotidien
- Ajouter un item dans une colonne
Sur la fiche projet, le bouton « + » en tête de chaque colonne ouvre un dialog. Le statut est pré-rempli avec celui de la colonne ; le rank est positionné en fin. L’API appelée est POST
/projects/:projectId/items. - Déplacer une carte
Drag-and-drop natif (dnd-kit). Drop sur une autre carte = insertion avant cette carte ; drop sur le fond d’une colonne = ajout en bas. L’UI applique le mouvement en optimistic update et déclenche POST
/projects/:projectId/items/:id/transition. En cas de conflit (deux personnes déplacent le même item simultanément), l’API renvoie un 409 et l’UI rollback. - Changer le statut depuis la fiche
Pas besoin de drag-and-drop : ouvrez une tâche (ou sous-tâche) — clic sur la carte ou Enter — puis utilisez le sélecteur Statut en haut du drawer. Le changement est appliqué immédiatement (même appel POST
/projects/:projectId/items/:id/transitionque le drag-drop), sans passer par le bouton « Enregistrer ». Pratique au clavier ou sur mobile, où glisser une carte entre colonnes est malcommode. - Suivre l'avancement
Le passage en colonne
isFinalremplit automatiquementcompletedAt. Côté Project, la première transition horsisInitialsetactualStart; le passage en statut final setactualEnd. Les filtres rapides (search, assignee, priorité) en haut du board réduisent la vue sans toucher au stockage.
Confort d’usage (board)
Le board kanban offre plusieurs raffinements de surface pour fluidifier l’usage quotidien.
Filtres rapides
À droite des filtres « assignee / priorité », trois boutons mutuellement exclusifs :
- Mes cartes — n’affiche que les items dont l’
assigneeActorcorrespond à l’utilisateur courant (lu depuis l’en-têteX-Actorenvoyé par le front). - Cette semaine — n’affiche que les items dont la
dueDatetombe d’ici à +7 jours et qui ne sont pas terminés (completedAtnull). - Bloquées — n’affiche que les items dont le statut a le code
blocked. Désactivé si l’instance n’a pas de statut « blocked » configuré.
Cliquer le filtre actif le désactive. Cumulable avec les filtres recherche / assignee / priorité.
Densité d’affichage
Toggle « Compact / Confort » dans la toolbar (persisté en localStorage par utilisateur). Mode compact : padding réduit sur les cards, masque le footer (assignee, due date, tags) pour gagner de la verticalité — utile sur grands boards pour balayer 30+ items d’un coup. Mode confort (défaut) : card complète avec toutes les méta-données.
Skeletons au chargement
Pendant le premier load (avant que les données arrivent), le board affiche trois colonnes « squelettes » (rectangles gris pulsants) à la place du texte « Chargement… ». Donne une impression de remplissage progressif au lieu d’un flash blanc puis tout d’un coup.
Animation de drop
Quand on relâche une card après un drag-drop, elle s’éclaire en vert (ring emerald pulsant)
pendant 600 ms avant de revenir à son apparence normale. Confirme visuellement que le mouvement
a bien été pris en compte par l’API (en plus de la persistance optimistic update).
Raccourcis clavier
Le board est entièrement navigable au clavier, façon Linear/Jira.
| Touche | Action |
|---|---|
| j / k | Carte suivante / précédente dans la colonne |
| h / l | Colonne précédente / suivante (focus première card) |
| Enter / e | Ouvrir le drawer édition de la card focused |
| n | Nouvelle carte (statut = colonne courante si focus, sinon premier statut) |
| / | Focus le champ recherche |
| Esc | Fermer le drawer ; sinon clear le focus carte |
| ? | Ouvrir la modal d’aide listant les raccourcis |
Les raccourcis sont désactivés tant qu’un input/textarea a le focus (sauf Esc qui blur)
et pendant un drag actif. Le bouton avec l’icône clavier en haut à droite ouvre la modal d’aide
à la souris pour ceux qui n’auraient pas encore vu le raccourci ?.
Sous-tâches
Un ProjectItem peut être rattaché à un autre via parentItemId pour matérialiser une
décomposition « objectif → activités ». Règle clé : profondeur maximale = 1 niveau — un parent
ne peut pas lui-même être enfant. Côté UI :
- À la création (+ Ajouter un item) ou dans le drawer d’édition, un sélecteur Parent (optionnel) liste les items du projet qui sont eux-mêmes sans parent. Les items déjà sous-tâches n’apparaissent pas dans cette liste.
- Sur la carte du board, une sous-tâche affiche un badge
↪ <code-parent>cliquable qui ouvre le drawer du parent. - Un parent affiche un compteur
n/totalindiquant le nombre de sous-tâches terminées (completedAtnon-null) sur le total. - Le drawer d’un parent comporte une section Sous-tâches en bas avec un bouton + Ajouter qui pré-remplit le parent dans la dialog de création.
- Un bouton Masquer sous-tâches dans la barre du board filtre la vue pour ne garder que les tâches autonomes et les parents (préférence persistée localement).
Les transitions de statut ne se cascadent pas : marquer un parent en « done » ne ferme pas
ses sous-tâches, et inversement. C’est volontaire — chaque activité a son propre cycle de vie.
Le drag-drop d’une sous-tâche dans une autre colonne ne touche pas son parentItemId.
Étiquettes
Pour distinguer la nature d’une tâche (et non son statut), chaque item peut porter une ou
plusieurs étiquettes colorées. Le jeu est fixe pour l’instant — pas d’écran d’administration :
Dév · Archi · Tests · Doc · Infra · Bug · UX · Refacto.
- À la création comme dans le drawer d’édition, un sélecteur affiche les étiquettes sous forme de chips cliquables (toggle) ; les sélectionnées s’allument à leur couleur.
- Sur la carte du board, les étiquettes apparaissent en pastilles colorées (3 max, puis
+N). - La barre de filtres du board propose une rangée de chips d’étiquettes : cliquer en active une ou plusieurs ; un item est affiché s’il porte au moins une des étiquettes cochées. Cumulable avec les autres filtres et remis à zéro par Réinitialiser.
Techniquement, les étiquettes sont stockées comme codes dans le champ tags existant des
items — aucune migration de schéma. Les tags libres hérités (texte arbitraire saisi avant les
étiquettes) restent éditables dans un champ dédié du drawer et s’affichent en gris neutre sur la
carte. Une bascule ultérieure vers un référentiel administrable (à la manière des
- ProjectKind
- types de projet
Images
Chaque tâche et sous-tâche peut porter une ou plusieurs images (captures d’écran d’un bug, maquettes, photos terrain, schémas…). La galerie se trouve dans le drawer d’édition de la tâche, sous la description.
- Ajouter : glisser-déposer des fichiers sur la zone pointillée, ou cliquer pour ouvrir le sélecteur (sélection multiple possible). Formats acceptés : PNG, JPEG, WebP, GIF, SVG, 5 Mo max par image.
- Visualiser : les images s’affichent en miniatures ; un clic ouvre la vue agrandie (lightbox).
- Retirer : la croix au survol d’une miniature détache l’image de la tâche. L’image n’est pas supprimée du stockage (les fichiers sont dédupliqués et peuvent être partagés entre plusieurs ressources) — seul le lien avec cette tâche est retiré.
- Sur la carte du board, une pastille
📎 Nindique le nombre d’images attachées.
Techniquement, les images réutilisent le module Documents : elles sont stockées comme documents
et rattachées à la tâche via un lien polymorphique (resourceType = project_item).
Aucune table dédiée n’a été ajoutée.
Dogfooding : Kanban Dev Envergure
Nous utilisons nous-mêmes le module Projects pour piloter le développement d’Envergure (sous le nom Kanban Dev Envergure). À chaque commit qui livre une tâche trackée, l’agent dev pousse un
POST/projects/:projectId/items/:id/transition automatique pour faire
glisser la carte vers la colonne correspondante (in_progress, puis done).
Cela vérifie en continu que l’API tient la charge et que les transitions concurrentes sont
correctement résolues.
Référence API
| Méthode | Chemin | Effet |
|---|---|---|
| GET | GET/projects |
Liste les projets de l’instance (filtres kindId, statusId, priority, assigneeActor, parentProjectId, search). |
| POST | POST/projects |
Crée un projet. |
| PATCH | PATCH/projects/:id |
Met à jour un projet (titre, description, kind, priorité, planning, parent, tags). |
| POST | POST/projects/:id/transition |
Change le statut d’un projet. |
| DELETE | DELETE/projects/:id |
Soft-delete (restaurable via DB). |
| GET | GET/projects/:projectId/items |
Liste les items d’un projet. |
| POST | POST/projects/:projectId/items |
Crée un item. |
| POST | POST/projects/:projectId/items/:id/transition |
Drag-drop kanban (statusId et/ou beforeItemId/afterItemId). |
| GET, POST, PATCH, DELETE | /project-kinds, /project-statuses |
CRUD des deux référentiels per-instance. |
Les mutations supportent expectedVersion pour de l’optimistic locking — utile sur
drag-drop concurrent.
Voir aussi
- Projets — entrée principale du module.
- Dossiers de travail — l’OT, équivalent métier d’un projet technique avec signature APRS.