services: redis: image: redis:8.8-alpine container_name: dyncoll_redis restart: always # Forma lista (NON stringa): evita lo shell-split di compose, così la password # può contenere caratteri speciali — es. '(' — senza rompere il parsing. command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--maxmemory", "256mb", "--maxmemory-policy", "allkeys-lru"] networks: - internal healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 5 volumes: - redis_data:/data labels: - "com.docker.compose.project=dyncoll-project" queue-worker: image: dyncoll:3.0 container_name: dyncoll_queue restart: always depends_on: db: condition: service_healthy redis: condition: service_healthy networks: - internal env_file: .env environment: APP_NAME: ${APP_NAME} APP_KEY: ${APP_KEY} APP_DEBUG: ${APP_DEBUG} APP_ENV: ${APP_ENV} DB_CONNECTION: mysql DB_HOST: db DB_PORT: ${DB_PORT} DB_DATABASE: ${DB_DATABASE} DB_USERNAME: ${DB_USERNAME} DB_PASSWORD: ${DB_PASSWORD} REDIS_HOST: redis REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_PORT: 6379 REDIS_CLUSTER: false QUEUE_CONNECTION: redis entrypoint: [] command: ["php", "artisan", "horizon"] scheduler: image: dyncoll:3.0 container_name: dyncoll_scheduler restart: always depends_on: db: condition: service_healthy redis: condition: service_healthy networks: - internal env_file: .env environment: APP_NAME: ${APP_NAME} APP_KEY: ${APP_KEY} APP_DEBUG: ${APP_DEBUG} APP_ENV: ${APP_ENV} DB_CONNECTION: mysql DB_HOST: db DB_PORT: ${DB_PORT} DB_DATABASE: ${DB_DATABASE} DB_USERNAME: ${DB_USERNAME} DB_PASSWORD: ${DB_PASSWORD} REDIS_HOST: redis REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_PORT: 6379 REDIS_CLUSTER: false QUEUE_CONNECTION: redis entrypoint: [] command: ["php", "artisan", "schedule:work"] db: image: mysql:8.4 container_name: dyncoll_db restart: always env_file: .env environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} MYSQL_DATABASE: ${DB_DATABASE} MYSQL_USER: ${DB_USERNAME} MYSQL_PASSWORD: ${DB_PASSWORD} ports: - "127.0.0.1:${DB_PORT}:3306" volumes: - mysql_data:/var/lib/mysql # Nessun import di dump qui: i dati v2 arrivano da migration Laravel + ETL # (`php artisan v1:import`), non da un dump SQL del DB di v1. # - ./db-init:/docker-entrypoint-initdb.d healthcheck: # Usa le env del container ($$ = $ letterale → espanso a runtime dalla shell, NON da compose) # e QUOTA la password: caratteri speciali (qui '{' e '(') non rompono lo shell, e la password # non finisce in chiaro nel `docker inspect`. test: ["CMD-SHELL", "mysqladmin ping -h localhost -P 3306 -u \"$$MYSQL_USER\" -p\"$$MYSQL_PASSWORD\""] interval: 10s timeout: 5s retries: 5 networks: - internal labels: - "io.portainer.accesscontrol.public=true" - "com.docker.compose.project=dyncoll-project" - "com.docker.compose.stack=dyncoll-project" backend: image: dyncoll:3.0 container_name: dyncoll-backend build: context: ./backend dockerfile: backend.Dockerfile args: APP_ENV: ${APP_ENV} depends_on: db: condition: service_healthy redis: condition: service_healthy ports: - ${APP_BACKEND_PORT}:8000 networks: - internal volumes: - ./backend:/var/www/html - ./backend/storage/app/public:/var/www/html/storage/app/public - ./.env:/var/www/html/.env environment: APP_NAME: ${APP_NAME} APP_KEY: ${APP_KEY} APP_DEBUG: ${APP_DEBUG} APP_ENV: ${APP_ENV} DB_CONNECTION: mysql DB_HOST: db DB_PORT: ${DB_PORT} DB_DATABASE: ${DB_DATABASE} DB_USERNAME: ${DB_USERNAME} DB_PASSWORD: ${DB_PASSWORD} MAIL_MAILER: ${MAIL_MAILER} MAIL_FROM_NAME: ${MAIL_FROM_NAME} MAIL_FROM_ADDRESS: "${MAIL_FROM_ADDRESS}" REDIS_HOST: redis REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_PORT: 6379 REDIS_CLUSTER: ${REDIS_CLUSTER} CACHE_STORE: redis SESSION_DRIVER: redis QUEUE_CONNECTION: redis labels: - "io.portainer.accesscontrol.public=true" - "com.docker.compose.project=dyncoll-project" - "com.docker.compose.stack=dyncoll-project" docs: image: squidfunk/mkdocs-material container_name: dyncoll_docs restart: always # L'immagine ha ENTRYPOINT ["mkdocs"]: serviamo il sito in ascolto su 8000. command: ["serve", "--dev-addr=0.0.0.0:8000"] volumes: # mkdocs si aspetta mkdocs.yml in /docs e i contenuti in /docs/docs - ./documentation:/docs:ro networks: - internal labels: - "com.docker.compose.project=dyncoll-project" frontend: image: dyncoll-frontend:3.0 container_name: dyncoll-frontend build: context: ./frontend dockerfile: frontend.Dockerfile target: production ports: - ${APP_FRONTEND_PORT}:80 depends_on: - backend volumes: # Il frontend "vede" gli upload di Laravel nella sua cartella storage - ./backend/storage/app/public:/usr/share/nginx/html/storage:ro networks: - internal labels: - "io.portainer.accesscontrol.public=true" - "com.docker.compose.project=dyncoll-project" - "com.docker.compose.stack=dyncoll-project" networks: internal: driver: bridge volumes: mysql_data: redis_data: