Skip to content
github-actions[bot] edited this page Oct 19, 2026 · 24 revisions

API

L'interface web s'appuie entièrement sur une API HTTP JSON. Cette page en donne les conventions ; le détail de chaque route et de chaque objet est dans le contrat OpenAPI.

Contrat OpenAPI

  • Servi par l'application sur /api/openapi.json (session requise).
  • Versionné dans le dépôt : docs/openapi.json. Un test échoue si la copie ne correspond plus à l'API, elle est donc toujours à jour.
  • Pour le parcourir, l'ouvrir dans un éditeur OpenAPI (Swagger Editor, Redocly, l'extension OpenAPI de VS Code…).

Conventions

  • Toutes les routes sont sous /api, en JSON (camelCase). Les énumérations s'écrivent en texte ("Preparation", "Conforme") ; un entier est refusé. Les dates sont en ISO 8601, renvoyées en UTC. Les identifiants sont des GUID.
  • Authentification par cookie de session : POST /api/auth/connexion avec { login, motDePasse }. Toutes les routes l'exigent, sauf la connexion, /api/sante, /api/sante/prete, /api/version, /api/charte et /api/charte/schema.json.
  • Protection CSRF : toute requête qui modifie (autre que GET, HEAD, OPTIONS) doit porter l'en-tête X-Requested-With (valeur libre), sinon 403.
  • Réponse des écritures : une modification d'une MEP renvoie la MEP complète, recalculée pour l'utilisateur courant (états des étapes, anomalies du plan, droits).
  • Concurrence : chaque étape et chaque section portent une revision, chaque bloc de formulaire de la MEP la sienne (revisions : identite, echeance, sauvegarde, planRepli, communication, responsablesTechniques, approbateurs), chaque système de la MEP revisionSauvegarde, et la MEP une version qui augmente à chaque écriture. Le client renvoie la révision de ce qu'il modifie, telle qu'il l'a lue (revision dans la saisie) ; si cette partie a changé entre-temps, la réponse est 409, avec un message qui la nomme (« « Plan de retour arrière » a été modifié par quelqu'un d'autre depuis votre dernière lecture… »), et il faut relire. Une révision n'augmente que lorsque le contenu de sa partie change : une écriture ailleurs dans la MEP (une autre étape, un autre bloc) ne la périme pas. Les écritures sur une même MEP passent l'une après l'autre (verrou de la MEP en base, attente bornée à 15 secondes, puis 409 « réessayez dans un instant ») : dix personnes qui écrivent en même temps sur des étapes ou des blocs différents aboutissent toutes. Les blocs acceptent encore version (celle de la MEP) à la place de revision, pour les scripts existants : elle est alors périmée par toute écriture sur la MEP. Le changement de type (PUT /api/meps/{id}/type) et la décision d'approbation (POST /api/meps/{id}/approbation) gardent version.
  • Temps réel : GET /api/meps/{id}/flux?session={onglet} est un flux Server-Sent Events. Il envoie event: maj avec data: {"version": n} à chaque modification (le client relit alors la MEP) et event: presence avec la liste des personnes qui ont la MEP ouverte, à l'ouverture puis à chaque changement : [{"utilisateurId": "…", "nom": "Bob Martin", "elements": ["etape:…"]}]. session (facultatif, 64 caractères au plus) identifie l'onglet du navigateur.
  • Verrous d'édition : le flux envoie aussi event: verrous avec la liste complète des verrous d'édition des étapes de la MEP, à chaque prise, prise de main, relâche ou expiration (voir « Graphe libre et sections »).
  • Présence : informative, elle ne verrouille rien et vit avec le flux (fermer l'onglet la retire). PUT /api/meps/{id}/presence avec { session, elements } déclare les éléments sur lesquels travaille l'onglet dont le flux est ouvert (liste vide : aucun) : 204, 404 si aucun flux de ce compte n'est ouvert avec cette session, 400 si une clé est invalide (10 au plus, 100 caractères au plus, lettres, chiffres, :, -, _, .). Clés utilisées par le front : etape:{id}, preparation:{section}, retour:fiche, recette:{idFiche}. GET /api/meps/{id}/presence renvoie la même liste que l'événement.
  • Journal : toute écriture est inscrite dans le journal de la MEP (GET /api/meps/{id}/journal, du plus récent au plus ancien). Paramètres, tous facultatifs (sans eux : tout le journal) : limite (1 à 500), apres (identifiant d'événement : seulement les plus récents que lui ; le navigateur ne relit que les nouveaux événements après chaque version), avant (seulement les plus anciens : page suivante), type (famille, comme l'export : etape, approbation, participant…), recherche (dans le détail, l'auteur et son compte, sans casse ; % et _ cherchés tels quels). 400 pour une limite hors bornes.

Codes de réponse

Chaque refus a un seul code, choisi selon sa cause, quelle que soit la route :

Code Sens
400 Saisie invalide : la demande est mal formée ou une valeur ne convient pas, quel que soit l'état des données. JSON illisible, champ obligatoire vide ou trop long, valeur ou référence inconnue (compte, étape d'une autre MEP, fuseau horaire), doublon d'un nom qui doit être unique, mot de passe actuel incorrect, formulaire d'une bibliothèque incomplet (tous les motifs dans erreurs).
401 Authentification requise : pas de session, ou session expirée.
403 Droits insuffisants : la personne n'a pas le droit de faire cela (pilote ou suppléant exigé, route réservée aux administrateurs, mot de passe provisoire à changer d'abord), ou en-tête X-Requested-With absent.
404 Introuvable : ressource inconnue, ou route inconnue.
409 Conflit : la partie modifiée a changé depuis sa lecture (revision, ou version là où elle est demandée), ou la MEP est restée verrouillée par d'autres écritures plus de 15 secondes.
413 Fichier ou requête trop volumineux (une pièce jointe est refusée dès sa taille annoncée, ou coupée dès qu'elle dépasse la taille maximale).
422 Règle métier : la demande est bien formée et permise à la personne, mais l'état des données la refuse (démarrer une étape qui attend une autre étape, retour arrière en préparation, MEP clôturée), ou l'action exige une information que la saisie n'apporte pas (motif, preuve, observation). Aussi : fichier importé dont le contenu est refusé (fichier de recette ou d'objets impactés incohérent, archive de sauvegarde).
429 Trop de requêtes : tentatives de connexion, flux ouverts, dépôts de pièces jointes d'un compte.
503 Service indisponible : sonde /api/sante/prete (l'application ne peut pas servir : base injoignable, schéma différent de celui de la version, surveillance des échéances arrêtée), connexion quand le serveur est trop sollicité.
507 Espace disque insuffisant pour une pièce jointe.

Les droits sont vérifiés avant l'état : une personne sans droit reçoit 403 même si l'action serait aussi refusée par une règle métier. Une route réservée aux administrateurs répond 403 « Réservé aux administrateurs. » à toute autre personne connectée. Une création répond 201 (avec l'adresse de l'objet créé) ou 200 selon la route, toujours avec l'objet créé ; le contrat OpenAPI donne le code de chaque route.

Les erreurs suivent le format problem details (RFC 9457), type de contenu application/problem+json :

{
  "type": "about:blank",
  "title": "Saisie invalide",
  "status": 400,
  "detail": "Le nom de l'équipe est obligatoire.",
  "message": "Le nom de l'équipe est obligatoire."
}

title est le libellé du code (tableau ci-dessus) ; detail et message portent la même phrase en français destinée à l'utilisateur (message reste pour les clients existants). Quand un refus a plusieurs motifs (formulaire de bibliothèque incomplet, réglages de connexion unique, import d'un fichier de recette incohérent), le corps porte aussi "erreurs": ["…"], un motif par ligne. Le contrat OpenAPI décrit ce corps sous ErreurDto.

