Consultation des specs dans l'app (menu Specs + rendu Markdown/Mermaid)

Nouvelle fonctionnalité : consulter les documents de spécification (exigences,
conception technique, plan de tâches) en lecture seule dans le frontend.

Backend :
- SpecsController (GET /api/specs, GET /api/specs/{cle}) protégé par l'auth
  globale ; SpecDocumentService avec whitelist (pas de path traversal) et
  lecture depuis le dossier specs/ embarqué, repli sur .kiro/specs en dev.
- DTOs SpecDocumentDto / SpecContenuDto ; service enregistré dans Program.cs.

Docker :
- Contexte de build backend = racine du dépôt (dockerfile: backend/Dockerfile)
  pour embarquer .kiro/specs/*.md dans l'image (app autonome).
- .dockerignore racine ajouté (exclut frontend/node_modules, bin/obj, etc.).

Frontend :
- SpecService + SpecsComponent (lazy-loadé) : page dédiée avec menu latéral par
  document ; rendu Markdown via marked (GFM) assaini par DOMPurify.
- Diagrammes Mermaid (ex. graph TB) rendus en SVG via mermaid.js importé
  dynamiquement ; déclenchement après résolution du @ViewChild (setTimeout).
- Barre de navigation : simple lien « Specs » (le choix du document se fait dans
  le menu latéral de la page, pas dans la barre).
- Routes /specs et /specs/:cle protégées par authGuard.

Specs : exigence 19 (consultation des documents) ajoutée à requirements.md ;
design.md complété (DTOs, endpoints, composant, rendu Mermaid, note Docker).
This commit is contained in:
2026-09-16 08:10:41 +02:00
parent 47e1416a16
commit 9d2b676c84
21 changed files with 1929 additions and 8 deletions
+41 -1
View File
@@ -33,6 +33,7 @@
| 21 | Authentification | Compte unique (e-mail + mot de passe), connexion par JWT (12 h par défaut), réinitialisation de mot de passe par e-mail, garde de session serveur |
| 22 | Trajet aller/retour | Case à cocher A/R doublant la distance comptée (Distance_Effective) sans ligne supplémentaire ; badge A/R en liste et mention « (A/R) » sur la carte |
| 23 | Barème multi-tranches & recopie | Tranches paramétrables par puissance fiscale (dernière tranche illimitée), coefficient sur 3 décimales, bouton « Recopier le dernier barème connu » |
| 24 | Consultation des specs | Lien « Specs » vers une page dédiée (menu latéral Exigences / Conception / Tâches) affichant les documents Markdown rendus (dont les diagrammes Mermaid), en lecture seule et derrière l'authentification |
### Contraintes techniques
@@ -144,7 +145,8 @@ src/
│ │ │ ├── adresse-cache.service.ts # Autocomplétion adresses
│ │ │ ├── adresse-nommee.service.ts # CRUD carnet d'adresses nommées
│ │ │ ├── profil.service.ts # CRUD profil
│ │ │ └── auth.service.ts # Inscription, connexion, session, reset mot de passe
│ │ │ ├── auth.service.ts # Inscription, connexion, session, reset mot de passe
│ │ │ └── spec.service.ts # Lecture des documents de spécification (specs)
│ │ ├── models/
│ │ │ ├── trajet.model.ts
│ │ │ ├── resume-mensuel.model.ts
@@ -201,6 +203,9 @@ src/
│ │ │ ├── register.component.ts # Création de l'unique compte (étape 1 de l'initialisation)
│ │ │ ├── forgot-password.component.ts # Demande de réinitialisation par email
│ │ │ └── reset-password.component.ts # Définition d'un nouveau mot de passe via jeton
│ │ ├── specs/
│ │ │ ├── specs.component.ts # Rendu Markdown des documents de spécification (lazy-loadé)
│ │ │ └── specs.component.html
│ ├── core/
│ │ └── guards/
│ │ ├── auth.guard.ts # Valide la session serveur (GET /api/auth/moi) avant les vues protégées
@@ -333,6 +338,14 @@ src/
> **Décision — stockage du JWT dans `localStorage`** : retenu pour sa simplicité, malgré le risque XSS, acceptable pour une application personnelle mono-utilisateur. Le cookie HttpOnly a été rejeté pour éviter la complexité de protection CSRF.
**`SpecsComponent`** (documents de spécification — Exigence 19)
- La barre de navigation principale expose un simple lien « Specs » vers `/specs` (redirigé vers le premier document) ; le choix du document se fait dans le **menu latéral** de la page, pas dans la barre.
- Route paramétrée `/specs/:cle` ; **lazy-loadée** (`loadComponent`) pour sortir la librairie Markdown du bundle initial
- Colonne gauche : menu listant les documents (`GET /api/specs`), le document indisponible étant signalé ; colonne droite : contenu rendu
- Rendu : le Markdown (`GET /api/specs/{cle}`) est converti en HTML par **`marked`** (GFM : titres, listes, tableaux, code), puis **assaini par `DOMPurify`** avant injection (`[innerHTML]`) — Exigence 19.7
- **Diagrammes Mermaid** : un renderer `marked` transforme les blocs ` ```mermaid ` en `<pre class="mermaid">` ; après injection du HTML (déclenchée via `setTimeout` pour laisser Angular résoudre le `@ViewChild`), **Mermaid.js** (importé dynamiquement) rend ces blocs en SVG (`securityLevel: 'loose'` pour accepter les libellés HTML type `<br/>`). En cas d'échec de rendu d'un diagramme, le bloc de code brut reste visible.
- Accès derrière `authGuard` (mêmes règles que les autres vues protégées)
**`ProfilConfigureGuard`** (garde de route Angular — `CanActivate` / `CanActivateFn`)
- Au chargement de l'application, appelle `ProfilService.getEtat()` (`GET /api/profil/etat`)
- Si `EstConfigure` est `false`, redirige vers la route d'onboarding (`/onboarding`) et bloque l'accès à la saisie / consultation des trajets tant que le profil n'est pas configuré
@@ -1167,6 +1180,22 @@ public record ResetPasswordDto(
string Token, // jeton en clair reçu par email
string MotDePasse // nouveau mot de passe, >= 8 caractères
);
// --- Documents de spécification (Exigence 19) ---
// Métadonnées d'un document (élément du sous-menu)
public record SpecDocumentDto(
string Cle, // whitelist : "requirements" | "design" | "tasks"
string Titre, // libellé lisible (ex. « Exigences »)
bool Disponible // fichier présent et lisible
);
// Contenu Markdown d'un document
public record SpecContenuDto(
string Cle,
string Titre,
string Markdown // contenu brut, rendu en HTML côté frontend
);
```
---
@@ -1274,6 +1303,15 @@ public record ResetPasswordDto(
| `PUT` | `/api/montants-regles` | Enregistrer/mettre à jour un montant réglé | `MontantRegleDto` | `200 OK` + `MontantRegleDto` |
| `GET` | `/api/regularisation/{annee}?vehiculeId={id}` | Synthèse annuelle de régularisation : `RegularisationAnnuelleDto` avec les 12 `LigneSyntheseMoisDto`, le coefficient et la base de la tranche annuelle, le total réel (barème plein) et la régularisation (réel − payé) | — | `200 OK` + `RegularisationAnnuelleDto` |
#### Documents de spécification (Exigence 19)
> Endpoints **protégés** (authentification requise). L'accès est restreint à une **whitelist** de clés (`requirements`, `design`, `tasks`) : aucun chemin de fichier n'est construit à partir d'une entrée libre (pas de path traversal).
| Méthode | Route | Description | Réponse succès |
|---------|-------|-------------|----------------|
| `GET` | `/api/specs` | Lister les documents et leur disponibilité (sous-menu) | `200 OK` + `SpecDocumentDto[]` |
| `GET` | `/api/specs/{cle}` | Contenu Markdown d'un document (clé whitelistée) | `200 OK` + `SpecContenuDto` ; `404` si clé inconnue / fichier absent |
#### Codes d'erreur standardisés
| Code HTTP | Cas |
@@ -1665,6 +1703,8 @@ volumes:
Les **migrations EF Core sont appliquées automatiquement au démarrage du backend** (`await dbContext.Database.MigrateAsync()` dans `Program.cs` avant `app.Run()`). Ainsi, au premier lancement, la base `/data/trajets.db` est créée sur le volume monté ; aux lancements suivants, elle est mise à jour avec les migrations en attente sans intervention manuelle.
> **Documents de spécification embarqués** : le `Dockerfile` backend a pour contexte la racine du dépôt et copie `.kiro/specs/schotziad-km-tracker/{requirements,design,tasks}.md` dans `./specs/` de l'image. Le `SpecDocumentService` lit en priorité ce dossier embarqué (`ContentRootPath/specs`), avec repli sur `.kiro/specs/...` en développement. L'application est ainsi autonome, sans montage du dépôt à l'exécution.
> **Migrations notables** : `VehiculeDenomination` (dénomination du véhicule), `TrajetGeometrieJson` (géométrie d'itinéraire portée par le trajet), `TrancheBaremeKmMaxNullable` / bornes exclusives / coefficient numérique (barème multi-tranches à dernière tranche illimitée), `AjoutAuthentification` (comptes + jetons de réinitialisation), `TrajetAllerRetour` (indicateur aller/retour).
## Error Handling
@@ -62,6 +62,7 @@ L'application est composée d'un frontend Angular/TypeScript et d'un backend C#.
- **Jeton_Reinitialisation** : Un jeton à usage unique et à durée de vie limitée, envoyé par e-mail, permettant de définir un nouveau Mot_De_Passe sans connaître l'ancien.
- **Aller_Retour** : Un indicateur booléen d'un Trajet signifiant que le déplacement est effectué dans les deux sens. Lorsqu'il est vrai, la Distance comptée du Trajet (Distance_Effective) est le double de la distance simple mesurée entre le départ et l'arrivée.
- **Distance_Effective** : La distance comptée d'un Trajet dans tous les agrégats (liste, totaux, carte, PDF, barème) : égale à la distance simple, ou à son double lorsque le Trajet est un Aller_Retour.
- **Document_Specification** : Un document de conception du projet consultable en lecture seule dans l'Application : les Exigences (requirements), la Conception technique (design) et le Plan de tâches (tasks), rendus depuis leur source Markdown.
---
@@ -432,3 +433,20 @@ L'application est composée d'un frontend Angular/TypeScript et d'un backend C#.
5. WHEN l'utilisateur consulte l'infobulle d'un Trajet Aller_Retour sur la Carte, THE Frontend SHALL faire suivre la distance affichée de la mention « (A/R) ».
6. THE Backend SHALL persister l'indicateur Aller_Retour de chaque Trajet et le conserver lors des modifications ne portant pas sur ce champ.
---
### Requirement 19: Consultation des documents de spécification
**User Story:** En tant qu'utilisateur, je veux consulter les documents de spécification du projet (exigences, conception technique, plan de tâches) directement dans l'application, afin de disposer d'une référence lisible sans quitter l'outil.
#### Acceptance Criteria
1. THE Frontend SHALL afficher, dans la barre de navigation principale, un lien « Specs » menant à une page dédiée ; cette page présente un menu latéral listant chaque Document_Specification disponible : « Exigences », « Conception technique » et « Plan de tâches ».
2. WHEN l'utilisateur sélectionne un Document_Specification dans le menu latéral, THE Frontend SHALL afficher le contenu du document rendu de façon lisible (titres, listes, tableaux, blocs de code) à partir de sa source Markdown, ET SHALL rendre les blocs de diagramme Mermaid (ex. `graph TB`) sous forme de schémas graphiques.
3. THE Backend SHALL exposer les Documents_Specification en lecture seule via une API, en restreignant les documents accessibles à une liste fermée (exigences, conception, tâches) afin d'empêcher tout accès à un fichier arbitraire.
4. THE Backend SHALL exiger un utilisateur authentifié pour accéder aux Documents_Specification (mêmes règles d'accès que les autres données de l'Application) ; en l'absence de jeton valide, THE Backend SHALL retourner une erreur HTTP 401.
5. IF l'utilisateur demande un Document_Specification inconnu ou absent, THEN THE Backend SHALL retourner une erreur HTTP 404 et THE Frontend SHALL afficher un message indiquant que le document est introuvable.
6. WHERE le fichier d'un Document_Specification n'est pas disponible (ex. plan de tâches incomplet ou absent), THE Frontend SHALL signaler ce document comme indisponible dans le menu latéral tout en affichant les autres documents.
7. THE Frontend SHALL assainir le contenu HTML issu du rendu Markdown avant affichage, afin d'éviter l'injection de contenu actif.
8. IF un diagramme Mermaid ne peut pas être rendu (syntaxe non reconnue), THEN THE Frontend SHALL conserver l'affichage du bloc de code brut correspondant sans empêcher le rendu des autres diagrammes ni du reste du document.