version: '3.8' # ============================================================================= # GoodGo Platform - Local Development Environment # ============================================================================= # # Prerequisites: # 1. Copy env.local.example to .env.local and configure values # 2. Ensure Docker and Docker Compose are installed # 3. Get Neon PostgreSQL URL from https://console.neon.tech # # Start: docker-compose up -d # Stop: docker-compose down # Logs: docker-compose logs -f [service-name] # # Access Points: # - Traefik Dashboard: http://localhost:8080 # - IAM Service: http://localhost/api/v1/auth (backward compatible) # - IAM Service: http://localhost/api/v1/identity, /api/v1/access, /api/v1/governance # - Web Admin: http://admin.localhost # - Web Client: http://localhost # # ============================================================================= services: # =========================================================================== # SHARED INFRASTRUCTURE # =========================================================================== # Traefik - API Gateway and Reverse Proxy traefik: image: traefik:v3.3 container_name: traefik-local command: - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=goodgo-network" - "--providers.file.directory=/etc/traefik/dynamic" - "--providers.file.watch=true" - "--entrypoints.web.address=:80" - "--log.level=${LOG_LEVEL:-INFO}" - "--accesslog=true" ports: - "80:80" # HTTP - "8080:8080" # Dashboard volumes: # EN: Use actual Docker Desktop socket path (not symlink) # VI: Sử dụng đường dẫn socket thực của Docker Desktop (không phải symlink) - ${HOME}/.docker/run/docker.sock:/var/run/docker.sock:ro - ../../infra/traefik:/etc/traefik:ro networks: - microservices-network restart: unless-stopped labels: - "traefik.enable=true" - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.localhost`)" - "traefik.http.routers.traefik-dashboard.entrypoints=web" - "traefik.http.routers.traefik-dashboard.service=api@internal" # =========================================================================== # BACKEND SERVICES # =========================================================================== # Storage Service .NET - File Storage Management storage-service: build: context: ../../services/storage-service-net dockerfile: Dockerfile image: goodgo/storage-service-net:latest container_name: storage-service-local environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://+:8080 # EN: Database - Neon PostgreSQL # VI: Cơ sở dữ liệu - Neon PostgreSQL - ConnectionStrings__DefaultConnection=Host=ep-holy-glitter-a4hongg7-pooler.us-east-1.aws.neon.tech;Port=5432;Database=storage_service;Username=neondb_owner;Password=npg_Ssfy6HKO0cXI;SSL Mode=Require # EN: Storage - External MinIO # VI: Storage - MinIO bên ngoài - Storage__Provider=minio - Storage__DefaultBucket=goodgo - Storage__MinIO__Endpoint=167.114.174.113:9000 - Storage__MinIO__AccessKey=minioadmin - Storage__MinIO__SecretKey=Velik@2026 - Storage__MinIO__UseSSL=false # EN: IAM Service Communication # VI: Giao tiếp IAM Service - IamService__BaseUrl=http://iam-service-net:8080 - IamService__ServiceName=storage-service # EN: Redis Cache # VI: Cache Redis - Redis__Host=167.114.174.113 - Redis__Port=6379 - Redis__Password=Velik@2026 ports: - "5002:8080" depends_on: iam-service-net: condition: service_healthy traefik: condition: service_started networks: - microservices-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"] interval: 30s timeout: 10s retries: 3 start_period: 40s labels: - "traefik.enable=true" - "traefik.http.routers.storage-service.rule=PathPrefix(`/api/v1/files`) || PathPrefix(`/api/v1/quota`)" - "traefik.http.routers.storage-service.entrypoints=web" - "traefik.http.services.storage-service.loadbalancer.server.port=8080" - "traefik.http.services.storage-service.loadbalancer.healthcheck.path=/health/live" - "traefik.http.services.storage-service.loadbalancer.healthcheck.interval=10s" # Membership Service .NET - Membership Management membership-service-net: build: context: ../../services/membership-service-net dockerfile: Dockerfile image: goodgo/membership-service-net:latest container_name: membership-service-net-local environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://+:8080 # EN: Database - Neon PostgreSQL # VI: Cơ sở dữ liệu - Neon PostgreSQL - ConnectionStrings__DefaultConnection=Host=ep-holy-glitter-a4hongg7-pooler.us-east-1.aws.neon.tech;Port=5432;Database=membership_service;Username=neondb_owner;Password=npg_Ssfy6HKO0cXI;SSL Mode=Require # EN: IAM Service Communication # VI: Giao tiếp IAM Service - IamService__BaseUrl=http://iam-service-net:8080 - IamService__ServiceName=membership-service ports: - "5003:8080" depends_on: iam-service-net: condition: service_healthy traefik: condition: service_started networks: - microservices-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"] interval: 30s timeout: 10s retries: 3 start_period: 40s labels: - "traefik.enable=true" - "traefik.http.routers.membership-service.rule=PathPrefix(`/api/v1/members`) || PathPrefix(`/api/v1/levels`) || PathPrefix(`/api/v1/memberships`) || PathPrefix(`/api/v1/subscriptions`)" - "traefik.http.routers.membership-service.entrypoints=web" - "traefik.http.services.membership-service.loadbalancer.server.port=8080" - "traefik.http.services.membership-service.loadbalancer.healthcheck.path=/health/live" - "traefik.http.services.membership-service.loadbalancer.healthcheck.interval=10s" # Merchant Service .NET - Merchant & Shop Management merchant-service-net: build: context: ../../services/merchant-service-net dockerfile: Dockerfile image: goodgo/merchant-service-net:latest container_name: merchant-service-net-local environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://+:8080 # EN: Database - Neon PostgreSQL # VI: Cơ sở dữ liệu - Neon PostgreSQL - ConnectionStrings__DefaultConnection=Host=ep-holy-glitter-a4hongg7-pooler.us-east-1.aws.neon.tech;Port=5432;Database=merchant_service;Username=neondb_owner;Password=npg_Ssfy6HKO0cXI;SSL Mode=Require # EN: IAM Service Communication # VI: Giao tiếp IAM Service - IamService__BaseUrl=http://iam-service-net:8080 - IamService__ServiceName=merchant-service # EN: JWT Configuration # VI: Cấu hình JWT - Jwt__Authority=http://iam-service-net:8080 - Jwt__Audience=goodgo-api - Jwt__RequireHttpsMetadata=false ports: - "5005:8080" depends_on: iam-service-net: condition: service_healthy traefik: condition: service_started networks: - microservices-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"] interval: 30s timeout: 10s retries: 3 start_period: 40s labels: - "traefik.enable=true" - "traefik.http.routers.merchant-service.rule=PathPrefix(`/api/v1/merchants`) || PathPrefix(`/api/v1/shops`)" - "traefik.http.routers.merchant-service.entrypoints=web" - "traefik.http.services.merchant-service.loadbalancer.server.port=8080" - "traefik.http.services.merchant-service.loadbalancer.healthcheck.path=/health/live" - "traefik.http.services.merchant-service.loadbalancer.healthcheck.interval=10s" # IAM Service .NET - Identity and Access Management (Duende IdentityServer) iam-service-net: build: context: ../../services/iam-service-net dockerfile: Dockerfile image: goodgo/iam-service-net:latest container_name: iam-service-net-local env_file: - .env environment: - ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT:-Development} - ASPNETCORE_URLS=http://+:8080 # EN: Database - Neon PostgreSQL # VI: Cơ sở dữ liệu - Neon PostgreSQL - ConnectionStrings__DefaultConnection=${IAM_DATABASE_URL} # EN: Redis Cache (external) # VI: Cache Redis (bên ngoài) - Redis__Host=${REDIS_HOST} - Redis__Port=${REDIS_PORT} - Redis__Password=${REDIS_PASSWORD} - Redis__Database=${REDIS_DATABASE} # EN: JWT Configuration # VI: Cấu hình JWT - Jwt__Secret=${JWT_SECRET} - Jwt__Issuer=${JWT_ISSUER} - Jwt__Audience=${JWT_AUDIENCE} - Jwt__AccessTokenExpiryMinutes=${JWT_ACCESS_TOKEN_EXPIRY_MINUTES} - Jwt__RefreshTokenExpiryDays=${JWT_REFRESH_TOKEN_EXPIRY_DAYS} # EN: Features # VI: Tính năng - Features__SwaggerEnabled=${FEATURE_SWAGGER_ENABLED} - Features__DetailedErrors=${FEATURE_DETAILED_ERRORS} # EN: IdentityServer - Fixed issuer for inter-service communication # VI: IdentityServer - Issuer cố định cho giao tiếp giữa các service - IdentityServer__IssuerUri=http://iam-service ports: - "5001:8080" depends_on: traefik: condition: service_started networks: - microservices-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"] interval: 30s timeout: 10s retries: 3 start_period: 15s labels: - "traefik.enable=true" - "traefik.http.routers.iam-service-net.rule=PathPrefix(`/api/v1/iam`) || PathPrefix(`/api/v1/auth`) || PathPrefix(`/api/v1/users`) || PathPrefix(`/api/v1/roles`)" - "traefik.http.routers.iam-service-net.entrypoints=web" - "traefik.http.services.iam-service-net.loadbalancer.server.port=8080" - "traefik.http.services.iam-service-net.loadbalancer.healthcheck.path=/health/live" - "traefik.http.services.iam-service-net.loadbalancer.healthcheck.interval=10s" # Wallet Service .NET - Wallet & PPoint Management wallet-service-net: build: context: ../../services/wallet-service-net dockerfile: Dockerfile image: goodgo/wallet-service-net:latest container_name: wallet-service-net-local environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://+:8080 # EN: Database - Neon PostgreSQL # VI: Cơ sở dữ liệu - Neon PostgreSQL - ConnectionStrings__DefaultConnection=Host=ep-holy-glitter-a4hongg7-pooler.us-east-1.aws.neon.tech;Port=5432;Database=wallet_service;Username=neondb_owner;Password=npg_Ssfy6HKO0cXI;SSL Mode=Require # EN: IAM Service Communication # VI: Giao tiếp IAM Service - IamService__BaseUrl=http://iam-service-net:8080 - IamService__ServiceName=wallet-service # EN: JWT Configuration # VI: Cấu hình JWT - Jwt__Authority=http://iam-service-net:8080 - Jwt__Audience=goodgo-api - Jwt__RequireHttpsMetadata=false ports: - "5004:8080" depends_on: iam-service-net: condition: service_healthy traefik: condition: service_started networks: - microservices-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"] interval: 30s timeout: 10s retries: 3 start_period: 40s labels: - "traefik.enable=true" - "traefik.http.routers.wallet-service.rule=PathPrefix(`/api/v1/wallets`) || PathPrefix(`/api/v1/points`)" - "traefik.http.routers.wallet-service.entrypoints=web" - "traefik.http.services.wallet-service.loadbalancer.server.port=8080" - "traefik.http.services.wallet-service.loadbalancer.healthcheck.path=/health/live" - "traefik.http.services.wallet-service.loadbalancer.healthcheck.interval=10s" # =========================================================================== # OBSERVABILITY (Optional - Uncomment to enable) # =========================================================================== # Jaeger - Distributed Tracing # jaeger: # image: jaegertracing/all-in-one:1.47 # container_name: jaeger-local # ports: # - "16686:16686" # UI # - "14268:14268" # Collector # environment: # - COLLECTOR_OTLP_ENABLED=true # networks: # - microservices-network # restart: unless-stopped # Prometheus - Metrics Collection # prometheus: # image: prom/prometheus:latest # container_name: prometheus-local # ports: # - "9090:9090" # volumes: # - ../../infra/observability/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro # - prometheus_data:/prometheus # networks: # - microservices-network # restart: unless-stopped # Grafana - Metrics Visualization # grafana: # image: grafana/grafana:latest # container_name: grafana-local # ports: # - "3001:3000" # environment: # - GF_SECURITY_ADMIN_PASSWORD=admin # volumes: # - grafana_data:/var/lib/grafana # networks: # - microservices-network # restart: unless-stopped # ============================================================================= # VOLUMES # ============================================================================= volumes: {} # ============================================================================= # NETWORKS # ============================================================================= networks: microservices-network: driver: bridge name: goodgo-network