summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/start-stack.sh80
-rwxr-xr-xscripts/stop-stack.sh42
2 files changed, 122 insertions, 0 deletions
diff --git a/scripts/start-stack.sh b/scripts/start-stack.sh
new file mode 100755
index 0000000..6324967
--- /dev/null
+++ b/scripts/start-stack.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+RUN_DIR="$ROOT_DIR/.run"
+LOG_DIR="$RUN_DIR/logs"
+
+BACKEND_PID_FILE="$RUN_DIR/backend.pid"
+FRONTEND_PID_FILE="$RUN_DIR/frontend.pid"
+BACKEND_LOG="$LOG_DIR/backend.log"
+FRONTEND_LOG="$LOG_DIR/frontend.log"
+
+BACKEND_HOST="${BACKEND_HOST:-127.0.0.1}"
+BACKEND_PORT="${BACKEND_PORT:-8001}"
+FRONTEND_HOST="${FRONTEND_HOST:-127.0.0.1}"
+FRONTEND_PORT="${FRONTEND_PORT:-3001}"
+API_BASE_URL="${NEXT_PUBLIC_API_BASE_URL:-http://${BACKEND_HOST}:${BACKEND_PORT}}"
+
+mkdir -p "$LOG_DIR"
+
+is_running() {
+ local pid_file="$1"
+ if [[ -f "$pid_file" ]]; then
+ local pid
+ pid="$(cat "$pid_file")"
+ if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
+ return 0
+ fi
+ rm -f "$pid_file"
+ fi
+ return 1
+}
+
+require_file() {
+ local path="$1"
+ local label="$2"
+ if [[ ! -e "$path" ]]; then
+ echo "$label not found: $path" >&2
+ exit 1
+ fi
+}
+
+require_file "$ROOT_DIR/backend/.venv/bin/uvicorn" "Backend virtualenv executable"
+require_file "$ROOT_DIR/frontend/node_modules" "Frontend dependencies"
+
+if is_running "$BACKEND_PID_FILE"; then
+ echo "Backend already running on PID $(cat "$BACKEND_PID_FILE")"
+else
+ (
+ cd "$ROOT_DIR/backend"
+ exec .venv/bin/uvicorn app.main:app --reload --host "$BACKEND_HOST" --port "$BACKEND_PORT"
+ ) >"$BACKEND_LOG" 2>&1 &
+ echo $! >"$BACKEND_PID_FILE"
+ echo "Started backend on http://${BACKEND_HOST}:${BACKEND_PORT} (PID $(cat "$BACKEND_PID_FILE"))"
+fi
+
+if is_running "$FRONTEND_PID_FILE"; then
+ echo "Frontend already running on PID $(cat "$FRONTEND_PID_FILE")"
+else
+ (
+ cd "$ROOT_DIR/frontend"
+ export NEXT_PUBLIC_API_BASE_URL="$API_BASE_URL"
+ exec npm run dev -- --hostname "$FRONTEND_HOST" --port "$FRONTEND_PORT"
+ ) >"$FRONTEND_LOG" 2>&1 &
+ echo $! >"$FRONTEND_PID_FILE"
+ echo "Started frontend on http://${FRONTEND_HOST}:${FRONTEND_PORT} (PID $(cat "$FRONTEND_PID_FILE"))"
+fi
+
+cat <<EOF
+
+Stack status
+- Frontend: http://${FRONTEND_HOST}:${FRONTEND_PORT}
+- Backend: http://${BACKEND_HOST}:${BACKEND_PORT}
+- API base: $API_BASE_URL
+- Logs: $LOG_DIR
+
+Stop both services with:
+ ./scripts/stop-stack.sh
+EOF
diff --git a/scripts/stop-stack.sh b/scripts/stop-stack.sh
new file mode 100755
index 0000000..606de01
--- /dev/null
+++ b/scripts/stop-stack.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+RUN_DIR="$ROOT_DIR/.run"
+
+BACKEND_PID_FILE="$RUN_DIR/backend.pid"
+FRONTEND_PID_FILE="$RUN_DIR/frontend.pid"
+
+stop_process() {
+ local name="$1"
+ local pid_file="$2"
+ if [[ ! -f "$pid_file" ]]; then
+ echo "$name not running"
+ return
+ fi
+
+ local pid
+ pid="$(cat "$pid_file")"
+
+ if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
+ kill "$pid" 2>/dev/null || true
+ for _ in {1..20}; do
+ if ! kill -0 "$pid" 2>/dev/null; then
+ break
+ fi
+ sleep 0.25
+ done
+ if kill -0 "$pid" 2>/dev/null; then
+ kill -9 "$pid" 2>/dev/null || true
+ fi
+ echo "Stopped $name (PID $pid)"
+ else
+ echo "$name pid file was stale"
+ fi
+
+ rm -f "$pid_file"
+}
+
+stop_process "frontend" "$FRONTEND_PID_FILE"
+stop_process "backend" "$BACKEND_PID_FILE"