services: # PostgreSQL Database postgres: image: postgres:15-alpine container_name: ocra-postgres environment: POSTGRES_DB: ${POSTGRES_DB:-oauth_demo} POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: # Use pg_isready instead of psql for the database healthcheck: it confirms # the server is accepting TCP connections without requiring a password, # which is exactly what we need to gate dependent services. test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\" -h 127.0.0.1 -p 5432 > /dev/null || exit 1"] interval: 5s timeout: 5s retries: 10 start_period: 15s mongodb: image: mongo:7.0 container_name: ocra-mongodb hostname: mongodb command: ["sh", "/docker/mongo-start.sh"] environment: MONGO_INITDB_DATABASE: ocra_audit MONGO_REPLICA_SET_NAME: rs0 MONGO_REPLICA_HOST: mongodb:27017 volumes: - mongo_data:/data/db - mongo_configdb:/data/configdb - ./docker/mongo-init.js:/docker/mongo-init.js:ro - ./docker/mongo-start.sh:/docker/mongo-start.sh:ro networks: default: aliases: - mongodb - ocra-mongodb healthcheck: test: ["CMD-SHELL", "mongosh --quiet --eval 'quit(db.hello().setName === \"rs0\" && db.hello().isWritablePrimary ? 0 : 1)' >/dev/null 2>&1 || exit 1"] interval: 10s timeout: 5s retries: 5 start_period: 30s backend: build: context: . dockerfile: backend/Dockerfile container_name: ocra-backend env_file: - ./backend/.env environment: DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/oauth_demo?schema=public} MONGO_URL: mongodb://mongodb:27017/?replicaSet=rs0 MONGO_AUDIT_DB: ${MONGO_AUDIT_DB:-ocra_audit} MONGO_CONTENT_DB: ${MONGO_CONTENT_DB:-ocra_content} PORT: 3002 SYS_ADMIN_EMAIL: ${SYS_ADMIN_EMAIL:-admin@ocra.it} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3001} SWAGGER_PUBLIC_SERVER_URL: ${SWAGGER_PUBLIC_SERVER_URL:-} NODE_ENV: ${NODE_ENV:-production} AAT_SPARQL_ENDPOINT: ${AAT_SPARQL_ENDPOINT:-https://vocab.getty.edu/sparql.json} AAT_REQUEST_TIMEOUT_MS: ${AAT_REQUEST_TIMEOUT_MS:-8000} VOCABULARY_SEARCH_CACHE_TTL_MS: ${VOCABULARY_SEARCH_CACHE_TTL_MS:-300000} VOCABULARY_CONCEPT_CACHE_TTL_MS: ${VOCABULARY_CONCEPT_CACHE_TTL_MS:-3600000} # OAuth Configuration ISSUER: ${ISSUER:-https://aai-demo.egi.eu/auth/realms/egi} CLIENT_ID: ${CLIENT_ID:-b5998dc7-d012-4e12-a800-16e3bdf3d3c5} CLIENT_SECRET: ${CLIENT_SECRET:-} RUN_DEMO_PROJECT_SEED: ${RUN_DEMO_PROJECT_SEED:-false} DEMO_PROJECT_MANAGER_EMAIL: ${DEMO_PROJECT_MANAGER_EMAIL:-} DEMO_PROJECT_MANAGER_SUB: ${DEMO_PROJECT_MANAGER_SUB:-} depends_on: postgres: condition: service_healthy mongodb: condition: service_healthy healthcheck: test: [ "CMD-SHELL", "node -e \"fetch('http://127.0.0.1:3002/health/ready').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))\"", ] interval: 15s timeout: 10s retries: 10 start_period: 120s volumes: - project_files:/app/project_files app: build: context: . dockerfile: frontend/Dockerfile container_name: ocra-frontend environment: ISSUER: ${ISSUER:-https://aai-demo.egi.eu/auth/realms/egi} CLIENT_ID: ${CLIENT_ID:-b5998dc7-d012-4e12-a800-16e3bdf3d3c5} REDIRECT_URI: ${REDIRECT_URI:-http://localhost:3001} SCOPE: ${SCOPE:-openid voperson_id email profile entitlements} VITE_API_BASE: ${VITE_API_BASE:-http://localhost:3002} SHOW_ECCCH_DEBUG_OPERATIONS: ${SHOW_ECCCH_DEBUG_OPERATIONS:-true} THREE_PRESENTER_DEBUG: ${THREE_PRESENTER_DEBUG:-true} DATABASE_URL: ${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/oauth_demo?schema=public} depends_on: postgres: condition: service_healthy mongodb: condition: service_healthy backend: condition: service_healthy volumes: postgres_data: project_files: mongo_data: mongo_configdb: