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.
This commit is contained in:
2026-09-14 07:50:26 +02:00
parent e3f946f7d4
commit 0e6a97ca61
133 changed files with 462 additions and 503 deletions
@@ -0,0 +1,42 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
// Résultat de recherche BAN (proxied via backend si nécessaire)
public record BANAdresseDto(
string Label,
double Latitude,
double Longitude,
string Postcode,
string City
);
// Suggestion autocomplétion
public record AdresseCacheDto(
string Adresse,
double Latitude,
double Longitude
);
// Entrée complète du Cache_Adresses (lookup exact par la création de Trajet)
public record AdresseCacheEntreeDto(
string Adresse,
double Latitude,
double Longitude,
string? GeometrieJson
);
// Carnet d'adresses — Adresse_Nommee retournée par le backend
public record AdresseNommeeDto(
int Id,
string Denomination,
string Adresse,
double? Latitude, // null si le géocodage a échoué
double? Longitude // null si le géocodage a échoué
);
// Carnet d'adresses — création / mise à jour d'une Adresse_Nommee
public record SaveAdresseNommeeDto(
string Denomination, // 1 à 100 car., unique après normalisation
string Adresse, // 1 à 255 car.
double? Latitude, // fournies par le frontend si sélection BAN
double? Longitude
);
@@ -0,0 +1,63 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
// Barème
public record TrancheBaremeDto(
int Id,
int Annee,
int PuissanceFiscale,
decimal KmMin,
decimal? KmMax, // null = illimité (borne max exclusive : [KmMin, KmMax[)
decimal Coefficient,
decimal Base
);
public record SaveTrancheBaremeDto(
int Annee,
int PuissanceFiscale,
decimal KmMin,
decimal? KmMax, // null = illimité (borne max exclusive : [KmMin, KmMax[)
decimal Coefficient,
decimal Base
);
// Montant réglé
public record MontantRegleDto(
int Annee,
int Mois,
int VehiculeId,
decimal Montant
);
// Indication de versement mensuel (informatif) affichée à la saisie
public record MontantPrevisionnelDto(
int Annee,
int Mois,
int VehiculeId,
decimal TotalAnnuelPartielKm,
decimal MontantBaremePlein, // barème plein sur le total partiel
decimal MontantPrevisionnel // = 80% (indicatif uniquement)
);
// Ligne mensuelle de la synthèse annuelle (aligne sur la synthèse réelle)
public record LigneSyntheseMoisDto(
int Mois,
decimal KmMois, // kilomètres parcourus dans le mois
decimal FraisPaye, // Montant_Regle du mois (saisi)
decimal FraisReelMensuel // km_du_mois × coefficient de la tranche annuelle
);
// Synthèse annuelle de régularisation pour un véhicule (page 1 du rapport)
public record RegularisationAnnuelleDto(
int Annee,
int VehiculeId,
string Plaque,
int PuissanceFiscale,
decimal CoefficientTranche, // coefficient de la tranche annuelle applicable
decimal BaseTranche, // base de la tranche annuelle applicable
string TrancheLibelle, // ex. "5 001 à 20 000 km — D2"
IReadOnlyList<LigneSyntheseMoisDto> Mois, // 12 lignes
decimal TotalKmAnnuel,
decimal TotalPaye, // somme des Montant_Regle
decimal MontantReel, // barème plein : total_km × coef + base
decimal Regularisation // MontantReel − TotalPaye
);
@@ -0,0 +1,5 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
/// <summary>Résultat de la copie du dernier barème vers une année cible.</summary>
/// <param name="TranchesCopiees">Nombre de tranches copiées (0 si aucun barème antérieur).</param>
public record CopieBaremeResultDto(int TranchesCopiees);
@@ -0,0 +1,22 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
// Profil
public record ProfilDto(
string? Nom,
string? Prenom,
string? Matricule,
string? AdresseDomicile,
bool DomicileGeocode
);
public record SaveProfilDto(
string? Nom,
string? Prenom,
string? Matricule, // max 8 car.
string AdresseDomicile
);
// État de configuration du profil (onboarding première utilisation)
public record EtatProfilDto(
bool EstConfigure // true ssi Profil.Nom et Profil.Prenom non vides ET au moins un Vehicule existe
);
@@ -0,0 +1,5 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
/// <summary>Résultat du recalcul en masse des distances des trajets.</summary>
/// <param name="TrajetsRecalcules">Nombre de trajets dont la distance a été recalculée.</param>
public record RecalculDistancesResultDto(int TrajetsRecalcules);
@@ -0,0 +1,25 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
// Résumé mensuel
public record ResumeMensuelDto(
int Annee,
int Mois,
IReadOnlyList<TrajetDto> Trajets,
decimal TotalKm // somme distances, 2 décimales
);
// Résumé annuel
public record ResumeAnnuelDto(
int Annee,
IReadOnlyList<ResumeMensuelDto> Mois, // toujours 12 éléments
decimal TotalKm
);
// Totaux affichés dans le Panneau_Totaux
public record TotauxDto(
DateOnly Date,
int VehiculeId, // véhicule sur lequel portent les totaux
decimal TotalJour,
decimal TotalMois,
decimal TotalAnnuelPartiel
);
@@ -0,0 +1,64 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
// Création — les coordonnées sont transmises par le Frontend (issues de la sélection BAN)
public record CreateTrajetDto(
string Date, // JJ/MM/AAAA en entrée
string AdresseDepart,
double? DepartLatitude, // null si adresse saisie manuellement sans BAN
double? DepartLongitude,
string AdresseArrivee,
double? ArriveeLatitude, // null si adresse saisie manuellement sans BAN
double? ArriveeLongitude,
string? Commentaire, // optionnel, max 500 car.
int? VehiculeId // optionnel ; null → véhicule courant à la date du trajet
);
// Mise à jour
public record UpdateTrajetDto(
string Date,
string AdresseDepart,
double? DepartLatitude,
double? DepartLongitude,
string AdresseArrivee,
double? ArriveeLatitude,
double? ArriveeLongitude,
string? Commentaire,
int? VehiculeId // optionnel ; null → véhicule courant à la date du trajet
);
// Réponse trajet
public record TrajetDto(
int Id,
DateOnly Date,
string AdresseDepart,
string AdresseArrivee,
decimal? Distance, // km, 2 décimales ; null si la distance n'a pas pu être calculée (Exigence 2.4)
string? Commentaire,
decimal Position, // rang dans la journée
int VehiculeId,
int PuissanceFiscale
);
// Trajet enrichi pour la carte
public record TrajetCarteDto(
int Id,
DateOnly Date,
string AdresseDepart,
string AdresseArrivee,
decimal Distance,
double? DepartLatitude,
double? DepartLongitude,
double? ArriveeLatitude,
double? ArriveeLongitude,
string? GeometrieJson // GeoJSON LineString ou null
);
// Réordonnancement manuel des trajets d'une journée
public record ReordonnerTrajetsDto(
IReadOnlyList<TrajetPositionDto> Trajets
);
public record TrajetPositionDto(
int Id,
decimal Position
);
@@ -0,0 +1,30 @@
namespace SchotzIadKmTracker.Api.Models.DTOs;
// Véhicules
public record VehiculeDto(
int Id,
string Denomination,
string Plaque,
int PuissanceFiscale,
DateOnly DateEffet
);
public record CreateVehiculeDto(
string Denomination,
string Plaque,
int PuissanceFiscale,
string DateEffet // JJ/MM/AAAA, <= date du jour
);
// Réponse à la création d'un véhicule : indique s'il faut proposer une réaffectation
public record VehiculeCreeDto(
VehiculeDto Vehicule,
bool ReaffectationProposee, // true si des trajets >= DateEffet ont une autre puissance fiscale
int NombreTrajetsConcernes
);
// Requête de réaffectation
public record ReaffectationDto(
int VehiculeId, // nouveau véhicule
bool Accepter // true = réaffecter les trajets >= DateEffet ; false = ne rien changer
);
@@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>Cache des adresses géocodées via ORS.</summary>
public class AdresseCache
{
public int Id { get; set; }
[Required, MaxLength(255)]
public string Adresse { get; set; } = string.Empty; // texte normalisé
public double Latitude { get; set; } // précision 6 décimales
public double Longitude { get; set; } // précision 6 décimales
/// <summary>Géométrie GeoJSON de l'itinéraire (null si indisponible).</summary>
public string? GeometrieJson { get; set; }
public DateTime DerniereUtilisation { get; set; } = DateTime.UtcNow;
}
@@ -0,0 +1,39 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>
/// Adresse enregistrée dans le Carnet_Adresses, identifiée par une Dénomination unique
/// et réutilisable par sa Dénomination lors de la saisie/insertion d'un Trajet.
/// </summary>
public class AdresseNommee
{
public int Id { get; set; }
/// <summary>Libellé libre et unique identifiant l'adresse (1 à 100 caractères).</summary>
[Required, MaxLength(100)]
public string Denomination { get; set; } = string.Empty;
/// <summary>
/// Forme normalisée de la Dénomination (trim + minuscules + sans accents) servant de clé
/// d'unicité via l'index unique UX_AdresseNommee_Denomination. Calculée par le backend.
/// </summary>
[Required, MaxLength(100)]
public string DenominationNormalisee { get; set; } = string.Empty;
/// <summary>Texte d'adresse résolu via l'autocomplétion BAN (1 à 255 caractères).</summary>
[Required, MaxLength(255)]
public string Adresse { get; set; } = string.Empty;
/// <summary>Latitude (précision 6 décimales) ; null si le géocodage a échoué.</summary>
public double? Latitude { get; set; }
/// <summary>Longitude (précision 6 décimales) ; null si le géocodage a échoué.</summary>
public double? Longitude { get; set; }
/// <summary>Vrai si les coordonnées ont été obtenues (cache ou BAN) ; faux sinon.</summary>
public bool GeocodageReussi { get; set; } = false;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>Montant réglé (remboursement reçu) pour un mois, une année et un véhicule.</summary>
public class MontantRegle
{
public int Id { get; set; }
[Required]
public int Annee { get; set; }
[Required]
public int Mois { get; set; } // 1–12
[Required]
public int VehiculeId { get; set; }
public Vehicule? Vehicule { get; set; }
/// <summary>Montant réglé en euros (&gt;= 0), deux décimales.</summary>
[Required]
public decimal Montant { get; set; }
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
@@ -0,0 +1,28 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>Profil utilisateur (singleton — une seule ligne).</summary>
public class Profil
{
public int Id { get; set; } = 1; // toujours 1
[MaxLength(100)]
public string? Nom { get; set; }
[MaxLength(100)]
public string? Prenom { get; set; }
/// <summary>Matricule (8 caractères maximum).</summary>
[MaxLength(8)]
public string? Matricule { get; set; }
[MaxLength(255)]
public string? AdresseDomicile { get; set; }
public double? DomicileLatitude { get; set; }
public double? DomicileLongitude { get; set; }
public bool DomicileGeocode { get; set; } = false;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
@@ -0,0 +1,60 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>Trajet kilométrique saisi par l'utilisateur.</summary>
public class Trajet
{
public int Id { get; set; }
[Required]
public DateOnly Date { get; set; }
[Required, MaxLength(255)]
public string AdresseDepart { get; set; } = string.Empty;
[Required, MaxLength(255)]
public string AdresseArrivee { get; set; } = string.Empty;
/// <summary>
/// Distance en kilomètres, arrondie à 2 décimales, strictement positive lorsqu'elle est
/// connue. <c>null</c> lorsque la distance n'a pas pu être calculée (aucune coordonnée
/// résoluble via le Cache_Adresses / la BAN) : le Trajet est alors persisté avec une
/// Distance nulle et un avertissement (Exigence 2.4). La modification ultérieure peut
/// recalculer la Distance si de nouvelles coordonnées deviennent disponibles (Exigence 5.10).
/// </summary>
public decimal? Distance { get; set; }
/// <summary>Commentaire optionnel (0–500 caractères).</summary>
[MaxLength(500)]
public string? Commentaire { get; set; }
/// <summary>
/// Géométrie GeoJSON (LineString) de l'itinéraire routier départ→arrivée, telle que
/// renvoyée par OpenRouteService, pour le tracé exact sur la carte. <c>null</c> lorsque
/// l'itinéraire routier n'a pas pu être obtenu (fallback vol d'oiseau) : la carte trace
/// alors une ligne droite. La géométrie dépend de la PAIRE départ→arrivée, c'est pourquoi
/// elle est portée par le Trajet et non par le Cache_Adresses (indexé par adresse seule).
/// </summary>
public string? GeometrieJson { get; set; }
/// <summary>
/// Rang du trajet dans la liste de la journée. Valeur décimale (ex. 1.0, 1.5, 2.0)
/// permettant l'insertion sans réordonnancement systématique.
/// Trié par ordre croissant pour l'affichage.
/// </summary>
[Required]
public decimal Position { get; set; }
/// <summary>Référence au véhicule associé au trajet (véhicule courant à la date de création par défaut).</summary>
[Required]
public int VehiculeId { get; set; }
public Vehicule? Vehicule { get; set; }
/// <summary>Puissance fiscale (CV) du véhicule au moment de l'association ; stockée pour l'historique.</summary>
[Required]
public int PuissanceFiscale { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}
@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>
/// Tranche du barème kilométrique URSSAF pour une année et une puissance fiscale.
/// Trois tranches par (année, puissance fiscale) : ≤5000 km, 5001–20000 km, &gt;20000 km.
/// </summary>
public class TrancheBareme
{
public int Id { get; set; }
[Required]
public int Annee { get; set; }
[Required]
public int PuissanceFiscale { get; set; }
/// <summary>Borne minimale de kilométrage annuel (incluse).</summary>
[Required]
public decimal KmMin { get; set; }
/// <summary>
/// Borne maximale de kilométrage annuel, EXCLUSIVE : la tranche couvre [KmMin, KmMax[.
/// <c>null</c> signifie « illimité » (dernière tranche, sans borne supérieure).
/// </summary>
public decimal? KmMax { get; set; }
/// <summary>Coefficient en euros par kilomètre.</summary>
[Required]
public decimal Coefficient { get; set; }
/// <summary>Base fixe en euros ajoutée au montant (nulle pour les tranches 1 et 3). Formule : km × Coefficient + Base.</summary>
public decimal Base { get; set; } = 0m;
}
@@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
namespace SchotzIadKmTracker.Api.Models.Entities;
/// <summary>Véhicule de l'utilisateur avec date d'effet. Historique conservé.</summary>
public class Vehicule
{
public int Id { get; set; }
/// <summary>Dénomination libre du véhicule (ex. « Voiture personnelle »), obligatoire (1–100 caractères).</summary>
[Required, MaxLength(100)]
public string Denomination { get; set; } = string.Empty;
/// <summary>Plaque d'immatriculation (1–15 caractères).</summary>
[Required, MaxLength(15)]
public string Plaque { get; set; } = string.Empty;
/// <summary>Puissance fiscale en chevaux fiscaux (entier positif).</summary>
[Required]
public int PuissanceFiscale { get; set; }
/// <summary>Date à partir de laquelle ce véhicule devient le véhicule courant (&lt;= date du jour).</summary>
[Required]
public DateOnly DateEffet { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public ICollection<Trajet> Trajets { get; set; } = new List<Trajet>();
}