services: # MySQL Database mysql: image: mysql:8.0 container_name: rezepte_mysql restart: always environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-change_this_root_password} MYSQL_DATABASE: ${MYSQL_DATABASE:-rezepte} MYSQL_USER: ${MYSQL_USER:-rezepte_user} MYSQL_PASSWORD: ${MYSQL_PASSWORD:-change_this_password} ports: - "${MYSQL_PORT:-3307}:3306" volumes: - mysql_data:/var/lib/mysql - ./sql-init:/docker-entrypoint-initdb.d networks: - rezepte_network # phpMyAdmin phpmyadmin: image: phpmyadmin:latest container_name: rezepte_phpmyadmin restart: always profiles: - admin ports: - "${PHPMYADMIN_PORT:-8083}:80" environment: PMA_HOST: mysql PMA_USER: ${MYSQL_USER:-rezepte_user} PMA_PASSWORD: ${MYSQL_PASSWORD:-change_this_password} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-change_this_root_password} depends_on: - mysql networks: - rezepte_network # Node.js Backend API backend: build: context: ./backend dockerfile: Dockerfile container_name: rezepte-backend environment: NODE_ENV: ${NODE_ENV:-production} PORT: ${BACKEND_PORT:-3001} # Explicit DB URL (override to ensure service hostname used inside container) DATABASE_URL: mysql://${MYSQL_USER:-rezepte_user}:${MYSQL_PASSWORD:-dev_password_123}@mysql:3306/${MYSQL_DATABASE:-rezepte} JWT_SECRET: ${JWT_SECRET:-please_change_to_secure_32_char_min} UPLOAD_PATH: ${UPLOAD_PATH:-/app/uploads} MAX_FILE_SIZE: ${MAX_FILE_SIZE:-5242880} CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000} ports: - "${BACKEND_PORT:-3001}:${BACKEND_PORT:-3001}" volumes: - uploads_data:/app/uploads - ./uploads:/app/legacy-uploads:ro networks: - rezepte_network depends_on: - mysql restart: unless-stopped # Frontend (React + Vite build served by nginx) frontend: build: context: ./frontend dockerfile: Dockerfile args: VITE_API_URL: http://localhost:3001/api container_name: rezepte-frontend ports: - "${FRONTEND_PORT:-3000}:80" networks: - rezepte_network depends_on: - backend restart: unless-stopped volumes: mysql_data: uploads_data: networks: rezepte_network: driver: bridge