name: open-productivity-platform services: postgres: image: postgres:16.4-alpine environment: POSTGRES_DB: ${POSTGRES_ADMIN_DATABASE:-postgres} POSTGRES_USER: ${POSTGRES_ADMIN_USER:-platform_admin} POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD:-local-development-only-change-me} PLATFORM_DB_NAME: ${PLATFORM_DB_NAME:-platform} PLATFORM_DB_USER: ${PLATFORM_DB_USER:-platform} PLATFORM_DB_PASSWORD: ${PLATFORM_DB_PASSWORD:-local-development-only-change-me} KEYCLOAK_DB_NAME: ${KEYCLOAK_DB_NAME:-keycloak} KEYCLOAK_DB_USER: ${KEYCLOAK_DB_USER:-keycloak} KEYCLOAK_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-local-development-only-change-me} ORGANIZATION_DB_NAME: ${ORGANIZATION_DB_NAME:-organization} ORGANIZATION_DB_USER: ${ORGANIZATION_DB_USER:-organization} ORGANIZATION_DB_PASSWORD: ${ORGANIZATION_DB_PASSWORD:-local-development-only-change-me} AUTHORIZATION_DB_NAME: ${AUTHORIZATION_DB_NAME:-authorization} AUTHORIZATION_DB_USER: ${AUTHORIZATION_DB_USER:-authorization} AUTHORIZATION_DB_PASSWORD: ${AUTHORIZATION_DB_PASSWORD:-local-development-only-change-me} AUDIT_PRIVACY_DB_NAME: ${AUDIT_PRIVACY_DB_NAME:-audit_privacy} AUDIT_PRIVACY_DB_USER: ${AUDIT_PRIVACY_DB_USER:-audit_privacy} AUDIT_PRIVACY_DB_PASSWORD: ${AUDIT_PRIVACY_DB_PASSWORD:-local-development-only-change-me} PERSON_EMPLOYMENT_DB_NAME: ${PERSON_EMPLOYMENT_DB_NAME:-person_employment} PERSON_EMPLOYMENT_DB_USER: ${PERSON_EMPLOYMENT_DB_USER:-person_employment} PERSON_EMPLOYMENT_DB_PASSWORD: ${PERSON_EMPLOYMENT_DB_PASSWORD:-local-development-only-change-me} DEPARTMENT_POSITION_DB_NAME: ${DEPARTMENT_POSITION_DB_NAME:-department_position} DEPARTMENT_POSITION_DB_USER: ${DEPARTMENT_POSITION_DB_USER:-department_position} DEPARTMENT_POSITION_DB_PASSWORD: ${DEPARTMENT_POSITION_DB_PASSWORD:-local-development-only-change-me} HIERARCHY_DB_NAME: ${HIERARCHY_DB_NAME:-hierarchy} HIERARCHY_DB_USER: ${HIERARCHY_DB_USER:-hierarchy} HIERARCHY_DB_PASSWORD: ${HIERARCHY_DB_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${POSTGRES_PORT:-5433}:5432" volumes: - postgres-data:/var/lib/postgresql/data - ./infra/postgres/init:/docker-entrypoint-initdb.d:ro networks: - platform-backend healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 5s timeout: 3s retries: 20 start_period: 10s rabbitmq: image: rabbitmq:3.13.7-management-alpine environment: RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-platform} RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${RABBITMQ_AMQP_PORT:-5672}:5672" - "127.0.0.1:${RABBITMQ_MANAGEMENT_PORT:-15672}:15672" volumes: - rabbitmq-data:/var/lib/rabbitmq networks: - platform-backend healthcheck: test: ["CMD-SHELL", "rabbitmq-diagnostics -q ping"] interval: 5s timeout: 5s retries: 20 start_period: 15s keycloak: image: quay.io/keycloak/keycloak:26.3.2 command: start-dev --import-realm environment: KC_DB: postgres KC_DB_URL_HOST: postgres KC_DB_URL_DATABASE: ${KEYCLOAK_DB_NAME:-keycloak} KC_DB_USERNAME: ${KEYCLOAK_DB_USER:-keycloak} KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-local-development-only-change-me} KC_HEALTH_ENABLED: "true" KC_HTTP_PORT: "8080" KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN_USER:-admin} KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-local-development-only-change-me} KEYCLOAK_DEV_USER_PASSWORD: ${KEYCLOAK_DEV_USER_PASSWORD:-local-development-only-change-me} volumes: - ./infra/keycloak/open-productivity-realm.json:/opt/keycloak/data/import/open-productivity-realm.json:ro ports: - "127.0.0.1:${KEYCLOAK_PORT:-8081}:8080" - "127.0.0.1:${KEYCLOAK_MANAGEMENT_PORT:-9000}:9000" depends_on: postgres: condition: service_healthy networks: - platform-backend healthcheck: test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000 && printf 'GET /health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && grep -q '200' <&3"] interval: 5s timeout: 5s retries: 30 start_period: 20s identity-adapter: build: context: . dockerfile: identity-adapter/Dockerfile environment: OIDC_ISSUER: http://keycloak:8080/realms/open-productivity depends_on: keycloak: condition: service_healthy networks: - platform-backend gateway-fixture: build: context: ./gateway-fixture profiles: [gateway-qa] networks: - platform-backend gateway: image: envoyproxy/envoy:v1.32.3 volumes: - ./infra/gateway/envoy.yaml:/etc/envoy/envoy.yaml:ro ports: - "127.0.0.1:${GATEWAY_PORT:-8080}:8080" - "127.0.0.1:${GATEWAY_ADMIN_PORT:-9901}:9901" depends_on: keycloak: condition: service_healthy identity-adapter: condition: service_started openhr-bff: condition: service_started healthcheck: test: ["CMD-SHELL", "test -r /proc/1/status"] interval: 5s timeout: 3s retries: 20 start_period: 10s networks: - platform-backend observability: build: context: ./observability environment: RABBITMQ_API: http://rabbitmq:15672/api RABBITMQ_USER: ${RABBITMQ_USER:-platform} RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${OBSERVABILITY_PORT:-9090}:9090" depends_on: rabbitmq: condition: service_healthy networks: - platform-backend openhr-bff: build: context: . dockerfile: openhr-bff/Dockerfile ports: - "127.0.0.1:${OPENHR_BFF_PORT:-8089}:8090" environment: PERSON_EMPLOYMENT_URL: http://person-employment-service:8086 HIERARCHY_URL: http://hierarchy-service:8088 AUTHORIZATION_URL: http://authorization-service:8084 PRIVACY_URL: http://audit-privacy-service:8092 OPENHR_FIXTURE_IDS: "true" depends_on: person-employment-service: condition: service_started hierarchy-service: condition: service_started authorization-service: condition: service_started audit-privacy-service: condition: service_started rabbitmq: condition: service_healthy networks: - platform-backend future-projection: build: context: . dockerfile: future-projection/Dockerfile ports: - "127.0.0.1:${FUTURE_PROJECTION_PORT:-8090}:8090" environment: RABBITMQ_HOST: rabbitmq RABBITMQ_USER: ${RABBITMQ_USER:-platform} RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD:-local-development-only-change-me} PROJECTION_DB_URL: jdbc:sqlite:/data/future-projection.db volumes: - future-projection-data:/data depends_on: rabbitmq: condition: service_healthy networks: - platform-backend organization-service: build: context: . dockerfile: organization-service/Dockerfile environment: ORG_DB_URL: jdbc:postgresql://postgres:5432/${ORGANIZATION_DB_NAME:-organization} ORG_DB_USER: ${ORGANIZATION_DB_USER:-organization} ORG_DB_PASSWORD: ${ORGANIZATION_DB_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${ORGANIZATION_SERVICE_PORT:-8082}:8082" depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy networks: - platform-backend authorization-service: build: context: . dockerfile: authorization-service/Dockerfile environment: AUTHORIZATION_DB_URL: jdbc:postgresql://postgres:5432/${AUTHORIZATION_DB_NAME:-authorization} AUTHORIZATION_DB_USER: ${AUTHORIZATION_DB_USER:-authorization} AUTHORIZATION_DB_PASSWORD: ${AUTHORIZATION_DB_PASSWORD:-local-development-only-change-me} AUTHORIZATION_FIXTURE_MODE: "true" ports: - "127.0.0.1:${AUTHORIZATION_SERVICE_PORT:-8084}:8084" depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy networks: - platform-backend audit-privacy-service: build: context: . dockerfile: audit-privacy-service/Dockerfile environment: PRIVACY_FIXTURE_MODE: "true" PRIVACY_DB_URL: jdbc:postgresql://postgres:5432/${AUDIT_PRIVACY_DB_NAME:-audit_privacy} PRIVACY_DB_USER: ${AUDIT_PRIVACY_DB_USER:-audit_privacy} PRIVACY_DB_PASSWORD: ${AUDIT_PRIVACY_DB_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${AUDIT_PRIVACY_SERVICE_PORT:-8092}:8092" depends_on: postgres: condition: service_healthy networks: - platform-backend person-employment-service: build: context: . dockerfile: person-employment-service/Dockerfile environment: PERSON_EMPLOYMENT_PROFILE: fixture PERSON_EMPLOYMENT_DB_URL: jdbc:postgresql://postgres:5432/${PERSON_EMPLOYMENT_DB_NAME:-person_employment} PERSON_EMPLOYMENT_DB_USER: ${PERSON_EMPLOYMENT_DB_USER:-person_employment} PERSON_EMPLOYMENT_DB_PASSWORD: ${PERSON_EMPLOYMENT_DB_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${PERSON_EMPLOYMENT_SERVICE_PORT:-8086}:8086" depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy networks: - platform-backend department-position-service: build: context: . dockerfile: department-position-service/Dockerfile environment: DEPARTMENT_POSITION_PROFILE: fixture DEPARTMENT_POSITION_DB_URL: jdbc:postgresql://postgres:5432/${DEPARTMENT_POSITION_DB_NAME:-department_position} DEPARTMENT_POSITION_DB_USER: ${DEPARTMENT_POSITION_DB_USER:-department_position} DEPARTMENT_POSITION_DB_PASSWORD: ${DEPARTMENT_POSITION_DB_PASSWORD:-local-development-only-change-me} restart: unless-stopped ports: - "127.0.0.1:${DEPARTMENT_POSITION_SERVICE_PORT:-8087}:8087" healthcheck: test: ["CMD-SHELL", "wget -qO- --header='X-Fixture-Organization: 48a69305-2902-5653-877d-44ce0c64c6f2' --header='X-Organization-Id: 48a69305-2902-5653-877d-44ce0c64c6f2' http://localhost:8087/api/v1/departments/tree >/dev/null"] interval: 5s timeout: 3s retries: 20 start_period: 10s depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy networks: - platform-backend hierarchy-service: build: context: . dockerfile: hierarchy-service/Dockerfile environment: HIERARCHY_PROFILE: fixture HIERARCHY_DB_URL: jdbc:postgresql://postgres:5432/${HIERARCHY_DB_NAME:-hierarchy} HIERARCHY_DB_USER: ${HIERARCHY_DB_USER:-hierarchy} HIERARCHY_DB_PASSWORD: ${HIERARCHY_DB_PASSWORD:-local-development-only-change-me} restart: unless-stopped ports: - "127.0.0.1:${HIERARCHY_SERVICE_PORT:-8088}:8088" healthcheck: test: ["CMD-SHELL", "wget -qO- --header='X-Fixture-Organization: 48a69305-2902-5653-877d-44ce0c64c6f2' --header='X-Organization-Id: 48a69305-2902-5653-877d-44ce0c64c6f2' http://localhost:8088/api/v1/hierarchy/status >/dev/null"] interval: 5s timeout: 3s retries: 20 start_period: 10s depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy networks: - platform-backend tenancy-provisioning: build: context: . dockerfile: tenancy-provisioning/Dockerfile environment: TENANCY_DB_URL: jdbc:postgresql://postgres:5432/${PLATFORM_DB_NAME:-platform} TENANCY_DB_USER: ${PLATFORM_DB_USER:-platform} TENANCY_DB_PASSWORD: ${PLATFORM_DB_PASSWORD:-local-development-only-change-me} TENANCY_PROVISIONER_KEY: ${TENANCY_PROVISIONER_KEY:-local-test-provisioner} ports: - "127.0.0.1:${TENANCY_PROVISIONING_PORT:-8083}:8083" depends_on: postgres: condition: service_healthy networks: - platform-backend minio: image: minio/minio:RELEASE.2025-04-22T22-12-26Z profiles: [object-store] command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-local-development-only-change-me} ports: - "127.0.0.1:${MINIO_API_PORT:-9002}:9000" - "127.0.0.1:${MINIO_CONSOLE_PORT:-9003}:9001" volumes: - minio-data:/data networks: - platform-backend healthcheck: test: ["CMD-SHELL", "curl --fail --silent http://127.0.0.1:9000/minio/health/ready >/dev/null"] interval: 5s timeout: 3s retries: 20 start_period: 10s volumes: postgres-data: rabbitmq-data: future-projection-data: minio-data: networks: platform-backend: name: platform-backend