# --------------------------------------------------------------------------- # Toolvana production topology. # # browser -> nginx -> php-fpm (web) stateless, page-cached # -> api (php-fpm) /api/v1 traffic isolation # # queue: postgres/mysql durable jobs; workers scale horizontally: # worker-1 .. worker-N (spark queue:work --loop) # scheduler (media:cleanup every 5 min + stale reaper) # # Replace the DB image or add Redis freely — the app only needs a # PDO-compatible database and the file cache driver works everywhere. # --------------------------------------------------------------------------- x-app-common: &app-common build: context: . dockerfile: docker/Dockerfile restart: unless-stopped env_file: .env.docker volumes: - media-storage:/app/writable/media - incoming-storage:/app/writable/incoming - session-storage:/app/writable/session - og-cache:/app/writable/og services: nginx: image: nginx:1.27-alpine restart: unless-stopped ports: - "80:80" - "443:443" # mount certs + full server block for TLS in production volumes: - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro - ./public:/app/public:ro - ./writable/og:/app/writable/og:ro depends_on: - web - api web: <<: *app-common environment: TV_ROLE: web # Dedicated pool for developer API + processing endpoints so large # conversions never starve page rendering. api: <<: *app-common environment: TV_ROLE: api worker-1: <<: *app-common command: ["php", "spark", "queue:work", "--loop", "--sleep", "2"] deploy: replicas: 3 # worker-1..worker-N: scale to taste scheduler: <<: *app-common command: > bash -c "while true; do php spark media:cleanup >> writable/logs/scheduler.log 2>&1; sleep 300; done" db: image: mariadb:11 restart: unless-stopped environment: MARIADB_DATABASE: toolvana MARIADB_USER: toolvana MARIADB_PASSWORD: ${DB_PASSWORD:-toolvana} MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root-secret} volumes: - db-data:/var/lib/mysql healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 10s retries: 5 volumes: db-data: media-storage: incoming-storage: session-storage: og-cache: