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

88 lines
4.5 KiB
C#

using SchotzIadKmTracker.Api.Models.Entities;
namespace SchotzIadKmTracker.Api.Repositories;
/// <summary>
/// Accès aux données des trajets et gestion des positions au sein d'une journée.
/// <para>
/// La <see cref="Trajet.Position"/> est une valeur décimale (REAL) permettant l'insertion
/// sans réordonnancement systématique : ajout en fin de journée → <c>max(Position) + 1.0</c>,
/// insertion entre deux positions P₁ et P₂ → <c>(P₁ + P₂) / 2</c>. Lorsque l'écart devient
/// trop faible (&lt; <see cref="SeuilRenumerotation"/>), la journée est renumérotée par pas de
/// 1.0 en transaction en préservant l'ordre relatif (Property 15, Exigences 11.7/11.8).
/// </para>
/// <para>
/// Ce repository fournit uniquement les primitives d'accès et de calcul de position ;
/// la logique métier (validation, calcul de distance, mise en cache) relève de TrajetService.
/// </para>
/// </summary>
public interface ITrajetRepository
{
/// <summary>
/// Seuil de précision en deçà duquel une renumérotation de la journée est déclenchée.
/// Conforme à la conception : écart &lt; 0.001.
/// </summary>
const decimal SeuilRenumerotation = 0.001m;
/// <summary>Retourne le trajet par identifiant, ou <c>null</c> s'il n'existe pas.</summary>
Task<Trajet?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
/// <summary>Retourne les trajets d'une journée triés par <see cref="Trajet.Position"/> croissante.</summary>
Task<List<Trajet>> GetByDateAsync(DateOnly date, CancellationToken cancellationToken = default);
/// <summary>
/// Résout le véhicule applicable à la date du trajet et copie sa <c>PuissanceFiscale</c>
/// sur le trajet (dénormalisation, Exigence 10.14). Ne modifie ni <c>VehiculeId</c> ni
/// <c>PuissanceFiscale</c> si aucun véhicule n'est applicable à cette date.
/// Coordonné avec <see cref="Services.IVehiculeService.GetVehiculeADateAsync"/>.
/// </summary>
Task AppliquerVehiculeADateAsync(Trajet trajet, CancellationToken cancellationToken = default);
/// <summary>
/// Calcule la position d'un trajet ajouté en fin de journée : <c>max(Position) + 1.0</c>
/// pour la date, ou <c>1.0</c> si la journée est vide.
/// </summary>
Task<decimal> CalculerPositionFinDeJourneeAsync(DateOnly date, CancellationToken cancellationToken = default);
/// <summary>
/// Calcule la position d'un trajet inséré entre les positions <paramref name="positionPrecedente"/>
/// (P₁) et <paramref name="positionSuivante"/> (P₂) : <c>(P₁ + P₂) / 2</c>.
/// </summary>
/// <exception cref="ArgumentException">Si P₁ n'est pas strictement inférieure à P₂.</exception>
decimal CalculerPositionEntre(decimal positionPrecedente, decimal positionSuivante);
/// <summary>
/// Indique si l'écart entre deux positions adjacentes est devenu trop faible
/// (&lt; <see cref="SeuilRenumerotation"/>) pour insérer une nouvelle valeur intermédiaire.
/// </summary>
bool NecessiteRenumerotation(decimal positionPrecedente, decimal positionSuivante);
/// <summary>Ajoute un trajet (sans persister). L'appelant gère la transaction et l'appel à <see cref="SauvegarderAsync"/>.</summary>
Task AddAsync(Trajet trajet, CancellationToken cancellationToken = default);
/// <summary>Marque un trajet existant comme modifié (sans persister).</summary>
void Update(Trajet trajet);
/// <summary>Supprime un trajet (sans persister).</summary>
void Delete(Trajet trajet);
/// <summary>Persiste les changements en attente.</summary>
Task<int> SauvegarderAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Applique un réordonnancement manuel : met à jour uniquement la <see cref="Trajet.Position"/>
/// des trajets fournis (par identifiant) sans altérer leurs autres champs, en transaction.
/// Les identifiants inconnus sont ignorés.
/// </summary>
Task ReordonnerAsync(
IReadOnlyList<(int Id, decimal Position)> positions,
CancellationToken cancellationToken = default);
/// <summary>
/// Renumérote les trajets d'une journée par pas de 1.0 (1.0, 2.0, 3.0, …) en préservant
/// l'ordre relatif courant (tri par Position puis Id), en transaction. Retourne la liste
/// renumérotée triée par Position croissante (Property 15).
/// </summary>
Task<List<Trajet>> RenumeroterJourneeAsync(DateOnly date, CancellationToken cancellationToken = default);
}