Le bundle initial dépasse le seuil par défaut (500kb) à cause des dépendances
applicatives (Leaflet, etc.), sans lien avec une régression. On relève le budget
initial à 1mb (warning) / 2mb (error) et le budget de style de composant à 4kb /
8kb pour supprimer les avertissements de build non pertinents.
Aucun impact fonctionnel.
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).
Aligne requirements.md et design.md sur l'état réel du code (écart accumulé
depuis le 14/09 en mode dev direct).
requirements.md :
- Intro : compte unique authentifié (au lieu de « sans authentification ».
- Glossaire : Compte, Adresse_Email, Mot_De_Passe, Session, JWT,
Jeton_Reinitialisation, Aller_Retour, Distance_Effective.
- Exigence 1 : case Aller/Retour. Exigence 10 : dénomination véhicule.
- Exigence 12 : refonte consultation par mois (sélecteur année/mois, liste
mensuelle groupée par jour repliable, nav jour bornée aux jours avec trajets).
- Exigence 13 : tranches de barème multiples (dernière illimitée, coef 3
décimales) + recopie du dernier barème.
- Exigence 16 : onboarding relié à l'authentification.
- Nouvelles exigences 17 (Authentification) et 18 (Trajet aller/retour).
design.md :
- Overview + contraintes : compte authentifié, port 2202, Caddy externe HTTPS.
- Déploiement : compose (port 2202, JWT_SECRET_KEY obligatoire, e-mail/MailKit,
AUTH_FRONTEND_BASE_URL), reverse-proxy Caddy externe, pas de UseHttpsRedirection.
- Nouvelle section « Évolutions majeures » : décisions d'architecture pour l'auth,
l'onboarding 2 étapes, l'aller/retour, la consultation par mois, le barème
multi-tranches, la dénomination véhicule et le recalcul ciblé des distances.
Ajoute .kiro/steering/spec-sync.md : règle de mise à jour des specs dans le même
commit que le code, à chaque évolution validée.
Le tooltip Leaflet avec un simple max-width se réduisait à quelques caractères
de large (nombreuses lignes illisibles). On lui donne une largeur franche de
220px et on retire word-break (qui coupait au milieu des mots), en gardant
overflow-wrap pour les mots trop longs. Le texte se répartit désormais
normalement sans déborder de la carte.
Build prod OK.
Leaflet applique par défaut white-space: nowrap aux tooltips, ce qui forçait
l'infobulle de survol sur une seule ligne et la faisait déborder hors de la
carte (illisible). On borne désormais .leaflet-tooltip en largeur (240px) et on
autorise le retour à la ligne, à l'identique des popups (clic).
Build prod OK.
- Backend : TrajetCarteDto expose désormais le commentaire du trajet ; la
projection de GET /api/trajets/journee/{date} le renseigne.
- Frontend : l'interface TrajetCarte porte le commentaire. L'infobulle affiche
le commentaire en première ligne (s'il existe, séparé par un léger trait) et
ajoute « (A/R) » après la distance pour un aller/retour.
- Style .carte-infobulle__commentaire (italique, discret) dans les styles
globaux.
Builds backend, frontend dev et prod OK.
Le mois et l'année sélectionnés (ex. « Septembre 2026 ») sont affichés à droite
du libellé « 📅 Choisir un mois », séparés par un léger trait. Vide tant qu'aucun
mois n'est choisi. Permet de connaître la période courante sans déplier le
sélecteur.
Build prod OK.
Un mois sans trajet est un cas normal, pas une erreur :
- Panneau totaux : plus d'alerte « Impossible de charger les totaux ». Un
jour/mois sans trajet affiche simplement des totaux à 0,00 km. Signal erreur
supprimé.
- Consultation : plus d'alerte « Impossible de charger les trajets du mois ».
Signal erreur et variable resumeEnErreur supprimés ; un échec de résumé
affiche une liste vide (les vraies indisponibilités serveur restent signalées
par l'intercepteur global).
- Message vide unique : « Aucun trajet pour ce mois » n'est plus affiché en
double (retiré de la liste, conservé côté consultation avec garde de
chargement).
Builds dev et prod OK.
Les totaux affichés sont relatifs au jour ciblé sur la carte. La bande
« ‹ Jour préc. / date / Jour suiv. › » est déplacée juste sous le sélecteur de
mois, au-dessus du panneau des totaux, afin que la date pilote visuellement les
totaux et la carte qui suivent.
Build prod OK.
Les boutons « Jour préc. » / « Jour suiv. » de la carte ne s'arrêtent plus sur
tous les jours du mois mais uniquement sur les jours comportant des trajets.
Exception : dans le mois en cours, le jour courant reste navigable même sans
trajet (pour pouvoir y ajouter un trajet).
- joursNavigables() : jours du mois avec trajets (+ aujourd'hui si mois courant),
triés. La date affichée n'a pas besoin d'en faire partie.
- jourNavigableAdjacent() : jour navigable strictement avant/après la date
affichée ; boutons désactivés s'il n'y en a pas.
- À la sélection d'un mois passé, la carte se recale sur le dernier jour ayant
des trajets si le jour par défaut tombe sur une journée vide.
Builds dev et prod OK.
- Sélecteur temporel : libellé « 📅 Choisir une date » → « 📅 Choisir un mois ».
- Liste mensuelle : chaque journée est désormais repliable (en-tête cliquable
avec chevron, date et nombre de trajets). Par défaut toutes les journées sont
repliées ; au changement de mois, seule la dernière journée comportant des
trajets est dépliée. Les mises à jour au sein du même mois (ajout, suppression,
réordonnancement) conservent l'état d'ouverture courant.
- La date, désormais portée par l'en-tête du groupe, est retirée de chaque ligne
de trajet (suppression du doublon) ; le commentaire occupe seul sa ligne.
Builds dev et prod OK.
Refonte de la navigation temporelle suite au retour d'usage :
- Sélecteur temporel limité à année/mois (suppression du segment jour).
Nouvel Output moisSelectionne: {annee, mois} en remplacement de
dateSelectionnee (jour ISO). Surbrillance des mois avec données conservée.
- Consultation : deux états distincts. Le signal mois pilote le chargement
de la liste (tous les trajets du mois, triés par date), le signal date
pilote la carte (trajets du jour) et la date par défaut à l'ajout/insertion.
Bande « ‹ Jour préc. / date / Jour suiv. › » au-dessus de la carte, bornée
au mois sélectionné. La navigation jour ne recharge que la carte.
- Liste : trajets du mois groupés par journée (en-tête de date). Un
cdkDropList indépendant par jour (listes non connectées) : le
réordonnancement par glisser-déposer est limité à chaque journée, avec
recalcul des positions internes et rétablissement en cas d'échec.
Builds dev et prod OK. Backend inchangé (API résumé mensuel/réordonner
déjà en place).
La page d'inscription n'est atteinte que lorsqu'aucun compte n'existe (application
mono-utilisateur) : le lien vers la connexion n'a pas de sens. Import RouterLink
devenu inutile retiré du composant.
Corrige un contournement : après réinitialisation de la base (même JWT_SECRET_KEY),
un jeton restait cryptographiquement valide et donnait accès alors que le compte
n'existait plus, permettant d'atteindre l'onboarding sans s'inscrire.
- Backend : JwtBearer.OnTokenValidated vérifie désormais l'existence du compte
référencé par le claim sub (lu sous 'sub' ou NameIdentifier selon le remapping)
et rejette le jeton (401) si le compte est introuvable.
- Backend : nouvel endpoint protégé GET /api/auth/moi (SessionController) renvoyant
200 si la session est réellement valide, 401 sinon.
- Frontend : authGuard valide la session côté serveur (GET /auth/moi) au lieu de se
fier au seul jeton local ; sur échec, redirection vers /login (jeton purgé par
l'intercepteur sur 401). AuthService.validerSession() ajouté.
Tests backend : 54/54 au vert.
- Onboarding : redirection automatique vers /register lorsqu'aucun compte n'existe
(première utilisation), au lieu d'afficher la page de connexion.
- Carte Leaflet en production : import normalisé (Leaflet est CommonJS, l'API pouvait
se retrouver sous .default en build prod -> échec d'initialisation). Nettoyage du
marqueur _leaflet_id du conteneur pour que « Réessayer » fonctionne après un échec.
Logs d'erreur explicites en cas d'échec d'import/init.
- Mise en page : layout applicatif en flex pleine hauteur (nav de hauteur naturelle,
<main> occupe le reste et défile si besoin) sans étirer les vues courtes. La vue
Trajets occupe l'espace restant (height:100%) sans scrollbar de page : seule la
liste défile. Reset global (body margin 0, box-sizing border-box) supprimant la
scrollbar de page parasite.
- Centrage uniforme des pages : ajout de margin:0 auto aux vues profil, véhicules,
barème, résumé mensuel/annuel et montants réglés (comme trajets et carnet).
Builds backend (solution) et frontend (production) OK.
Évite d'embarquer les artefacts .NET (~220 Mo) et les bases SQLite locales dans le
contexte de build de l'image backend. Build de l'image API validé sans le projet de tests.
Évite un conflit avec une instance existante sur 8080. Seul le port HÔTE change
(2202:80) ; les ports internes des conteneurs (backend 8080) sont inchangés, donc
le proxy interne nginx -> backend n'est pas affecté. Auth__FrontendBaseUrl par défaut
et Caddyfile.example alignés sur 2202.
Configuration reverse_proxy vers l'IP de la machine Docker (port 8080 publié par le
compose), en-têtes X-Forwarded-*, sonde /health, et recommandations de sécurité
(restreindre le port 8080 à l'IP de Caddy / réseau privé) pour éviter un accès HTTP
direct contournant le TLS.
- Retire app.UseHttpsRedirection() : le conteneur écoute en HTTP, la terminaison
TLS est assurée par le reverse-proxy (Caddy) placé devant. Évite les redirections
parasites derrière le proxy.
- Ajoute Caddyfile.example (Caddy devant le compose existant : TLS auto + reverse_proxy
vers le frontend nginx qui sert l'app et proxifie /api).
- .env.example : précise AUTH_FRONTEND_BASE_URL = URL publique HTTPS en production
(liens de réinitialisation de mot de passe).
- Totaux : rafraîchissement immédiat du panneau (jour/mois/année + montant
prévisionnel) après création/modification/suppression/réordonnancement d'un
trajet, sans changer de jour (ViewChild + méthode publique rafraichir()).
- Trajets Aller/Retour : case à cocher au formulaire ; la distance comptée est
doublée (distance simple stockée + booléen AllerRetour, distance effective
utilisée dans tous les agrégats : totaux, résumés, barème, régularisation, PDF).
Migration TrajetAllerRetour. Badge « A/R » dans une colonne dédiée en début de
ligne pour garder date/adresses alignées.
- Mise en page de la page Trajets : vue à hauteur fixe où seule la liste défile ;
colonne gauche figée (sélecteur de date + navigation, totaux, carte) et bande
fixe (véhicule + bouton d'ajout) au-dessus de la liste. Layout applicatif global
en pleine hauteur (app.component).
- run-dev.sh : chargement de la clé JWT depuis .env (ou secret de dev aléatoire) et
Auth__FrontendBaseUrl sur le frontend dev ; rappel du lien de reset journalisé.
Build backend (solution) et frontend (production) OK.