docs: 添加系统部署指南和更新 API 配置
添加 DEPLOYMENT_GUIDE.md: - 完整的 Nginx 反向代理配置 (rwaapi.szaiai.com) - Docker Compose 生产环境部署配置 - 后端服务端口规划和 API 路由映射 - 前端 API 调用对照表 - SSL/HTTPS 配置说明 - 部署步骤和常见问题 更新前端 API 配置: - api_endpoints.dart: 更新 baseUrl 为 https://rwaapi.szaiai.com - api_endpoints.dart: 添加 /api/v1 前缀到所有端点 - api_endpoints.dart: 添加 telemetry 遥测端点 - api_client.dart: 更新默认 baseUrl 为生产环境地址 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
acb424a2da
commit
2d50ad32a9
|
|
@ -0,0 +1,781 @@
|
|||
# RWA Durian 系统部署指南
|
||||
|
||||
本文档描述了 RWA Durian 系统的完整部署架构,包括前端 API 调用、Nginx 反向代理配置和后端服务部署。
|
||||
|
||||
## 1. 系统架构概览
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 用户设备 │
|
||||
│ (Android/iOS App) │
|
||||
└─────────────────────────────────┬───────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ https://rwaapi.szaiai.com │
|
||||
│ (Nginx 反向代理) │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ /identity │ │ /wallet │ │ /planting │ │ /referral │ ... │
|
||||
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
||||
└─────────┼───────────────┼───────────────┼───────────────┼───────────────────┘
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Docker Network │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ Identity │ │ Wallet │ │ Planting │ │ Referral │ ... │
|
||||
│ │ :3000 │ │ :3002 │ │ :3003 │ │ :3004 │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ PostgreSQL │ │ Redis │ │ Kafka │ │
|
||||
│ │ :5432 │ │ :6379 │ │ :9092 │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 2. 后端服务端口规划
|
||||
|
||||
| 服务名称 | 端口 | API 前缀 | 说明 |
|
||||
|---------|------|----------|------|
|
||||
| Identity Service | 3000 | `/api/v1` | 用户身份、认证、钱包创建 |
|
||||
| MPC Service | 3001 | `/api/v1` | MPC 密钥分片管理 |
|
||||
| Wallet Service | 3002 | `/api/v1` | 钱包余额、交易 |
|
||||
| Planting Service | 3003 | `/api/v1` | 认种业务 |
|
||||
| Referral Service | 3004 | `/api/v1` | 推荐关系、分享 |
|
||||
| Reward Service | 3005 | `/api/v1` | 挖矿奖励、收益 |
|
||||
| Authorization Service | 3006 | `/api/v1` | 权限管理 |
|
||||
| Leaderboard Service | 3007 | `/api` | 排行榜 |
|
||||
| Reporting Service | 3008 | `/api/v1` | 遥测统计、报表 |
|
||||
| Backup Service | 3009 | - | MPC 备份 (内部服务) |
|
||||
|
||||
## 3. Nginx 配置
|
||||
|
||||
### 3.1 主配置文件 `/etc/nginx/nginx.conf`
|
||||
|
||||
```nginx
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'rt=$request_time uct="$upstream_connect_time" '
|
||||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml application/json application/javascript
|
||||
application/xml application/xml+rss text/javascript;
|
||||
|
||||
# 限流配置
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 API 网关配置 `/etc/nginx/conf.d/rwaapi.conf`
|
||||
|
||||
```nginx
|
||||
# 上游服务定义
|
||||
upstream identity_service {
|
||||
server identity-service:3000;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream wallet_service {
|
||||
server wallet-service:3002;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream planting_service {
|
||||
server planting-service:3003;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream referral_service {
|
||||
server referral-service:3004;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream reward_service {
|
||||
server reward-service:3005;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream leaderboard_service {
|
||||
server leaderboard-service:3007;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
upstream reporting_service {
|
||||
server reporting-service:3008;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name rwaapi.szaiai.com;
|
||||
|
||||
# 强制 HTTPS 重定向
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name rwaapi.szaiai.com;
|
||||
|
||||
# SSL 证书配置
|
||||
ssl_certificate /etc/nginx/ssl/rwaapi.szaiai.com.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/rwaapi.szaiai.com.key;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:50m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
# 现代 SSL 配置
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# HSTS
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
|
||||
# 安全头
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# CORS 配置
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
|
||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
||||
|
||||
# 处理 OPTIONS 预检请求
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
# 限流
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
limit_conn conn_limit 10;
|
||||
|
||||
# 健康检查端点
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 'OK';
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Identity Service - 用户身份认证
|
||||
# ============================================
|
||||
location /api/v1/user {
|
||||
proxy_pass http://identity_service/api/v1/user;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/auth {
|
||||
proxy_pass http://identity_service/api/v1/auth;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Wallet Service - 钱包操作
|
||||
# ============================================
|
||||
location /api/v1/wallet {
|
||||
proxy_pass http://wallet_service/api/v1/wallet;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/trading {
|
||||
proxy_pass http://wallet_service/api/v1/trading;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/deposit {
|
||||
proxy_pass http://wallet_service/api/v1/deposit;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Planting Service - 认种业务
|
||||
# ============================================
|
||||
location /api/v1/planting {
|
||||
proxy_pass http://planting_service/api/v1/planting;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Referral Service - 推荐系统
|
||||
# ============================================
|
||||
location /api/v1/referral {
|
||||
proxy_pass http://referral_service/api/v1/referral;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/community {
|
||||
proxy_pass http://referral_service/api/v1/community;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Reward Service - 挖矿奖励
|
||||
# ============================================
|
||||
location /api/v1/mining {
|
||||
proxy_pass http://reward_service/api/v1/mining;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/reward {
|
||||
proxy_pass http://reward_service/api/v1/reward;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Leaderboard Service - 排行榜
|
||||
# ============================================
|
||||
location /api/v1/ranking {
|
||||
proxy_pass http://leaderboard_service/api/ranking;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/leaderboard {
|
||||
proxy_pass http://leaderboard_service/api/leaderboard;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# Reporting Service - 遥测统计
|
||||
# ============================================
|
||||
location /api/v1/telemetry {
|
||||
proxy_pass http://reporting_service/api/v1/telemetry;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
location /api/v1/report {
|
||||
proxy_pass http://reporting_service/api/v1/report;
|
||||
include /etc/nginx/conf.d/proxy_params.conf;
|
||||
}
|
||||
|
||||
# 默认 404
|
||||
location / {
|
||||
return 404 '{"error": "Not Found", "message": "API endpoint not found"}';
|
||||
add_header Content-Type application/json;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 代理参数配置 `/etc/nginx/conf.d/proxy_params.conf`
|
||||
|
||||
```nginx
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
proxy_busy_buffers_size 8k;
|
||||
```
|
||||
|
||||
## 4. 前端配置修改
|
||||
|
||||
### 4.1 修改 API 端点配置
|
||||
|
||||
文件: `frontend/mobile-app/lib/core/constants/api_endpoints.dart`
|
||||
|
||||
```dart
|
||||
class ApiEndpoints {
|
||||
ApiEndpoints._();
|
||||
|
||||
// Base URL - 生产环境
|
||||
static const String baseUrl = 'https://rwaapi.szaiai.com';
|
||||
|
||||
// Base URL - 开发环境 (可选)
|
||||
static const String baseUrlDev = 'https://rwaapi-dev.szaiai.com';
|
||||
|
||||
// API 版本前缀
|
||||
static const String apiPrefix = '/api/v1';
|
||||
|
||||
// Auth & User (-> Identity Service)
|
||||
static const String user = '$apiPrefix/user';
|
||||
static const String auth = '$apiPrefix/auth';
|
||||
static const String autoCreate = '$user/auto-create';
|
||||
static const String login = '$auth/login';
|
||||
static const String refreshToken = '$auth/refresh';
|
||||
static const String logout = '$auth/logout';
|
||||
static const String profile = '$user/profile';
|
||||
|
||||
// Wallet (-> Wallet Service)
|
||||
static const String wallet = '$apiPrefix/wallet';
|
||||
static const String balance = '$wallet/balance';
|
||||
static const String createWallet = '$wallet/create';
|
||||
static const String importWallet = '$wallet/import';
|
||||
|
||||
// Trading (-> Wallet Service)
|
||||
static const String trading = '$apiPrefix/trading';
|
||||
static const String exchange = '$trading/exchange';
|
||||
static const String settlement = '$trading/settlement';
|
||||
static const String transactions = '$trading/transactions';
|
||||
|
||||
// Deposit (-> Wallet Service)
|
||||
static const String deposit = '$apiPrefix/deposit';
|
||||
static const String depositAddress = '$deposit/address';
|
||||
static const String confirmDeposit = '$deposit/confirm';
|
||||
|
||||
// Mining & Reward (-> Reward Service)
|
||||
static const String mining = '$apiPrefix/mining';
|
||||
static const String miningStatus = '$mining/status';
|
||||
static const String startMining = '$mining/start';
|
||||
static const String stopMining = '$mining/stop';
|
||||
static const String claimReward = '$mining/claim';
|
||||
static const String hashPower = '$mining/hash-power';
|
||||
|
||||
// Ranking (-> Leaderboard Service)
|
||||
static const String ranking = '$apiPrefix/ranking';
|
||||
static const String dailyRanking = '$ranking/daily';
|
||||
static const String weeklyRanking = '$ranking/weekly';
|
||||
static const String monthlyRanking = '$ranking/monthly';
|
||||
|
||||
// Planting (-> Planting Service)
|
||||
static const String planting = '$apiPrefix/planting';
|
||||
static const String plantingPrice = '$planting/price';
|
||||
static const String submitPlanting = '$planting/submit';
|
||||
|
||||
// Community & Referral (-> Referral Service)
|
||||
static const String community = '$apiPrefix/community';
|
||||
static const String referral = '$apiPrefix/referral';
|
||||
static const String referralList = '$community/referrals';
|
||||
static const String earnings = '$community/earnings';
|
||||
static const String generateReferralLink = '$referral/generate-link';
|
||||
|
||||
// Telemetry (-> Reporting Service)
|
||||
static const String telemetry = '$apiPrefix/telemetry';
|
||||
static const String telemetrySession = '$telemetry/session';
|
||||
static const String telemetryHeartbeat = '$telemetry/heartbeat';
|
||||
static const String telemetryEvents = '$telemetry/events';
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 修改 API 客户端默认 URL
|
||||
|
||||
文件: `frontend/mobile-app/lib/core/network/api_client.dart`
|
||||
|
||||
```dart
|
||||
// 修改默认 Base URL
|
||||
static const String _defaultBaseUrl = 'https://rwaapi.szaiai.com';
|
||||
|
||||
// 开发模式可使用本地地址
|
||||
// static const String _defaultBaseUrl = 'http://10.0.2.2:3000'; // Android 模拟器
|
||||
// static const String _defaultBaseUrl = 'http://localhost:3000'; // iOS 模拟器
|
||||
```
|
||||
|
||||
## 5. Docker Compose 部署
|
||||
|
||||
### 5.1 主部署文件 `docker-compose.prod.yml`
|
||||
|
||||
```yaml
|
||||
services:
|
||||
# ============================================
|
||||
# Nginx API Gateway
|
||||
# ============================================
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||
- ./nginx/logs:/var/log/nginx
|
||||
depends_on:
|
||||
- identity-service
|
||||
- wallet-service
|
||||
- planting-service
|
||||
- referral-service
|
||||
- reward-service
|
||||
- leaderboard-service
|
||||
- reporting-service
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Identity Service
|
||||
# ============================================
|
||||
identity-service:
|
||||
build: ./services/identity-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_identity
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Wallet Service
|
||||
# ============================================
|
||||
wallet-service:
|
||||
build: ./services/wallet-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_wallet
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Planting Service
|
||||
# ============================================
|
||||
planting-service:
|
||||
build: ./services/planting-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_planting
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Referral Service
|
||||
# ============================================
|
||||
referral-service:
|
||||
build: ./services/referral-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_referral
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Reward Service
|
||||
# ============================================
|
||||
reward-service:
|
||||
build: ./services/reward-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_reward
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Leaderboard Service
|
||||
# ============================================
|
||||
leaderboard-service:
|
||||
build: ./services/leaderboard-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_leaderboard
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# Reporting Service
|
||||
# ============================================
|
||||
reporting-service:
|
||||
build: ./services/reporting-service
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@postgres:5432/rwa_reporting
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- REDIS_HOST=redis
|
||||
- KAFKA_BROKERS=kafka:29092
|
||||
- APP_ENV=production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================
|
||||
# 基础设施
|
||||
# ============================================
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||
- POSTGRES_MULTIPLE_DATABASES=rwa_identity,rwa_wallet,rwa_planting,rwa_referral,rwa_reward,rwa_leaderboard,rwa_reporting
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./scripts/init-multi-db.sh:/docker-entrypoint-initdb.d/init-multi-db.sh
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD}
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
zookeeper:
|
||||
image: confluentinc/cp-zookeeper:7.5.0
|
||||
environment:
|
||||
ZOOKEEPER_CLIENT_PORT: 2181
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
kafka:
|
||||
image: confluentinc/cp-kafka:7.5.0
|
||||
depends_on:
|
||||
- zookeeper
|
||||
environment:
|
||||
KAFKA_BROKER_ID: 1
|
||||
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
||||
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT_INTERNAL://kafka:29092
|
||||
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT_INTERNAL:PLAINTEXT
|
||||
KAFKA_LISTENERS: PLAINTEXT_INTERNAL://0.0.0.0:29092
|
||||
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT_INTERNAL
|
||||
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
||||
networks:
|
||||
- rwa-network
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
rwa-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
### 5.2 环境变量文件 `.env.prod`
|
||||
|
||||
```bash
|
||||
# Database
|
||||
DB_PASSWORD=your_secure_database_password
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=your_super_secure_jwt_secret_at_least_32_chars
|
||||
|
||||
# Redis
|
||||
REDIS_PASSWORD=your_secure_redis_password
|
||||
|
||||
# Wallet Encryption
|
||||
WALLET_ENCRYPTION_SALT=your_wallet_encryption_salt
|
||||
|
||||
# Service JWT (for inter-service communication)
|
||||
SERVICE_JWT_SECRET=your_service_jwt_secret
|
||||
```
|
||||
|
||||
## 6. 部署步骤
|
||||
|
||||
### 6.1 服务器准备
|
||||
|
||||
```bash
|
||||
# 1. 安装 Docker 和 Docker Compose
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# 2. 创建部署目录
|
||||
mkdir -p /opt/rwadurian
|
||||
cd /opt/rwadurian
|
||||
|
||||
# 3. 克隆代码
|
||||
git clone https://github.com/your-org/rwadurian.git .
|
||||
|
||||
# 4. 创建 Nginx 配置目录
|
||||
mkdir -p nginx/{conf.d,ssl,logs}
|
||||
|
||||
# 5. 复制 Nginx 配置
|
||||
cp docs/nginx/* nginx/
|
||||
|
||||
# 6. 安装 SSL 证书 (使用 Let's Encrypt 或购买的证书)
|
||||
# 将证书放到 nginx/ssl/ 目录
|
||||
```
|
||||
|
||||
### 6.2 启动服务
|
||||
|
||||
```bash
|
||||
# 1. 复制并配置环境变量
|
||||
cp .env.example .env.prod
|
||||
vim .env.prod # 修改为生产环境配置
|
||||
|
||||
# 2. 启动所有服务
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
|
||||
# 3. 查看服务状态
|
||||
docker compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 4. 查看日志
|
||||
docker compose -f docker-compose.prod.yml logs -f
|
||||
|
||||
# 5. 运行数据库迁移
|
||||
docker compose -f docker-compose.prod.yml exec identity-service npx prisma migrate deploy
|
||||
docker compose -f docker-compose.prod.yml exec wallet-service npx prisma migrate deploy
|
||||
# ... 其他服务
|
||||
```
|
||||
|
||||
### 6.3 验证部署
|
||||
|
||||
```bash
|
||||
# 健康检查
|
||||
curl https://rwaapi.szaiai.com/health
|
||||
|
||||
# 测试 API
|
||||
curl https://rwaapi.szaiai.com/api/v1/user/auto-create \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"deviceId": "test-device-123"}'
|
||||
```
|
||||
|
||||
## 7. API 端点对照表
|
||||
|
||||
| 前端调用 | Nginx 路由 | 后端服务 | 服务端口 |
|
||||
|---------|-----------|---------|---------|
|
||||
| `/api/v1/user/*` | `/api/v1/user` | Identity Service | 3000 |
|
||||
| `/api/v1/auth/*` | `/api/v1/auth` | Identity Service | 3000 |
|
||||
| `/api/v1/wallet/*` | `/api/v1/wallet` | Wallet Service | 3002 |
|
||||
| `/api/v1/trading/*` | `/api/v1/trading` | Wallet Service | 3002 |
|
||||
| `/api/v1/deposit/*` | `/api/v1/deposit` | Wallet Service | 3002 |
|
||||
| `/api/v1/mining/*` | `/api/v1/mining` | Reward Service | 3005 |
|
||||
| `/api/v1/ranking/*` | `/api/v1/ranking` | Leaderboard Service | 3007 |
|
||||
| `/api/v1/planting/*` | `/api/v1/planting` | Planting Service | 3003 |
|
||||
| `/api/v1/referral/*` | `/api/v1/referral` | Referral Service | 3004 |
|
||||
| `/api/v1/community/*` | `/api/v1/community` | Referral Service | 3004 |
|
||||
| `/api/v1/telemetry/*` | `/api/v1/telemetry` | Reporting Service | 3008 |
|
||||
|
||||
## 8. 监控与日志
|
||||
|
||||
### 8.1 Nginx 日志
|
||||
|
||||
```bash
|
||||
# 访问日志
|
||||
tail -f /opt/rwadurian/nginx/logs/access.log
|
||||
|
||||
# 错误日志
|
||||
tail -f /opt/rwadurian/nginx/logs/error.log
|
||||
```
|
||||
|
||||
### 8.2 服务日志
|
||||
|
||||
```bash
|
||||
# 查看特定服务日志
|
||||
docker compose -f docker-compose.prod.yml logs -f identity-service
|
||||
|
||||
# 查看所有服务日志
|
||||
docker compose -f docker-compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
## 9. 常见问题
|
||||
|
||||
### Q1: 502 Bad Gateway
|
||||
- 检查后端服务是否正常运行
|
||||
- 检查 Nginx upstream 配置的服务名是否正确
|
||||
- 检查 Docker 网络是否正确连接
|
||||
|
||||
### Q2: CORS 错误
|
||||
- 确认 Nginx 配置中 CORS 头已正确设置
|
||||
- 确认 OPTIONS 预检请求处理正确
|
||||
|
||||
### Q3: SSL 证书问题
|
||||
- 检查证书文件路径和权限
|
||||
- 确认证书未过期
|
||||
- 使用 `openssl s_client -connect rwaapi.szaiai.com:443` 测试
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-12-01
|
||||
**维护者**: RWA Team
|
||||
|
|
@ -1,65 +1,78 @@
|
|||
class ApiEndpoints {
|
||||
ApiEndpoints._();
|
||||
|
||||
// Base URL
|
||||
static const String baseUrl = 'https://api.rwadurian.com';
|
||||
static const String baseUrlDev = 'https://api-dev.rwadurian.com';
|
||||
// Base URL - 生产环境
|
||||
static const String baseUrl = 'https://rwaapi.szaiai.com';
|
||||
// Base URL - 开发环境
|
||||
static const String baseUrlDev = 'https://rwaapi-dev.szaiai.com';
|
||||
|
||||
// Auth
|
||||
static const String auth = '/auth';
|
||||
// API 版本前缀
|
||||
static const String apiPrefix = '/api/v1';
|
||||
|
||||
// Auth (-> Identity Service)
|
||||
static const String auth = '$apiPrefix/auth';
|
||||
static const String login = '$auth/login';
|
||||
static const String register = '$auth/register';
|
||||
static const String refreshToken = '$auth/refresh';
|
||||
static const String logout = '$auth/logout';
|
||||
|
||||
// User
|
||||
static const String user = '/user';
|
||||
// User (-> Identity Service)
|
||||
static const String user = '$apiPrefix/user';
|
||||
static const String autoCreate = '$user/auto-create';
|
||||
static const String profile = '$user/profile';
|
||||
static const String updateProfile = '$user/profile/update';
|
||||
static const String updateAvatar = '$user/avatar';
|
||||
|
||||
// Wallet
|
||||
static const String wallet = '/wallet';
|
||||
// Wallet (-> Wallet Service)
|
||||
static const String wallet = '$apiPrefix/wallet';
|
||||
static const String createWallet = '$wallet/create';
|
||||
static const String importWallet = '$wallet/import';
|
||||
static const String balance = '$wallet/balance';
|
||||
|
||||
// Mining
|
||||
static const String mining = '/mining';
|
||||
// Mining (-> Reward Service)
|
||||
static const String mining = '$apiPrefix/mining';
|
||||
static const String miningStatus = '$mining/status';
|
||||
static const String startMining = '$mining/start';
|
||||
static const String stopMining = '$mining/stop';
|
||||
static const String claimReward = '$mining/claim';
|
||||
static const String hashPower = '$mining/hash-power';
|
||||
|
||||
// Ranking
|
||||
static const String ranking = '/ranking';
|
||||
// Ranking (-> Leaderboard Service)
|
||||
static const String ranking = '$apiPrefix/ranking';
|
||||
static const String dailyRanking = '$ranking/daily';
|
||||
static const String weeklyRanking = '$ranking/weekly';
|
||||
static const String monthlyRanking = '$ranking/monthly';
|
||||
|
||||
// Trading
|
||||
static const String trading = '/trading';
|
||||
// Trading (-> Wallet Service)
|
||||
static const String trading = '$apiPrefix/trading';
|
||||
static const String exchange = '$trading/exchange';
|
||||
static const String settlement = '$trading/settlement';
|
||||
static const String transactions = '$trading/transactions';
|
||||
|
||||
// Deposit
|
||||
static const String deposit = '/deposit';
|
||||
// Deposit (-> Wallet Service)
|
||||
static const String deposit = '$apiPrefix/deposit';
|
||||
static const String depositAddress = '$deposit/address';
|
||||
static const String confirmDeposit = '$deposit/confirm';
|
||||
static const String depositRecords = '$deposit/records';
|
||||
|
||||
// Planting
|
||||
static const String planting = '/planting';
|
||||
// Planting (-> Planting Service)
|
||||
static const String planting = '$apiPrefix/planting';
|
||||
static const String plantingPrice = '$planting/price';
|
||||
static const String submitPlanting = '$planting/submit';
|
||||
static const String provinces = '$planting/provinces';
|
||||
static const String cities = '$planting/cities';
|
||||
|
||||
// Community
|
||||
static const String community = '/community';
|
||||
// Community & Referral (-> Referral Service)
|
||||
static const String community = '$apiPrefix/community';
|
||||
static const String referral = '$apiPrefix/referral';
|
||||
static const String referralList = '$community/referrals';
|
||||
static const String earnings = '$community/earnings';
|
||||
static const String claimEarnings = '$community/claim';
|
||||
static const String generateReferralLink = '$referral/generate-link';
|
||||
|
||||
// Telemetry (-> Reporting Service)
|
||||
static const String telemetry = '$apiPrefix/telemetry';
|
||||
static const String telemetrySession = '$telemetry/session';
|
||||
static const String telemetryHeartbeat = '$telemetry/heartbeat';
|
||||
static const String telemetryEvents = '$telemetry/events';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,10 @@ class ApiClient {
|
|||
_setupInterceptors();
|
||||
}
|
||||
|
||||
static const String _defaultBaseUrl = 'http://10.0.2.2:3001'; // Android 模拟器访问本机
|
||||
// 生产环境 API 地址
|
||||
static const String _defaultBaseUrl = 'https://rwaapi.szaiai.com';
|
||||
// 开发环境 (Android 模拟器访问本机): 'http://10.0.2.2:3000'
|
||||
// 开发环境 (iOS 模拟器访问本机): 'http://localhost:3000'
|
||||
|
||||
/// 设置拦截器
|
||||
void _setupInterceptors() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue