#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BACKEND_DIR="$ROOT_DIR/backend" FRONTEND_DIR="$ROOT_DIR/frontend" BACKEND_VENV="${BACKEND_VENV:-$BACKEND_DIR/.venv313}" BACKEND_PORT="${BACKEND_PORT:-8000}" FRONTEND_PORT="${FRONTEND_PORT:-5173}" PYTHON_BIN="${PYTHON_BIN:-python3.13}" BACKEND_PID="" cleanup() { if [[ -n "$BACKEND_PID" ]] && kill -0 "$BACKEND_PID" >/dev/null 2>&1; then echo "" echo "Encerrando backend..." kill "$BACKEND_PID" >/dev/null 2>&1 || true wait "$BACKEND_PID" 2>/dev/null || true fi } trap cleanup EXIT INT TERM require_command() { local command_name="$1" if ! command -v "$command_name" >/dev/null 2>&1; then echo "Comando obrigatório não encontrado: $command_name" >&2 exit 1 fi } port_in_use() { local port="$1" lsof -nP -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1 } pick_available_port() { local port="$1" while port_in_use "$port"; do port=$((port + 1)) done echo "$port" } python_version_of_venv() { local venv_dir="$1" if [[ -x "$venv_dir/bin/python" ]]; then "$venv_dir/bin/python" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' fi } ensure_backend_env() { require_command "$PYTHON_BIN" local desired_version desired_version="$("$PYTHON_BIN" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" if [[ ! -d "$BACKEND_VENV" ]]; then echo "Criando ambiente virtual do backend com $PYTHON_BIN..." "$PYTHON_BIN" -m venv "$BACKEND_VENV" else local current_version current_version="$(python_version_of_venv "$BACKEND_VENV")" if [[ "$current_version" != "$desired_version" ]]; then echo "A venv em $BACKEND_VENV usa Python $current_version, mas o script espera Python $desired_version." >&2 echo "Apague essa venv ou rode com BACKEND_VENV apontando para outra pasta." >&2 echo "Sugestão segura:" >&2 echo " mv \"$BACKEND_VENV\" \"${BACKEND_VENV}.old\"" >&2 echo "Depois rode novamente ./dev.sh" >&2 exit 1 fi fi echo "Instalando/verificando dependências do backend..." # shellcheck disable=SC1091 source "$BACKEND_VENV/bin/activate" pip install -r "$BACKEND_DIR/requirements.txt" >/dev/null } ensure_frontend_env() { require_command npm if [[ ! -d "$FRONTEND_DIR/node_modules" ]] || [[ ! -x "$FRONTEND_DIR/node_modules/.bin/vite" ]]; then echo "Instalando dependências do frontend..." (cd "$FRONTEND_DIR" && npm install) fi } prepare_ports() { if port_in_use "$BACKEND_PORT"; then local requested_port="$BACKEND_PORT" BACKEND_PORT="$(pick_available_port "$BACKEND_PORT")" echo "Porta $requested_port já está em uso no backend. Usando $BACKEND_PORT." fi if port_in_use "$FRONTEND_PORT"; then local requested_port="$FRONTEND_PORT" FRONTEND_PORT="$(pick_available_port "$FRONTEND_PORT")" echo "Porta $requested_port já está em uso no frontend. Usando $FRONTEND_PORT." fi } start_backend() { echo "Subindo backend em http://127.0.0.1:$BACKEND_PORT ..." ( cd "$BACKEND_DIR" # shellcheck disable=SC1091 source "$BACKEND_VENV/bin/activate" uvicorn app.main:app --reload --host 127.0.0.1 --port "$BACKEND_PORT" ) & BACKEND_PID=$! } start_frontend() { echo "Subindo frontend em http://127.0.0.1:$FRONTEND_PORT ..." cd "$FRONTEND_DIR" VITE_API_BASE_URL="http://127.0.0.1:$BACKEND_PORT" npm run dev -- --host 127.0.0.1 --port "$FRONTEND_PORT" } echo "Preparando ambiente de desenvolvimento..." ensure_backend_env ensure_frontend_env prepare_ports start_backend start_frontend