version: '3.8' # ============================================================================== # Goa GEL Platform - Docker Compose # ============================================================================== # # Quick Start (no config needed): # docker-compose up -d # # Production: Copy .env.example to .env and update security values # # Services: # - Frontend: http://localhost:4200 # - API: http://localhost:3001 # - Blockscout: http://localhost:4000 # - MinIO: http://localhost:9001 (admin console) # # ============================================================================== services: # ================================ # PostgreSQL Database # ================================ postgres: image: postgres:15-alpine container_name: goa-gel-postgres restart: unless-stopped ports: - "5432:5432" environment: POSTGRES_DB: goa_gel_platform POSTGRES_USER: postgres POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-postgres_dev_password} volumes: - postgres_data:/var/lib/postgresql/data networks: - goa-gel-network healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d goa_gel_platform"] interval: 10s timeout: 5s retries: 5 # ================================ # Redis Cache & Queue # ================================ redis: image: redis:7-alpine container_name: goa-gel-redis restart: unless-stopped ports: - "6379:6379" command: redis-server --appendonly yes volumes: - redis_data:/data networks: - goa-gel-network healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 # ================================ # MinIO Object Storage # ================================ minio: image: minio/minio:latest container_name: goa-gel-minio restart: unless-stopped ports: - "9000:9000" - "9001:9001" environment: MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin} MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minio_dev_password} command: server /data --console-address ":9001" volumes: - minio_data:/data networks: - goa-gel-network healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 # ================================ # Hyperledger Besu Node # ================================ besu-node-1: image: hyperledger/besu:24.1.0 container_name: goa-gel-besu-1 restart: unless-stopped user: root ports: - "8545:8545" - "8546:8546" - "30303:30303" command: - --network=dev - --miner-enabled - --miner-coinbase=0xfe3b557e8fb62b89f4916b721be55ceb828dbd73 - --rpc-http-enabled - --rpc-http-host=0.0.0.0 - --rpc-http-port=8545 - --rpc-http-cors-origins=* - --rpc-http-api=ETH,NET,WEB3,DEBUG,MINER,ADMIN,TXPOOL,TRACE - --rpc-ws-enabled - --rpc-ws-host=0.0.0.0 - --rpc-ws-port=8546 - --host-allowlist=* - --min-gas-price=0 - --data-path=/var/lib/besu volumes: - besu_data:/var/lib/besu networks: - goa-gel-network healthcheck: test: ["CMD-SHELL", "exit 0"] interval: 30s timeout: 10s retries: 3 # ================================ # Blockscout Database # ================================ blockscout-db: image: postgres:15-alpine container_name: goa-gel-blockscout-db restart: unless-stopped environment: POSTGRES_DB: blockscout POSTGRES_USER: blockscout POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-blockscout_dev_password} volumes: - blockscout_db_data:/var/lib/postgresql/data networks: - goa-gel-network healthcheck: test: ["CMD-SHELL", "pg_isready -U blockscout -d blockscout"] interval: 10s timeout: 5s retries: 5 # ================================ # Blockscout Explorer # ================================ blockscout: image: blockscout/blockscout:6.3.0 container_name: goa-gel-blockscout restart: unless-stopped ports: - "4000:4000" environment: DATABASE_URL: postgresql://blockscout:${DATABASE_PASSWORD:-blockscout_dev_password}@blockscout-db:5432/blockscout ETHEREUM_JSONRPC_VARIANT: besu ETHEREUM_JSONRPC_HTTP_URL: http://besu-node-1:8545 ETHEREUM_JSONRPC_WS_URL: ws://besu-node-1:8546 ETHEREUM_JSONRPC_TRACE_URL: http://besu-node-1:8545 NETWORK: Goa-GEL Private Network SUBNETWORK: Development LOGO: /images/blockscout_logo.svg LOGO_FOOTER: /images/blockscout_logo.svg COIN: ETH COIN_NAME: Ether INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: "true" INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER: "false" FETCH_REWARDS_WAY: trace_block TRACE_FIRST_BLOCK: "0" TRACE_LAST_BLOCK: "" POOL_SIZE: 80 POOL_SIZE_API: 10 ECTO_USE_SSL: "false" SECRET_KEY_BASE: ${BLOCKSCOUT_SECRET_KEY_BASE:-RMgI4C1HSkxsEjdhtGMfwAHfyT6CKWXOgzCboJflfSm4jeAlic52io05KB6mqzc5} PORT: 4000 DISABLE_EXCHANGE_RATES: "true" SHOW_TXS_CHART: "true" HISTORY_FETCH_INTERVAL: 30 TXS_HISTORIAN_INIT_LAG: 0 TXS_STATS_DAYS_TO_COMPILE_AT_INIT: 10 HEART_BEAT_TIMEOUT: 60 BLOCKSCOUT_HOST: localhost BLOCKSCOUT_PROTOCOL: http API_V2_ENABLED: "true" MIX_ENV: prod depends_on: blockscout-db: condition: service_healthy besu-node-1: condition: service_healthy networks: - goa-gel-network command: sh -c "bin/blockscout eval \"Elixir.Explorer.ReleaseTasks.create_and_migrate()\" && bin/blockscout start" # ================================ # NestJS API Backend # ================================ api: build: context: ./backend dockerfile: Dockerfile container_name: goa-gel-api restart: unless-stopped ports: - "3001:3001" environment: # Application NODE_ENV: ${NODE_ENV:-production} PORT: 3001 # CORS - set to frontend URL for remote access CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:4200} # Database (must match postgres service) DATABASE_HOST: postgres DATABASE_PORT: 5432 DATABASE_NAME: goa_gel_platform DATABASE_USER: postgres DATABASE_PASSWORD: ${DATABASE_PASSWORD:-postgres_dev_password} # Redis REDIS_HOST: redis REDIS_PORT: 6379 # MinIO (must match minio service) MINIO_ENDPOINT: minio MINIO_PORT: 9000 MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minio_dev_password} MINIO_BUCKET_DOCUMENTS: goa-gel-documents # Blockchain BESU_RPC_URL: http://besu-node-1:8545 BESU_CHAIN_ID: 1337 BESU_NETWORK_ID: 2024 # Smart Contracts (populated after blockchain contract deployment) CONTRACT_ADDRESS_LICENSE_NFT: ${CONTRACT_ADDRESS_LICENSE_NFT:-} CONTRACT_ADDRESS_APPROVAL_MANAGER: ${CONTRACT_ADDRESS_APPROVAL_MANAGER:-} CONTRACT_ADDRESS_DEPARTMENT_REGISTRY: ${CONTRACT_ADDRESS_DEPARTMENT_REGISTRY:-} CONTRACT_ADDRESS_WORKFLOW_REGISTRY: ${CONTRACT_ADDRESS_WORKFLOW_REGISTRY:-} PLATFORM_WALLET_PRIVATE_KEY: ${PLATFORM_WALLET_PRIVATE_KEY:-} # Security JWT_SECRET: ${JWT_SECRET:-dev_jwt_secret_change_in_production_min32chars} # Misc FORCE_RESEED: ${FORCE_RESEED:-false} depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy besu-node-1: condition: service_healthy networks: - goa-gel-network volumes: - api_data:/app/data healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:3001/api/v1/health"] interval: 30s timeout: 10s start_period: 60s retries: 5 # ================================ # Angular Frontend # ================================ frontend: build: context: ./frontend dockerfile: Dockerfile container_name: goa-gel-frontend restart: unless-stopped ports: - "4200:80" environment: # Runtime API URL - browsers need the public/external URL to reach the API # For local: http://localhost:3001/api/v1 # For remote: http://:3001/api/v1 or https://api.yourdomain.com/api/v1 API_BASE_URL: ${API_BASE_URL:-http://localhost:3001/api/v1} depends_on: api: condition: service_healthy networks: - goa-gel-network healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost/"] interval: 30s timeout: 10s retries: 3 # ================================ # Documentation Service (Optional) # ================================ documentation: build: context: ./Documentation dockerfile: Dockerfile container_name: goa-gel-documentation restart: unless-stopped ports: - "8080:80" networks: - goa-gel-network profiles: - docs # Only starts with: docker-compose --profile docs up healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost/"] interval: 30s timeout: 10s retries: 3 networks: goa-gel-network: driver: bridge volumes: postgres_data: redis_data: minio_data: besu_data: blockscout_db_data: api_data: