name: musify-dev # Infrastructure stack for Musify development: everything the backend needs # (Postgres, Zitadel, RabbitMQ, SeaweedFS + bucket, Jaeger/OTLP). The .NET apps # run from the IDE and connect over the published ports. Config in deploy/.env # # docker compose -f deploy/docker-compose.yml up -d services: postgres: image: postgres:17-alpine container_name: musify-postgres environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} ports: - "${POSTGRES_HOST_PORT}:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped pgadmin: image: dpage/pgadmin4:latest container_name: musify-pgadmin environment: PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL} PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD} PGADMIN_CONFIG_SERVER_MODE: "False" depends_on: postgres: condition: service_healthy ports: - "${PGADMIN_HOST_PORT}:80" volumes: - pgadmin_data:/var/lib/pgadmin restart: unless-stopped zitadel: image: ghcr.io/zitadel/zitadel:latest container_name: musify-zitadel command: 'start-from-init --masterkeyFromEnv --tlsMode disabled' environment: ZITADEL_MASTERKEY: ${ZITADEL_MASTERKEY} ZITADEL_EXTERNALSECURE: "false" ZITADEL_EXTERNALDOMAIN: ${ZITADEL_EXTERNAL_DOMAIN} ZITADEL_EXTERNALPORT: ${ZITADEL_EXTERNAL_PORT} ZITADEL_TLS_ENABLED: "false" # Reuses the same Postgres: the admin user creates the 'zitadel' database # and the 'zitadel' user on first start. ZITADEL_DATABASE_POSTGRES_HOST: postgres ZITADEL_DATABASE_POSTGRES_PORT: 5432 ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: ${POSTGRES_USER} ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: ${POSTGRES_PASSWORD} ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable # Initial console admin. Login: @zitadel. ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME: ${ZITADEL_ADMIN_USERNAME} ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: ${ZITADEL_ADMIN_PASSWORD} ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: "false" # Service account + PAT for automatic provisioning. Zitadel writes the PAT # to PATPATH on init; provision.ps1 uses it to create the project and app. ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_USERNAME: zitadel-admin-sa ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_NAME: Admin Service Account ZITADEL_FIRSTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE: "2099-01-01T00:00:00Z" ZITADEL_FIRSTINSTANCE_PATPATH: /output/admin-sa.pat depends_on: postgres: condition: service_healthy ports: - "${ZITADEL_EXTERNAL_PORT}:8080" volumes: - ./zitadel/.output:/output restart: unless-stopped rabbitmq: image: rabbitmq:4-management-alpine container_name: musify-rabbitmq environment: RABBITMQ_DEFAULT_USER: ${RABBITMQ_DEFAULT_USER} RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS} ports: - "5672:5672" # AMQP -> MassTransit (API + Worker) - "15672:15672" # management UI volumes: - rabbitmq_data:/var/lib/rabbitmq healthcheck: test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped seaweedfs: image: chrislusf/seaweedfs:latest container_name: musify-seaweedfs # All-in-one dev server: master + volume + filer + S3 gateway. command: > server -ip.bind=0.0.0.0 -dir=/data -master.volumeSizeLimitMB=1024 -volume.max=0 -filer -s3 -s3.config=/etc/seaweedfs/s3.conf ports: - "9333:9333" # master (admin/UI) - "8888:8888" # filer HTTP -> StreamingGateway - "8333:8333" # S3 API -> WebApi/Worker (InfrastructureStorage:Address) volumes: - seaweedfs_data:/data - ./seaweedfs/s3.conf:/etc/seaweedfs/s3.conf:ro healthcheck: test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:9333/cluster/healthz"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped # One-shot: creates the app bucket in SeaweedFS (it is not auto-created). seaweedfs-init: image: amazon/aws-cli:latest container_name: musify-seaweedfs-init depends_on: seaweedfs: condition: service_healthy environment: AWS_ACCESS_KEY_ID: ${S3_ACCESS_KEY} AWS_SECRET_ACCESS_KEY: ${S3_SECRET_KEY} AWS_DEFAULT_REGION: us-east-1 entrypoint: ["/bin/sh", "-c"] command: - | aws --endpoint-url http://seaweedfs:8333 s3 mb s3://${S3_BUCKET} 2>/dev/null || true aws --endpoint-url http://seaweedfs:8333 s3 ls restart: "no" # OTLP collector + trace UI (MassTransit/EF/HTTP spans). OtlpEndpoint = :4317 jaeger: image: jaegertracing/all-in-one:latest container_name: musify-jaeger environment: COLLECTOR_OTLP_ENABLED: "true" ports: - "16686:16686" # UI - "4317:4317" # OTLP gRPC - "4318:4318" # OTLP HTTP restart: unless-stopped volumes: postgres_data: pgadmin_data: rabbitmq_data: seaweedfs_data: