services: api: build: context: ./backend dockerfile: Dockerfile container_name: procurement-api depends_on: minio-init: condition: service_completed_successfully required: true postgres: condition: service_healthy required: true environment: PROCUREMENT_CASDOOR_ADMIN_PASSWORD: "123" PROCUREMENT_CASDOOR_ADMIN_USER: admin PROCUREMENT_CASDOOR_APP_NAME: inventory-app PROCUREMENT_CASDOOR_AUDIENCE: inventory-app-client PROCUREMENT_CASDOOR_CLIENT_ID: inventory-app-client PROCUREMENT_CASDOOR_CLIENT_SECRET: inventory-app-secret-2026 PROCUREMENT_CASDOOR_ENDPOINT: http://casdoor:8000 PROCUREMENT_CASDOOR_ISSUER: https://${AUTH_HOST} PROCUREMENT_CASDOOR_ORGANIZATION: inventory PROCUREMENT_DATABASE_URL: postgresql+asyncpg://postgres:postgres@postgres:5432/procurement PROCUREMENT_MINIO_ACCESS_KEY: minioadmin PROCUREMENT_MINIO_BUCKET: procurement-files PROCUREMENT_MINIO_ENDPOINT: minio:9000 PROCUREMENT_MINIO_SECRET_KEY: minioadmin PROCUREMENT_MINIO_SECURE: "false" labels: traefik.enable: "true" traefik.http.routers.api-redir.entrypoints: web traefik.http.routers.api-redir.middlewares: redirect-https@file traefik.http.routers.api-redir.rule: Host(`${API_HOST}`) traefik.http.routers.api.entrypoints: websecure traefik.http.routers.api.rule: Host(`${API_HOST}`) traefik.http.routers.api.tls: "true" traefik.http.routers.api.tls.certresolver: letsencrypt traefik.http.services.api.loadbalancer.server.port: "8000" networks: default: null traefik_network: null ports: - "8000" restart: unless-stopped casdoor: container_name: procurement-casdoor depends_on: postgres: condition: service_healthy required: true environment: RUNNING_IN_DOCKER: "true" dataSourceName: user=casdoor password=casdoor host=postgres port=5432 sslmode=disable dbname=casdoor dbName: casdoor driverName: postgres origin: https://${AUTH_HOST} image: casbin/casdoor:latest labels: traefik.enable: "true" traefik.http.routers.casdoor-redir.entrypoints: web traefik.http.routers.casdoor-redir.middlewares: redirect-https@file traefik.http.routers.casdoor-redir.rule: Host(`${AUTH_HOST}`) traefik.http.routers.casdoor.entrypoints: websecure traefik.http.routers.casdoor.rule: Host(`${AUTH_HOST}`) traefik.http.routers.casdoor.tls: "true" traefik.http.routers.casdoor.tls.certresolver: letsencrypt traefik.http.services.casdoor.loadbalancer.server.port: "8000" networks: default: null traefik_network: null ports: - "8080:8000" restart: unless-stopped frontend: build: context: ./frontend dockerfile: Dockerfile args: DEV_LOGIN_ENABLED: "true" container_name: procurement-frontend depends_on: api: condition: service_started required: true labels: traefik.enable: "true" traefik.http.routers.frontend-redir.entrypoints: web traefik.http.routers.frontend-redir.middlewares: redirect-https@file traefik.http.routers.frontend-redir.rule: Host(`${APP_HOST}`) traefik.http.routers.frontend.entrypoints: websecure traefik.http.routers.frontend.rule: Host(`${APP_HOST}`) traefik.http.routers.frontend.tls: "true" traefik.http.routers.frontend.tls.certresolver: letsencrypt traefik.http.services.frontend.loadbalancer.server.port: "80" networks: default: null traefik_network: null restart: unless-stopped minio: command: - server - /data - --console-address - :9001 container_name: procurement-minio environment: MINIO_ROOT_PASSWORD: minioadmin MINIO_ROOT_USER: minioadmin image: minio/minio:latest labels: traefik.enable: "true" traefik.http.routers.minio-api-redir.entrypoints: web traefik.http.routers.minio-api-redir.middlewares: redirect-https@file traefik.http.routers.minio-api-redir.rule: Host(`${S3_HOST}`) traefik.http.routers.minio-api.entrypoints: websecure traefik.http.routers.minio-api.rule: Host(`${S3_HOST}`) traefik.http.routers.minio-api.service: minio-api-svc traefik.http.routers.minio-api.tls: "true" traefik.http.routers.minio-api.tls.certresolver: letsencrypt traefik.http.routers.minio-console-redir.entrypoints: web traefik.http.routers.minio-console-redir.middlewares: redirect-https@file traefik.http.routers.minio-console-redir.rule: Host(`${STORAGE_HOST}`) traefik.http.routers.minio-console.entrypoints: websecure traefik.http.routers.minio-console.rule: Host(`${STORAGE_HOST}`) traefik.http.routers.minio-console.service: minio-console-svc traefik.http.routers.minio-console.tls: "true" traefik.http.routers.minio-console.tls.certresolver: letsencrypt traefik.http.services.minio-api-svc.loadbalancer.server.port: "9000" traefik.http.services.minio-console-svc.loadbalancer.server.port: "9001" networks: default: null traefik_network: null ports: - "9000" - "9001" restart: unless-stopped volumes: - minio_data:/data minio-init: container_name: procurement-minio-init depends_on: minio: condition: service_started required: true entrypoint: - /bin/sh - -c - " until mc alias set local http://$${MINIO_ENDPOINT} $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}; do\n echo 'waiting for minio server...'; sleep 2;\ndone; mc mb --ignore-existing local/$${MINIO_BUCKET}; echo bucket $${MINIO_BUCKET} ready; " environment: MINIO_BUCKET: procurement-files MINIO_ENDPOINT: minio:9000 MINIO_ROOT_PASSWORD: minioadmin MINIO_ROOT_USER: minioadmin image: minio/mc:latest networks: default: null restart: 'no' postgres: container_name: procurement-postgres environment: POSTGRES_DB: procurement POSTGRES_PASSWORD: postgres POSTGRES_USER: postgres healthcheck: test: - CMD-SHELL - pg_isready -U postgres -d procurement timeout: 5s interval: 5s retries: 10 image: postgres:18 networks: default: null ports: - "5433:5432" restart: unless-stopped volumes: - postgres_data:/var/lib/postgresql - ./sql/migration.sql:/docker-entrypoint-initdb.d/01-migration.sql:ro - ./sql/02-casdoor-db.sql:/docker-entrypoint-initdb.d/02-casdoor-db.sql:ro traefik: command: - --providers.docker=true - --providers.docker.exposedbydefault=false - --providers.docker.network=traefik_network - --providers.file.filename=/etc/traefik/dynamic.yml - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json - --certificatesresolvers.letsencrypt.acme.httpchallenge=true - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web - --log.level=INFO container_name: procurement-traefik environment: TRAEFIK_ACME_EMAIL: ${TRAEFIK_ACME_EMAIL} image: traefik:v3.6 networks: traefik_network: null ports: - "80" - "443" restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock - ./infra/traefik-dynamic.yml:/etc/traefik/dynamic.yml:ro - traefik_certs:/certs networks: default: name: v15_default traefik_network: name: traefik_network driver: bridge volumes: minio_data: name: v15_minio_data postgres_data: name: v15_postgres_data traefik_certs: name: v15_traefik_certs