Groupes de routes

Préfixe Contenu
/api/auth Connexion, déconnexion, utilisateur courant, changement de mot de passe ; options de la page de connexion et connexion unique (/api/auth/sso/… : départ vers le fournisseur, liaison depuis le profil).
/api/utilisateurs Annuaire des comptes, pour tout utilisateur connecté (choisir une personne, la relier à un compte) : { id, login, nomAffiche, nomPersonne, role, contact, expertises, actif, comptePrincipalId, equipeIds }, sans les droits ni l'état du mot de passe (estAdmin, doitChangerMotDePasse : seulement dans /api/auth/moi pour soi, et dans /api/admin/utilisateurs). comptePrincipalId : compte principal de la même personne, ou null ; nomPersonne : nom affiché de la personne. PUT /api/utilisateurs/moi/profil modifie son propre profil. Les comptes se créent seulement depuis la console (POST /api/admin/utilisateurs) ; le profil d'un autre compte se modifie par PUT /api/admin/utilisateurs/{id}/profil.
/api/equipes Liste des équipes, de leurs membres (membreIds), de leur contact support et de leur signature, pour tout utilisateur connecté.
/api/meps Liste (`?modele=true
/api/meps/{id}/communication, /api/meps/{id}/variables-texte Section Communication (PUT, avec revision : revisions.communication) et valeurs des variables des modèles de texte pour la MEP (GET ?equipe=<id> : équipe dont on prend la signature et le contact ; la réponse indique l'équipe proposée, celle du pilote).
/api/modeles-texte Modèles de texte : catalogue des variables (GET /api/modeles-texte/variables), liste d'une équipe (?equipe=<id>), création, modification (version, 409 en cas de conflit), POST /api/modeles-texte/{id}/retablir (modèles fournis), suppression (422 pour un modèle fourni). Contact support et signature d'une équipe : PUT /api/equipes/{id}/communication. Voir Modèles de texte.
/api/catalogue/systemes Catalogue global des systèmes, avec les environnements, les catégories et le nombre d'objets de leur fiche. Historique des MEP d'un système : GET /api/catalogue/systemes/{id}/historique et …/historique/excel ; activité de tous les systèmes : GET /api/catalogue/systemes/activite (voir « Recherche des MEP » plus bas). Fiche : objets GET/POST /api/catalogue/systemes/{id}/objets, PUT/DELETE …/objets/{oid}, environnements PUT …/environnements, catégories PUT …/categories (renommage par ancien). Catégories par défaut : GET/PUT /api/catalogue/categories. Les écritures sont réservées aux administrateurs.
/api/resolutions Résolutions types et leurs versions. Chaque résolution porte utilisations (nombre de MEP où elle est liée à une étape) et creeeLe ; la liste est triée par utilisations, puis par création.
/api/modeles-recette Bibliothèque de recettes : modèles de fiches par système du catalogue, création depuis une fiche (POST /api/modeles-recette/depuis-fiche), suppression réservée aux administrateurs. Chaque modèle porte utilisations (nombre de MEP où il a été inséré) et creeLe ; la liste est triée par utilisations, puis par création.
/api/etapes-modeles Bibliothèque d'étapes : étapes modèles par systèmes du catalogue (?systemeCatalogueId= : celles qui touchent ce système), triées par utilisations puis creeLe. Création et modification par tout utilisateur (version obligatoire en modification, 409 si périmée), création depuis une étape d'une MEP (POST /api/etapes-modeles/depuis-etape { mepId, etapeId, action }), suppression réservée aux administrateurs. Insertion d'une copie dans le plan : POST /api/meps/{id}/etapes/depuis-modele { modeleId, plan, apres, entre, paralleleA, sectionId } (même place qu'une étape créée, voir « Graphe libre et sections »), qui renvoie la MEP ; l'étape copiée porte modeleEtapeId.
/api/parametres, /api/criteres-go-no-go Paramètres globaux.
/api/pieces-jointes Téléchargement d'une pièce jointe.
/api/admin Console d'administration : comptes (dont POST /api/admin/utilisateurs/{id}/relier { comptePrincipalId, desactiver } et POST …/{id}/delier pour les comptes d'une même personne), équipes (POST /api/admin/equipes, PUT et DELETE /api/admin/equipes/{id}, saisie { nom, description, membreIds }, membreIds absent : membres inchangés), journal d'administration, vérification des mises à jour, réglages de la connexion unique (/api/admin/sso) (administrateurs seulement).
/api/application Version en cours, lien de signalement et, pour un administrateur, dernière version publiée.
/api/demo Mode démonstration uniquement (DEMO=true ; sinon 404 comme une route inconnue) : GET /api/demo (sans session) donne les comptes de démonstration ; POST /api/demo/connexion { login } ouvre la session d'un compte de démonstration, avec les mêmes protections que /api/auth/connexion (en-tête anti-CSRF, limite par adresse, blocage progressif), 403 pour tout autre login ; POST /api/demo/reinitialiser (administrateurs) remet la base dans son état initial et ferme la session (après avoir arrêté la simulation) ; GET /api/demo/simulation donne l'état de la simulation de collègues (actif, jusqua, mepId, outil, collegues, lanceePar) et POST /api/demo/simulation { actif } la lance ou l'arrête (toute personne connectée ; 422 si la MEP « Facturation électronique » n'est pas en préparation).
/api/suivi Tableau de bord « Suivi en direct » (tout utilisateur connecté) : GET /api/suivi renvoie { enCours, prevues, prochaine, cloturees, maintenant } : enCours, les MEP lancées (exécution, recette, retour arrière ; hors modèles), complètes et vues par la personne qui demande (droits compris), comme GET /api/meps/{id} ; prevues, les MEP en préparation annoncées (section Communication) aujourd'hui ou demain dans leur fuseau ({ id, outil, versionCible, type, date, heure, debut, fuseauHoraire, pilote }, par heure de début) ; prochaine, la première MEP annoncée qui n'a pas encore commencé (null sinon) ; cloturees, les MEP clôturées depuis 24 heures ({ id, outil, versionCible, type, issue, etat, clotureeLe, pilote }, la plus récente d'abord). GET /api/suivi/flux : flux SSE qui envoie event: maj avec { version, meps, liste } quand une modification change ce que montre le tableau de bord : version, le nombre de modifications diffusées ; meps, les MEP lancées dont la carte a changé (le navigateur ne relit qu'elles, par GET /api/meps/{id}) ; liste vrai quand les listes changent (MEP lancée, clôturée, annoncée, retirée, renommée…, ou plus de 20 cartes d'un coup) : le navigateur relit alors /api/suivi. Une écriture sur une MEP non lancée qui ne change ni sa phase, ni son annonce, ni son nom, sa version cible ou son pilote n'envoie rien. Les MEP lancées de GET /api/suivi sont lues en un nombre fixe de requêtes, quel que soit leur nombre. Commentaire : ping toutes les 20 secondes, flux renouvelé toutes les heures, 429 quand trop de flux sont ouverts.
/api/sante, /api/sante/prete, /api/version Sondes : /api/sante (vivacité) répond { statut: "ok" } dès que le processus répond ; /api/sante/prete (disponibilité) répond { statut, base, schema, echeances }, 200 avec statut: "prete" quand la base est joignable (base: "ok"), à son schéma (schema: "ok", sinon migrations-en-attente, plus-recent ou inconnu) et que la surveillance des échéances a tourné depuis moins de 5 minutes (echeances: "ok", sinon en-retard, ou desactivee), 503 avec statut: "indisponible" sinon. /api/version renvoie { version, charte } : l'empreinte du front servi (pour proposer de recharger un onglet après un déploiement) et celle de la charte visuelle en vigueur (l'onglet recharge alors seulement /charte.css, sans recharger la page).
/api/charte, /api/admin/charte Charte visuelle (voir Exploiter). Sans session : GET /api/charte renvoie { charte, empreinte, origine } (origine : console, fichier ou defaut) et GET /api/charte/schema.json le schéma JSON du fichier charte.json. Hors de /api, GET /charte.css sert les variables CSS de la charte (seulement celles qui diffèrent des couleurs par défaut), avec un ETag égal à l'empreinte (304 en revalidation). Administrateurs : GET /api/admin/charte (charte en vigueur, origine, auteur et date de la dernière modification, état du fichier charte.json : chemin, présence, erreurs, avertissements numérotés par ligne), PUT /api/admin/charte avec la charte au format du fichier (400 si elle est invalide ; elle remplace le fichier pour tous, inscrit charte.modifiee au journal d'administration), DELETE /api/admin/charte (efface la charte de la console : le fichier, ou à défaut la charte par défaut, reprend la main ; charte.retablie), POST /api/admin/charte/verifier { contenu } (vérifie le texte d'un fichier sans rien enregistrer : { valide, erreurs, avertissements, charte }). Un contraste faible est un avertissement, jamais un refus. Les exports Excel suivent la charte en vigueur.

Exports Excel des vues, en lecture seule (classeur .xlsx, tout utilisateur connecté) : GET /api/meps/excel (liste, avec les filtres de la page d'accueil, ceux de GET /api/meps décrits dans « Recherche des MEP » ; ?modele=true : modèles, où seuls recherche et equipe s'appliquent ; 404 pour une équipe inconnue ; une feuille « Échecs » liste les échecs d'étape de ces MEP, limités aux systèmes filtrés), GET /api/meps/{id}/preparation/excel, GET /api/meps/{id}/etapes/excel, GET /api/meps/{id}/retour-arriere/excel et GET /api/meps/{id}/journal/excel (?type=<famille> : préfixe du type d'événement, etape, recette… ; ?recherche= : dans le détail, l'auteur et son compte). La recette et les objets impactés gardent leurs routes d'export et d'import ci-dessus.

Rapport de fin d'une MEP clôturée : GET /api/meps/{id}/rapport renvoie { mepId, figeLe, calculeApres, synthese, pointsBloquants, testsUnitaires, mep, journal }, figé à la clôture (POST /api/meps/{id}/cloturer l'enregistre juste après avoir clôturé) et identique ensuite à chaque lecture. mep est la MEP telle qu'à la clôture, sans les droits de personne (droits neutres), avec son etat, ses echecsSurvenus et ses echecsRecette (pour un rapport figé avant leur apparition, repris des compteurs de la MEP) ; journal, tout son journal (le plus récent d'abord) ; testsUnitaires, comme …/tests-unitaires. synthese : { etapes, etapesReussies, go, finDeploiement, dureeReelleMinutes, dureePrevueMinutes (plus long chemin des durées estimées), echecs, echecsRepris, resolutions, recetteTests, recetteConformes, recetteEchecs, retourArriere, premierGo, retoursEnPreparation, etapesAjouteesApresGo } (premierGo : le premier Go, gardé après un retour en préparation). pointsBloquants : un point par échec d'étape tiré du journal (etape.echec, rattaché à l'étape par l'etapeId de l'événement), { plan, code, action, echecLe, par, motif, resolution, statutResolution, dureeResolutionMinutes, repriseLe, repriseReussieLe, arretMinutes }, la résolution étant la dernière démarrée sur l'étape entre l'échec et la reprise. Une MEP clôturée avant l'existence des rapports obtient le sien à la première lecture (calculeApres: true), figé à son tour. 422 avant la clôture. GET /api/meps/{id}/rapport/excel : le même rapport en classeur Excel (rapport-Outil-Version.xlsx), également 422 avant la clôture.

GET /api/meps/{id}/tests-unitaires donne le suivi des tests unitaires d'une MEP : nombre de tests faits et non faits, nombre de simples vérifications, puis pour chaque test l'étape, son état, le résultat attendu, le résultat constaté et l'exécutant. Chaque étape de la MEP porte aussi fin (TestUnitaire ou Verification) et resultatConstate ; gestion-mep meps exporter reprend ce suivi (testsUnitaires).

Plan de retour arrière facultatif : PUT /api/meps/{id} accepte retourArriereActive (absent : inchangé ; modifiable seulement en préparation). Il n'accepte plus echeanceRepli : voir l'échéance ci-dessous. Une MEP (GET /api/meps/{id}) et chaque ligne de GET /api/meps portent retourArriereActive. Sans plan de retour arrière, POST /api/meps/{id}/retour-arriere répond 422. L'activation et la désactivation sont inscrites au journal de la MEP (types repli.active et repli.desactive).

Échéance de retour arrière : PUT /api/meps/{id}/echeance avec { revision, echeanceRepli, motif } (revision : revisions.echeance) (echeanceRepli à null : la retirer). En préparation, tout éditeur ; en exécution et en recette, le pilote, un suppléant ou un administrateur (403 sinon). 422 sur un modèle, sans plan de retour arrière, une fois le retour arrière déclenché, sur une MEP clôturée ou annulée, pour une échéance passée, ou sans motif (il n'est facultatif que pour la première saisie en préparation). Journal : echeance.modifiee, « Échéance de retour arrière : 23/10/2026 23:00 → 24/10/2026 01:00 (Europe/Paris) : motif », heures dans le fuseau de la MEP. droits.peutModifierEcheance dit si l'utilisateur peut l'appeler. Atteinte en exécution, l'échéance déclenche le retour arrière ; atteinte en recette, elle est seulement signalée : echeanceSignalee (date du signalement, remise à null par un nouveau report) et un événement echeance.depassee attribué à « Système », une seule fois.

Séparation des tâches et résolutions figées : chaque entrée de approbations porte empechement, null ou le rôle qui interdit à ce compte d'approuver (pilote, suppléant du pilote, responsable technique, suivi de , par un compte relié) ; tant qu'un tel approbateur reste désigné, erreursPlan le signale et le Go répond 422. PUT /api/meps/{id}/approbateurs refuse un tel compte (422 : c'est l'état de la MEP qui l'interdit) et une même personne désignée deux fois par des comptes reliés (400) ; POST /api/meps/{id}/approbation répond 403 à qui n'est pas approbateur désigné ou est empêché. La première approbation (au plus tard le Go) fige les résolutions types liées : resolutionsFigees ([{ resolutionTypeId, version, titre, symptomes, diagnostic, systemeCatalogueIds, corrections, verificationInstruction, verificationAttendu }]) et resolutionsFigeesLe, journal resolutions.figees. Le déroulé (POST /api/meps/{id}/etapes/{eid}/resolutions) applique cette copie. Une modification du contenu en préparation efface approbations, copie figée et relecture (procedure.reinitialisee). L'échec d'une correction ou de la vérification finale ne déclenche plus le retour arrière : resolution.echouee, l'étape reste en échec. Les événements d'étape du journal portent etapeId.

Fuseau horaire : PUT /api/meps/{id} accepte dans fuseauHoraire un identifiant IANA (Europe/Paris, America/New_York) ; un identifiant Windows (Romance Standard Time) est enregistré sous son équivalent IANA, une valeur vide laisse le fuseau inchangé, un fuseau inconnu répond 400. Le jour d'une MEP, les filtres par date, le suivi en direct, les textes de communication et les exports Excel convertissent tous les heures dans ce fuseau, de la même façon (heure qui n'existe pas au passage à l'heure d'été : décalée d'autant ; heure qui existe deux fois : la première).

MEP complète ou simplifiée : une MEP (GET /api/meps/{id}) et chaque ligne de GET /api/meps portent type (Complete ou Simplifiee ; les MEP existantes sont complètes). POST /api/meps accepte type (absent : Complete ; 400 pour un modèle simplifié). PUT /api/meps/{id}/type { version, type } change le type en préparation (422 après, ou pour un modèle ; 403 pour qui n'est ni pilote, ni suppléant, ni administrateur, quand un pilote est désigné) : vers Complete, tout est conservé et les suppléants implicites deviennent suppleantIds ; vers Simplifiee, durées, criticités, résolutions liées des étapes, versions et suppléants choisis sont effacés. Le journal reçoit un événement mep.type. Dans une MEP simplifiée, suppleantIds liste les suppléants implicites (toutes les personnes sauf le pilote, aucune sans pilote, et sauf un administrateur ajouté parce qu'il a démarré une étape ou pris la main : il n'y est qu'exécutant), PUT /api/meps/{id} ignore versionActuelle, versionCible et suppleantIds, une étape enregistrée perd sa durée, sa criticité et ses résolutions liées, et POST /api/meps/{id}/etapes/{eid}/resolutions accepte toute résolution type active d'un système de l'étape ou sans système.

L'API ne propose pas encore de jeton d'accès : un script doit se connecter et conserver le cookie de session.

Recherche des MEP

GET /api/meps, GET /api/meps/page, GET /api/meps/facettes et GET /api/meps/excel acceptent les mêmes filtres que l'adresse de la page d'accueil (/?systeme=…&etat=…) et que gestion-mep meps lister. Ils se combinent (et) ; les listes sont séparées par des virgules (une valeur de la liste suffit). Une valeur invalide répond 400 avec les valeurs admises.

Paramètre Filtre
recherche Texte, sans accents ni casse : outil, version, objet, pilote, personnes (tous leurs comptes reliés) et noms des systèmes.
systeme Systèmes touchés : identifiant du catalogue, ou libre:Nom pour un système saisi à la main dans la MEP (nom sans casse ni accents).
environnement Noms d'environnements, sur les systèmes filtrés (sur tous les systèmes de la MEP sans systeme).
equipe Identifiants d'équipes : MEP dont une personne fait partie de l'équipe.
personne Identifiant du compte principal d'une personne : MEP où elle intervient, par n'importe lequel de ses comptes.
role Avec personne seulement : pilote, suppleant, responsable (responsable technique d'un système), executant (d'une étape), approbateur.
etat preparation (sans les MEP reportées), reportee (en préparation avec un report), execution, recette, retour-arriere, reussie, incidents (réussie avec au moins un échec d'étape, même repris), repliee (clôturée après un retour arrière), echec (clôturée en échec), annulee.
du, au Bornes incluses (AAAA-MM-JJ) sur le jour de la MEP : celui du Go, à défaut celui de sa création.
echec 1 : au moins un échec d'étape survenu sur les systèmes filtrés (sur la MEP sans systeme).
phase, type Filtres plus anciens, gardés pour les adresses existantes : Preparation…Cloturee, Annulee, complete ou simplifiee.

La liste est triée par jour décroissant, puis par création décroissante. GET /api/meps et l'export Excel renvoient toute la liste filtrée.

Liste paginée (page d'accueil) : GET /api/meps/page?limite=30&apres=… (avec modele et les filtres ci-dessus) renvoie { meps, total, ensemble, suivant } : meps, une page (limite de 1 à 200, 30 par défaut), dans le même ordre ; total, le nombre de MEP qui correspondent aux filtres ; ensemble, le nombre de MEP (ou de modèles) sans filtre ; suivant, le curseur à passer dans apres pour la page suivante (null : c'était la dernière). Le curseur désigne la dernière MEP lue : une MEP créée entre deux pages ne décale pas la suite. 400 pour une limite hors bornes ou un curseur illisible. GET /api/meps/facettes (mêmes paramètres, sans limite ni apres) donne les comptes de la barre de filtres : { total, ensemble, systemes, environnements, equipes, personnes, etats, libres, environnementsProposes, sans }. Pour chaque valeur d'un critère (clé : identifiant du catalogue en minuscules ou libre: et le nom normalisé pour systemes ; nom normalisé, sans casse ni accents, pour environnements ; identifiant pour equipes et personnes ; nom de l'état pour etats), le nombre de MEP qu'on obtiendrait en la choisissant à la place des valeurs choisies de ce critère. libres : noms des systèmes saisis à la main ; environnementsProposes : environnements des systèmes retenus par le filtre systeme, relevés dans les MEP ; sans : pour chaque critère actif (recherche, systeme, environnement, equipe, personne, etat, periode), le nombre de MEP sans lui. Le serveur restreint d'abord la liste en base (type, phase, états, systèmes, équipes, période élargie d'un jour), puis applique la règle exacte ci-dessous.

Les règles sont écrites deux fois, côté serveur (backend/src/GestionMep.Api/Services/FiltreMeps.cs) et côté navigateur (frontend/src/rechercheMeps.ts), et vérifiées des deux côtés par les mêmes cas (frontend/src/vecteurs-filtre-meps.json).

Champs de chaque résumé utiles à la recherche : etat (Preparation, Reportee, Execution, Recette, RetourArriere, Reussie, AvecIncidents, Repliee, Echec, Annulee), reporteeAu (date visée d'une MEP reportée, ou null), annuleeLe, jour, go, clotureeLe, echecsSurvenus (échecs d'étape survenus, repris ou non), echecsRecette (tests de recette en échec, saisis ou refusés à l'import Excel, refaits ou non ; avec echecsSurvenus, ils font « Réussie avec incidents »), systemes ([{ catalogueId, nom, environnements, echecs }], catalogueId null pour un système saisi à la main) et intervenants ([{ personneId, nom, roles }], une ligne par personne).

Historique d'un système du catalogue : GET /api/catalogue/systemes/{id}/historique renvoie { systemeId, nom, resume, meps }. meps : toutes les MEP qui l'ont touché (hors modèles, même tri), { id, outil, versionCible, objet, type, etat, jour, go, clotureeLe, pilote, environnements, autresSystemes, echecs, rapport }, où environnements sont ceux touchés sur ce système et echecs les échecs d'étape survenus sur ce système ({ plan, code, action, echecLe, motif, repris, resolution, statutResolution }). resume : { total, douzeMois, enCours, cloturees, reussies, avecIncidents, repliees, echecs, echecsRepris, derniereMepId, enEchec, annulees } (enEchec : clôturées en échec, comptées dans cloturees ; annulees : à part, ni en cours ni clôturées) (la dernière MEP lancée, à défaut la plus récente). GET /api/catalogue/systemes/{id}/historique/excel : le même historique en classeur (feuilles Synthèse, MEP et Échecs). 404 pour un système inconnu. GET /api/catalogue/systemes/activite : [{ systemeId, nbMep, derniereMepId, derniereOutil, derniereVersion, derniereJour, derniereEtat }], un élément par système touché par au moins une MEP (colonne « Dernière MEP » du catalogue).

Cycle de vie : annuler, reporter, corriger en avant, changer de pilote, supprimer

Une MEP (GET /api/meps/{id}) porte annulation ({ motif, etatProduction, par, le } ou null), report ({ motif, dateVisee, par, le } ou null), premierGo (heure du premier Go, gardée après un retour en préparation), pilotageSecours ({ par, le, motif, ancienPilote, nouveauPilote } ou null) et, dans cloture, etatService et referenceIncident (vides hors clôture en échec). Chaque étape porte ajouteeApresGo. droits ajoute peutAnnuler, peutReporter, peutSupprimer, peutChangerPilote et peutAjouterPersonne, que l'interface utilise pour son menu « ⋯ Plus d'actions ». La phase Annulee est terminale (lecture seule, comme Cloturee), et l'issue Echec s'ajoute à Reussie et Repliee.

Requête Effet
POST /api/meps/{id}/annuler { motif, etatProduction } : annule la MEP, en préparation seulement (422 sinon, ou pour un modèle). etatProduction obligatoire si la MEP a déjà eu un Go. Pilote, suppléant ou administrateur (403 sinon). Journal mep.annulee.
POST /api/meps/{id}/reporter { motif, dateVisee } (dateVisee facultative, AAAA-MM-JJ) : reporte la MEP en préparation, ou remplace le report. Pilote ou suppléant. Journal mep.reportee.
POST /api/meps/{id}/reprendre Lève le report (422 si la MEP n'est pas reportée). Pilote ou suppléant. Journal mep.reprise. Le Go lève aussi le report.
POST /api/meps/{id}/no-go { motif, reporter, dateVisee } : reporter à vrai reporte aussi la MEP, avec le même motif.
POST /api/meps/{id}/phase { phase: "Preparation", motif } depuis l'exécution, { phase: "Execution", motif } depuis la recette (« corriger en avant » : les tests en échec redeviennent à faire) : motif obligatoire (422 sans).
POST /api/meps/{id}/etapes-correctives { action, systemeIds, instructions, resultatAttendu, dureeEstimeeMinutes, criticite } : ajoute une étape corrective pendant l'exécution, à la suite du plan, code suivant, ajouteeApresGo vrai. Pilote ou suppléant. Renvoie la MEP.
POST /api/meps/{id}/cloturer { echec: true, etatService, referenceIncident, ceQuiAMarche, incidents, actions } : clôture en échec, depuis le retour arrière, ou depuis la recette si le retour arrière est impossible (422 sinon). etatService et le bilan sont obligatoires.
POST /api/meps/{id}/pilotage { participantId | utilisateurId, motif, ancienPiloteSuppleant, suppleantsGardes } : change le pilote de l'exécution au retour arrière (422 en préparation ou après la clôture). Un compte absent de la MEP y est ajouté. ancienPiloteSuppleant absent : oui ; suppleantsGardes absent : tous. Passation par le pilote ou un suppléant (pilotage.passe), pilotage de secours par un administrateur qui ne pilote pas (pilotage.secours, et mep.pilotage-secours au journal d'administration).
DELETE /api/meps/{id} { motif, nom } : suppression définitive, administrateur seulement (403 sinon, même pour le créateur), pour un modèle ou une MEP qui n'a jamais eu de Go (422 sinon). nom : outil et version cible, saisis à l'identique (400 sinon). 204. Une ligne mep.supprimee au journal d'administration ; les onglets ouverts sur la MEP reçoivent une notification et leur prochaine lecture répond 404.

Après le Go (de l'exécution au retour arrière), POST /api/meps/{id}/participants est ouvert au pilote, aux suppléants et aux administrateurs (journal participant.ajoute, « Participant ajouté après le Go »).

Graphe libre et sections

Le plan est un graphe libre : seuls les liens comptent (« B attend A »). ligne et ordre d'une étape sont en lecture seule : ils sont recalculés après chaque opération (profondeur dans le graphe, puis place précédente) et servent d'indice d'ordre à l'affichage et aux exports. Il n'y a plus de règle « un lien descend toujours » : seuls un cycle et une étape qui s'attend elle-même (422), et un lien vers l'autre plan (400), sont refusés, sans rien modifier. Les opérations par ligne (l'ancien …/placer avec ligne, position, nouvelleLigne) n'existent plus.

Une étape porte aPlacer (vrai : dans le bac « Étapes à placer », hors du graphe et sans aucun lien ; une étape qui reçoit un lien en sort d'elle-même ; une étape au bac bloque le Go), dependances (préalables effectifs, seuls utilisés par l'exécution), dependancesDerivees (la part qui vient des cercles de section), sectionId (null : hors section) et portsAttendus (cercles de sortie d'autres sections qu'elle attend). Une MEP porte sections : { id, plan, titre, description, systemeIds, auteurId, auteur, creeLe, placee, revision, ports, rang }, chaque cercle (ports) valant { id, sens: Entree|Sortie, titre, description, ordre, etapes, sources }. Une section est un repère : elle ne s'exécute pas ; ses cercles donnent des préalables à ses étapes. Préalables effectifs d'une étape = ses préalables directs, plus, pour chaque cercle d'entrée de sa section qui la contient, ce qui y arrive (sources : une étape, ou les étapes d'un cercle de sortie d'une autre section), plus les étapes de chaque cercle de sortie qu'elle attend.

Étapes et sections portent aussi rang, l'ordre de gauche à droite choisi dans le graphe, commun à tout le monde : 0 tant que personne n'a réordonné le plan (l'affichage suit alors ligne, ordre, code) ; ensuite chaque élément du plan a un rang, une étape créée prend celui qui suit sa voisine et une section créée se place en fin. Le rang ne change ni les liens ni l'exécution.

Requête Effet
POST /api/meps/{id}/etapes Crée une étape (champs de la fiche) à une place, au plus une : apres (Id d'étape ou de cercle : elle l'attend), entre { de, vers } (insertion sur ce lien : vers attend la nouvelle étape, qui attend de), paralleleA (mêmes préalables et mêmes suivants que cette étape) ; rien : isolée. sectionId : sa section (absente : celle de la place). Dans une section, une étape sans préalable dans la section attend le premier cercle d'entrée et une étape que rien n'attend est attendue par le premier cercle de sortie. dependances (préalables explicites) ne se combine pas avec une place (400).
PUT /api/meps/{id}/etapes/{eid} Fiche de l'étape (revision obligatoire). dependances : préalables directs ; ceux qui viennent des cercles restent. Absentes (ou null) : inchangées (la fiche de l'interface ne les envoie pas) ; liste vide : aucun préalable direct.
POST /api/meps/{id}/etapes/{eid}/deplacer { apres, surLien { de, vers }, paralleleA, sectionId, sortirDeSection } : la carte quitte sa place (ce qui l'attendait attend ce qu'elle attendait, sans lien redondant), change de section si demandé (sinon celle de sa nouvelle place), puis s'insère.
POST /api/meps/{id}/etapes/{eid}/retirer-du-plan Retire l'étape du graphe sans la supprimer : ses liens disparaissent (ce qui l'attendait attend ce qu'elle attendait, sans lien redondant) et elle passe dans le bac (aPlacer). Elle garde sa section et sa fiche.
POST /api/meps/{id}/etapes/{eid}/placer-depuis-le-bac { apres, surLien { de, vers }, paralleleA, sectionId } (corps vide : à part) : replace une étape du bac à cet endroit, comme une étape créée ; dans une section, elle se relie à ses premiers cercles. 422 pour une étape qui n'est pas dans le bac.
DELETE /api/meps/{id}/etapes/{eid} Supprime l'étape : ce qui l'attendait attend ce qu'elle attendait.
GET /api/meps/{id}/liens/redondants?plan=&sectionId= Liens inutiles du plan (Deploiement par défaut) : [{ de, vers, libelle }], où vers attend déjà de par un autre chemin (étapes ou cercles de section). sectionId : seulement les liens entre éléments de cette section (ses étapes et ses cercles), l'autre chemin passant lui aussi par la section.
POST /api/meps/{id}/liens/optimiser { plan, liens: [{ de, vers }], sectionId? } : retire en une opération les liens inutiles montrés (éditeur, préparation). 409 si la liste ne correspond plus au plan ; refus si l'ordre d'exécution changeait. Journal plan.liens-optimises.
POST /api/meps/{id}/liens et …/liens/retirer { de, vers } : ajoute ou retire le lien « vers attend de ». Liens possibles : étape → étape ; étape hors de la section, ou cercle de sortie d'une autre section → cercle d'entrée ; cercle d'entrée → étape de sa section ; étape de la section → cercle de sortie ; cercle de sortie → étape hors de sa section. 404 si un Id est inconnu ; 400 pour retirer un lien qui n'existe pas ; 422 pour un lien impossible, un cycle, ou un préalable qui ne vient que d'un cercle (« délier le cercle »).
PUT /api/meps/{id}/ordre { plan, ids } : ordre de gauche à droite des étapes et sections du plan (ids dans l'ordre voulu, les absents suivent dans leur ordre actuel). Les rangs deviennent 1, 2, 3… ; aucun lien ne change et les approbations sont gardées. 400 sans plan ni ids, ou pour un Id inconnu ou répété. Journal : graphe.ordre.
POST /api/meps/{id}/sections { plan, titre, description, systemeIds, placee } (placee absent : dans le bac). 201 { sectionId, mep }. La section reçoit un cercle d'entrée « Début » et un cercle de sortie « Fin ».
PUT /api/meps/{id}/sections/{sid} { revision, titre, description, systemeIds } (409 si la révision est périmée).
PUT /api/meps/{id}/sections/{sid}/placement { placee } : placer dans le plan, ou remettre dans le bac (ses cercles sont déliés du plan : ce qui attendait la section attend ce qu'elle attendait). Une section restée dans le bac bloque le Go (anomalie de « Vérifier le plan »).
DELETE /api/meps/{id}/sections/{sid} Ses étapes restent, hors section, avec leurs préalables effectifs (ceux des cercles deviennent directs).
POST /api/meps/{id}/sections/{sid}/ports { sens, titre, description } (titre absent : « Entrée 2 »…).
PUT /api/meps/{id}/sections/{sid}/ports/{pid} { titre, description }.
PUT /api/meps/{id}/sections/{sid}/ports/ordre { sens, ports } : tous les cercles de ce bord, de gauche à droite.
DELETE /api/meps/{id}/sections/{sid}/ports/{pid} Les liens qui passaient par le cercle disparaissent.
POST /api/meps/{id}/etapes/{eid}/verrou { session, prendreLaMain } : verrou d'édition de l'étape pour l'onglet session (celui du flux). Renvoie { pris, verrou } ; tenu par un autre onglet, pris vaut faux sauf avec prendreLaMain (sans confirmation, le verrou garde alors reprisDeNom, reprisDeSession). Renouveler toutes les 20 s environ : il expire après une minute sans signe de vie, et à la fermeture du dernier flux de l'onglet. Indicatif : la révision protège toujours l'enregistrement.
DELETE /api/meps/{id}/etapes/{eid}/verrou?session= Relâche le verrou s'il est tenu par cet onglet (204).
GET /api/meps/{id}/verrous Verrous en cours (même liste que l'événement verrous).

Ces opérations se font en préparation (422 ensuite), avec les droits d'édition du contenu (403), remettent les approbations à zéro et sont inscrites au journal (etape.creee, etape.deplacee, etape.retiree-du-plan, etape.placee, plan.lien-ajoute, plan.lien-retire, section.creee, section.renommee, section.modifiee, section.placee, section.bac, section.supprimee, section.cercle-ajoute, section.cercle-modifie, section.cercle-supprime). Les étapes dont les préalables effectifs changent prennent une révision de plus ; une section prend une révision de plus à chaque changement (cercles et liens compris). Avertissements de « Vérifier le plan » : cercle sans étape, cercle d'entrée où rien n'arrive.

Clone this wiki locally