- Add dev-native.sh script for fast local development (10s vs 3-5min Docker builds) - Fix cookie security flags to respect APP_ENV (dev uses Secure=false, prod uses Secure=true) - Pin backend to Python 3.13 (3.14 not yet supported by pydantic-core) - Add comprehensive NATIVE_DEV_SETUP.md documentation - Update CLAUDE.md to recommend native dev workflow - Add .pids/ and .logs/ to .gitignore for native dev artifacts Benefits: - Instant startup (5-10 seconds) - Hot-reload enabled (backend + frontend) - Native debugging support - No Docker rebuilds needed - Discord OAuth works on localhost with proper cookie settings
339 lines
8.4 KiB
Bash
Executable File
339 lines
8.4 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Paper Dynasty Game Engine - Native Development Mode
|
|
#
|
|
# Fast development workflow - no Docker rebuilds, instant restarts, hot-reload
|
|
#
|
|
# Usage:
|
|
# ./dev-native.sh start Start all services natively
|
|
# ./dev-native.sh stop Stop all services
|
|
# ./dev-native.sh logs Show logs from all services
|
|
# ./dev-native.sh restart Restart all services
|
|
#
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
print_status() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
print_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
print_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
PID_DIR="$SCRIPT_DIR/.pids"
|
|
LOG_DIR="$SCRIPT_DIR/.logs"
|
|
|
|
# Create directories
|
|
mkdir -p "$PID_DIR" "$LOG_DIR"
|
|
|
|
# Check dependencies
|
|
check_dependencies() {
|
|
local missing=0
|
|
|
|
if ! command -v uv &> /dev/null; then
|
|
print_error "uv not found - install from https://docs.astral.sh/uv/"
|
|
missing=1
|
|
fi
|
|
|
|
if ! command -v node &> /dev/null; then
|
|
print_error "node not found - install Node.js 22+"
|
|
missing=1
|
|
fi
|
|
|
|
if ! command -v docker &> /dev/null; then
|
|
print_error "docker not found - needed for Redis"
|
|
missing=1
|
|
fi
|
|
|
|
if [[ $missing -eq 1 ]]; then
|
|
exit 1
|
|
fi
|
|
|
|
print_success "All dependencies found"
|
|
}
|
|
|
|
# Setup environment files
|
|
setup_env() {
|
|
print_status "Setting up development environment files..."
|
|
|
|
# Backend
|
|
if [[ ! -f "backend/.env" ]] || ! grep -q "localhost:8000" "backend/.env" 2>/dev/null; then
|
|
print_status "Copying backend/.env.dev -> backend/.env"
|
|
cp backend/.env.dev backend/.env
|
|
fi
|
|
|
|
# Frontend
|
|
if [[ ! -f "frontend-sba/.env" ]] || ! grep -q "localhost:8000" "frontend-sba/.env" 2>/dev/null; then
|
|
print_status "Copying frontend-sba/.env.dev -> frontend-sba/.env"
|
|
cp frontend-sba/.env.dev frontend-sba/.env
|
|
fi
|
|
|
|
print_success "Environment files ready"
|
|
}
|
|
|
|
# Start Redis (Docker)
|
|
start_redis() {
|
|
print_status "Starting Redis (Docker)..."
|
|
|
|
if docker ps | grep -q "strat-gameplay-webapp-redis"; then
|
|
print_warning "Redis already running"
|
|
return 0
|
|
fi
|
|
|
|
docker compose up -d redis
|
|
|
|
# Wait for Redis to be healthy
|
|
local max_wait=30
|
|
local waited=0
|
|
|
|
while [[ $waited -lt $max_wait ]]; do
|
|
if docker compose ps redis 2>/dev/null | grep -q "healthy"; then
|
|
print_success "Redis is healthy"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
|
|
print_error "Redis failed to start"
|
|
return 1
|
|
}
|
|
|
|
# Start Backend (native Python with uv)
|
|
start_backend() {
|
|
print_status "Starting backend (native uvicorn)..."
|
|
|
|
cd backend
|
|
|
|
# Check if backend is already running
|
|
if [[ -f "$PID_DIR/backend.pid" ]]; then
|
|
local pid=$(cat "$PID_DIR/backend.pid")
|
|
if ps -p "$pid" > /dev/null 2>&1; then
|
|
print_warning "Backend already running (PID: $pid)"
|
|
cd ..
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Start backend in background
|
|
nohup uv run python -m uvicorn app.main:socket_app \
|
|
--host 0.0.0.0 \
|
|
--port 8000 \
|
|
--reload \
|
|
> "$LOG_DIR/backend.log" 2>&1 &
|
|
|
|
local pid=$!
|
|
echo $pid > "$PID_DIR/backend.pid"
|
|
|
|
cd ..
|
|
|
|
# Wait for backend to respond
|
|
local max_wait=10
|
|
local waited=0
|
|
|
|
while [[ $waited -lt $max_wait ]]; do
|
|
if curl -sf http://localhost:8000/api/health > /dev/null 2>&1; then
|
|
print_success "Backend started (PID: $pid)"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
|
|
print_error "Backend failed to start - check logs: tail -f $LOG_DIR/backend.log"
|
|
return 1
|
|
}
|
|
|
|
# Start Frontend (native npm)
|
|
start_frontend() {
|
|
print_status "Starting frontend (native nuxt dev)..."
|
|
|
|
cd frontend-sba
|
|
|
|
# Check if frontend is already running
|
|
if [[ -f "$PID_DIR/frontend.pid" ]]; then
|
|
local pid=$(cat "$PID_DIR/frontend.pid")
|
|
if ps -p "$pid" > /dev/null 2>&1; then
|
|
print_warning "Frontend already running (PID: $pid)"
|
|
cd ..
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# Ensure node_modules exists
|
|
if [[ ! -d "node_modules" ]]; then
|
|
print_status "Installing frontend dependencies..."
|
|
npm ci
|
|
fi
|
|
|
|
# Start frontend in background
|
|
nohup npm run dev > "$LOG_DIR/frontend.log" 2>&1 &
|
|
|
|
local pid=$!
|
|
echo $pid > "$PID_DIR/frontend.pid"
|
|
|
|
cd ..
|
|
|
|
# Wait for frontend to respond
|
|
local max_wait=30
|
|
local waited=0
|
|
|
|
while [[ $waited -lt $max_wait ]]; do
|
|
if curl -sf http://localhost:3000 > /dev/null 2>&1; then
|
|
print_success "Frontend started (PID: $pid)"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
|
|
print_error "Frontend failed to start - check logs: tail -f $LOG_DIR/frontend.log"
|
|
return 1
|
|
}
|
|
|
|
# Stop all services
|
|
stop_services() {
|
|
print_status "Stopping all services..."
|
|
|
|
# Stop backend
|
|
if [[ -f "$PID_DIR/backend.pid" ]]; then
|
|
local pid=$(cat "$PID_DIR/backend.pid")
|
|
if ps -p "$pid" > /dev/null 2>&1; then
|
|
print_status "Stopping backend (PID: $pid)..."
|
|
kill $pid
|
|
rm "$PID_DIR/backend.pid"
|
|
fi
|
|
fi
|
|
|
|
# Stop frontend
|
|
if [[ -f "$PID_DIR/frontend.pid" ]]; then
|
|
local pid=$(cat "$PID_DIR/frontend.pid")
|
|
if ps -p "$pid" > /dev/null 2>&1; then
|
|
print_status "Stopping frontend (PID: $pid)..."
|
|
kill $pid
|
|
rm "$PID_DIR/frontend.pid"
|
|
fi
|
|
fi
|
|
|
|
# Stop Redis
|
|
print_status "Stopping Redis..."
|
|
docker compose stop redis
|
|
|
|
print_success "All services stopped"
|
|
}
|
|
|
|
# Show logs
|
|
show_logs() {
|
|
print_status "Showing logs (Ctrl+C to exit)..."
|
|
echo ""
|
|
|
|
# Use multitail if available, otherwise tail
|
|
if command -v multitail &> /dev/null; then
|
|
multitail -s 2 \
|
|
-l "tail -f $LOG_DIR/backend.log" \
|
|
-l "tail -f $LOG_DIR/frontend.log"
|
|
else
|
|
print_warning "Install 'multitail' for better log viewing"
|
|
tail -f "$LOG_DIR/backend.log" "$LOG_DIR/frontend.log"
|
|
fi
|
|
}
|
|
|
|
# Start all services
|
|
start_all() {
|
|
print_status "Starting native development environment..."
|
|
echo ""
|
|
|
|
check_dependencies
|
|
setup_env
|
|
|
|
start_redis || exit 1
|
|
start_backend || exit 1
|
|
start_frontend || exit 1
|
|
|
|
echo ""
|
|
print_success "Development environment ready!"
|
|
echo ""
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo -e "${GREEN} Native Development Mode${NC}"
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo ""
|
|
echo " Backend API: http://localhost:8000"
|
|
echo " API Docs: http://localhost:8000/docs"
|
|
echo " Frontend: http://localhost:3000"
|
|
echo ""
|
|
echo " Features:"
|
|
echo " ✓ Hot-reload enabled (backend + frontend)"
|
|
echo " ✓ No Docker rebuilds"
|
|
echo " ✓ Instant restarts"
|
|
echo ""
|
|
echo " Logs:"
|
|
echo " Backend: tail -f $LOG_DIR/backend.log"
|
|
echo " Frontend: tail -f $LOG_DIR/frontend.log"
|
|
echo " All: ./dev-native.sh logs"
|
|
echo ""
|
|
echo " Commands:"
|
|
echo " ./dev-native.sh logs View logs"
|
|
echo " ./dev-native.sh stop Stop services"
|
|
echo " ./dev-native.sh restart Restart services"
|
|
echo ""
|
|
}
|
|
|
|
# Restart all services
|
|
restart_all() {
|
|
stop_services
|
|
sleep 2
|
|
start_all
|
|
}
|
|
|
|
# Show usage
|
|
show_usage() {
|
|
echo "Paper Dynasty - Native Development Mode"
|
|
echo ""
|
|
echo "Usage: ./dev-native.sh <command>"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " start Start all services natively (instant, hot-reload)"
|
|
echo " stop Stop all services"
|
|
echo " logs Tail logs from all services"
|
|
echo " restart Restart all services"
|
|
echo ""
|
|
echo "Benefits:"
|
|
echo " • No Docker rebuilds (saves minutes)"
|
|
echo " • Instant startup"
|
|
echo " • Hot-reload on file changes (backend + frontend)"
|
|
echo " • Native debugging support"
|
|
echo ""
|
|
echo "Requirements:"
|
|
echo " • uv (Python package manager)"
|
|
echo " • Node.js 22+"
|
|
echo " • Docker (for Redis only)"
|
|
echo ""
|
|
}
|
|
|
|
# Main
|
|
case "${1:-}" in
|
|
start)
|
|
start_all
|
|
;;
|
|
stop)
|
|
stop_services
|
|
;;
|
|
logs)
|
|
show_logs
|
|
;;
|
|
restart)
|
|
restart_all
|
|
;;
|
|
*)
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|