Files
MadJax 0e6a97ca61 Renommage : TrajetKmTracker -> SchotzIadKmTracker (backend, specs, frontend)
- Backend : projets, solution, namespaces et références
  TrajetKmTracker.Api/.Tests -> SchotzIadKmTracker.Api/.Tests
  (dossiers, .csproj, .sln, .http, namespaces C#). GUID UserSecretsId préservé.
- Specs : dossier .kiro/specs/trajet-km-tracker -> schotziad-km-tracker
  et mise à jour des références internes (chemins, tags de propriétés).
- Frontend : projet Angular trajet-km-tracker -> schotziad-km-tracker
  (package.json, angular.json, chemin dist, Dockerfile), titre applicatif
  'SchotzIAD KM Tracker'.
- Docker et scripts (backend/Dockerfile, frontend/Dockerfile, run-dev.sh) mis à jour.
- Suppression du fichier résiduel package.json.bak.

Backend (solution) et frontend (build production) compilent sans erreur.
2026-09-14 07:50:26 +02:00

29 KiB
Raw Permalink Blame History

Implementation Plan: SchotzIAD KM Tracker

Overview

Ce plan décompose la conception en tâches de codage incrémentales. Le backend (ASP.NET Core / C# / EF Core / SQLite) est construit d'abord — entités, calculs métier, intégrations BAN/ORS, PDF — puis le frontend Angular consomme l'API. Chaque tâche s'appuie sur les précédentes et se termine par l'intégration, sans code orphelin. Les sous-tâches de test (unitaire, propriété, intégration) sont marquées optionnelles par * et référencent explicitement les propriétés de correction et exigences validées.

Langage backend : C# (ASP.NET Core, .NET 8). Langage frontend : TypeScript (Angular). Tests : xUnit + FsCheck + FluentAssertions + Moq (backend), Jest + Angular Testing Library (frontend).

Tasks

  • 1. Initialiser la solution et le socle backend

    • Créer la solution .NET et le projet SchotzIadKmTracker.Api (ASP.NET Core Web API, .NET 8)
    • Créer le projet de tests SchotzIadKmTracker.Tests (xUnit) avec les dépendances FsCheck, FluentAssertions, Moq, Microsoft.AspNetCore.Mvc.Testing
    • Ajouter les packages : EF Core + provider SQLite, FluentValidation.AspNetCore, QuestPDF
    • Configurer Program.cs : services de base, Swagger, middleware ProblemDetails, CORS pour le frontend Angular
    • Requirements: 6.1
  • 2. Modèle de données et contexte EF Core

    • 2.1 Définir les entités du domaine

      • Créer Trajet (Date, AdresseDepart, AdresseArrivee, Distance, Commentaire, Position REAL, VehiculeId, PuissanceFiscale dénormalisée, CreatedAt/UpdatedAt)
      • Créer Vehicule (Plaque, PuissanceFiscale, DateEffet), Profil (singleton Id=1, Nom/Prenom/Matricule/AdresseDomicile + coordonnées + DomicileGeocode)
      • Créer AdresseCache (Adresse unique, Latitude/Longitude, GeometrieJson, DerniereUtilisation), TrancheBareme (Annee, PuissanceFiscale, KmMin, KmMax, Coefficient, Base), MontantRegle (Annee, Mois, VehiculeId, Montant)
      • Créer AdresseNommee (Denomination unique 100 car., DenominationNormalisee, Adresse 255 car., Latitude?, Longitude?, GeocodageReussi, CreatedAt/UpdatedAt)
      • Requirements: 6.1, 6.2, 9.6, 10.1, 10.9, 13.1, 14.1, 15.4, 15.5
    • 2.2 Configurer AppDbContext et les migrations

      • Déclarer les DbSet, contraintes (CHECK Distance > 0, Montant >= 0, PuissanceFiscale > 0), index (Date, Date+Position, VehiculeId, DateEffet, Annee+PuissanceFiscale) et index uniques (Profil singleton, MontantsRegles par période/véhicule, AdresseCache par adresse)
      • Ajouter la table AdressesNommees avec l'index unique UX_AdresseNommee_Denomination sur DenominationNormalisee
      • Générer la migration initiale et l'appliquer à trajets.db
      • Requirements: 6.1, 6.2, 9.6, 14.3, 15.6
    • * 2.3 Écrire les tests d'intégration du schéma

      • Vérifier la création de la base, les contraintes CHECK et les index uniques (rejet des doublons de période/véhicule)
      • Requirements: 6.1, 14.3
  • 3. DTOs, options de configuration et validateurs

    • 3.1 Créer les DTOs et enregistrements

      • CreateTrajetDto, UpdateTrajetDto, TrajetDto, TrajetCarteDto, ReordonnerTrajetsDto, TrajetPositionDto
      • ResumeMensuelDto, ResumeAnnuelDto, TotauxDto, AdresseCacheDto, BANAdresseDto
      • ProfilDto, SaveProfilDto, VehiculeDto, CreateVehiculeDto, VehiculeCreeDto, ReaffectationDto
      • TrancheBaremeDto, SaveTrancheBaremeDto, MontantRegleDto, MontantPrevisionnelDto, LigneSyntheseMoisDto, RegularisationAnnuelleDto
      • AdresseNommeeDto, SaveAdresseNommeeDto
      • EtatProfilDto (EstConfigure)
      • Créer BANOptions et ORSOptions, les lier depuis appsettings.json
      • Requirements: 1.1, 1.10, 2.1, 15.4, 15.5
    • 3.2 Implémenter les validateurs FluentValidation

      • CreateTrajetDtoValidator / UpdateTrajetDtoValidator : date obligatoire au format JJ/MM/AAAA et existante, adresses 1–255 car., commentaire ≤ 500 car.
      • SaveProfilDtoValidator (matricule ≤ 8 car.), CreateVehiculeDtoValidator (DateEffet ≤ aujourd'hui), MontantRegleDto (montant ≥ 0)
      • SaveAdresseNommeeDtoValidator : dénomination 1–100 car. (absente/vide/>100 → 15.6), adresse 1–255 car. (absente/vide/>255 → 15.8) ; l'unicité normalisée (doublon → 15.7) est vérifiée côté service
      • Requirements: 1.4, 1.5, 1.6, 1.7, 1.12, 6.3, 10.2, 10.11, 14.4, 15.6, 15.7, 15.8
    • * 3.3 Écrire les tests unitaires des validateurs

      • Property 4 : Rejet systématique des données d'entrée invalides (backend)
      • Validates: Requirements 1.5, 1.6, 1.7, 6.3
  • 4. Intégrations externes : BAN et ORS

    • 4.1 Implémenter IBANClient / BANClient

      • Appel GET /search/?q={query}&limit=5 avec timeout configurable ; mapper vers BANAdresseDto ; lever BANIndisponibleException en cas d'échec/timeout
      • Requirements: 1.13, 2.4, 9.1
    • 4.2 Implémenter IORSClient / ORSClient

      • Appel POST /v2/directions/driving-car avec coordonnées connues, extraction distance (km) + géométrie GeoJSON, timeout 10 s ; ne jamais appeler ORS avec des coordonnées nulles
      • Requirements: 2.1, 2.2, 8.7
    • 4.3 Implémenter IDistanceCalculator / DistanceCalculatorService

      • Coordonnées connues → ORS ; coordonnées manquantes → géocodage BAN puis ORS ; échec ORS/timeout → fallback Haversine ; échec BAN total → distance nulle + avertissement
      • Implémenter HaversineKm, arrondi 2 décimales, borne 0,01–99 999,99 km
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.6
    • * 4.4 Écrire le test de propriété de priorité BAN sur ORS

      • Property 16 : Priorité BAN sur ORS pour la résolution des coordonnées
      • Validates: Requirements 2.4
    • * 4.5 Écrire les tests unitaires BAN/ORS/Distance

      • BAN succès/non trouvé/timeout, ORS succès/timeout → Haversine, coordonnées manquantes → BAN puis ORS
      • Requirements: 2.1, 2.2, 2.3, 2.6
  • 5. Cache des adresses géocodées

    • 5.1 Implémenter AdresseCacheService et le repository associé

      • Recherche locale (min 3 car.), upsert d'une adresse (coordonnées inchangées si existante, mise à jour de DerniereUtilisation), éviction LRU au-delà de 1 000 entrées
      • Requirements: 9.1, 9.2, 9.3, 9.5, 9.6
    • * 5.2 Écrire le test de propriété de cohérence du cache

      • Property 10 : Cohérence du cache adresses après géocodage
      • Validates: Requirements 9.1, 9.2
    • * 5.3 Écrire le test de propriété LRU

      • Property 11 : Politique LRU du cache adresses
      • Validates: Requirements 9.5
  • 6. Gestion des véhicules et du profil

    • 6.1 Implémenter VehiculeService et le repository véhicules

      • CRUD historique, détermination du Véhicule_Courant (DateEffet max ≤ aujourd'hui), rejet DateEffet future, conservation de l'historique
      • Détection des trajets à réaffecter (date ≥ DateEffet et PuissanceFiscale différente) → VehiculeCreeDto.ReaffectationProposee
      • Réaffectation acceptée (mise à jour VehiculeId + PuissanceFiscale des trajets ≥ DateEffet) / refusée (aucun changement), en transaction
      • Requirements: 10.9, 10.10, 10.11, 10.12, 10.13, 10.15, 10.16, 10.17, 10.18
    • * 6.2 Écrire le test de propriété d'association du véhicule courant

      • Property 19 : Association du véhicule courant par défaut
      • Validates: Requirements 10.13, 10.14
    • * 6.3 Écrire le test de propriété de réaffectation bornée

      • Property 20 : Réaffectation bornée à la date d'effet
      • Validates: Requirements 10.16, 10.17
    • * 6.4 Écrire le test de propriété de conservation de l'historique

      • Property 22 : Conservation de l'historique des véhicules
      • Validates: Requirements 10.12, 10.18
    • 6.5 Implémenter ProfilService et le controller ProfilController

      • GET/PUT profil singleton, géocodage BAN de l'Adresse_Domicile (DomicileGeocode true/false), mise en cache, validation matricule ≤ 8 car.
      • Exposer GET /api/vehicules, GET /api/vehicules/courant, POST /api/vehicules, POST /api/vehicules/reaffectation
      • Exposer GET /api/profil/etat retournant EtatProfilDto(EstConfigure) (true ssi Profil Nom+Prénom non vides ET au moins un Véhicule)
      • Requirements: 10.1, 10.2, 10.3, 10.7, 10.8, 10.18, 16.1, 16.2
    • * 6.6 Écrire le test de propriété de cohérence du profil domicile

      • Property 12 : Cohérence du profil domicile
      • Validates: Requirements 10.2, 10.7
    • * 6.7 Écrire le test de propriété de détermination de l'état de configuration du profil

      • Property 31 : Détermination de l'état de configuration du profil
      • Validates: Requirements 16.1, 16.2
  • 7. Checkpoint — S'assurer que tous les tests passent

    • Ensure all tests pass, ask the user if questions arise.
  • 8. Service et API des trajets (CRUD + positions)

    • 8.1 Implémenter TrajetRepository et la gestion des positions

      • Résolution du véhicule à la date du trajet et copie de la PuissanceFiscale (dénormalisation)
      • Attribution de Position : fin de journée max(Position)+1.0, insertion (P1+P2)/2, renumérotation par pas de 1.0 si précision < 0.001 (transaction)
      • Requirements: 10.14, 11.7, 11.8
    • 8.2 Implémenter TrajetService (création)

      • Validation, association véhicule courant si VehiculeId absent, calcul de distance via DistanceCalculatorService, mise en cache des adresses résolues, persistance transactionnelle
      • Gérer distance nulle + avertissement quand aucune coordonnée n'est résoluble
      • Requirements: 1.2, 1.3, 1.11, 2.4, 2.5, 6.3, 6.7, 6.8, 10.14
    • * 8.3 Écrire le test de propriété de précision des distances

      • Property 3 : Précision de stockage des distances
      • Validates: Requirements 2.2, 2.5, 6.2
    • * 8.4 Écrire le test de propriété de persistance du commentaire

      • Property 13 : Persistance optionnelle du commentaire
      • Validates: Requirements 1.11, 1.12
    • 8.5 Implémenter TrajetService (modification, suppression, réordonnancement)

      • Modification : recalcul distance uniquement si adresse modifiée, commentaire seul sans recalcul, rollback si recalcul échoue, 404 si inexistant
      • Suppression transactionnelle ; PATCH /api/trajets/reordonner met à jour les Position sans altérer les autres champs
      • Requirements: 5.2, 5.3, 5.5, 5.6, 5.8, 5.9, 5.10, 6.7, 6.8, 11.9
    • * 8.6 Écrire le test de propriété de recalcul conditionnel

      • Property 6 : Recalcul conditionnel de la distance
      • Validates: Requirements 5.2, 5.3
    • * 8.7 Écrire les tests de propriété sur les positions

      • Property 14 : Cohérence de l'ordre des trajets d'une journée
      • Property 15 : Unicité et cohérence des positions au sein d'une journée
      • Validates: Requirements 11.7, 11.8, 11.9
    • 8.8 Implémenter TrajetsController et brancher le controller adresses

      • POST/GET/PUT/DELETE /api/trajets, PATCH /api/trajets/reordonner, GET /api/trajets/journee/{date} (avec géométries), GET /api/adresses/search
      • Requirements: 1.3, 5.5, 5.6, 8.7, 9.3
    • * 8.9 Écrire le test de propriété d'invariant de suppression

      • Property 5 : Invariant de suppression
      • Validates: Requirements 5.5, 6.4
  • 9. Résumés, totaux et navigation temporelle

    • 9.1 Implémenter ResumeService (mensuel et annuel)

      • Résumé mensuel filtré par véhicule, trié par date puis Position, total 2 décimales ; validation mois [1,12] et année [2000,2100]
      • Résumé annuel : toujours 12 mois (0 si vide), total = somme des 12 mois
      • Requirements: 3.1, 3.2, 3.3, 3.4, 3.6, 3.8, 4.2, 4.3, 4.4, 4.7, 6.5, 6.6
    • * 9.2 Écrire les tests de propriété des totaux et résumés

      • Property 1 : Cohérence du total mensuel — Validates: Requirements 3.3, 6.5
      • Property 2 : Cohérence du total annuel — Validates: Requirements 4.3, 6.6
      • Property 7 : Mois toujours présents dans le résumé annuel — Validates: Requirements 4.2, 4.4
      • Property 8 : Rejet des paramètres de résumé hors plage — Validates: Requirements 3.6
    • 9.3 Implémenter TotauxService et la navigation temporelle

      • Totaux jour/mois/Total_Annuel_Partiel filtrés par véhicule (cumul jusqu'au mois inclus, exclusion des mois postérieurs)
      • Années disponibles (données + année courante), mois disponibles, jours disponibles
      • Requirements: 12.7, 12.8, 12.15, 12.16, 12.19
    • * 9.4 Écrire les tests de propriété des totaux filtrés et partiels

      • Property 17 : Total annuel partiel borné au mois sélectionné — Validates: Requirements 12.8
      • Property 21 : Totaux filtrés par véhicule — Validates: Requirements 12.19
    • 9.5 Implémenter ResumesController et les controllers de navigation

      • GET /api/resumes/mensuel/{annee}/{mois}, GET /api/resumes/annuel/{annee}
      • GET /api/annees-disponibles, /api/mois-disponibles/{annee}, /api/jours-disponibles/{annee}/{mois}, /api/totaux/{date}
      • Requirements: 3.8, 4.1, 12.15, 12.16
  • 10. Barème kilométrique et régularisation

    • 10.1 Implémenter BaremeService et le controller barème

      • CRUD des tranches, validation du non-chevauchement par (année, puissance fiscale)
      • Sélection de tranche contenant le total annuel, formule km × Coefficient + Base, barème non configuré → montant zéro + avertissement
      • GET /api/bareme/{annee}, POST/PUT/DELETE /api/bareme
      • Requirements: 13.1, 13.2, 13.3, 13.4
    • * 10.2 Écrire les tests de propriété de sélection de tranche

      • Property 24 : Sélection de tranche du barème — Validates: Requirements 13.3, 13.4
      • Property 27 : Sélection de tranche par le total annuel — Validates: Requirements 13.3, 14.6
    • 10.3 Implémenter MontantRegleService (upsert et montant prévisionnel)

      • Upsert par (année, mois, véhicule), rejet montant négatif
      • Montant_Previsionnel = 80% du barème sur le Total_Annuel_Partiel (indicatif, hors régularisation)
      • Requirements: 13.5, 13.6, 14.1, 14.2, 14.3, 14.4
    • * 10.4 Écrire les tests de propriété montants réglés / prévisionnel

      • Property 23 : Indication de versement à 80% (informative) — Validates: Requirements 13.5, 13.6
      • Property 26 : Unicité du montant réglé par période et véhicule — Validates: Requirements 14.3
    • 10.5 Implémenter RemboursementService (régularisation annuelle)

      • Montant_Reel = barème plein 100% sur total annuel, Frais_Reel_Mensuel = km_mois × coef tranche annuelle, Regularisation = Montant_Reel − total réglé
      • Construire RegularisationAnnuelleDto (12 lignes + totaux)
      • GET /api/montant-previsionnel/..., GET/PUT /api/montants-regles, GET /api/regularisation/{annee}
      • Requirements: 14.5, 14.6, 14.7, 14.8
    • * 10.6 Écrire le test de propriété de régularisation

      • Property 25 : Cohérence de la régularisation annuelle (barème plein)
      • Validates: Requirements 13.3, 14.5, 14.6, 14.7
  • 11. Export PDF (QuestPDF)

    • 11.1 Implémenter PdfService — rapport mensuel

      • En-tête : identité (nom, prénom, matricule), véhicule (plaque, puissance fiscale, coef/base tranche), période, adresse départ profil, totaux mois/année, TOTAL IK du mois, Montant_Regle
      • Liste des trajets (date, motif/commentaire, départ → arrivée, km) ; timeout 15 s
      • Requirements: 7.1, 7.4, 7.6, 7.8, 7.10, 7.11
    • 11.2 Implémenter PdfService — synthèse annuelle et rapports par véhicule

      • Page synthèse (identité, année, domicile, barème de l'année, véhicule, tranche) + 12 lignes (km, réglé, frais réel) + totaux (km annuel, réglé, réel, régularisation)
      • Génération d'un PDF distinct par véhicule si plusieurs véhicules sur la période
      • Requirements: 7.2, 7.4, 7.6, 7.7, 7.8, 7.9, 7.12
    • 11.3 Implémenter ExportsPdfController

      • GET /api/exports/mensuel/{annee}/{mois} et GET /api/exports/annuel/{annee} ; en-tête Content-Disposition trajets_MM_AAAA.pdf / trajets_AAAA.pdf, timeout → 503
      • Requirements: 7.3, 7.4, 7.5
    • * 11.4 Écrire le test de propriété de nommage PDF

      • Property 9 : Nommage des fichiers PDF exportés
      • Validates: Requirements 7.4
    • * 11.5 Écrire les tests unitaires PDF

      • En-tête identité/véhicule, PDF distinct par véhicule, montants mensuels, régularisation annuelle
      • Requirements: 7.6, 7.8, 7.9, 7.12
  • 12. Checkpoint backend — S'assurer que tous les tests passent

    • Ensure all tests pass, ask the user if questions arise.
  • * 13. Tests d'intégration backend end-to-end

    • * 13.1 Tests d'intégration trajets et distance (WebApplicationFactory + SQLite en mémoire)

      • POST avec/sans coordonnées (BAN puis ORS, fallback Haversine, distance nulle + 201), insertion entre deux trajets, PATCH réordonner, PUT/DELETE
      • Requirements: 1.3, 2.4, 2.6, 5.5, 11.8
    • * 13.2 Tests d'intégration résumés, totaux, véhicules, barème et exports

      • Résumés mensuel/annuel, totaux partiels, réaffectation accepter/refuser, barème chevauchant → 400, upsert montant réglé, régularisation, export PDF 2 véhicules → 2 fichiers
      • Requirements: 3.8, 4.1, 7.9, 10.16, 12.8, 13.2, 14.3, 14.7
  • 14. Socle frontend Angular et services

    • 14.1 Initialiser l'application Angular et le socle core

      • Créer l'app Angular, app-routing.module.ts, modèles TypeScript, notification.service.ts, TimeoutInterceptor (10 s), DateJjMmAAAAValidator
      • Requirements: 1.9, 1.5
    • 14.2 Implémenter les services HTTP Angular

      • TrajetService, VehiculeService, BANService (autocomplétion), AdresseCacheService, ProfilService, BaremeService, RemboursementService
      • ProfilService.getEtat() : appelle GET /api/profil/etat et retourne EtatProfilDto
      • Requirements: 1.2, 9.3, 9.4, 16.2
    • * 14.3 Écrire les tests unitaires des services

      • Mock HttpClient, comportement du TimeoutInterceptor
      • Requirements: 1.9
  • 15. Saisie et édition des trajets (frontend)

    • 15.1 Implémenter TrajetFormComponent

      • Reactive Form (date, adresses 1–255, commentaire 0–500), validations synchrones, mode création/édition/insertion, autocomplétion BAN dès 3 car. + stockage coordonnées, boutons « Utiliser mon domicile », avertissement saisie manuelle sans coordonnées
      • Requirements: 1.1, 1.4, 1.5, 1.8, 1.10, 1.13, 1.14, 1.15, 1.16, 1.17, 5.1, 10.4, 10.5, 10.6, 11.1, 11.2, 11.3, 11.4
    • 15.2 Implémenter TrajetListComponent

      • Liste triée par Position, actions modifier/supprimer (avec ConfirmDialog)/insérer après/insérer avant le suivant, drag & drop → PATCH reordonner, rafraîchissement < 1 000 ms, icône + tooltip commentaire
      • Requirements: 5.1, 5.4, 5.7, 11.6, 11.9
    • * 15.3 Écrire les tests des composants de saisie

      • Validation, autocomplétion BAN, mode insertion pré-rempli, drag & drop, tri par Position
      • Requirements: 1.4, 1.5, 1.13, 11.1, 11.6
  • 16. Consultation, navigation temporelle et carte (frontend)

    • 16.1 Implémenter SelecteurTemporelComponent

      • Sélecteurs année/mois/jour avec surbrillance des périodes ayant des données, désactivation des dates futures
      • Requirements: 12.1, 12.2, 12.3, 12.4, 12.5
    • 16.2 Implémenter PanneauTotauxComponent

      • Totaux jour/mois/Total_Annuel_Partiel à 2 décimales, Montant_Previsionnel 80% indicatif, recalcul au changement
      • Requirements: 12.7, 12.8, 13.5, 13.6, 13.7, 13.8
    • 16.3 Implémenter CarteTrajetsComponent

      • Leaflet + tuiles OpenStreetMap, tracés GeoJSON par trajet, fallback ligne droite, infobulles, zoom/déplacement, message si vide ou carte indisponible
      • Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.8
    • 16.4 Implémenter ConsultationJourComponent (layout principal)

      • Deux colonnes (liste scrollable + panneau sticky totaux/carte), boutons jour ±1 (« suivant » désactivé si futur), sélecteur de véhicule filtrant liste/totaux/carte, rafraîchissement < 1 000 ms
      • Requirements: 12.6, 12.9, 12.10, 12.11, 12.12, 12.13, 12.14, 12.17, 12.18, 12.20
    • * 16.5 Écrire les tests des composants de consultation

      • Surbrillance/dates futures, 3 totaux + prévisionnel, tracés carte + fallback, layout et filtrage par véhicule
      • Requirements: 8.2, 8.5, 12.5, 12.8, 12.18
  • 17. Profil, véhicules, barème et montants réglés (frontend)

    • 17.1 Implémenter ProfilComponent, VehiculesComponent et ReaffectationDialogComponent

      • Profil (nom/prénom/matricule 8 car./domicile) + avertissement géocodage ; historique véhicules trié, ajout avec DateEffet ≤ aujourd'hui, dialog de réaffectation (nombre de trajets, accepter/refuser)
      • Requirements: 10.1, 10.2, 10.8, 10.9, 10.10, 10.11, 10.15, 10.16, 10.17
    • 17.2 Implémenter BaremeComponent et MontantsReglesComponent

      • Saisie des 3 tranches par puissance fiscale/année avec détection de chevauchement ; saisie Montant_Regle par mois + prévisionnel indicatif, rejet négatif, montants 2 décimales
      • Requirements: 13.1, 13.7, 14.1, 14.4, 14.8
    • 17.3 Implémenter ResumeMensuelComponent et ResumeAnnuelComponent

      • Résumé mensuel (liste + total 2 décimales, bouton export), résumé annuel (12 lignes + total ≤ 999 999,99, bouton export), déclenchement téléchargement PDF + gestion d'erreur
      • Requirements: 3.1, 3.5, 3.7, 4.1, 4.5, 4.6, 7.3
    • * 17.4 Écrire les tests des composants profil/véhicules/barème/montants/résumés

      • Matricule 8 car., date effet future bloquée, dialog réaffectation, chevauchement barème, montant négatif rejeté, affichage 2 décimales et max annuel
      • Requirements: 4.5, 10.2, 10.11, 13.1, 14.4
  • 18. Checkpoint final — S'assurer que tous les tests passent

    • Ensure all tests pass, ask the user if questions arise.
  • 19. Carnet d'adresses nommées (backend)

    • 19.1 Implémenter AdresseNommeeService et AdressesNommeesController

      • CRUD des Adresses_Nommées ; normalisation (trim + minuscules + suppression des accents) pour l'unicité de la Dénomination et le matching du Cache_Adresses
      • Réutilisation du Cache_Adresses si l'adresse normalisée y est présente (sans appel BAN) ; sinon géocodage/re-géocodage via BAN (timeout 5 s)
      • Si BAN indisponible/timeout : persistance sans coordonnées + GeocodageReussi = false et réponse indiquant l'absence de coordonnées ; mise en cache des coordonnées obtenues
      • Suppression sans impact sur les Trajets existants (conservation de leur adresse et coordonnées)
      • Endpoints GET/POST/PUT/DELETE /api/adresses-nommees
      • Requirements: 15.1, 15.4, 15.5, 15.6, 15.7, 15.8, 15.9, 15.10, 15.11, 15.12, 15.14
    • * 19.2 Écrire le test de propriété d'unicité de la dénomination

      • Property 28 : Unicité normalisée de la dénomination
      • Validates: Requirements 15.6, 15.7
    • * 19.3 Écrire le test de propriété de préservation des trajets à la suppression

      • Property 29 : Préservation des trajets à la suppression d'une adresse nommée
      • Validates: Requirements 15.14
    • * 19.4 Écrire le test de propriété de réutilisation du cache et cohérence du géocodage

      • Property 30 : Réutilisation du cache et cohérence du géocodage des adresses nommées
      • Validates: Requirements 15.9, 15.10, 15.11, 15.12
  • 20. Carnet d'adresses nommées (frontend)

    • 20.1 Implémenter AdresseNommeeService (Angular) et CarnetAdressesComponent

      • AdresseNommeeService : getAdressesNommees, create, update, delete (HTTP)
      • CarnetAdressesComponent : liste triée par Dénomination, formulaire de création/modification avec autocomplétion BAN (min 3 car., debounce 300 ms, max 5 suggestions), confirmation de suppression, message de succès CRUD, avertissement si le géocodage a échoué
      • Requirements: 15.1, 15.2, 15.3, 15.4, 15.11, 15.13, 15.15
    • 20.2 Étendre TrajetFormComponent avec le sélecteur d'Adresse_Nommee

      • Pour les champs adresse de départ et adresse d'arrivée, ajouter un sélecteur d'Adresse_Nommee (par Dénomination) en mode création ET insertion
      • À la sélection, remplir le champ + associer les coordonnées (remplace le contenu pré-rempli en mode insertion)
      • Requirements: 1.18, 1.19, 11.10, 11.11, 15.16
    • * 20.3 Écrire les tests des composants carnet et du sélecteur dans le formulaire

      • Composant Carnet_Adresses (liste, formulaire, confirmation, message), sélecteur d'Adresse_Nommee dans TrajetFormComponent
      • Requirements: 15.2, 15.13, 1.19
  • 21. Onboarding profil à la première utilisation (frontend)

    • 21.1 Implémenter OnboardingComponent

      • Formulaire une étape : identité (nom, prénom, matricule), Adresse_Domicile optionnelle avec autocomplétion BAN, au moins un Véhicule (plaque, puissance fiscale, date d'effet ≤ aujourd'hui)
      • Bouton « Commencer » désactivé tant que les champs requis manquent
      • À l'enregistrement réussi du profil + véhicule → navigation vers la vue de consultation
      • Gestion d'erreur de persistance : message d'erreur + conservation des données saisies
      • Requirements: 16.3, 16.5, 16.6, 16.7, 16.8, 16.9, 16.10, 16.12
    • 21.2 Implémenter le guard ProfilConfigureGuard (CanActivate)

      • Appelle ProfilService.getEtat() au chargement ; redirige vers /onboarding si EstConfigure = false et bloque l'accès aux routes trajets/consultation ; laisse passer si true
      • Gère l'échec de récupération de l'état par un message de connexion + action « Réessayer »
      • Déclarer le guard sur les routes protégées dans app-routing
      • Requirements: 16.3, 16.4, 16.11, 16.13
    • * 21.3 Écrire les tests du parcours d'onboarding et du guard

      • Bouton « Commencer » désactivé, navigation après enregistrement, redirection du guard, cas EstConfigure true/false, erreur + retry
      • Requirements: 16.3, 16.8, 16.10, 16.11, 16.13
  • 22. Conteneurisation et déploiement Docker Compose

    • 22.1 Écrire le Dockerfile backend multi-stage

      • Étape build (SDK) → étape runtime (aspnet), exposition du port 8080
      • Base SQLite sous le volume /data/trajets.db via ConnectionStrings__Default
      • Application automatique des migrations EF Core au démarrage (Database.MigrateAsync() dans Program.cs)
      • Endpoint de santé GET /health (AddHealthChecks / MapHealthChecks)
      • Requirements: 6.1
    • 22.2 Écrire le Dockerfile frontend multi-stage et la configuration nginx.conf

      • Étape build (node) → étape serve (nginx)
      • nginx.conf : fallback SPA vers index.html + reverse-proxy /api vers backend:8080
    • 22.3 Écrire le docker-compose.yml

      • Services backend + frontend, volume nommé trajets-data:/data pour la persistance SQLite
      • Clé ORS via variable d'environnement ${ORS_API_KEY} depuis un fichier .env non commité
      • Mapping hôte 8080 → nginx, depends_on: service_healthy, restart: unless-stopped, healthcheck backend
      • Ajouter .env au .gitignore

Notes

  • Les tâches marquées * sont optionnelles (tests unitaires, tests de propriété, tests d'intégration) et peuvent être ignorées pour un MVP plus rapide ; les tâches d'implémentation cœur ne le sont jamais.
  • Chaque tâche référence des exigences précises pour la traçabilité ; les sous-tâches de test de propriété référencent explicitement la propriété de correction validée (numéro + exigences).
  • Les 31 propriétés de correction sont couvertes par des tests FsCheck (backend) répartis au plus près de leur implémentation pour détecter les erreurs tôt.
  • La clé ORS n'est jamais commitée : User Secrets en développement, variables d'environnement en production.
  • Les checkpoints garantissent une validation incrémentale du backend puis du frontend.

Task Dependency Graph

{
  "waves": [
    { "id": 0, "tasks": ["1"] },
    { "id": 1, "tasks": ["2.1"] },
    { "id": 2, "tasks": ["2.2", "3.1"] },
    { "id": 3, "tasks": ["2.3", "3.2", "4.1", "4.2"] },
    { "id": 4, "tasks": ["3.3", "4.3", "5.1", "6.1", "6.5"] },
    { "id": 5, "tasks": ["4.4", "4.5", "5.2", "5.3", "6.2", "6.3", "6.4", "6.6", "6.7", "8.1"] },
    { "id": 6, "tasks": ["8.2", "10.1", "19.1"] },
    { "id": 7, "tasks": ["8.3", "8.4", "8.5", "10.2", "10.3", "19.2", "19.3", "19.4"] },
    { "id": 8, "tasks": ["8.6", "8.7", "8.8", "10.4", "10.5"] },
    { "id": 9, "tasks": ["8.9", "9.1", "9.3", "10.6", "11.1", "11.2"] },
    { "id": 10, "tasks": ["9.2", "9.4", "9.5", "11.3"] },
    { "id": 11, "tasks": ["11.4", "11.5", "13.1", "13.2"] },
    { "id": 12, "tasks": ["14.1", "22.1"] },
    { "id": 13, "tasks": ["14.2"] },
    { "id": 14, "tasks": ["14.3", "15.1", "16.1", "16.3", "17.1", "20.1", "21.1"] },
    { "id": 15, "tasks": ["15.2", "16.2", "16.4", "17.2", "17.3", "20.2", "21.2", "22.2"] },
    { "id": 16, "tasks": ["15.3", "16.5", "17.4", "20.3", "21.3", "22.3"] }
  ]
}