name: web-music-player # `docker compose up` → https://localhost:8443 (self-signed cert; browser warns # once). Values below are dev defaults; override any of them in a root `.env` # (auto-loaded by Compose) — see `.env.example`. services: db: image: postgres:17-alpine environment: POSTGRES_USER: ${POSTGRES_USER:-wmp} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-wmp} POSTGRES_DB: ${POSTGRES_DB:-wmp} volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-wmp} -d ${POSTGRES_DB:-wmp}'] interval: 5s timeout: 5s retries: 10 api: build: context: ./backend depends_on: db: condition: service_healthy keycloak: condition: service_started environment: NODE_ENV: production PORT: '3000' DATABASE_URL: ${DATABASE_URL:-postgres://wmp:wmp@db:5432/wmp} AUTH_ENABLED: ${AUTH_ENABLED:-true} # Public realm URL: the `iss` the backend requires on tokens and the host # the browser is redirected to. Backchannel calls (code exchange, JWKS) # go to the in-cluster address instead — see OIDC_INTERNAL_URL. OIDC_ISSUER_URL: ${OIDC_ISSUER_URL:-http://localhost:8081/realms/wmp} OIDC_INTERNAL_URL: ${OIDC_INTERNAL_URL:-http://keycloak:8080/realms/wmp} OIDC_AUDIENCE: ${OIDC_AUDIENCE:-wmp-api} OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-wmp-api} OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-dev-secret-change-me} OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI:-https://localhost:8443/api/auth/callback} OIDC_POST_LOGIN_REDIRECT: ${OIDC_POST_LOGIN_REDIRECT:-/} SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true} STORAGE_DRIVER: ${STORAGE_DRIVER:-local} STORAGE_LOCAL_DIR: /data/uploads MAX_UPLOAD_BYTES: ${MAX_UPLOAD_BYTES:-20971520} LOG_LEVEL: ${LOG_LEVEL:-info} volumes: - uploads:/data/uploads expose: - '3000' web: build: context: . dockerfile: frontend/Dockerfile depends_on: api: condition: service_healthy ports: - '${HTTP_PORT:-8080}:80' - '${HTTPS_PORT:-8443}:443' volumes: - web-certs:/etc/nginx/certs # Optional S3-compatible storage: `docker compose --profile storage-s3 up` minio: image: minio/minio profiles: ['storage-s3'] command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${S3_ACCESS_KEY_ID:-minioadmin} MINIO_ROOT_PASSWORD: ${S3_SECRET_ACCESS_KEY:-minioadmin} volumes: - minio-data:/data ports: - '9000:9000' - '9001:9001' createbuckets: image: minio/mc profiles: ['storage-s3'] depends_on: - minio entrypoint: > /bin/sh -c " until /usr/bin/mc alias set local http://minio:9000 ${S3_ACCESS_KEY_ID:-minioadmin} ${S3_SECRET_ACCESS_KEY:-minioadmin}; do sleep 1; done; /usr/bin/mc mb --ignore-existing local/${S3_BUCKET:-wmp-audio}; exit 0; " # OIDC identity provider (ADR-0005). Own Postgres instance (keycloak-db) so # Keycloak's schema stays separate from the application database. Admin # console at http://localhost:${KEYCLOAK_PORT:-8081}. Drop a realm JSON into # ./keycloak/import to have it loaded on first start. keycloak-db: image: postgres:17-alpine environment: POSTGRES_USER: ${KEYCLOAK_DB_USER:-keycloak} POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-keycloak} POSTGRES_DB: ${KEYCLOAK_DB_NAME:-keycloak} volumes: - keycloak-db-data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${KEYCLOAK_DB_USER:-keycloak} -d ${KEYCLOAK_DB_NAME:-keycloak}'] interval: 5s timeout: 5s retries: 10 keycloak: image: quay.io/keycloak/keycloak:26.0 command: start-dev --import-realm depends_on: keycloak-db: condition: service_healthy environment: KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN:-admin} KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin} KC_DB: postgres KC_DB_URL: jdbc:postgresql://keycloak-db:5432/${KEYCLOAK_DB_NAME:-keycloak} KC_DB_USERNAME: ${KEYCLOAK_DB_USER:-keycloak} KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-keycloak} KC_HTTP_ENABLED: 'true' # Pinned so the token `iss` is deterministic. The browser reaches Keycloak # here; the API reaches it in-cluster at http://keycloak:8080 — # BACKCHANNEL_DYNAMIC lets that host differ from KC_HOSTNAME. KC_HOSTNAME: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8081} KC_HOSTNAME_BACKCHANNEL_DYNAMIC: 'true' KC_HEALTH_ENABLED: 'true' ports: - '${KEYCLOAK_PORT:-8081}:8080' volumes: - ./keycloak/import:/opt/keycloak/data/import:ro volumes: db-data: uploads: web-certs: minio-data: keycloak-db-data: