feat(services): add unified Docker deployment system

- 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 <noreply@anthropic.com>
This commit is contained in:
Developer 2025-12-02 02:12:49 -08:00
parent 7d257cd35f
commit f99cac21cf
10 changed files with 1464 additions and 0 deletions

View File

@ -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

16
backend/services/.gitignore vendored Normal file
View File

@ -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

173
backend/services/README.md Normal file
View File

@ -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 <service>` | 查看指定服务日志 |
| `./deploy.sh migrate` | 运行数据库迁移 |
| `./deploy.sh rebuild-svc <name>` | 重建指定服务 |
## 服务列表
| 服务 | 端口 | 说明 |
|------|------|------|
| 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
```

View File

@ -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"]

470
backend/services/deploy.sh Normal file
View File

@ -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 <command> [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 <name> - Start a specific service"
echo " stop-svc <name> - Stop a specific service"
echo " rebuild-svc <name> - 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

View File

@ -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

View File

@ -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"]

View File

@ -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"]

View File

@ -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!"

View File

@ -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"]