From e55902d813d0381fdadbd3560e4ea1ad77ba1633 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Fri, 6 Feb 2026 23:45:29 +0000 Subject: [PATCH] Add frontend and Caddy to Docker Compose dev environment Containerize the frontend dev server (Vite) and add a Caddy reverse proxy for HTTPS termination, replacing the manual local setup. The Caddy config proxies /api/* to the backend and everything else to the frontend dev server. Also simplify start.sh: remove --local Poetry mode, extract get_compose_cmd helper, and document new services and DEV_HOST env var. --- crawler/docker-compose.yml | 35 ++++++++- crawler/frontend/Caddyfile.dev | 11 +++ crawler/start.sh | 135 +++++++++++---------------------- 3 files changed, 89 insertions(+), 92 deletions(-) create mode 100644 crawler/frontend/Caddyfile.dev diff --git a/crawler/docker-compose.yml b/crawler/docker-compose.yml index 5756abe..e0f4eb0 100644 --- a/crawler/docker-compose.yml +++ b/crawler/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.8" - services: redis: image: redis:8 @@ -111,6 +109,37 @@ services: networks: - rec-network + frontend: + image: node:24-alpine + container_name: rec-frontend + working_dir: /app + ports: + - "5173:5173" + volumes: + - ./frontend:/app + - frontend_node_modules:/app/node_modules + environment: + - DEV_HOST=${DEV_HOST:-localhost} + command: sh -c "npm ci && npm run dev -- --host" + networks: + - rec-network + + caddy: + image: caddy:alpine + container_name: rec-caddy + ports: + - "443:443" + volumes: + - ./frontend/Caddyfile.dev:/etc/caddy/Caddyfile + - caddy_data:/data + environment: + - DEV_HOST=${DEV_HOST:-localhost} + depends_on: + - frontend + - app + networks: + - rec-network + networks: rec-network: driver: bridge @@ -119,3 +148,5 @@ volumes: redis_data: mysql_data: app_venv: + frontend_node_modules: + caddy_data: diff --git a/crawler/frontend/Caddyfile.dev b/crawler/frontend/Caddyfile.dev new file mode 100644 index 0000000..a6262bf --- /dev/null +++ b/crawler/frontend/Caddyfile.dev @@ -0,0 +1,11 @@ +{$DEV_HOST:localhost}:443 { + tls internal + + handle /api/* { + reverse_proxy app:5001 + } + + handle { + reverse_proxy frontend:5173 + } +} diff --git a/crawler/start.sh b/crawler/start.sh index 965e330..3e7d8a0 100755 --- a/crawler/start.sh +++ b/crawler/start.sh @@ -2,9 +2,13 @@ set -eu # Real Estate Crawler - Development Server +# Starts all backend services + frontend + Caddy HTTPS proxy via Docker Compose. +# # Usage: -# ./start.sh - Start with Docker (recommended) -# ./start.sh --local - Start locally (requires Poetry and dependencies) +# ./start.sh - Start all services (backend + frontend) +# ./start.sh --build - Rebuild images before starting +# ./start.sh --down - Stop and remove all containers +# ./start.sh --logs - Follow logs from all services # ./start.sh --help - Show help show_help() { @@ -14,16 +18,40 @@ show_help() { echo "" echo "Options:" echo " (default) Start all services with Docker Compose" - echo " --local Run locally with Poetry (requires local deps)" echo " --build Rebuild Docker images before starting" echo " --down Stop and remove all containers" echo " --logs Follow logs from all services" echo " --help Show this help message" echo "" + echo "Services started:" + echo " redis Redis broker + cache (port 6379)" + echo " mysql MySQL database (port 3306)" + echo " app FastAPI backend (hot-reload) (port 5001)" + echo " celery Celery background worker" + echo " celery-beat Celery periodic scheduler" + echo " frontend Vite dev server (hot-reload) (port 5173)" + echo " caddy HTTPS reverse proxy (port 443)" + echo "" + echo "Environment variables:" + echo " DEV_HOST Hostname for HTTPS access (default: localhost)" + echo " Set this to your dev machine's hostname for OIDC auth." + echo "" echo "Examples:" - echo " ./start.sh # Start with Docker" - echo " ./start.sh --build # Rebuild and start" - echo " ./start.sh --local # Run locally with Poetry" + echo " ./start.sh # Start everything" + echo " ./start.sh --build # Rebuild and start" + echo " DEV_HOST=devvm.local ./start.sh # Start with custom hostname" +} + +get_compose_cmd() { + if command -v docker &> /dev/null; then + echo "docker compose" + elif command -v podman-compose &> /dev/null; then + echo "podman-compose" + else + echo "❌ Error: Neither docker nor podman-compose found." >&2 + echo " Install Docker: https://docs.docker.com/get-docker/" >&2 + exit 1 + fi } start_docker() { @@ -32,96 +60,26 @@ start_docker() { build_flag="--build" fi - echo "🐳 Starting services with Docker Compose..." + echo "Starting all services with Docker Compose..." echo "" - # Check if docker/podman is available - if command -v docker &> /dev/null; then - COMPOSE_CMD="docker compose" - elif command -v podman-compose &> /dev/null; then - COMPOSE_CMD="podman-compose" - else - echo "❌ Error: Neither docker nor podman-compose found." - echo " Install Docker: https://docs.docker.com/get-docker/" - echo " Or run locally: ./start.sh --local" - exit 1 - fi + local compose_cmd + compose_cmd=$(get_compose_cmd) - $COMPOSE_CMD up $build_flag + $compose_cmd up $build_flag } stop_docker() { - echo "🛑 Stopping all containers..." - if command -v docker &> /dev/null; then - docker compose down - elif command -v podman-compose &> /dev/null; then - podman-compose down - fi + echo "Stopping all containers..." + local compose_cmd + compose_cmd=$(get_compose_cmd) + $compose_cmd down } show_logs() { - if command -v docker &> /dev/null; then - docker compose logs -f - elif command -v podman-compose &> /dev/null; then - podman-compose logs -f - fi -} - -start_local() { - echo "🛠️ Starting locally with Poetry..." - echo "" - - # Check Poetry is available - if ! command -v poetry &> /dev/null; then - echo "❌ Error: Poetry not found." - echo " Install: curl -sSL https://install.python-poetry.org | python3 -" - echo " Or use Docker: ./start.sh" - exit 1 - fi - - # Source .env if it exists - if [[ -f .env ]]; then - set -a - source .env - set +a - fi - - ENV_MODE=${ENV:-"dev"} - - # Ensure Redis is running - if ! nc -z localhost 6379 2>/dev/null; then - echo "📦 Starting Redis container..." - docker run -d --rm --name rec-redis-local -p 6379:6379 redis:latest || true - sleep 2 - fi - - echo "✅ Redis OK" - - # Test celery connection - poetry run python celery_app.py - - # Start Celery worker in background - echo "🔧 Starting Celery worker..." - if [[ "$ENV_MODE" == "dev" ]]; then - poetry run celery -A celery_app worker --loglevel=info & - else - poetry run alembic upgrade head - poetry run celery -A celery_app worker --beat --loglevel=info & - fi - CELERY_PID=$! - - cleanup() { - echo "" - echo "🛑 Stopping Celery worker (PID: $CELERY_PID)..." - kill "$CELERY_PID" 2>/dev/null || true - wait "$CELERY_PID" 2>/dev/null || true - } - trap cleanup EXIT SIGINT SIGTERM - - # Start uvicorn - echo "🚀 Starting API server on http://localhost:5001" - echo "" - poetry run uvicorn api.app:app --host 0.0.0.0 --port 5001 --reload + local compose_cmd + compose_cmd=$(get_compose_cmd) + $compose_cmd logs -f } # Parse arguments @@ -129,9 +87,6 @@ case "${1:-}" in --help|-h) show_help ;; - --local) - start_local - ;; --down) stop_docker ;;