name: ${COMPOSE_PROJECT_NAME:-dtf-cloud} x-app: &app build: context: . dockerfile: local/Dockerfile environment: &environment APP_ENV: ${APP_ENV:-local} DATABASE_URL: postgresql://${APP_DB_USER:-dtf_app}:${APP_DB_PASSWORD:-local-app-database-only}@db:5432/${POSTGRES_DB:-dtf_local} S3_ENDPOINT: http://storage:9000 S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT:-http://localhost:9000} S3_BUCKET: ${S3_BUCKET:-dtf-local-artwork} AWS_ACCESS_KEY_ID: ${S3_APP_USER:-dtf_app} AWS_SECRET_ACCESS_KEY: ${S3_APP_PASSWORD:-local-app-storage-only} AWS_DEFAULT_REGION: us-east-1 OPERATOR_USER: ${OPERATOR_USER:-operator} OPERATOR_PASSWORD: ${OPERATOR_PASSWORD:-local-operator-only} PAYMENT_ADAPTER: ${PAYMENT_ADAPTER:-fake} FREIGHT_ADAPTER: ${FREIGHT_ADAPTER:-fake} TINY_ADAPTER: ${TINY_ADAPTER:-fake} WHATSAPP_ADAPTER: ${WHATSAPP_ADAPTER:-fake} STORAGE_ADAPTER: ${STORAGE_ADAPTER:-s3-local} MOCK_FREIGHT_CENTS: ${MOCK_FREIGHT_CENTS:-1500} MAX_UPLOAD_BYTES: ${MAX_UPLOAD_BYTES:-5368709120} UPLOAD_PART_BYTES: ${UPLOAD_PART_BYTES:-8388608} STORAGE_QUOTA_BYTES: ${STORAGE_QUOTA_BYTES:-53687091200} OWNER_UPLOAD_QUOTA_BYTES: ${OWNER_UPLOAD_QUOTA_BYTES:-10737418240} MAX_PENDING_UPLOADS: ${MAX_PENDING_UPLOADS:-10} SCAN_MAX_BYTES: ${SCAN_MAX_BYTES:-134217728} networks: [local] init: true security_opt: [no-new-privileges:true] cap_drop: [ALL] read_only: true tmpfs: [/tmp] pids_limit: 128 logging: driver: json-file options: {max-size: "10m", max-file: "3"} services: scanner: image: clamav/clamav@sha256:9cb27d7660bdf66e9878c832cb433dd8aa152cfbe16f3c2c0084c80b04ae22b4 entrypoint: [clamd, --foreground=true, --config-file=/etc/clamav/clamd.conf] volumes: [./local/clamd.conf:/etc/clamav/clamd.conf:ro] networks: [local] mem_limit: 3g pids_limit: 128 security_opt: [no-new-privileges:true] healthcheck: test: [CMD, clamdscan, --config-file=/etc/clamav/clamd.conf, --ping, "3"] start_period: 60s interval: 10s timeout: 5s retries: 30 db-init: build: context: . dockerfile: local/Dockerfile command: python -m local.bootstrap environment: DATABASE_ADMIN_URL: postgresql://${POSTGRES_USER:-dtf_local}:${POSTGRES_PASSWORD:-local-database-only}@db:5432/${POSTGRES_DB:-dtf_local} APP_DB_USER: ${APP_DB_USER:-dtf_app} APP_DB_PASSWORD: ${APP_DB_PASSWORD:-local-app-database-only} networks: [local] depends_on: db: {condition: service_healthy} storage-init: image: minio/minio:RELEASE.2025-04-22T22-12-26Z entrypoint: [/bin/sh, /init.sh] environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:-dtf_local} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-local-storage-only} S3_APP_USER: ${S3_APP_USER:-dtf_app} S3_APP_PASSWORD: ${S3_APP_PASSWORD:-local-app-storage-only} S3_BUCKET: ${S3_BUCKET:-dtf-local-artwork} volumes: - ./local/storage-init.sh:/init.sh:ro - ./local/storage-policy.json:/policy.json:ro - ./local/storage-lifecycle.json:/lifecycle.json:ro networks: [local] depends_on: storage: {condition: service_healthy} db: image: postgres:17-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-dtf_local} POSTGRES_USER: ${POSTGRES_USER:-dtf_local} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-local-database-only} volumes: [postgres-data:/var/lib/postgresql/data] networks: [local] healthcheck: test: [CMD-SHELL, 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"'] interval: 5s timeout: 3s retries: 30 storage: image: minio/minio:RELEASE.2025-04-22T22-12-26Z command: server /data --console-address :9001 environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:-dtf_local} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-local-storage-only} ports: ["127.0.0.1:9000:9000", "127.0.0.1:9001:9001"] volumes: [storage-data:/data] networks: [local, edge] healthcheck: test: [CMD, curl, -f, http://localhost:9000/minio/health/ready] interval: 5s timeout: 3s retries: 30 api: <<: *app command: uvicorn local.app:app --host 0.0.0.0 --port 8000 --no-access-log depends_on: db-init: {condition: service_completed_successfully} storage-init: {condition: service_completed_successfully} healthcheck: test: [CMD, python, -c, "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 5s timeout: 3s retries: 30 worker: <<: *app command: python -m local.worker depends_on: api: {condition: service_healthy} scanner: {condition: service_healthy} healthcheck: test: [CMD, python, -c, "import urllib.request; urllib.request.urlopen('http://localhost:8002/health')"] interval: 5s timeout: 3s retries: 12 site: build: context: . dockerfile: local/Dockerfile.web environment: S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT:-http://localhost:9000} ports: ["127.0.0.1:${SITE_PORT:-8080}:80", "127.0.0.1:${API_PORT:-8000}:81"] networks: [local, edge] depends_on: api: {condition: service_healthy} healthcheck: test: [CMD, wget, -q, -O, /dev/null, http://127.0.0.1/health] interval: 5s timeout: 3s retries: 12 kanban: build: context: . dockerfile: local/Dockerfile.web environment: WEB_INDEX: kanban.html S3_PUBLIC_ENDPOINT: ${S3_PUBLIC_ENDPOINT:-http://localhost:9000} ports: ["127.0.0.1:${KANBAN_PORT:-8081}:80"] networks: [local, edge] depends_on: api: {condition: service_healthy} healthcheck: test: [CMD, wget, -q, -O, /dev/null, http://127.0.0.1/health] interval: 5s timeout: 3s retries: 12 volumes: postgres-data: storage-data: networks: local: internal: true edge: