Files
SchotzIAD/.kiro/specs/trajet-km-tracker/tasks.md
T
MadJax e3f946f7d4 SchotzIAD KM Tracker : suivi des trajets kilométriques (Angular + .NET 8)
Application complète de saisie et de suivi des trajets kilométriques avec
calcul de distance routière (OpenRouteService), barème kilométrique, résumés
et régularisation annuelle.

Backend (ASP.NET Core .NET 8, EF Core, SQLite) :
- Trajets (CRUD, réordonnancement, insertion), calcul de distance ORS avec
  fallback Haversine, géométrie d'itinéraire stockée par trajet, recalcul en masse.
- Profil, véhicules (avec dénomination), carnet d'adresses nommées, cache d'adresses.
- Barème kilométrique : tranches multiples par puissance fiscale, borne max
  exclusive avec 'illimité' (KmMax nullable), coefficient à 3 décimales,
  recopie du dernier barème connu.
- Résumés mensuel/annuel, montants réglés, régularisation, export PDF.

Frontend (Angular 22, zoneless + signals) :
- Consultation par jour, navigation temporelle synchronisée, carte Leaflet,
  formulaire de trajet (adresses nommées, domicile, autocomplétion BAN).
- Détection de changement zoneless (indépendante de zone.js).

Hébergement : Docker Compose (nginx + backend), scripts run-dev.sh / run-docker.sh.
2026-09-14 02:08:27 +02:00

29 KiB
Raw 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 TrajetKmTracker.Api (ASP.NET Core Web API, .NET 8)
    • Créer le projet de tests TrajetKmTracker.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"] }
  ]
}