#!/usr/bin/env bash # ───────────────────────────────────────────────────────────────────────────── # VPS Monitor — script de démarrage rapide # Lance le backend Python et le frontend React en développement. # Usage : ./start.sh # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail # ── Couleurs ───────────────────────────────────────────────────────────────── R="\033[0m"; BOLD="\033[1m"; GRN="\033[32m"; YEL="\033[33m" RED="\033[31m"; CYN="\033[36m"; DIM="\033[2m" log() { echo -e "${CYN}[VPS Monitor]${R} $*"; } ok() { echo -e "${GRN}[✓]${R} $*"; } warn() { echo -e "${YEL}[!]${R} $*"; } die() { echo -e "${RED}[✗]${R} $*" >&2; exit 1; } # ── Répertoires ─────────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BACKEND_DIR="$SCRIPT_DIR/backend" FRONTEND_DIR="$SCRIPT_DIR/frontend" VENV_DIR="$BACKEND_DIR/.venv" PIDS_FILE="$SCRIPT_DIR/.pids" BACKEND_PORT="${BACKEND_PORT:-8000}" FRONTEND_PORT="${FRONTEND_PORT:-5173}" # ── Nettoyage à la sortie ───────────────────────────────────────────────────── cleanup() { echo "" log "Arrêt des services…" if [[ -f "$PIDS_FILE" ]]; then while IFS= read -r pid; do kill "$pid" 2>/dev/null && echo -e " ${DIM}PID $pid arrêté${R}" || true done < "$PIDS_FILE" rm -f "$PIDS_FILE" fi ok "Arrêt propre." } trap cleanup EXIT INT TERM # ───────────────────────────────────────────────────────────────────────────── # 1. Vérification des prérequis # ───────────────────────────────────────────────────────────────────────────── echo "" echo -e "${BOLD}${CYN}══════════════════════════════════════════${R}" echo -e "${BOLD}${CYN} VPS Monitor — Démarrage ${R}" echo -e "${BOLD}${CYN}══════════════════════════════════════════${R}" echo "" log "Vérification des prérequis…" PYTHON_BIN="" for bin in python3 python; do if command -v "$bin" &>/dev/null && "$bin" -c "import sys; assert sys.version_info >= (3,10)" 2>/dev/null; then PYTHON_BIN="$bin" break fi done [[ -z "$PYTHON_BIN" ]] && die "Python 3.10+ requis (python3 ou python introuvable)." ok "Python : $($PYTHON_BIN --version)" command -v node &>/dev/null || die "Node.js requis (https://nodejs.org)." ok "Node : $(node --version)" command -v npm &>/dev/null || die "npm requis." ok "npm : $(npm --version)" echo "" # ───────────────────────────────────────────────────────────────────────────── # 2. Configuration du backend # ───────────────────────────────────────────────────────────────────────────── log "Préparation du backend…" # Environnement virtuel if [[ ! -d "$VENV_DIR" ]]; then log "Création du virtualenv Python…" "$PYTHON_BIN" -m venv "$VENV_DIR" fi VENV_PYTHON="$VENV_DIR/bin/python" VENV_PIP="$VENV_DIR/bin/pip" # Dépendances backend INSTALLED_MARKER="$VENV_DIR/.installed" REQ_HASH=$(md5sum "$BACKEND_DIR/requirements.txt" 2>/dev/null | cut -d' ' -f1 || echo "none") if [[ ! -f "$INSTALLED_MARKER" ]] || [[ "$(cat "$INSTALLED_MARKER" 2>/dev/null)" != "$REQ_HASH" ]]; then log "Installation des dépendances Python…" "$VENV_PIP" install --quiet --upgrade pip "$VENV_PIP" install --quiet -r "$BACKEND_DIR/requirements.txt" echo "$REQ_HASH" > "$INSTALLED_MARKER" ok "Dépendances Python installées." else ok "Dépendances Python déjà à jour." fi # Fichier .env du backend if [[ ! -f "$BACKEND_DIR/.env" ]]; then if [[ -f "$BACKEND_DIR/.env.example" ]]; then cp "$BACKEND_DIR/.env.example" "$BACKEND_DIR/.env" warn "Fichier .env créé depuis .env.example → $BACKEND_DIR/.env" warn "Pensez à vérifier la config (CORS_ORIGINS, etc.)." fi fi # Dossier data mkdir -p "$BACKEND_DIR/data" echo "" # ───────────────────────────────────────────────────────────────────────────── # 3. Configuration du frontend # ───────────────────────────────────────────────────────────────────────────── log "Préparation du frontend…" if [[ ! -d "$FRONTEND_DIR/node_modules" ]]; then log "Installation des dépendances npm…" npm install --prefix "$FRONTEND_DIR" --silent ok "Dépendances npm installées." else ok "node_modules déjà présent." fi echo "" # ───────────────────────────────────────────────────────────────────────────── # 4. Démarrage des services # ───────────────────────────────────────────────────────────────────────────── rm -f "$PIDS_FILE" LOGS_DIR="$SCRIPT_DIR/.logs" mkdir -p "$LOGS_DIR" log "Démarrage du backend (port $BACKEND_PORT)…" ( cd "$BACKEND_DIR" # Charge .env si python-dotenv est dispo, sinon exporte manuellement if [[ -f ".env" ]]; then set -a; source .env; set +a fi "$VENV_DIR/bin/uvicorn" main:app \ --host 0.0.0.0 \ --port "$BACKEND_PORT" \ --reload \ --log-level warning \ 2>&1 | sed 's/^/ [backend] /' ) & BACKEND_PID=$! echo "$BACKEND_PID" >> "$PIDS_FILE" # Attend que le backend réponde log "Attente du backend…" for i in $(seq 1 20); do if curl -sf "http://localhost:$BACKEND_PORT/api/vps" >/dev/null 2>&1; then break fi sleep 0.5 done ok "Backend prêt." log "Démarrage du frontend (port $FRONTEND_PORT)…" ( npm run dev --prefix "$FRONTEND_DIR" -- \ --port "$FRONTEND_PORT" \ --strictPort \ 2>&1 | sed 's/^/ [frontend] /' ) & FRONTEND_PID=$! echo "$FRONTEND_PID" >> "$PIDS_FILE" # ───────────────────────────────────────────────────────────────────────────── # 5. Résumé # ───────────────────────────────────────────────────────────────────────────── sleep 1 echo "" echo -e "${BOLD}${GRN}══════════════════════════════════════════${R}" echo -e "${BOLD}${GRN} Application démarrée ! ${R}" echo -e "${BOLD}${GRN}══════════════════════════════════════════${R}" echo "" echo -e " ${BOLD}Frontend${R} → ${CYN}http://localhost:$FRONTEND_PORT${R}" echo -e " ${BOLD}Backend${R} → ${CYN}http://localhost:$BACKEND_PORT${R}" echo -e " ${BOLD}API docs${R} → ${CYN}http://localhost:$BACKEND_PORT/docs${R}" echo "" echo -e " ${DIM}Ctrl+C pour arrêter${R}" echo "" # Ouvre le navigateur automatiquement (si disponible) if command -v xdg-open &>/dev/null; then xdg-open "http://localhost:$FRONTEND_PORT" &>/dev/null & elif command -v open &>/dev/null; then open "http://localhost:$FRONTEND_PORT" &>/dev/null & fi # ───────────────────────────────────────────────────────────────────────────── # 6. Attente — affiche les logs des deux services en temps réel # ───────────────────────────────────────────────────────────────────────────── wait "$BACKEND_PID" "$FRONTEND_PID"