From f99cac21cf700963a8c62b6f5a685bb21a82d181 Mon Sep 17 00:00:00 2001 From: Developer Date: Tue, 2 Dec 2025 02:12:49 -0800 Subject: [PATCH] feat(services): add unified Docker deployment system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add docker-compose.yml for all 11 backend services - Add deploy.sh automation script with install/build/up/down commands - Add init-databases.sh for PostgreSQL multi-database initialization - Add .env.example template with secure key placeholders - Fix empty Dockerfiles for admin/referral/reporting/wallet services Services included: - identity-service (:3000) - wallet-service (:3001) - backup-service (:3002) - planting-service (:3003) - referral-service (:3004) - reward-service (:3005) - mpc-service (:3006) - leaderboard-service (:3007) - reporting-service (:3008) - authorization-service (:3009) - admin-service (:3010) Infrastructure: PostgreSQL, Redis, Kafka/Zookeeper ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/services/.env.example | 32 ++ backend/services/.gitignore | 16 + backend/services/README.md | 173 ++++++ backend/services/admin-service/Dockerfile | 61 +++ backend/services/deploy.sh | 470 ++++++++++++++++ backend/services/docker-compose.yml | 510 ++++++++++++++++++ backend/services/referral-service/Dockerfile | 61 +++ backend/services/reporting-service/Dockerfile | 61 +++ backend/services/scripts/init-databases.sh | 19 + backend/services/wallet-service/Dockerfile | 61 +++ 10 files changed, 1464 insertions(+) create mode 100644 backend/services/.env.example create mode 100644 backend/services/.gitignore create mode 100644 backend/services/README.md create mode 100644 backend/services/deploy.sh create mode 100644 backend/services/docker-compose.yml create mode 100644 backend/services/scripts/init-databases.sh diff --git a/backend/services/.env.example b/backend/services/.env.example new file mode 100644 index 00000000..11d76da7 --- /dev/null +++ b/backend/services/.env.example @@ -0,0 +1,32 @@ +# ============================================================================= +# RWA Backend Services - Environment Configuration Template +# ============================================================================= +# Copy this file to .env and fill in the values +# WARNING: Never commit .env to version control! +# ============================================================================= + +# PostgreSQL Database +POSTGRES_USER=rwa_user +POSTGRES_PASSWORD=your_secure_password_here + +# Redis (leave empty for no password) +REDIS_PASSWORD= + +# JWT Configuration (generate with: openssl rand -base64 32) +JWT_SECRET=your_jwt_secret_here + +# Service-to-Service Authentication +SERVICE_JWT_SECRET=your_service_jwt_secret_here + +# Wallet Encryption Salt +WALLET_ENCRYPTION_SALT=your_wallet_salt_here + +# Backup Encryption Key (256-bit hex: openssl rand -hex 32) +BACKUP_ENCRYPTION_KEY=your_64_char_hex_key_here + +# MPC Share Master Key (256-bit hex: openssl rand -hex 32) +SHARE_MASTER_KEY=your_64_char_hex_key_here + +# MPC System Address (running on 192.168.1.100) +MPC_COORDINATOR_URL=http://192.168.1.100:8081 +MPC_MESSAGE_ROUTER_URL=ws://192.168.1.100:8082 diff --git a/backend/services/.gitignore b/backend/services/.gitignore new file mode 100644 index 00000000..ca386f0e --- /dev/null +++ b/backend/services/.gitignore @@ -0,0 +1,16 @@ +# Environment files (contain secrets) +.env +.env.local +.env.production.local + +# Docker volumes (if local) +postgres_data/ +redis_data/ + +# Logs +*.log +logs/ + +# OS files +.DS_Store +Thumbs.db diff --git a/backend/services/README.md b/backend/services/README.md new file mode 100644 index 00000000..7b5b8385 --- /dev/null +++ b/backend/services/README.md @@ -0,0 +1,173 @@ +# RWA Backend Services + +็ปŸไธ€้ƒจ็ฝฒ็ฎก็† RWA ๅŽ็ซฏๅพฎๆœๅŠกใ€‚ + +## ๆžถๆž„ๆฆ‚่งˆ + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ 192.168.1.100 (Gateway) โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Nginx โ”‚ โ”‚ MPC-System (Go) โ”‚ โ”‚ +โ”‚ โ”‚ (Reverse โ”‚ โ”‚ - session-coordinator (:8081) โ”‚ โ”‚ +โ”‚ โ”‚ Proxy) โ”‚ โ”‚ - message-router (:8082) โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ - server-party-1/2/3 (:8083-8085) โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ - account-service (:8080) โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ”‚ Internal Network + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ 192.168.1.111 (Backend) โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Docker Compose Services โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ PostgreSQL โ”‚ โ”‚ Redis โ”‚ โ”‚ Kafka โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ (:5432) โ”‚ โ”‚ (:6379) โ”‚ โ”‚ (:9092) โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ identity โ”‚ โ”‚ wallet โ”‚ โ”‚ backup โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ (:3000) โ”‚ โ”‚ (:3001) โ”‚ โ”‚ (:3002) โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ planting โ”‚ โ”‚ referral โ”‚ โ”‚ reward โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ (:3003) โ”‚ โ”‚ (:3004) โ”‚ โ”‚ (:3005) โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ mpc โ”‚ โ”‚ leaderboard โ”‚ โ”‚ reporting โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ (:3006) โ”‚ โ”‚ (:3007) โ”‚ โ”‚ (:3008) โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚authorizationโ”‚ โ”‚ admin โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ”‚ (:3009) โ”‚ โ”‚ (:3010) โ”‚ โ”‚ โ”‚ +โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +## ๅฟซ้€Ÿๅผ€ๅง‹ + +### 1. ้ฆ–ๆฌกๅฎ‰่ฃ… + +```bash +# ่ฟ›ๅ…ฅๆœๅŠก็›ฎๅฝ• +cd ~/rwadurian/backend/services + +# ่ฟ่กŒๅฎ‰่ฃ…๏ผˆ่‡ชๅŠจ็”Ÿๆˆๅฎ‰ๅ…จๅฏ†้’ฅ๏ผ‰ +./deploy.sh install +``` + +### 2. ๆž„ๅปบ้•œๅƒ + +```bash +./deploy.sh build +``` + +### 3. ๅฏๅŠจๆœๅŠก + +```bash +./deploy.sh up +``` + +### 4. ๆฃ€ๆŸฅ็Šถๆ€ + +```bash +./deploy.sh status +./deploy.sh health +``` + +## ๅธธ็”จๅ‘ฝไปค + +| ๅ‘ฝไปค | ่ฏดๆ˜Ž | +|------|------| +| `./deploy.sh install` | ้ฆ–ๆฌกๅฎ‰่ฃ…๏ผŒ็”Ÿๆˆ้…็ฝฎ | +| `./deploy.sh build` | ๆž„ๅปบๆ‰€ๆœ‰ Docker ้•œๅƒ | +| `./deploy.sh up` | ๅฏๅŠจๆ‰€ๆœ‰ๆœๅŠก | +| `./deploy.sh down` | ๅœๆญขๆ‰€ๆœ‰ๆœๅŠก | +| `./deploy.sh restart` | ้‡ๅฏๆ‰€ๆœ‰ๆœๅŠก | +| `./deploy.sh status` | ๆŸฅ็œ‹ๆœๅŠก็Šถๆ€ | +| `./deploy.sh health` | ๆฃ€ๆŸฅๆœๅŠกๅฅๅบท | +| `./deploy.sh logs` | ๆŸฅ็œ‹ๆ‰€ๆœ‰ๆ—ฅๅฟ— | +| `./deploy.sh logs ` | ๆŸฅ็œ‹ๆŒ‡ๅฎšๆœๅŠกๆ—ฅๅฟ— | +| `./deploy.sh migrate` | ่ฟ่กŒๆ•ฐๆฎๅบ“่ฟ็งป | +| `./deploy.sh rebuild-svc ` | ้‡ๅปบๆŒ‡ๅฎšๆœๅŠก | + +## ๆœๅŠกๅˆ—่กจ + +| ๆœๅŠก | ็ซฏๅฃ | ่ฏดๆ˜Ž | +|------|------|------| +| identity-service | 3000 | ่บซไปฝ่ฎค่ฏๆœๅŠก | +| wallet-service | 3001 | ้’ฑๅŒ…่ดฆๆœฌๆœๅŠก | +| backup-service | 3002 | MPC ๅค‡ไปฝๆœๅŠก | +| planting-service | 3003 | ่ฎค็งๆœๅŠก | +| referral-service | 3004 | ๆŽจ่็ณป็ปŸๆœๅŠก | +| reward-service | 3005 | ๅฅ–ๅŠฑๆœๅŠก | +| mpc-service | 3006 | MPC ไธญ้—ดๅฑ‚ๆœๅŠก | +| leaderboard-service | 3007 | ๆŽ’่กŒๆฆœๆœๅŠก | +| reporting-service | 3008 | ๆŠฅ่กจๆœๅŠก | +| authorization-service | 3009 | ๆŽˆๆƒๆœๅŠก | +| admin-service | 3010 | ็ฎก็†ๅŽๅฐๆœๅŠก | + +## ๅŸบ็ก€่ฎพๆ–ฝ + +| ๆœๅŠก | ็ซฏๅฃ | ่ฏดๆ˜Ž | +|------|------|------| +| PostgreSQL | 5432 | ไธปๆ•ฐๆฎๅบ“ | +| Redis | 6379 | ็ผ“ๅญ˜/ไผš่ฏ | +| Kafka | 9092 | ๆถˆๆฏ้˜Ÿๅˆ— | +| Zookeeper | 2181 | Kafka ๅ่ฐƒ | + +## ็Žฏๅขƒ้…็ฝฎ + +้…็ฝฎๆ–‡ไปถ `.env` ็”ฑ `./deploy.sh install` ่‡ชๅŠจ็”Ÿๆˆ๏ผŒๅŒ…ๅซ๏ผš + +- ๆ•ฐๆฎๅบ“ๅฏ†็  +- JWT ๅฏ†้’ฅ +- ๅŠ ๅฏ†ๅฏ†้’ฅ +- MPC ็ณป็ปŸๅœฐๅ€ + +**้‡่ฆ**: `.env` ๆ–‡ไปถๅŒ…ๅซๆ•ๆ„Ÿไฟกๆฏ๏ผŒ่ฏทๅ‹ฟๆไบคๅˆฐ Git๏ผ + +## ไธŽ MPC-System ้›†ๆˆ + +mpc-service ้œ€่ฆ่ฟžๆŽฅๅˆฐ่ฟ่กŒๅœจ 192.168.1.100 ไธŠ็š„ MPC-System๏ผš + +- Session Coordinator: `http://192.168.1.100:8081` +- Message Router: `ws://192.168.1.100:8082` + +็กฎไฟ 192.168.1.111 ่ƒฝๅคŸ่ฎฟ้—ฎ 192.168.1.100 ็š„่ฟ™ไบ›็ซฏๅฃใ€‚ + +## ๆ•…้šœๆŽ’้™ค + +### ๆŸฅ็œ‹ๆœๅŠกๆ—ฅๅฟ— + +```bash +./deploy.sh logs identity-service +``` + +### ้‡ๅปบๅ•ไธชๆœๅŠก + +```bash +./deploy.sh rebuild-svc mpc-service +``` + +### ๆ•ฐๆฎๅบ“่ฟžๆŽฅ้—ฎ้ข˜ + +```bash +# ่ฟ›ๅ…ฅ postgres ๅฎนๅ™จ +docker exec -it rwa-postgres psql -U rwa_user -d rwa_identity +``` + +### ๆธ…็†้‡ๆ–ฐๅผ€ๅง‹ + +```bash +./deploy.sh clean # ๅˆ ้™คๆ‰€ๆœ‰ๅฎนๅ™จๅ’Œๆ•ฐๆฎ +./deploy.sh install +./deploy.sh build +./deploy.sh up +``` diff --git a/backend/services/admin-service/Dockerfile b/backend/services/admin-service/Dockerfile index e69de29b..5fef8a4d 100644 --- a/backend/services/admin-service/Dockerfile +++ b/backend/services/admin-service/Dockerfile @@ -0,0 +1,61 @@ +# ============================================================================= +# Admin Service Dockerfile +# ============================================================================= + +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ +COPY tsconfig*.json ./ +COPY nest-cli.json ./ + +# Copy Prisma schema if exists +COPY prisma ./prisma/ 2>/dev/null || true + +# Install dependencies +RUN npm ci + +# Generate Prisma client if schema exists +RUN if [ -f "prisma/schema.prisma" ]; then npx prisma generate; fi + +# Copy source code +COPY src ./src + +# Build TypeScript +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +# Install production dependencies only +COPY package*.json ./ +RUN npm ci --only=production + +# Copy Prisma schema and generate client if exists +COPY prisma ./prisma/ 2>/dev/null || true +RUN if [ -f "prisma/schema.prisma" ]; then npx prisma generate; fi + +# Copy built files +COPY --from=builder /app/dist ./dist + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nestjs -u 1001 + +# Switch to non-root user +USER nestjs + +# Expose port +EXPOSE 3010 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget -q --spider http://localhost:3010/health || exit 1 + +# Start service +CMD ["node", "dist/main.js"] diff --git a/backend/services/deploy.sh b/backend/services/deploy.sh new file mode 100644 index 00000000..606e4223 --- /dev/null +++ b/backend/services/deploy.sh @@ -0,0 +1,470 @@ +#!/bin/bash +# +# RWA Backend Services - Deployment Script +# ========================================= +# +# Usage: +# ./deploy.sh install # First time setup (generate secrets, init databases) +# ./deploy.sh up # Start all services +# ./deploy.sh down # Stop all services +# ./deploy.sh restart # Restart all services +# ./deploy.sh status # Show service status +# ./deploy.sh logs [svc] # View logs (optional: specific service) +# ./deploy.sh build # Rebuild all images +# ./deploy.sh migrate # Run database migrations +# ./deploy.sh health # Check health of all services +# + +set -e + +# =========================================================================== +# Configuration +# =========================================================================== +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="$SCRIPT_DIR/.env" +COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } +log_step() { echo -e "${BLUE}[STEP]${NC} $1"; } + +# =========================================================================== +# Helper Functions +# =========================================================================== + +generate_random_password() { + openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32 +} + +generate_hex_key() { + openssl rand -hex 32 +} + +check_docker() { + if ! command -v docker &> /dev/null; then + log_error "Docker is not installed. Please install Docker first." + exit 1 + fi + + if ! docker compose version &> /dev/null; then + log_error "Docker Compose is not installed. Please install Docker Compose first." + exit 1 + fi + + log_info "Docker version: $(docker --version)" + log_info "Docker Compose version: $(docker compose version --short)" +} + +# =========================================================================== +# Install / Initialize +# =========================================================================== + +install() { + log_step "Installing RWA Backend Services..." + + check_docker + + # Generate .env file if not exists + if [ ! -f "$ENV_FILE" ]; then + log_step "Generating secure configuration..." + + POSTGRES_PASSWORD=$(generate_random_password) + JWT_SECRET=$(generate_random_password) + SERVICE_JWT_SECRET=$(generate_random_password) + WALLET_ENCRYPTION_SALT=$(generate_random_password) + BACKUP_ENCRYPTION_KEY=$(generate_hex_key) + SHARE_MASTER_KEY=$(generate_hex_key) + + cat > "$ENV_FILE" << EOF +# ============================================================================= +# RWA Backend Services - Production Environment Configuration +# ============================================================================= +# Generated: $(date) +# WARNING: Keep this file secure! Do not commit to version control! +# ============================================================================= + +# PostgreSQL Database +POSTGRES_USER=rwa_user +POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + +# Redis (leave empty for no password) +REDIS_PASSWORD= + +# JWT Configuration +JWT_SECRET=${JWT_SECRET} + +# Service-to-Service Authentication +SERVICE_JWT_SECRET=${SERVICE_JWT_SECRET} + +# Wallet Encryption +WALLET_ENCRYPTION_SALT=${WALLET_ENCRYPTION_SALT} + +# Backup Encryption (256-bit hex key) +BACKUP_ENCRYPTION_KEY=${BACKUP_ENCRYPTION_KEY} + +# MPC Share Master Key (256-bit hex key) +SHARE_MASTER_KEY=${SHARE_MASTER_KEY} + +# MPC System Address (on 192.168.1.100) +MPC_COORDINATOR_URL=http://192.168.1.100:8081 +MPC_MESSAGE_ROUTER_URL=ws://192.168.1.100:8082 +EOF + + chmod 600 "$ENV_FILE" + log_info "Environment file created: $ENV_FILE" + log_info "Secrets have been auto-generated" + else + log_info "Environment file already exists: $ENV_FILE" + fi + + # Create scripts directory + mkdir -p "$SCRIPT_DIR/scripts" + + # Create database init script + create_db_init_script + + log_info "Installation complete!" + log_info "" + log_info "Next steps:" + log_info " 1. Review and edit .env if needed" + log_info " 2. Run: ./deploy.sh build" + log_info " 3. Run: ./deploy.sh up" +} + +create_db_init_script() { + cat > "$SCRIPT_DIR/scripts/init-databases.sh" << 'DBSCRIPT' +#!/bin/bash +set -e + +# Function to create database if not exists +create_database() { + local database=$1 + echo "Creating database: $database" + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL + SELECT 'CREATE DATABASE $database' + WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$database')\gexec +EOSQL +} + +# Create all required databases +for db in rwa_identity rwa_wallet rwa_mpc rwa_backup rwa_planting rwa_referral rwa_reward rwa_leaderboard rwa_reporting rwa_authorization; do + create_database "$db" +done + +echo "All databases created successfully!" +DBSCRIPT + + chmod +x "$SCRIPT_DIR/scripts/init-databases.sh" + log_info "Database init script created" +} + +# =========================================================================== +# Docker Compose Operations +# =========================================================================== + +up() { + log_step "Starting RWA Backend Services..." + + if [ ! -f "$ENV_FILE" ]; then + log_error "Environment file not found. Run './deploy.sh install' first." + exit 1 + fi + + # Start infrastructure first + log_info "Starting infrastructure services..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d postgres redis zookeeper kafka + + # Wait for infrastructure + log_info "Waiting for infrastructure to be ready..." + sleep 10 + + # Start application services + log_info "Starting application services..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d + + log_info "All services started!" + log_info "" + log_info "Check status with: ./deploy.sh status" + log_info "View logs with: ./deploy.sh logs" +} + +down() { + log_step "Stopping RWA Backend Services..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" down + log_info "All services stopped" +} + +restart() { + log_step "Restarting RWA Backend Services..." + down + sleep 3 + up +} + +build() { + log_step "Building Docker images..." + + if [ ! -f "$ENV_FILE" ]; then + log_error "Environment file not found. Run './deploy.sh install' first." + exit 1 + fi + + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" build --parallel + log_info "All images built successfully" +} + +# =========================================================================== +# Status and Monitoring +# =========================================================================== + +status() { + echo "" + echo "============================================" + echo "RWA Backend Services Status" + echo "============================================" + echo "" + + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" ps + + echo "" + echo "============================================" + echo "Service Health Check" + echo "============================================" + echo "" + + health +} + +health() { + local services=( + "identity-service:3000" + "wallet-service:3001" + "backup-service:3002" + "planting-service:3003" + "referral-service:3004" + "reward-service:3005" + "mpc-service:3006" + "leaderboard-service:3007" + "reporting-service:3008" + "authorization-service:3009" + "admin-service:3010" + ) + + for svc in "${services[@]}"; do + name="${svc%%:*}" + port="${svc##*:}" + + if curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port/health" 2>/dev/null | grep -q "200"; then + echo -e "${GREEN}[OK]${NC} $name (port $port)" + else + echo -e "${RED}[FAIL]${NC} $name (port $port)" + fi + done + + echo "" + + # Infrastructure health + echo "Infrastructure:" + + if docker exec rwa-postgres pg_isready -U rwa_user &>/dev/null; then + echo -e " ${GREEN}[OK]${NC} PostgreSQL" + else + echo -e " ${RED}[FAIL]${NC} PostgreSQL" + fi + + if docker exec rwa-redis redis-cli ping &>/dev/null; then + echo -e " ${GREEN}[OK]${NC} Redis" + else + echo -e " ${RED}[FAIL]${NC} Redis" + fi + + if docker exec rwa-kafka kafka-topics --bootstrap-server localhost:9092 --list &>/dev/null; then + echo -e " ${GREEN}[OK]${NC} Kafka" + else + echo -e " ${RED}[FAIL]${NC} Kafka" + fi +} + +logs() { + local service="$1" + + if [ -n "$service" ]; then + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs -f "$service" + else + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" logs -f + fi +} + +# =========================================================================== +# Database Operations +# =========================================================================== + +migrate() { + log_step "Running database migrations..." + + local services=( + "identity-service" + "wallet-service" + "backup-service" + "planting-service" + "referral-service" + "reward-service" + "mpc-service" + "leaderboard-service" + "reporting-service" + "authorization-service" + ) + + for svc in "${services[@]}"; do + log_info "Running migrations for $svc..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec "$svc" npx prisma migrate deploy 2>/dev/null || \ + log_warn "Migration skipped for $svc (no migrations or service not running)" + done + + log_info "Migrations complete" +} + +# =========================================================================== +# Cleanup +# =========================================================================== + +clean() { + log_warn "This will remove all containers, volumes, and images!" + read -p "Are you sure? (y/N): " confirm + + if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then + log_step "Cleaning up..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" down -v --rmi all + log_info "Cleanup complete" + else + log_info "Cleanup cancelled" + fi +} + +# =========================================================================== +# Single Service Operations +# =========================================================================== + +start_service() { + local service="$1" + if [ -z "$service" ]; then + log_error "Please specify a service name" + exit 1 + fi + + log_info "Starting $service..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d "$service" +} + +stop_service() { + local service="$1" + if [ -z "$service" ]; then + log_error "Please specify a service name" + exit 1 + fi + + log_info "Stopping $service..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" stop "$service" +} + +rebuild_service() { + local service="$1" + if [ -z "$service" ]; then + log_error "Please specify a service name" + exit 1 + fi + + log_info "Rebuilding $service..." + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" build "$service" + docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d "$service" +} + +# =========================================================================== +# Main +# =========================================================================== + +case "${1:-}" in + install) + install + ;; + up|start) + up + ;; + down|stop) + down + ;; + restart) + restart + ;; + build) + build + ;; + status|ps) + status + ;; + health) + health + ;; + logs) + logs "$2" + ;; + migrate) + migrate + ;; + clean) + clean + ;; + start-svc) + start_service "$2" + ;; + stop-svc) + stop_service "$2" + ;; + rebuild-svc) + rebuild_service "$2" + ;; + *) + echo "RWA Backend Services Deployment Script" + echo "" + echo "Usage: $0 [options]" + echo "" + echo "Commands:" + echo " install - First time setup (generate secrets, create configs)" + echo " up/start - Start all services" + echo " down/stop - Stop all services" + echo " restart - Restart all services" + echo " build - Build all Docker images" + echo " status/ps - Show service status" + echo " health - Check health of all services" + echo " logs [svc] - View logs (optionally for specific service)" + echo " migrate - Run database migrations" + echo " clean - Remove all containers, volumes, and images" + echo "" + echo "Single Service Commands:" + echo " start-svc - Start a specific service" + echo " stop-svc - Stop a specific service" + echo " rebuild-svc - Rebuild and restart a specific service" + echo "" + echo "Services:" + echo " identity-service, wallet-service, backup-service, planting-service," + echo " referral-service, reward-service, mpc-service, leaderboard-service," + echo " reporting-service, authorization-service, admin-service" + echo "" + echo "Examples:" + echo " $0 install # First time setup" + echo " $0 build # Build images" + echo " $0 up # Start all services" + echo " $0 logs identity-service # View identity-service logs" + echo " $0 rebuild-svc mpc-service # Rebuild specific service" + echo "" + exit 1 + ;; +esac diff --git a/backend/services/docker-compose.yml b/backend/services/docker-compose.yml new file mode 100644 index 00000000..87026de7 --- /dev/null +++ b/backend/services/docker-compose.yml @@ -0,0 +1,510 @@ +# ============================================================================= +# RWA Backend Services - Docker Compose +# ============================================================================= +# Usage: +# ./deploy.sh up # Start all services +# ./deploy.sh down # Stop all services +# ./deploy.sh logs # View logs +# ./deploy.sh status # Check status +# ============================================================================= + +services: + # =========================================================================== + # Infrastructure Services + # =========================================================================== + + postgres: + image: postgres:16-alpine + container_name: rwa-postgres + environment: + POSTGRES_USER: ${POSTGRES_USER:-rwa_user} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-rwa_secure_password} + POSTGRES_MULTIPLE_DATABASES: rwa_identity,rwa_wallet,rwa_mpc,rwa_backup,rwa_planting,rwa_referral,rwa_reward,rwa_leaderboard,rwa_reporting,rwa_authorization + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + - ./scripts/init-databases.sh:/docker-entrypoint-initdb.d/init-databases.sh:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-rwa_user}"] + interval: 5s + timeout: 5s + retries: 10 + restart: unless-stopped + networks: + - rwa-network + + redis: + image: redis:7-alpine + container_name: rwa-redis + command: redis-server --appendonly yes ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD} + ports: + - "6379:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 5s + retries: 10 + restart: unless-stopped + networks: + - rwa-network + + zookeeper: + image: confluentinc/cp-zookeeper:7.5.0 + container_name: rwa-zookeeper + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: 2000 + healthcheck: + test: ["CMD", "nc", "-z", "localhost", "2181"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + networks: + - rwa-network + + kafka: + image: confluentinc/cp-kafka:7.5.0 + container_name: rwa-kafka + depends_on: + zookeeper: + condition: service_healthy + ports: + - "9092:9092" + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:29092,PLAINTEXT_HOST://0.0.0.0:9092 + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" + healthcheck: + test: ["CMD", "kafka-topics", "--bootstrap-server", "localhost:9092", "--list"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + restart: unless-stopped + networks: + - rwa-network + + # =========================================================================== + # Application Services + # =========================================================================== + + identity-service: + build: + context: ./identity-service + dockerfile: Dockerfile + container_name: rwa-identity-service + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - APP_PORT=3000 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_identity?schema=public + - JWT_SECRET=${JWT_SECRET} + - JWT_ACCESS_EXPIRES_IN=2h + - JWT_REFRESH_EXPIRES_IN=30d + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=0 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=identity-service + - KAFKA_GROUP_ID=identity-service-group + - WALLET_ENCRYPTION_SALT=${WALLET_ENCRYPTION_SALT} + - MPC_SERVICE_URL=http://mpc-service:3006 + - MPC_MODE=remote + - BACKUP_SERVICE_URL=http://backup-service:3002 + - BACKUP_SERVICE_ENABLED=true + - SERVICE_JWT_SECRET=${SERVICE_JWT_SECRET} + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + wallet-service: + build: + context: ./wallet-service + dockerfile: Dockerfile + container_name: rwa-wallet-service + ports: + - "3001:3001" + environment: + - NODE_ENV=production + - APP_PORT=3001 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_wallet?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=1 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=wallet-service + - KAFKA_GROUP_ID=wallet-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3001/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + backup-service: + build: + context: ./backup-service + dockerfile: Dockerfile + container_name: rwa-backup-service + ports: + - "3002:3002" + environment: + - NODE_ENV=production + - APP_PORT=3002 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_backup?schema=public + - SERVICE_JWT_SECRET=${SERVICE_JWT_SECRET} + - ALLOWED_SERVICES=identity-service,recovery-service + - BACKUP_ENCRYPTION_KEY=${BACKUP_ENCRYPTION_KEY} + - BACKUP_ENCRYPTION_KEY_ID=key-v1 + - MAX_RETRIEVE_PER_DAY=3 + - MAX_STORE_PER_MINUTE=10 + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3002/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + planting-service: + build: + context: ./planting-service + dockerfile: Dockerfile + container_name: rwa-planting-service + ports: + - "3003:3003" + environment: + - NODE_ENV=production + - APP_PORT=3003 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_planting?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=2 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=planting-service + - KAFKA_GROUP_ID=planting-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3003/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + referral-service: + build: + context: ./referral-service + dockerfile: Dockerfile + container_name: rwa-referral-service + ports: + - "3004:3004" + environment: + - NODE_ENV=production + - APP_PORT=3004 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_referral?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=3 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=referral-service + - KAFKA_GROUP_ID=referral-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3004/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + reward-service: + build: + context: ./reward-service + dockerfile: Dockerfile + container_name: rwa-reward-service + ports: + - "3005:3005" + environment: + - NODE_ENV=production + - APP_PORT=3005 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_reward?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=4 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=reward-service + - KAFKA_GROUP_ID=reward-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3005/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + mpc-service: + build: + context: ./mpc-service + dockerfile: Dockerfile + container_name: rwa-mpc-service + ports: + - "3006:3006" + environment: + - NODE_ENV=production + - APP_PORT=3006 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_mpc?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=5 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=mpc-service + - KAFKA_GROUP_ID=mpc-service-group + - MPC_COORDINATOR_URL=http://192.168.1.100:8081 + - MPC_MESSAGE_ROUTER_WS_URL=ws://192.168.1.100:8082 + - SHARE_MASTER_KEY=${SHARE_MASTER_KEY} + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3006/api/v1/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + leaderboard-service: + build: + context: ./leaderboard-service + dockerfile: Dockerfile + container_name: rwa-leaderboard-service + ports: + - "3007:3007" + environment: + - NODE_ENV=production + - APP_PORT=3007 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_leaderboard?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=6 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=leaderboard-service + - KAFKA_GROUP_ID=leaderboard-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3007/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + reporting-service: + build: + context: ./reporting-service + dockerfile: Dockerfile + container_name: rwa-reporting-service + ports: + - "3008:3008" + environment: + - NODE_ENV=production + - APP_PORT=3008 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_reporting?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=7 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=reporting-service + - KAFKA_GROUP_ID=reporting-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3008/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + authorization-service: + build: + context: ./authorization-service + dockerfile: Dockerfile + container_name: rwa-authorization-service + ports: + - "3009:3009" + environment: + - NODE_ENV=production + - APP_PORT=3009 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_authorization?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=8 + - KAFKA_BROKERS=kafka:29092 + - KAFKA_CLIENT_ID=authorization-service + - KAFKA_GROUP_ID=authorization-service-group + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_started + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3009/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + + admin-service: + build: + context: ./admin-service + dockerfile: Dockerfile + container_name: rwa-admin-service + ports: + - "3010:3010" + environment: + - NODE_ENV=production + - APP_PORT=3010 + - DATABASE_URL=postgresql://${POSTGRES_USER:-rwa_user}:${POSTGRES_PASSWORD:-rwa_secure_password}@postgres:5432/rwa_identity?schema=public + - JWT_SECRET=${JWT_SECRET} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_PASSWORD=${REDIS_PASSWORD:-} + - REDIS_DB=9 + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3010/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + networks: + - rwa-network + +# =========================================================================== +# Volumes +# =========================================================================== +volumes: + postgres_data: + driver: local + redis_data: + driver: local + +# =========================================================================== +# Networks +# =========================================================================== +networks: + rwa-network: + driver: bridge diff --git a/backend/services/referral-service/Dockerfile b/backend/services/referral-service/Dockerfile index e69de29b..9e8e6e48 100644 --- a/backend/services/referral-service/Dockerfile +++ b/backend/services/referral-service/Dockerfile @@ -0,0 +1,61 @@ +# ============================================================================= +# Referral Service Dockerfile +# ============================================================================= + +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ +COPY tsconfig*.json ./ +COPY nest-cli.json ./ + +# Copy Prisma schema +COPY prisma ./prisma/ + +# Install dependencies +RUN npm ci + +# Generate Prisma client +RUN npx prisma generate + +# Copy source code +COPY src ./src + +# Build TypeScript +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +# Install production dependencies only +COPY package*.json ./ +RUN npm ci --only=production + +# Copy Prisma schema and generate client +COPY prisma ./prisma/ +RUN npx prisma generate + +# Copy built files +COPY --from=builder /app/dist ./dist + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nestjs -u 1001 + +# Switch to non-root user +USER nestjs + +# Expose port +EXPOSE 3004 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget -q --spider http://localhost:3004/health || exit 1 + +# Start service +CMD ["node", "dist/main.js"] diff --git a/backend/services/reporting-service/Dockerfile b/backend/services/reporting-service/Dockerfile index e69de29b..08ab8368 100644 --- a/backend/services/reporting-service/Dockerfile +++ b/backend/services/reporting-service/Dockerfile @@ -0,0 +1,61 @@ +# ============================================================================= +# Reporting Service Dockerfile +# ============================================================================= + +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ +COPY tsconfig*.json ./ +COPY nest-cli.json ./ + +# Copy Prisma schema +COPY prisma ./prisma/ + +# Install dependencies +RUN npm ci + +# Generate Prisma client +RUN npx prisma generate + +# Copy source code +COPY src ./src + +# Build TypeScript +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +# Install production dependencies only +COPY package*.json ./ +RUN npm ci --only=production + +# Copy Prisma schema and generate client +COPY prisma ./prisma/ +RUN npx prisma generate + +# Copy built files +COPY --from=builder /app/dist ./dist + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nestjs -u 1001 + +# Switch to non-root user +USER nestjs + +# Expose port +EXPOSE 3008 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget -q --spider http://localhost:3008/health || exit 1 + +# Start service +CMD ["node", "dist/main.js"] diff --git a/backend/services/scripts/init-databases.sh b/backend/services/scripts/init-databases.sh new file mode 100644 index 00000000..02687005 --- /dev/null +++ b/backend/services/scripts/init-databases.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +# Function to create database if not exists +create_database() { + local database=$1 + echo "Creating database: $database" + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL + SELECT 'CREATE DATABASE $database' + WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$database')\gexec +EOSQL +} + +# Create all required databases +for db in rwa_identity rwa_wallet rwa_mpc rwa_backup rwa_planting rwa_referral rwa_reward rwa_leaderboard rwa_reporting rwa_authorization; do + create_database "$db" +done + +echo "All databases created successfully!" diff --git a/backend/services/wallet-service/Dockerfile b/backend/services/wallet-service/Dockerfile index e69de29b..9c9df090 100644 --- a/backend/services/wallet-service/Dockerfile +++ b/backend/services/wallet-service/Dockerfile @@ -0,0 +1,61 @@ +# ============================================================================= +# Wallet Service Dockerfile +# ============================================================================= + +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ +COPY tsconfig*.json ./ +COPY nest-cli.json ./ + +# Copy Prisma schema +COPY prisma ./prisma/ + +# Install dependencies +RUN npm ci + +# Generate Prisma client +RUN npx prisma generate + +# Copy source code +COPY src ./src + +# Build TypeScript +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +# Install production dependencies only +COPY package*.json ./ +RUN npm ci --only=production + +# Copy Prisma schema and generate client +COPY prisma ./prisma/ +RUN npx prisma generate + +# Copy built files +COPY --from=builder /app/dist ./dist + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nestjs -u 1001 + +# Switch to non-root user +USER nestjs + +# Expose port +EXPOSE 3001 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget -q --spider http://localhost:3001/health || exit 1 + +# Start service +CMD ["node", "dist/main.js"]