services: backend: build: context: ./backend dockerfile: Dockerfile container_name: picpeak-backend restart: unless-stopped environment: - NODE_ENV=${NODE_ENV:-production} - PORT=3001 - JWT_SECRET=${JWT_SECRET} - ADMIN_USERNAME=${ADMIN_USERNAME:-admin} - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com} - ADMIN_PASSWORD=${ADMIN_PASSWORD} - DATABASE_CLIENT=pg - DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME} - DB_TYPE=postgresql - DB_HOST=postgres - DB_PORT=5432 - DB_USER=${DB_USER} - DB_PASSWORD=${DB_PASSWORD} - DB_NAME=${DB_NAME} - EXTERNAL_MEDIA_ROOT=${EXTERNAL_MEDIA_ROOT:-/app/storage/external-media} - SMTP_HOST=${SMTP_HOST} - SMTP_PORT=${SMTP_PORT} - SMTP_SECURE=${SMTP_SECURE:-false} - SMTP_USER=${SMTP_USER} - SMTP_PASS=${SMTP_PASS} - EMAIL_FROM=${EMAIL_FROM:-noreply@picpeak.local} - FRONTEND_URL=${FRONTEND_URL:-http://localhost:3000} - ADMIN_URL=${ADMIN_URL:-http://localhost:3001} - TZ=${TZ:-UTC} - STORAGE_PATH=/app/storage # Optional: run container as matching host user to avoid bind mount permission issues - PUID=${PUID:-1001} - PGID=${PGID:-1001} # Use host-matching user ID/GID so bind-mounted folders are writable user: "${PUID:-1001}:${PGID:-1001}" volumes: - ./events:/app/events - ./data:/app/data - ./logs:/app/logs - ./backup:/backup - ./storage:/app/storage ports: - "${BACKEND_PORT:-3001}:3001" depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:3001/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - picpeak-network postgres: image: postgres:15-alpine container_name: picpeak-postgres restart: unless-stopped environment: - POSTGRES_USER=${DB_USER} - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=${DB_NAME} - PGDATA=/var/lib/postgresql/data/pgdata - TZ=${TZ:-UTC} volumes: - postgres-data:/var/lib/postgresql/data ports: - "${DB_PORT:-5432}:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"] interval: 10s timeout: 5s retries: 5 start_period: 20s networks: - picpeak-network redis: image: redis:7-alpine container_name: picpeak-redis restart: unless-stopped command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-picpeak_redis_pass} volumes: - redis-data:/data ports: - "${REDIS_PORT:-6379}:6379" healthcheck: test: ["CMD", "redis-cli", "--raw", "incr", "ping"] interval: 10s timeout: 5s retries: 3 networks: - picpeak-network frontend: build: context: ./frontend dockerfile: Dockerfile args: - VITE_API_URL=${VITE_API_URL:-http://localhost:3001/api} - VITE_UMAMI_URL=${VITE_UMAMI_URL:-} - VITE_UMAMI_WEBSITE_ID=${VITE_UMAMI_WEBSITE_ID:-} - VITE_UMAMI_SHARE_URL=${VITE_UMAMI_SHARE_URL:-} container_name: picpeak-frontend restart: unless-stopped environment: - NODE_ENV=${NODE_ENV:-production} ports: - "${FRONTEND_PORT:-3000}:80" depends_on: - backend healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1/health"] interval: 30s timeout: 10s retries: 3 networks: - picpeak-network volumes: postgres-data: driver: local redis-data: driver: local networks: picpeak-network: driver: bridge