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 (fige actualEnd / 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

  1. 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.

  2. Ouvrir le formulaire

    Depuis la liste des projets, cliquez sur « + Nouveau projet ». Le formulaire est servi par la route /projects/new.

  3. 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.

  4. Valider

    L’appel POST/projects crée le projet et lui assigne automatiquement le statut isInitial de l’instance. Vous êtes redirigé vers la vue kanban.

Utiliser le kanban

Travail au quotidien

  1. 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.

  2. 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.

  3. 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/transition que le drag-drop), sans passer par le bouton « Enregistrer ». Pratique au clavier ou sur mobile, où glisser une carte entre colonnes est malcommode.

  4. Suivre l'avancement

    Le passage en colonne isFinal remplit automatiquement completedAt. Côté Project, la première transition hors isInitial set actualStart ; le passage en statut final set actualEnd. 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’assigneeActor correspond à l’utilisateur courant (lu depuis l’en-tête X-Actor envoyé par le front).
  • Cette semaine — n’affiche que les items dont la dueDate tombe d’ici à +7 jours et qui ne sont pas terminés (completedAt null).
  • 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/total indiquant le nombre de sous-tâches terminées (completedAt non-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
) reste possible sans casser l’existant.

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 📎 N indique 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.