# ============================================================ # SuperApp SaaS Platform - Docker Compose # postgres, redis, keycloak, core-service, identity-access, # celery-worker, celery-beat, frontend # ============================================================ services: postgres: image: postgres:15-alpine container_name: superapp_postgres restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} ports: - "${POSTGRES_PORT:-5432}:5432" volumes: - postgres_data:/var/lib/postgresql/data - ./infrastructure/postgres/init-dbs.sql:/docker-entrypoint-initdb.d/02-init-dbs.sql healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 networks: - superapp_net redis: image: redis:7-alpine container_name: superapp_redis restart: unless-stopped ports: - "${REDIS_PORT:-6379}:6379" volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - superapp_net keycloak: image: quay.io/keycloak/keycloak:24.0 container_name: superapp_keycloak restart: unless-stopped command: start-dev --import-realm --features=token-exchange environment: KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-admin} KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin} KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} KC_DB_USERNAME: ${POSTGRES_USER} KC_DB_PASSWORD: ${POSTGRES_PASSWORD} KC_HTTP_ENABLED: "true" KC_HOSTNAME_STRICT: "false" KC_PROXY: edge KC_HOSTNAME: ${KEYCLOAK_HOSTNAME:-auth.torbatyar.ir} KC_HOSTNAME_STRICT_HTTPS: ${KEYCLOAK_HOSTNAME_STRICT_HTTPS:-false} JAVA_OPTS_KC_HEAP: "-Xms256m -Xmx512m" ports: - "8080:8080" volumes: - ./infrastructure/keycloak/realm:/opt/keycloak/data/import - ./infrastructure/keycloak/themes:/opt/keycloak/themes depends_on: postgres: condition: service_healthy networks: - superapp_net core-service: build: context: . dockerfile: backend/core-service/Dockerfile.dev container_name: superapp_core_service restart: unless-stopped env_file: - .env ports: - "8000:8000" volumes: - ./backend/core-service:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy redis: condition: service_healthy keycloak: condition: service_started command: > sh -c "alembic upgrade 0001_initial && alembic stamp head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload" networks: - superapp_net identity-access-service: build: context: . dockerfile: backend/services/identity-access/Dockerfile.dev container_name: superapp_identity_service restart: unless-stopped env_file: - .env environment: DATABASE_URL: ${IDENTITY_DATABASE_URL} DATABASE_URL_SYNC: ${IDENTITY_DATABASE_URL_SYNC} IDENTITY_KEYCLOAK_CLIENT_ID: identity-access-service KEYCLOAK_IDENTITY_CLIENT_SECRET: ${KEYCLOAK_IDENTITY_CLIENT_SECRET:-change-me-identity} PLATFORM_ADMIN_MOBILES: ${PLATFORM_ADMIN_MOBILES:-} KEYCLOAK_SERVER_URL: http://keycloak:8080 KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080} CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} ports: - "8001:8001" volumes: - ./backend/services/identity-access:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy keycloak: condition: service_started core-service: condition: service_started command: > sh -c "python scripts/ensure_db.py && alembic upgrade 0001_initial && alembic stamp head && (python scripts/enable_mobile_auth_client.py || true) && uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload" networks: - superapp_net accounting-service: build: context: . dockerfile: backend/services/accounting/Dockerfile.dev container_name: superapp_accounting_service restart: unless-stopped env_file: - .env environment: ACCOUNTING_DATABASE_URL: ${ACCOUNTING_DATABASE_URL} ACCOUNTING_DATABASE_URL_SYNC: ${ACCOUNTING_DATABASE_URL_SYNC} CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} AUTH_REQUIRED: ${AUTH_REQUIRED:-true} KEYCLOAK_SERVER_URL: ${KEYCLOAK_SERVER_URL:-http://keycloak:8080} KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080} KEYCLOAK_REALM: ${KEYCLOAK_REALM:-superapp} JWT_VERIFY_SIGNATURE: ${JWT_VERIFY_SIGNATURE:-true} ports: - "8002:8002" volumes: - ./backend/services/accounting:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy core-service: condition: service_started command: > sh -c "python scripts/ensure_db.py && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8002 --reload" networks: - superapp_net crm-service: build: context: . dockerfile: backend/services/crm/Dockerfile.dev container_name: superapp_crm_service restart: unless-stopped env_file: - .env environment: CRM_DATABASE_URL: ${CRM_DATABASE_URL} CRM_DATABASE_URL_SYNC: ${CRM_DATABASE_URL_SYNC} CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} AUTH_REQUIRED: ${AUTH_REQUIRED:-true} KEYCLOAK_SERVER_URL: ${KEYCLOAK_SERVER_URL:-http://keycloak:8080} KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080} KEYCLOAK_REALM: ${KEYCLOAK_REALM:-superapp} JWT_VERIFY_SIGNATURE: ${JWT_VERIFY_SIGNATURE:-true} ports: - "8003:8003" volumes: - ./backend/services/crm:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy core-service: condition: service_started command: > sh -c "python scripts/ensure_db.py && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8003 --reload" networks: - superapp_net loyalty-service: build: context: . dockerfile: backend/services/loyalty/Dockerfile.dev container_name: superapp_loyalty_service restart: unless-stopped env_file: - .env environment: LOYALTY_DATABASE_URL: ${LOYALTY_DATABASE_URL} LOYALTY_DATABASE_URL_SYNC: ${LOYALTY_DATABASE_URL_SYNC} CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} AUTH_REQUIRED: ${AUTH_REQUIRED:-true} KEYCLOAK_SERVER_URL: ${KEYCLOAK_SERVER_URL:-http://keycloak:8080} KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080} KEYCLOAK_REALM: ${KEYCLOAK_REALM:-superapp} JWT_VERIFY_SIGNATURE: ${JWT_VERIFY_SIGNATURE:-true} ports: - "8004:8004" volumes: - ./backend/services/loyalty:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy core-service: condition: service_started command: > sh -c "python scripts/ensure_db.py && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8004 --reload" networks: - superapp_net communication-service: build: context: . dockerfile: backend/services/communication/Dockerfile.dev container_name: superapp_communication_service restart: unless-stopped env_file: - .env environment: COMMUNICATION_DATABASE_URL: ${COMMUNICATION_DATABASE_URL} COMMUNICATION_DATABASE_URL_SYNC: ${COMMUNICATION_DATABASE_URL_SYNC} CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} AUTH_REQUIRED: ${AUTH_REQUIRED:-true} KEYCLOAK_SERVER_URL: ${KEYCLOAK_SERVER_URL:-http://keycloak:8080} KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080} KEYCLOAK_REALM: ${KEYCLOAK_REALM:-superapp} JWT_VERIFY_SIGNATURE: ${JWT_VERIFY_SIGNATURE:-true} ports: - "8005:8005" volumes: - ./backend/services/communication:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy core-service: condition: service_started command: > sh -c "python scripts/ensure_db.py && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8005 --reload" networks: - superapp_net sports-center-service: build: context: . dockerfile: backend/services/sports_center/Dockerfile.dev container_name: superapp_sports_center_service restart: unless-stopped env_file: - .env environment: SPORTS_CENTER_DATABASE_URL: ${SPORTS_CENTER_DATABASE_URL} SPORTS_CENTER_DATABASE_URL_SYNC: ${SPORTS_CENTER_DATABASE_URL_SYNC} CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} AUTH_REQUIRED: ${AUTH_REQUIRED:-true} KEYCLOAK_SERVER_URL: ${KEYCLOAK_SERVER_URL:-http://keycloak:8080} KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080} KEYCLOAK_REALM: ${KEYCLOAK_REALM:-superapp} JWT_VERIFY_SIGNATURE: ${JWT_VERIFY_SIGNATURE:-true} ports: - "8006:8006" volumes: - ./backend/services/sports_center:/app - ./backend/shared-lib:/shared-lib depends_on: postgres: condition: service_healthy core-service: condition: service_started command: > sh -c "python scripts/ensure_db.py && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8006 --reload" networks: - superapp_net frontend: build: context: ./frontend dockerfile: Dockerfile.dev container_name: superapp_frontend restart: unless-stopped ports: - "${FRONTEND_PORT:-3000}:3000" environment: NEXT_PUBLIC_BACKEND_URL: ${NEXT_PUBLIC_BACKEND_URL:-http://localhost:8000} NEXT_PUBLIC_API_BASE_URL: ${NEXT_PUBLIC_API_BASE_URL:-http://localhost:8000} NEXT_PUBLIC_IDENTITY_API_URL: ${NEXT_PUBLIC_IDENTITY_API_URL:-http://localhost:8001} NEXT_PUBLIC_KEYCLOAK_URL: ${NEXT_PUBLIC_KEYCLOAK_URL:-http://localhost:8080} NEXT_PUBLIC_KEYCLOAK_REALM: ${NEXT_PUBLIC_KEYCLOAK_REALM:-superapp} NEXT_PUBLIC_KEYCLOAK_CLIENT_ID: ${NEXT_PUBLIC_KEYCLOAK_CLIENT_ID:-superapp-frontend} NEXT_PUBLIC_PLATFORM_BASE_DOMAIN: ${NEXT_PUBLIC_PLATFORM_BASE_DOMAIN:-torbatyar.ir} NEXT_PUBLIC_ACCOUNTING_API_URL: ${NEXT_PUBLIC_ACCOUNTING_API_URL:-http://localhost:8002} ACCOUNTING_SERVICE_URL: ${ACCOUNTING_SERVICE_URL:-http://accounting-service:8002} # polling برای hot-reload پایدار روی volume mount ویندوز WATCHPACK_POLLING: "true" CHOKIDAR_USEPOLLING: "true" volumes: - ./frontend:/app - frontend_node_modules:/app/node_modules depends_on: core-service: condition: service_started identity-access-service: condition: service_started networks: - superapp_net celery-worker: build: context: . dockerfile: backend/core-service/Dockerfile.dev container_name: superapp_celery_worker restart: unless-stopped env_file: - .env volumes: - ./backend/core-service:/app - ./backend/shared-lib:/shared-lib depends_on: redis: condition: service_healthy postgres: condition: service_healthy command: celery -A app.workers.celery_app.celery_app worker --loglevel=INFO -Q default,core_events,notifications,webhooks networks: - superapp_net celery-beat: build: context: . dockerfile: backend/core-service/Dockerfile.dev container_name: superapp_celery_beat restart: unless-stopped env_file: - .env volumes: - ./backend/core-service:/app - ./backend/shared-lib:/shared-lib depends_on: redis: condition: service_healthy command: celery -A app.workers.celery_app.celery_app beat --loglevel=INFO networks: - superapp_net volumes: postgres_data: redis_data: frontend_node_modules: networks: superapp_net: driver: bridge