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 # =========================================================================== # Redis - Shared cache and session store redis: image: redis:7-alpine container_name: redis-cache-local command: redis-server /etc/redis/redis.conf ports: - "${REDIS_PORT:-6379}:6379" volumes: - redis_data:/data - ../../infra/databases/redis/redis.conf:/etc/redis/redis.conf healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 networks: - microservices-network restart: unless-stopped # 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 # =========================================================================== # IAM Service - Identity and Access Management iam-service: build: context: ../.. dockerfile: services/iam-service/Dockerfile container_name: iam-service-local env_file: - .env.local environment: # Service-specific - PORT=5001 - SERVICE_NAME=iam-service - API_VERSION=${API_VERSION:-v1} # Shared from .env.local (explicit for clarity) - NODE_ENV=${NODE_ENV:-development} - LOG_LEVEL=${LOG_LEVEL:-debug} - DATABASE_URL=${DATABASE_URL} - REDIS_HOST=${REDIS_HOST:-redis} - REDIS_PORT=${REDIS_PORT:-6379} - JWT_SECRET=${JWT_SECRET} - JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-15m} - JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET} - JWT_REFRESH_EXPIRES_IN=${JWT_REFRESH_EXPIRES_IN:-7d} - ENCRYPTION_KEY=${ENCRYPTION_KEY} - CORS_ORIGIN=${CORS_ORIGIN} - TRACING_ENABLED=${TRACING_ENABLED:-false} - JAEGER_ENDPOINT=${JAEGER_ENDPOINT} ports: - "5001:5001" depends_on: redis: condition: service_healthy traefik: condition: service_started networks: - microservices-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5001/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s labels: # Traefik service discovery - "traefik.enable=true" - "traefik.http.routers.iam-service.rule=PathPrefix(`/api/v1/auth`) || PathPrefix(`/api/v1/users`) || PathPrefix(`/api/v1/identity`) || PathPrefix(`/api/v1/access`) || PathPrefix(`/api/v1/governance`) || PathPrefix(`/api/v1/rbac`) || PathPrefix(`/api/v1/mfa`) || PathPrefix(`/api/v1/sessions`)" - "traefik.http.routers.iam-service.entrypoints=web" - "traefik.http.services.iam-service.loadbalancer.server.port=5001" - "traefik.http.services.iam-service.loadbalancer.healthcheck.path=/health" - "traefik.http.services.iam-service.loadbalancer.healthcheck.interval=10s" # =========================================================================== # FRONTEND APPLICATIONS (Temporarily disabled) # =========================================================================== # Uncomment when needed for development # # Web Admin - Admin Dashboard (Next.js) # web-admin: # build: # context: ../.. # dockerfile: apps/web-admin/Dockerfile # container_name: web-admin-local # environment: # - NODE_ENV=${NODE_ENV:-development} # - NEXT_PUBLIC_API_URL=http://localhost/api/v1 # ports: # - "3000:3000" # depends_on: # - iam-service # - traefik # networks: # - microservices-network # restart: unless-stopped # labels: # # Traefik service discovery # - "traefik.enable=true" # - "traefik.http.routers.web-admin.rule=Host(`admin.localhost`)" # - "traefik.http.routers.web-admin.entrypoints=web" # - "traefik.http.services.web-admin.loadbalancer.server.port=3000" # # Web Client - Client Application (Next.js) # web-client: # build: # context: ../.. # dockerfile: apps/web-client/Dockerfile # container_name: web-client-local # environment: # - NODE_ENV=${NODE_ENV:-development} # - NEXT_PUBLIC_API_URL=http://localhost/api/v1 # ports: # - "3001:3000" # depends_on: # - iam-service # - traefik # networks: # - microservices-network # restart: unless-stopped # labels: # # Traefik service discovery # - "traefik.enable=true" # - "traefik.http.routers.web-client.rule=Host(`localhost`)" # - "traefik.http.routers.web-client.entrypoints=web" # - "traefik.http.services.web-client.loadbalancer.server.port=3000" # =========================================================================== # 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: redis_data: driver: local # prometheus_data: # driver: local # grafana_data: # driver: local # ============================================================================= # NETWORKS # ============================================================================= networks: microservices-network: driver: bridge name: goodgo-network