From dcb417cbf251a427861b2cbeb50e7f6a9f06f212 Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Tue, 19 May 2026 00:38:46 -0700 Subject: unified start/stop script and included systemd files --- README.md | 47 ++++++++++++++++++++++++----- scripts/start-stack.sh | 80 -------------------------------------------------- scripts/stop-stack.sh | 42 -------------------------- 3 files changed, 39 insertions(+), 130 deletions(-) delete mode 100755 scripts/start-stack.sh delete mode 100755 scripts/stop-stack.sh diff --git a/README.md b/README.md index 9f1de30..d41c8d6 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ The implementation copies and adapts finance logic from Prism v1 into `backend/` - `components/PriceChart.tsx` Plotly price chart - `lib/api.ts` typed REST client - `types/api.ts` shared frontend response types +- `scripts/stack.sh` unified start/stop/restart/status script +- `systemd/` systemd unit files for running as a system service - `.env.example` optional environment variables - `pytest.ini` backend pytest import path config @@ -95,23 +97,52 @@ The UI stores the selected ticker in the URL, for example `/?ticker=AAPL`. ## Quick Start -Start the whole local stack: +`scripts/stack.sh` manages both services as a local development stack: ```bash -./scripts/start-stack.sh +./scripts/stack.sh start # start backend + frontend in background +./scripts/stack.sh stop # stop both +./scripts/stack.sh restart # stop then start +./scripts/stack.sh status # show running PIDs and URLs ``` -Stop both services: +Notes: + +- expects `backend/.venv` and `frontend/node_modules` to already exist +- default ports are backend `8001` and frontend `3001` +- logs are written to `.run/logs/` +- override hosts/ports via env vars: `BACKEND_HOST`, `BACKEND_PORT`, `FRONTEND_HOST`, `FRONTEND_PORT` + +## Running as a systemd Service + +Unit files live in `systemd/`. Install them for the current user: ```bash -./scripts/stop-stack.sh +# Copy units +cp systemd/prismv2-backend.service ~/.config/systemd/user/ +cp systemd/prismv2-frontend.service ~/.config/systemd/user/ +cp systemd/prismv2.target ~/.config/systemd/user/ + +systemctl --user daemon-reload + +# Start both services via the target +systemctl --user enable --now prismv2.target + +# Control individual services +systemctl --user status prismv2-backend.service +systemctl --user restart prismv2-frontend.service +systemctl --user stop prismv2.target + +# View logs +journalctl --user -u prismv2-backend.service -f +journalctl --user -u prismv2-frontend.service -f ``` -Notes: +To start automatically on login, enable lingering once: -- the scripts expect `backend/.venv` and `frontend/node_modules` to already exist -- default ports are backend `8001` and frontend `3001` -- logs are written to `.run/logs/` +```bash +loginctl enable-linger $USER +``` ## Verification diff --git a/scripts/start-stack.sh b/scripts/start-stack.sh deleted file mode 100755 index 6324967..0000000 --- a/scripts/start-stack.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/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 </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" -- cgit v1.3-2-g0d8e