41 KiB
review.md — Journal des décisions EME
Ce fichier trace chaque étape réalisée et chaque choix technique, avec sa justification. Il est mis à jour au fil de l'avancement. Lecture du plus ancien (haut) au plus récent (bas).
Règles métier ->
docs/regles-metier/regles-gestion.md· Contexte ->CONTEXT.md· Plan ->TODO.md
Conventions et choix transverses
Ces décisions s'appliquent à tout le projet, sauf mention contraire.
| Décision | Pourquoi |
|---|---|
Statuts métier en String côté Prisma (pas d'enum natif) |
SQL Server ne supporte pas les enums Prisma. Les valeurs sont validées côté TypeScript via src/models/enums.ts. |
Timestamps automatiques : createdAt @default(now()), updatedAt @updatedAt |
Évite d'avoir à fournir ces valeurs manuellement ; updatedAt est géré par Prisma au runtime. |
actif Boolean @default(true) |
Une entité créée est active par défaut. |
@unique sur les identifiants fonctionnels |
Intégrité : un identifiant en double casse l'authentification / l'unicité métier. |
Champs nullable selon les cardinalités 0..1 du diagramme de classes |
Un champ non connu à la création (ex. date de retour) ou optionnel doit être NULL, sinon le workflow métier est bloqué. |
onDelete: NoAction, onUpdate: NoAction sur les données de traçabilité (Emprunt, Checklist, ChecklistElement, Anomalie, Historique) |
Ces données ne doivent jamais être supprimées/altérées automatiquement en cascade. Toute suppression sera explicite côté service. Évite aussi l'erreur SQL Server "multiple cascade paths". |
ERD tenu à jour en miroir du schéma (docs/conceptions/uml/ERD.md) |
La source de vérité doit refléter le code réel (nullable, UK, etc.). |
Workflow Git : develop comme branche d'intégration + branches dédiées feat/..., fix/..., docs/... |
master reste figé ; chaque changement logique est isolé sur une branche puis mergé dans develop, conformément à CLAUDE.md. |
Process avant chaque migration : prisma format -> prisma validate -> npm run build -> migration |
Détecter toute erreur de schéma/typage avant de toucher la base. |
DTO nommés XxxResponse (sortie) et XxxRequest (entrée) |
Le sens est explicite dans le nom. Sortie = mapping (toXxxResponse), entrée = validation. |
État actuel synthétique
Cette section résume l'état courant du projet. Le journal chronologique plus bas conserve l'historique complet, y compris des étapes devenues obsolètes après branchement API.
| Bloc | État | Commentaire |
|---|---|---|
| Infrastructure | Terminé | Docker Compose SQL Server + Adminer, monorepo, backend Node/TS, frontend Flutter Web. |
| Base de données | Terminé pour la V1 | Schéma Prisma 16 entités, migrations, seeds et fixtures de démonstration. |
| API étudiant | Terminé pour la V1 | Catalogue, détail matériel, création d'emprunt, mes emprunts, restitution, anomalie automatique. |
| Frontend étudiant | Fonctionnel pour la V1 | Parcours API complet, ordre identification puis choix validé, interface premium et responsive fidèle à la maquette. |
| Authentification | Prête pour Azure, démo active | Double mode sécurisé : x-user-email seulement en développement, MSAL/OIDC + Bearer JWT en mode Azure. Validation réelle en attente des identifiants Entra ID. |
| API responsable | Terminé pour la V1 | Dashboard, emprunts, stock, anomalies, notifications, historique et export CSV, avec contrôle du rôle et du campus. |
| Frontend responsable | Fonctionnel pour la V1 | Espace de supervision responsive avec navigation dédiée, dashboard métier, vues API et export CSV opérationnel. |
| Tests automatisés | Non démarré | Tests backend/frontend/E2E à ajouter ; tests runtime manuels effectués. |
| Documentation | Partielle | README principal et documents de conception présents ; OpenAPI, guides utilisateur et captures restent à produire. |
Commandes validées
Commandes utilisées et validées dans l'environnement de développement local :
docker compose up -d
cd eme-backend
npm run dev
npm run build
npm run lint
npm run seed
npm run fixtures
cd ../eme-frontend
npm run build:auth
flutter run -d web-server --web-port 5000
C:\flutter\flutter\bin\cache\dart-sdk\bin\dart.exe analyze
Notes :
- le backend écoute sur
http://localhost:3000; - le frontend web de démo écoute sur
http://localhost:5000; - Adminer est disponible sur
http://localhost:8081; - le wrapper
flutterpeut rester bloqué dans l'environnement Codex ; l'analyse directe avec l'exécutable Dart fonctionne et ne signale aucune erreur ; - la compilation Web complète a été validée avec l'exécutable Dart du SDK Flutter et produit
build/web.
Scénario de démo validé
Scénario étudiant validé avec SQL Server Docker et backend compilé :
- Afficher le catalogue des matériels disponibles du campus.
- Ouvrir le détail d'un matériel et vérifier les accessoires.
- Créer un emprunt avec checklist de départ.
- Vérifier que l'emprunt apparaît dans
mes-emprunts. - Restituer conforme : l'emprunt passe
CLOTUREet le matériel redevient disponible. - Restituer non conforme : l'emprunt passe
RETOUR_NON_CONFORMEet le matériel sort du catalogue disponible.
Scénario responsable validé avec SQL Server Docker et backend compilé :
- Karim (
RESPONSABLE) accède au dashboard, aux emprunts, au stock, aux anomalies, aux notifications et à l'historique de son campus. - Lucas (
ETUDIANT) reçoit une réponse403sur les routes responsable. - Une anomalie peut avancer dans le cycle
DETECTEE -> EN_COURS_TRAITEMENT -> RESOLUE -> CLOTUREE. - Chaque transition enregistre le responsable et crée une entrée d'historique.
- L'API génère l'export CSV de l'historique et l'interface Flutter déclenche son téléchargement.
Note outillage — migrations en environnement non-interactif
prisma migrate dev se bloque quand il doit demander une confirmation (ex. ajout de contrainte @unique sur table existante) car le terminal est non-interactif.
Contournement utilisé : générer le SQL avec prisma migrate diff --from-config-datasource --to-schema ... --script, écrire le fichier de migration, puis appliquer avec prisma migrate deploy. Résultat strictement identique à migrate dev, sans perte de données.
En terminal interactif (VS Code), migrate dev fonctionne normalement (taper y).
Journal chronologique
Étape 0 — Audit initial
- Constat : Block 0 (bootstrap) terminé mais non coché ; schéma à 4/16 entités ; aucune migration ; aucun commit Git.
- Décision : compléter le schéma par petits blocs (et non d'un coup) pour valider/committer au fur et à mesure.
Étape 1 — Configuration des migrations Prisma
- Correction
DATABASE_URL(mot de passe désaligné avecDB_PASSWORD). - Découverte : Prisma 7 interdit
urldansschema.prisma-> la connexion vit dansprisma.config.ts. Ligneurlretirée du datasource.
Étape 2 — Modèles de référence (Campus, Role, Utilisateur, CategorieMateriel)
- Defaults + timestamps auto ajoutés sur Campus, Utilisateur, CategorieMateriel (Role n'a pas de timestamps -> non modifié).
@uniquesurRole.code,Utilisateur.microsoftId,Utilisateur.email.Utilisateur.classe-> nullable : unRESPONSABLEn'a pas de classe (seuls les étudiants en ont).- Ajout dans l'ERD des annotations
UK(surcode,microsoft_id,email) etnullable(surclasse). - Choix laissé de côté : tailles
@db.NVarChar(n)(colonnes restées enNVARCHAR(1000)par défaut). À reconsidérer plus tard.
Étape 3 — Bloc A : Infrastructure (SallePret, PosteEmprunt) — commit d026b75
SallePretrattachée àCampus(FKcampus_id) ;PosteEmpruntrattaché àSallePret(FKsalle_pret_id).
Étape 4 — Bloc B : CarteEtudiante — commit dfa73cd
- Rattachée à
Utilisateur. - Dette notée :
qr_codedevrait être@unique(sert à l'identification, RG02) — non posé pour rester fidèle à l'ERD.
Étape 5 — Bloc C : Matériel (Materiel, Accessoire, MaterielAccessoire) — commit 0774ee3
- Table de liaison
MaterielAccessoireentreMaterieletAccessoire, sans colonnescreated_at/updated_at. - Dette notée :
@@unique([materielId, accessoireId])etMateriel.statut @default("DISPONIBLE").
Étape 6 — Bloc D : Transactions (Emprunt, Checklist, ChecklistElement) — commit 6908a2b
- Champs de retour/optionnels nullable :
dateRetourReelle,modeIdentificationRetour,commentaireDepart,commentaireRetour,Checklist.commentaire,ChecklistElement.commentaire.- Pourquoi : RG12 crée l'emprunt au départ ; les infos de retour n'existent pas encore. En
NOT NULL, la création serait impossible.
- Pourquoi : RG12 crée l'emprunt au départ ; les infos de retour n'existent pas encore. En
ChecklistElement.accessoireIdrendu nullable : un élément de checklist peut être un libellé libre, sans accessoire catalogué associé (cardinalité 0..1).- Les 9 FK en
NoAction: traçabilité + évitement des cascade paths. - Annotation
nullableajoutée dans l'ERD sur les champs de retour/commentaires d'Empruntetaccessoire_id/commentairede checklist.
Étape 7 — Stratégie Git : branche develop
- Création de
developdepuismaster. Désormais tous les commits vont surdevelop;masterfigé au Bloc C.
Étape 8 — Bloc E : Suivi (Anomalie, Notification, Historique) — commit 0fc9f9e
- Schéma 16/16 complet.
- Nullable selon
0..1:Anomalie.traiteeParId(null tant que non pris en charge),observation,dateResolution;Notification.anomalieId; les 5 FK optionnelles d'Historique(un événement n'a pas toujours d'emprunt/matériel/etc.). - Double relation
AnomalieversUtilisateurnommée :@relation("AnomalieEtudiant")(étudiant concerné) et@relation("AnomalieResponsable")(responsable qui traite). - Defaults :
Anomalie.detecteeAutomatiquement @default(true),Notification.lu @default(false),Notification.dateCreation @default(now()). - Les 12 FK en
NoAction(traçabilité). NotificationetHistoriquecréées sans colonneupdatedAt(seulementdate_creation/created_at).- Annotation
nullableajoutée dans l'ERD surtraitee_par_id,observation,date_resolution,anomalie_idet les 5 FK optionnelles d'Historique.
Étape 9 — Seeds de référence — commit 2c3a5db
- Fichier
prisma/seed.tsautonome (adapter MSSQL, lecture directe des variables DB), lancé vianpm run seed(script ajouté aupackage.json). - Choix
npm run seed(ts-node) plutôt queprisma db seed: l'API de configuration du seed en Prisma 7 (prisma.config.ts) n'étant pas confirmée, un script direct est plus fiable. - Données : 2 rôles (
ETUDIANT,RESPONSABLE), 1 campus (Campus Saint-Christophe, Cergy, 95800, adresse provisoire), 1 salle (Salle de prêt principale), 1 poste (POSTE-01), 6 catégories (Ordinateur portable, Vidéoprojecteur, Tablette, Caméra, Périphérique audio, Câble / Adaptateur). - Idempotence :
upsertsurRole.code;findFirstavantcreatepour les entités sans clé unique. Relance vérifiée (aucun doublon). - Incident : le client Prisma était obsolète (ne connaissait que les 4 modèles de référence). Régénéré avec
npx prisma generateavant le seed. Leçon : après des migrations, régénérer/vérifier le client avant d'exécuter du code qui l'utilise.
Étape 10 — Fixtures de test
- Fichier
prisma/fixtures.ts+ scriptnpm run fixtures(séparé du seed : données de dev/test, non installées en production). - Non destructif : détection via un email témoin (
marie.dupont@ensitech.eu) ; si présent, le script s'arrête (cohérent avec le principe "pas de suppression automatique"). - Contenu : 4 utilisateurs (3 étudiants + 1 responsable), 3 cartes, 6 matériels (statuts variés), 3 accessoires + liaisons, 4 emprunts couvrant
EN_COURS/EN_RETARD/CLOTURE/RETOUR_NON_CONFORME, 6 checklists, 1 anomalie + 1 notification, 2 entrées d'historique. - Idempotence vérifiée (2e exécution = skip).
Contexte métier clarifié — structure ENSUP (impacte la modélisation)
- ENSUP est un groupe multi-campus (Saint-Christophe/Cergy, Saint-Quentin, Nantes, Marseille...).
- Chaque campus héberge deux écoles : ENSUP (filières généralistes) et Ensitech (informatique). Bâtiments et salles partagés.
- La distinction d'école se fait par le domaine email :
ensitech.eu(info) etensup.eu(reste). La validation de domaine (RG, à venir) doit accepter les deux. - Le modèle n'a pas d'entité "École" : seule
Campusexiste. Un campus = un lieu physique partagé par les deux écoles (et non une école). - MVP : on démarre avec le seul campus Saint-Christophe (Cergy) ; les autres campus viendront ensuite.
Étape 11 — Block 1 : middlewares backend
- Structure en couches :
utils/logger.ts,errors/app-error.ts,middlewares/(request-logger, not-found, error-handler). - Gestionnaire d'erreurs global : une
AppErrorrenvoie son statut + message ; toute autre erreur devient une 500 (stack exposée uniquement endevelopment) et est tracée. - Logger de requêtes (méthode, URL, statut, durée) + logger applicatif horodaté.
- CORS restreint à
env.frontendUrl(était ouvert à toutes les origines).SIGTERMgéré en plus deSIGINT(arrêt propre du container Docker). - Express 5 propage nativement les erreurs des handlers async : pas de wrapper
asyncHandlernécessaire. - Vérifié au runtime :
/health200, route inconnue 404 en JSON, requêtes journalisées.
Étape 12 — Block 1 : ESLint + Prettier
- ESLint 10 (flat config
eslint.config.mjs) + typescript-eslint 8 ; Prettier 3 (.prettierrc.json). - Règles de qualité strictes encodées :
no-explicit-any,no-non-null-assertion,explicit-module-boundary-types,no-unused-vars(ignore le préfixe_),prefer-const.eslint-config-prettierdésactive les règles en conflit avec Prettier. - Prettier : quotes simples, point-virgule, 100 colonnes, 2 espaces, trailing commas.
- Scripts :
lint,lint:fix,format,format:check. - État : lint vert sur tout le code existant ; formatage appliqué (3 fichiers) ; build OK.
Étape 13 — Correctif tooling : type-check des scripts Prisma
- Problème :
prisma/seed.tsetfixtures.tsétaient hors duincludedu tsconfig ; l'IDE ne chargeait pas les types Node (processnon reconnu, 2 erreurs). - Correctif :
tsconfig.jsonélargi àsrc+prismaennoEmit(IDE ettsc --noEmit) ; nouveautsconfig.build.jsondédié à la compilationsrc->dist(npm run build). - Bénéfice : les scripts Prisma sont désormais type-checkés (angle mort comblé).
Étape 14 — Block 4 : architecture en couches + 1er endpoint (catalogue matériel)
- Mise en place de l'architecture en couches :
routes/->controllers/->services/->repositories/(un dossier par couche). - Auth simulée temporaire : middleware
current-userqui résout l'utilisateur via l'en-têtex-user-emailet posereq.user(typé viatypes/authenticated-user.ts+ augmentationExpress.Request). À remplacer par la validation JWT au Block 3. - Endpoint
GET /api/materiels(catalogue) : applique RG10 (matérielsDISPONIBLEdu campus de l'étudiant), filtrescategorieIdetq(recherche nom/marque/modèle/référence). - Format de réponse standardisé :
{ "data": ... }(cohérent avec{ "error": ... }). - Vérifié au runtime : 401 sans en-tête / utilisateur inconnu, 200 avec les disponibles du campus, filtres OK, 400 sur
categorieIdinvalide.
Étape 15 — Block 4 : endpoint "mes emprunts en cours"
- Endpoint
GET /api/mes-emprunts: retourne les emprunts non restitués (EN_COURS,EN_RETARD) de l'utilisateur courant, triés par date de retour prévue, avec le matériel et sa catégorie inclus. - RG15 : filtrage par
utilisateurId(chacun ne voit que ses propres emprunts). - Réutilise l'architecture en couches et l'auth simulée déjà en place.
- Vérifié au runtime : Marie 1 (
EN_COURS, sonCLOTUREexclu), Lucas 1 (EN_RETARD), Sofia 0 (sonRETOUR_NON_CONFORMEexclu), 401 sans en-tête.
Étape 16 — Block 4 : profil et identification
GET /api/auth/me(protégé) : renvoie le profil complet de l'utilisateur courant (role + campus).GET /api/auth/carte/:qr(public) : identification par QR code (RG02/RG03) ; contrôles carte active, non expirée et compte actif ; renvoie le profil.- Refactor du routage :
currentUserappliqué par sous-routeur (au lieu d'un middleware global) pour laisser la route d'identification publique. - Vérifié au runtime :
/me200 (profil Marie) et 401 sans en-tête ;/carteQR valide 200 sans en-tête (route publique), QR inconnu 404.
Étape 17 — DTO de sortie sur les endpoints existants
- Dossier
src/dtos/: par ressource, une interfaceXxxResponse+ un mapper purtoXxxResponse(utilisateur, matériel, emprunt). - Mapping effectué dans le controller (couche présentation) ; les services continuent de renvoyer les entités (réutilisables).
- Champs internes désormais masqués :
microsoftId, timestamps, FK brutes,numeroInventaire/numeroSerie. - Vérifié au runtime sur
/me,/materiels,/mes-emprunts.
Étape 18 — Durcissement du .gitignore (sécurité)
- Trou comblé :
**/.envne couvrait pas les variantes (.env.local,.env.production...). Ajout de**/.env.*avec exception!**/.env.example. - Préventif : clés/certificats (
*.pem,*.key,*.crt,*.cert,*.pfx,*.p12) pour Azure AD/TLS à venir ; dumps de base (*.bak,*.dump) ;**/coverage/;*.tsbuildinfo. - Vérifié : aucun secret n'était déjà suivi ; les vrais
.envrestent ignorés ;.env.example(placeholders) reste versionné.
Étape 19 — Block 4 : création d'emprunt (POST /api/emprunts)
- Écriture transactionnelle : réservation atomique du matériel (
updateMany where statut=DISPONIBLE), création de l'emprunt (EN_COURS), de la checklist de départ et de ses éléments. Rollback global si une étape échoue. - Règles : RG07 (matériel disponible), RG10 (matériel du campus de l'étudiant), RG11 (checklist obligatoire non vide), RG12 (matériel ->
EMPRUNTE, horodatage). - Validation d'entrée manuelle (
CreerEmpruntRequest,parseCreerEmpruntRequest) : aucune dépendance ajoutée. Durée d'emprunt par défaut : +14 jours. - Contrôle du poste (existe + même campus, RG05). Routage :
POST /api/empruntsetGET /api/mes-empruntssur des routeurs séparés. - Vérifié au runtime : 401 sans auth, 400 checklist vide, 404 matériel inconnu, 201 création (matériel ->
EMPRUNTE, +14j), 409 doublon (réservation atomique).
Étape 20 — Block 4 : restitution + anomalie automatique (POST /api/emprunts/:id/restitution)
- Comparaison automatique départ/retour (RG17) : un élément présent au départ mais absent/détérioré au retour rend la restitution non conforme (RG20). Appariement par
accessoireIdsinon parnomElement. - Restitution atomique : checklist de retour + mise à jour emprunt/matériel + (si non conforme) anomalie
DETECTEE+ notifications. - RG15 (propriétaire), statut restituable, RG18 (conforme ->
CLOTURE+ matérielDISPONIBLE), RG19 (non conforme ->RETOUR_NON_CONFORME+ matérielDETERIORE/NON_CONFORME). - RG24 : notification à tous les responsables (
RESPONSABLE) du campus de l'emprunt. - Vérifié au runtime : 404/403/409 ; restitution conforme (CLOTURE + DISPONIBLE) ; non conforme (RETOUR_NON_CONFORME + NON_CONFORME + anomalie + notification à Karim).
- Block 4 (API Étudiant) terminé : 6/6 endpoints.
Étape 21 — Frontend : setup Flutter Web + écran d'accueil ENSUP
- Projet Flutter Web créé (
eme-frontend/),google_fontsajouté (Darker Grotesque pour les titres, Titillium Web pour le corps). - Thème ENSUP (
theme/ensup_colors.dart,theme/ensup_theme.dart) : couleurs de la charte graphique. - Composants réutilisables :
EnsupTopBar,ProfileCard,ActionCard. - Écran d'accueil (
screens/home_screen.dart) fidèle à la maquette : topbar bleu foncé, carte profil, deux cartes Emprunter/Restituer. Données statiques (pas encore branché à l'API). - Convention
CLAUDE.mdrespectée : guillemets doubles en Dart (règle lintprefer_single_quotesdésactivée en conséquence). flutter analyze: aucun problème. App lancée dans Chrome (http://localhost:5000).
Étape 22 — Suppression du PDF de charte graphique
- PDF de charte ENSUP retiré du dépôt (redondant : la maquette validée applique la charte, et les couleurs/typos sont dans
CONTEXT.md§7). - Références mises à jour dans
CLAUDE.mdetCONTEXT.mdpour pointer vers la maquette. - Le PDF reste récupérable dans l'historique Git si besoin (logo officiel source).
Étape 23 — Frontend : écran d'identification (écran de démarrage)
- Correction : l'écran de démarrage est l'identification (
s-loginde la maquette), pas l'accueil étudiant. Logo, "Bienvenue sur EME", deux options (scanner carte / compte ENSUP Microsoft 365), bouton accès responsable. EnsupTopBarrendue réutilisable (utilisateur optionnel, marque paramétrable) ; nouveau widgetIdentificationOption; coins ENSUP aussi sur cet écran.- Navigation identification -> accueil étudiant (
HomeScreen).
Étape 24 — Frontend : écran catalogue matériel
- Écran catalogue (
s-catalogue) : recherche fonctionnelle + filtres par catégorie (chips) + liste de matériels avec statut (Disponible/Emprunté) et état vide. - Nouveaux composants :
MaterielCard,StatusPill, modèleMaterielItem. Données statiques (4 matériels de la maquette). - Navigation : Accueil (Emprunter) -> Catalogue ; bouton retour vers l'accueil. « Sélectionner » -> placeholder (détail à venir).
Étape 25 — Frontend : écran détail matériel
- Écran détail (
s-detail) : caractéristiques (référence, catégorie, marque, modèle, état, campus, statut) + accessoires du kit (tags) + aperçu + boutons « Démarrer l'emprunt » / « Retour au catalogue ». - Modèle
MaterielItemenrichi (marque, modèle, état, accessoires) ; données statiques mises à jour. - Navigation : Catalogue (Sélectionner) -> Détail ; « Démarrer l'emprunt » -> placeholder (checklist à venir).
Note historique : les étapes 21 à 25 décrivent l'état initial statique du frontend. Elles ont été remplacées fonctionnellement par les branchements API des étapes 26 à 32.
Dette technique en attente
À traiter ensemble plus tard (avec mise à jour ERD en miroir) :
| Dette | Statut | Impact V1 |
|---|---|---|
CarteEtudiante.qr_code -> @unique |
À faire avec migration + ERD | Moyen : sécurise l'identification QR. |
MaterielAccessoire -> @@unique([materielId, accessoireId]) |
À faire avec migration + ERD | Moyen : évite les doublons d'accessoires. |
Materiel.statut -> @default("DISPONIBLE") |
À faire avec migration + ERD | Faible : le code fournit déjà le statut explicitement. |
Tailles de colonnes @db.NVarChar(n) |
À cadrer | Faible V1, important pour qualité BDD. |
| Swagger/OpenAPI | À faire | Moyen : utile pour tester/documenter l'API. |
| Validation réelle Azure AD | En attente des identifiants Entra ID | Fort : le code OIDC/MSAL/JWT est prêt, mais une connexion Microsoft réelle doit encore être testée sur le tenant ENSUP. |
| Limite d'emprunts actifs par étudiant | À valider métier | Non bloquant V1 ; décision métier non présente dans les règles actuelles. |
Étape 26 — Connexion frontend ↔ API (catalogue)
- Package
httpajouté. Coucheservices/api_client.dart: URL de base, en-tête d'auth simulée (x-user-email: lucas.martin@ensitech.eu), gestion des erreurs (serveur injoignable, message{error:{message}}). services/materiel_service.dart(getCatalogue) +MaterielItem.fromJson(icône déduite de la catégorie, champs absents complétés).- Écran catalogue branché via
FutureBuilder: chargement / données / erreur + bouton Réessayer. Filtres de catégorie déduits des vraies données. - CORS backend assoupli en développement (
origin: truesiNODE_ENV=development), strict en production. - Testé en réel côté backend : Docker SQL Server OK, backend compilé OK,
/health,/api/auth/me,/api/materielsOK, 401 sansx-user-emailOK.
Étape 27 — Connexion frontend ↔ API (détail matériel)
- Correctif runtime backend :
npm run devlance maintenantts-node --files, sinon l'augmentationExpress.Request.usern'était pas chargée parts-nodemalgré un build TypeScript vert. - Endpoint
GET /api/materiels/:idajouté : détail filtré par campus utilisateur, avec catégorie, campus et accessoires du kit. - Frontend :
MaterielItemporte maintenant l'id,MaterielService.getDetail(id)consomme le nouvel endpoint, et le catalogue charge le détail réel avant de naviguer vers l'écran détail. - Testé en réel côté backend :
/api/materiels/1renvoie le PC avec accessoires (Chargeur,Souris) ;/api/materiels/abcrenvoie 400. - Limite environnement :
flutter analyze,flutter analyze --no-pubetdart formatrestent bloqués jusqu'au timeout dans le sandbox. À relancer dans un terminal Flutter local.
Étape 28 — Connexion frontend ↔ API (création d'emprunt)
- Branche dédiée
feat/frontend-emprunt-apicréée après merge defeat/catalogue-detail-apidansdevelop. ApiClient.postajouté etEmpruntService.creerEmpruntconsommePOST /api/empruntsavec l'auth simulée.- Checklist de départ branchée sur l'API : construction du payload (
materielId,posteEmpruntId,modeIdentification, commentaire, éléments), état de chargement, affichage d'erreur via snackbar. - Un matériel sans accessoire génère un élément de checklist portant le nom du matériel, afin de respecter RG11 côté backend (checklist obligatoire non vide).
- Confirmation alimentée par la réponse API (
id,dateEmprunt, matériel renvoyé). - Testé sans mutation de données :
POST /api/empruntsavec checklist vide renvoie bien 400La checklist de depart est obligatoire (RG11).
Étape 29 — Données de démonstration catalogue
- Branche dédiée
feat/demo-catalogue-fixturescréée après merge defeat/frontend-emprunt-apidansdevelop. prisma/fixtures.tsenrichi avec un catalogue de démonstration idempotent : si les fixtures de base existent déjà, le script assure seulement les matériels de catalogue manquants.- 8 matériels disponibles ajoutés : Lenovo ThinkPad, MacBook Air, Surface Pro, vidéoprojecteur Epson, caméra Canon, casque Jabra, kit câbles HDMI/USB-C, enceinte JBL.
- Accessoires associés assurés sans doublon logique par recherche de nom/référence avant création.
- Vérifié en réel :
npm run fixturesOK ;GET /api/materielspour Lucas renvoie 10 matériels disponibles.
Étape 30 — Connexion frontend ↔ API (restitution)
- Branche dédiée
feat/frontend-restitution-apicréée après merge defeat/demo-catalogue-fixturesdansdevelop. EmpruntItem.fromJsonajouté pour mapperGET /api/mes-emprunts.EmpruntService.getMesEmprunts()etEmpruntService.restituerEmprunt()ajoutés.- Écran de sélection restitution branché sur les vrais emprunts en cours, avec chargement, erreur, état vide et chargement du détail matériel avant la checklist.
- Checklist retour branchée sur
POST /api/emprunts/:id/restitution, avec commentaire optionnel, état de chargement et erreurs via snackbar. - Le résultat affiché se base sur le statut renvoyé par le backend (
CLOTURE=> conforme, sinon anomalie), afin de rester cohérent avec la comparaison serveur. - Vérifié sans mutation :
GET /api/mes-empruntsrenvoie les emprunts de Lucas ; restitution d'un identifiant inexistant renvoie 404.
Étape 31 — Stabilisation parcours étudiant complet
- Branche dédiée
feat/student-flow-stabilizationcréée après merge defeat/frontend-restitution-apidansdevelop. - Docker SQL Server relancé puis tests runtime faits avec le backend compilé.
- Flux conforme validé en réel : catalogue -> détail -> création emprunt -> apparition dans
mes-emprunts-> restitution conforme -> statutCLOTURE-> matériel de nouveau visible dans le catalogue. - Flux non conforme validé en réel : création emprunt -> restitution avec élément absent -> statut
RETOUR_NON_CONFORME-> matériel retiré du catalogue disponible. - Aucun correctif code nécessaire après ces tests ; backend
buildetlintrestent verts.
Étape 32 — Polish V1 étudiant
- Branche dédiée
feat/v1-student-polishcréée après merge defeat/student-flow-stabilizationdansdevelop. - Identité simulée et campus MVP centralisés dans
lib/demo_identity.darttant que l'auth Azure AD n'est pas branchée. - Libellés UI harmonisés sur le contexte réel du MVP :
Saint-Christophe · Cergy/Ensitech Cergyau lieu deParis · Ensitech. - Commentaire obsolète du modèle
MaterielItemcorrigé : les données viennent maintenant de l'API. TODO.mdmis à jour : les parcours emprunt et restitution étudiant sont maintenant branchés API.
Étape 33 — Clarification du journal de décisions
- Branche dédiée
docs/review-current-statecréée depuisdevelop. - Ajout d'une synthèse d'état courant pour éviter de devoir relire tout l'historique.
- Correction de la convention Git :
developest la branche d'intégration, les travaux passent par branches dédiées. - Ajout des commandes validées et du scénario de démo étudiant testé.
- Dette technique reformatée en tableau avec statut et impact V1.
- Clarification des étapes frontend statiques historiques : elles sont conservées pour mémoire mais remplacées par les branchements API ultérieurs.
Étape 34 — API responsable : dashboard
- Branche dédiée
feat/responsable-dashboard-apicréée depuisdevelop. - Endpoint
GET /api/responsable/dashboardajouté, protégé par rôleRESPONSABLE. - Périmètre campus appliqué via
user.campusId(RG27). - KPIs exposés : matériels par statut, emprunts par statut, anomalies par statut, notifications non lues.
- Activité récente exposée depuis l'historique, avec utilisateur, matériel et emprunt associé.
- Vérifié au runtime : Karim (
RESPONSABLE) obtient 200 avec KPIs ; Lucas (ETUDIANT) obtient 403.
Étape 35 — API responsable : consultation des emprunts
- Branche dédiée
feat/responsable-emprunts-apicréée après merge du dashboard responsable dansdevelop. - Endpoint
GET /api/responsable/empruntsajouté, protégé par rôleRESPONSABLE. - Filtrage par campus du responsable appliqué systématiquement (RG27).
- Filtre optionnel
statutajouté pour RG28 :EN_COURS,EN_RETARD,CLOTURE,RETOUR_NON_CONFORME,ANNULE. - Réponse enrichie avec l'étudiant, le matériel, la catégorie, les dates et le statut.
- Vérifié au runtime : Karim obtient les emprunts du campus,
statut=EN_COURSfiltre correctement, statut invalide renvoie 400, Lucas obtient 403.
Étape 36 — API responsable : consultation du stock
- Branche dédiée
feat/responsable-stock-apicréée après merge de la consultation des emprunts responsable dansdevelop. - Endpoint
GET /api/responsable/materielsajouté, protégé par rôleRESPONSABLE. - Filtrage par campus du responsable appliqué systématiquement (RG27/RG29).
- Filtres optionnels ajoutés :
statut,categorieId,q(nom, marque, modèle, référence). - Contrairement au catalogue étudiant, cet endpoint retourne tout le stock actif du campus, quel que soit le statut.
- Réponse enrichie avec catégorie et accessoires attendus.
- Vérifié au runtime : Karim obtient tout le stock du campus,
statut=DISPONIBLEetq=MacBookfiltrent correctement, statut invalide renvoie 400, Lucas obtient 403.
Étape 37 — API responsable : consultation des anomalies
- Branche dédiée
feat/responsable-anomalies-apicréée après merge de la consultation du stock responsable dansdevelop. - Endpoint
GET /api/responsable/anomaliesajouté, protégé par rôleRESPONSABLE. - Filtrage par campus du responsable appliqué systématiquement via l'emprunt lié à l'anomalie (RG27).
- Filtres optionnels ajoutés :
statut(DETECTEE,EN_COURS_TRAITEMENT,RESOLUE,CLOTUREE) ettype. - Réponse enrichie avec anomalie, emprunt, étudiant concerné, matériel, catégorie et responsable de traitement si renseigné.
- Limite volontaire : consultation uniquement ; le cycle de traitement/résolution reste à développer.
Étape 38 — API responsable : notifications
- Branche dédiée
feat/responsable-notifications-apicréée après merge de la consultation des anomalies responsable dansdevelop. - Endpoint
GET /api/responsable/notificationsajouté, protégé par rôleRESPONSABLE. - Filtre optionnel
lu=true|falseajouté pour séparer les notifications lues et non lues. - Endpoint
PATCH /api/responsable/notifications/:id/luajouté pour marquer une notification du responsable connecté comme lue. - Endpoint
PATCH /api/responsable/notifications/lu-toutesajouté pour marquer toutes les notifications non lues du responsable connecté comme lues. - Réponse enrichie avec l'anomalie liée et le matériel concerné lorsque la notification pointe vers une anomalie.
Étape 39 — API responsable : historique et export
- Branche dédiée
feat/responsable-historique-apicréée après merge des notifications responsable dansdevelop. - Endpoint
GET /api/responsable/historiqueajouté, protégé par rôleRESPONSABLE. - Filtrage par campus du responsable appliqué systématiquement (RG27).
- Filtres optionnels ajoutés :
action,utilisateurId,materielId,empruntId,dateDebut,dateFin. - Endpoint
GET /api/responsable/historique/export.csvajouté avec les mêmes filtres. - Export CSV généré côté API avec les colonnes principales : date, action, description, utilisateur, email, matériel, emprunt.
Étape 40 — API responsable : cycle de statut des anomalies
- Branche dédiée
feat/responsable-anomalies-cycle-apicréée après merge de l'historique responsable dansdevelop. - Endpoint
PATCH /api/responsable/anomalies/:id/statutajouté, protégé par rôleRESPONSABLE. - Filtrage par campus appliqué avant toute modification pour empêcher le traitement d'une anomalie hors campus (RG27).
- Transitions autorisées :
DETECTEE -> EN_COURS_TRAITEMENT -> RESOLUE -> CLOTUREE. - Le responsable connecté est enregistré dans
traiteeParId; une observation optionnelle peut être conservée. - Une entrée d'historique
TRAITEMENT_ANOMALIEest créée à chaque transition.
Étape 41 — Frontend responsable : premier branchement API
- Branche dédiée
feat/responsable-frontend-apicréée pour isoler le travail frontend responsable. - Le bouton "Accès responsable matériel" de l'écran d'identification ouvre maintenant un écran responsable.
- Client API étendu pour accepter l'e-mail simulé du responsable (
karim.benali@ensup.eu) et les requêtesPATCH. - Service frontend responsable ajouté pour consommer dashboard, emprunts, stock, anomalies, notifications et historique.
- Écran responsable ajouté avec onglets : dashboard, emprunts, stock, anomalies, notifications, historique.
- Les anomalies peuvent être avancées au prochain statut autorisé via l'API.
- Vérification statique effectuée avec l'exécutable Dart direct :
dart analyzeOK. Le wrapperflutterreste instable dans cette session et bloque au lancement web automatisé.
Étape 42 — Frontend responsable : polish opérationnel
- Branche dédiée
feat/responsable-frontend-polishcréée après merge du premier branchement responsable. - Statuts responsables remplacés par des libellés métier lisibles et des badges colorés.
- Recherche ajoutée sur les onglets emprunts, stock, anomalies, notifications et historique.
- Les lignes de listes affichent désormais une méta-information utile : identifiant emprunt, marque/modèle, date de détection, date de notification ou auteur historique.
- Action "Tout marquer lu" ajoutée dans l'onglet notifications.
- Action export CSV rendue visible dans l'onglet historique avec indication de l'endpoint disponible.
- Vérification statique :
dart analyzeOK.
Étape 43 — Synchronisation de l'état courant
- Synthèse mise en cohérence avec les étapes 34 à 42 : API et frontend responsable désormais fonctionnels pour la V1.
- Documentation corrigée pour refléter l'existence du README principal.
- Limites restantes explicitées : authentification Azure AD, téléchargement CSV frontend, tests automatisés, OpenAPI et guides utilisateur.
- Commandes de vérification actualisées : build et lint backend verts, analyse Dart directe sans erreur.
Étape 44 — Refonte premium de l'espace responsable
- Branche dédiée
style/responsable-premium-dashboardcréée depuisdevelop. - L'espace responsable adopte une structure de supervision distincte du parcours étudiant : barre supérieure métier, navigation latérale sur ordinateur et navigation compacte sur petit écran.
- Dashboard enrichi avec disponibilités, emprunts en cours, retards, anomalies actives, notifications non lues, activité récente et taux de disponibilité du parc.
- Accès directs ajoutés depuis les points d'attention vers les vues emprunts, stock, anomalies et notifications.
- Les listes métier partagent désormais une hiérarchie visuelle, une recherche et des lignes responsives cohérentes avec la charte ENSUP.
- Aucun changement backend ni métier ; rendu validé manuellement dans le navigateur et
dart analyzesans erreur.
Étape 45 — Téléchargement CSV de l'historique responsable
- Branche dédiée
feat/responsable-historique-exportcréée depuisdevelop. - Client HTTP étendu pour récupérer un fichier binaire avec son type de contenu et son nom.
- Le bouton
Export CSVappelle désormais l'endpoint responsable avec l'identité simulée de Karim et déclenche le téléchargement navigateur. - Un état de chargement bloque les doubles clics et les erreurs API sont affichées dans l'interface.
- Endpoint vérifié au runtime : réponse
200, typetext/csv, nomhistorique-responsable.csvet contenu non vide. - Vérification statique :
dart analyzesans erreur.
Étape 46 — Refonte premium de l'espace étudiant
- L'ordre actuel du parcours est confirmé : identification, puis choix
EmprunterouRestituer. - Branche dédiée
style/student-premium-workspacecréée depuisdevelop. - Charte et maquette conservées : couleurs ENSUP, typographies, barre supérieure, coins de marque et structure des écrans.
- Barre supérieure rendue responsive, avec priorité donnée au titre et à l'identité sur les petites largeurs.
- Accueil rééquilibré avec profil identifié, hiérarchie renforcée et cartes d'action adaptatives avec états de survol.
- Catalogue, détail matériel et sélection de restitution enrichis sans modifier leurs données ni leurs actions.
- Détail et checklists passent automatiquement de deux colonnes à une colonne sur écran étroit ; tableau de contrôle et lignes de matériel évitent les débordements.
- Écrans de confirmation et de résultat conservés fonctionnellement et harmonisés via les composants partagés.
- Vérification statique :
dart analyzesans erreur.
Étape 47 — Sécurisation SSO Microsoft Entra ID
- Branche dédiée
feat/block-3-azure-ssocréée depuisdevelop. - Backend configuré avec deux modes :
demoen développement etazurepour une authentification réelle ; le mode démo est explicitement interdit en production. - Middleware d'authentification refactoré vers un service dédié. En mode Azure,
x-user-emailest ignoré et un Bearer Token Microsoft est obligatoire. - Validation JWT ajoutée : signature RSA via les clés JWKS Microsoft, algorithme
RS256, issuer, audience, tenant, scopeaccess_as_user, identifiantoidet domainesensup.eu/ensitech.eu. - L'utilisateur, son rôle et son campus restent résolus depuis
eme_db. Un étudiant obtient403sur la supervision, tandis que le responsable de démonstration obtient200. - Frontend doté d'un double mode de session. La simulation sélectionne Lucas ou Karim sans pouvoir être utilisée en mode Azure.
- Bibliothèque officielle
@azure/msal-browserintégrée via un bundle local construit avec esbuild et un pont typédart:js_interop. - Flux OpenID Connect préparé avec connexion Microsoft, acquisition silencieuse de l'Access Token, appel de
/api/auth/me, navigation selon le rôle local, restauration après actualisation et déconnexion MSAL. - Profil authentifié typé et affiché dans les espaces étudiant et responsable : nom, initiales, classe, rôle et campus ne sont plus figés sur les identités de démonstration.
- Vérifications réussies : build et lint backend, analyse Dart, compilation Flutter Web complète et contrôles runtime des rôles en mode démo.
- Limite actuelle : faute d'identifiants Entra ID, le flux Microsoft réel n'a pas encore pu être exécuté. Le QR sécurisé reste un sous-bloc séparé à développer après le SSO.
- Commits :
313bb1c,530bd52,ef31e2a,dc208fa,36224f3.
Dernière mise à jour : 2026-07-23 — SSO Microsoft Entra ID prêt à configurer, mode démo sécurisé actif.