services: mysql: image: mysql:8.0 container_name: rezepte-mysql-prod restart: unless-stopped environment: MYSQL_DATABASE: rezepte MYSQL_USER: rezepte_user MYSQL_PASSWORD: ${MYSQL_PASSWORD:-change_this_password} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-change_this_root_password} volumes: - mysql_data:/var/lib/mysql # SQL files must be present on server - ./Rezepte.sql:/docker-entrypoint-initdb.d/01-rezepte.sql:ro - ./ingredients.sql:/docker-entrypoint-initdb.d/02-ingredients.sql:ro - ./Zubereitung.sql:/docker-entrypoint-initdb.d/03-zubereitung.sql:ro - ./rezepte_bilder.sql:/docker-entrypoint-initdb.d/04-bilder.sql:ro healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] timeout: 20s retries: 10 networks: - rezepte-network backend: # Use pre-built image from registry instead of building image: ${BACKEND_IMAGE:-ghcr.io/your-username/rezepte-backend:latest} container_name: rezepte-backend-prod restart: unless-stopped environment: - NODE_ENV=production - DATABASE_URL=mysql://rezepte_user:${MYSQL_PASSWORD:-change_this_password}@mysql:3306/rezepte - JWT_SECRET=${JWT_SECRET:-change_this_jwt_secret_min_32_characters} - CORS_ORIGIN=${CORS_ORIGIN:-http://localhost} - PORT=3001 volumes: - uploads_data:/app/uploads # Legacy uploads can be mounted if needed # - ./legacy-uploads:/app/legacy-uploads:ro depends_on: mysql: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"] interval: 30s timeout: 10s retries: 3 networks: - rezepte-network ports: - "3001:3001" frontend: # Use pre-built image from registry instead of building image: ${FRONTEND_IMAGE:-ghcr.io/your-username/rezepte-frontend:latest} container_name: rezepte-frontend-prod restart: unless-stopped ports: - "80:80" depends_on: - backend healthcheck: test: ["CMD", "curl", "-f", "http://localhost/"] interval: 30s timeout: 10s retries: 3 networks: - rezepte-network volumes: mysql_data: driver: local uploads_data: driver: local networks: rezepte-network: driver: bridge