- 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.
144 lines
6.2 KiB
Bash
Executable File
144 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Lance en mode développement le backend (port 8080) et le frontend Angular (port 4200)
|
||
# avec la base SQLite réelle. À utiliser hors Docker, pour le développement local.
|
||
#
|
||
# Usage : ./run-dev.sh
|
||
# Arrêt : Ctrl+C (les deux processus sont arrêtés ensemble).
|
||
|
||
set -uo pipefail
|
||
RACINE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
||
# --- Backend (.NET 8) -------------------------------------------------------
|
||
export PATH="$HOME/.dotnet:$HOME/.dotnet/tools:$PATH"
|
||
export DOTNET_ROOT="$HOME/.dotnet"
|
||
|
||
# Base réelle, chemin ABSOLU pour éviter deux bases selon le dossier de lancement.
|
||
export ConnectionStrings__Default="Data Source=$RACINE/backend/SchotzIadKmTracker.Api/trajets.db"
|
||
export ASPNETCORE_ENVIRONMENT=Development
|
||
|
||
# Clé OpenRouteService : lue depuis .env (ORS_API_KEY) et injectée sous le nom attendu
|
||
# par la configuration .NET (ORS__ApiKey). Sans clé valide, le backend calcule les
|
||
# distances à vol d'oiseau (fallback Haversine) au lieu de la distance routière réelle.
|
||
if [[ -z "${ORS__ApiKey:-}" && -f "$RACINE/.env" ]]; then
|
||
ORS_KEY_FROM_ENV="$(grep -E '^ORS_API_KEY=' "$RACINE/.env" | head -n1 | cut -d= -f2- || true)"
|
||
if [[ -n "$ORS_KEY_FROM_ENV" ]]; then
|
||
export ORS__ApiKey="$ORS_KEY_FROM_ENV"
|
||
echo "→ Clé ORS chargée depuis .env (calcul de distance routière activé)."
|
||
else
|
||
echo "⚠ Aucune clé ORS dans .env : distances calculées à vol d'oiseau."
|
||
fi
|
||
fi
|
||
|
||
# --- Authentification (dev) -------------------------------------------------
|
||
# Clé de signature JWT : lue depuis .env (JWT_SECRET_KEY). Si absente, on génère
|
||
# un secret ALÉATOIRE de développement (valable pour cette session). En dev, cela
|
||
# signifie que les sessions existantes sont invalidées à chaque relance du script,
|
||
# ce qui est acceptable ; en production, définis JWT_SECRET_KEY dans .env.
|
||
if [[ -z "${JWT__SecretKey:-}" ]]; then
|
||
JWT_KEY_FROM_ENV=""
|
||
if [[ -f "$RACINE/.env" ]]; then
|
||
JWT_KEY_FROM_ENV="$(grep -E '^JWT_SECRET_KEY=' "$RACINE/.env" | head -n1 | cut -d= -f2- || true)"
|
||
fi
|
||
# Ignore la valeur placeholder du .env.example si elle a été copiée telle quelle.
|
||
if [[ -n "$JWT_KEY_FROM_ENV" && "$JWT_KEY_FROM_ENV" != "change-me-generate-a-long-random-secret" ]]; then
|
||
export JWT__SecretKey="$JWT_KEY_FROM_ENV"
|
||
echo "→ Clé JWT chargée depuis .env."
|
||
else
|
||
# Secret de dev aléatoire (>= 32 octets) : openssl si dispo, sinon /dev/urandom.
|
||
if command -v openssl >/dev/null 2>&1; then
|
||
export JWT__SecretKey="$(openssl rand -base64 48)"
|
||
else
|
||
export JWT__SecretKey="$(head -c 48 /dev/urandom | base64)"
|
||
fi
|
||
echo "⚠ Aucune clé JWT dans .env : secret de développement aléatoire généré (sessions invalidées à chaque relance)."
|
||
fi
|
||
fi
|
||
|
||
# URL de base du frontend pour les liens de réinitialisation (dev = ng serve sur 4200).
|
||
export Auth__FrontendBaseUrl="${Auth__FrontendBaseUrl:-http://localhost:4200}"
|
||
|
||
# SMTP non configuré en dev : le lien de réinitialisation est journalisé dans la
|
||
# sortie du backend (repli LoggingEmailService). Cherche « reset-password?token= »
|
||
# dans les logs pour tester la réinitialisation sans email réel.
|
||
|
||
echo "→ Démarrage du backend sur http://localhost:8080 (base : $RACINE/backend/SchotzIadKmTracker.Api/trajets.db)"
|
||
dotnet run --project "$RACINE/backend/SchotzIadKmTracker.Api" --urls http://localhost:8080 &
|
||
PID_BACK=$!
|
||
|
||
# --- Frontend (Angular via nvm/Node 22) -------------------------------------
|
||
export NVM_DIR="$HOME/.nvm"
|
||
# shellcheck source=/dev/null
|
||
. "$NVM_DIR/nvm.sh"
|
||
nvm use 22 >/dev/null
|
||
|
||
# Vide le cache de compilation Angular pour garantir un bundle à jour, notamment
|
||
# le polyfill zone.js (sans lui, la vue ne se rafraîchit pas sur les réponses HTTP :
|
||
# `window.Zone` doit être défini au runtime). Un cache périmé peut resservir un
|
||
# ancien polyfills sans zone.js.
|
||
echo "→ Nettoyage du cache Angular (.angular/cache)"
|
||
rm -rf "$RACINE/frontend/.angular/cache"
|
||
|
||
echo "→ Démarrage du frontend sur http://localhost:4200 (première compilation : patiente…)"
|
||
( cd "$RACINE/frontend" && npm start ) &
|
||
PID_FRONT=$!
|
||
|
||
# --- Arrêt propre des deux processus ----------------------------------------
|
||
cleanup() {
|
||
echo ""
|
||
echo "→ Arrêt…"
|
||
kill "$PID_BACK" "$PID_FRONT" 2>/dev/null || true
|
||
pkill -f "SchotzIadKmTracker.Api" 2>/dev/null || true
|
||
}
|
||
trap cleanup EXIT INT TERM
|
||
|
||
# --- Attente active : ng serve prêt à répondre en HTTP 200 ------------------
|
||
# La première compilation (surtout après vidage du cache) peut prendre 30–60 s.
|
||
# Tant que ng serve n'a pas fini, le port répond « connexion refusée » (HTTP 000)
|
||
# et le navigateur chargerait une page incomplète (zone.js absent → window.Zone
|
||
# undefined). On ne montre l'invitation qu'une fois le serveur réellement prêt.
|
||
attendre_frontend() {
|
||
local url="http://localhost:4200/"
|
||
local max=120 # secondes
|
||
local t=0
|
||
printf "→ Compilation du frontend"
|
||
while [ "$t" -lt "$max" ]; do
|
||
# Le process ng serve est-il toujours vivant ?
|
||
if ! kill -0 "$PID_FRONT" 2>/dev/null; then
|
||
echo ""
|
||
echo "✗ Le frontend s'est arrêté avant d'être prêt (voir les logs ci-dessus)."
|
||
return 1
|
||
fi
|
||
local code
|
||
code=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || echo 000)
|
||
if [ "$code" = "200" ]; then
|
||
echo " prêt."
|
||
return 0
|
||
fi
|
||
printf "."
|
||
sleep 2
|
||
t=$((t + 2))
|
||
done
|
||
echo ""
|
||
echo "✗ Le frontend n'a pas répondu 200 au bout de ${max}s. Vérifie les logs ng serve."
|
||
return 1
|
||
}
|
||
|
||
if attendre_frontend; then
|
||
echo ""
|
||
echo "======================================================================"
|
||
echo " Application prête."
|
||
echo " Backend : http://localhost:8080/api"
|
||
echo " Frontend : http://localhost:4200 ← ouvre cette URL maintenant"
|
||
echo ""
|
||
echo " Au premier chargement, fais Ctrl+Shift+R pour vider le cache navigateur."
|
||
echo " Vérif : dans la console DevTools, 'window.Zone' doit renvoyer un objet."
|
||
echo ""
|
||
echo " Auth : à la 1re utilisation, crée le compte via /register puis connecte-toi."
|
||
echo " Reset de mot de passe (dev) : le lien est journalisé dans la sortie backend"
|
||
echo " ci-dessus (cherche « reset-password?token= »), aucun email n'est envoyé."
|
||
echo "======================================================================"
|
||
echo ""
|
||
fi
|
||
|
||
wait
|