From 79e2b9bfdde936dcb68a500cda2aebeda560d185 Mon Sep 17 00:00:00 2001 From: Developer Date: Tue, 2 Dec 2025 19:01:12 -0800 Subject: [PATCH] =?UTF-8?q?docs(admin-service):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E7=9A=84=E6=8A=80=E6=9C=AF=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E4=BD=93=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 文档结构: - docs/ARCHITECTURE.md: DDD+Hexagonal 架构设计详解 - docs/API.md: RESTful API 完整接口文档 - docs/DEVELOPMENT.md: 开发环境设置和代码规范 - docs/TESTING.md: 三层测试架构 (Unit/Integration/E2E) - docs/DEPLOYMENT.md: 本地/Docker/生产环境部署指南 - docs/README.md: 文档中心导航和快速入门 架构文档 (ARCHITECTURE.md): - 服务职责和核心功能说明 - DDD 领域模型 (聚合根、值对象、领域服务) - 六边形架构分层设计 - 数据流和依赖方向详解 - SOLID 原则应用示例 - 性能优化和安全性考量 API 文档 (API.md): - 6 个核心 API 端点完整说明 - 请求/响应格式和数据模型 - 错误处理和状态码规范 - cURL/Postman 使用示例 - 版本控制和更新策略 - 最佳实践和常见问题 开发文档 (DEVELOPMENT.md): - VSCode 配置和推荐插件 - 本地环境初始化步骤 - Git 工作流和 Commit 规范 - 完整开发迭代流程示例 - TypeScript/DDD/NestJS/Prisma 代码规范 - 调试技巧和常见开发任务 测试文档 (TESTING.md): - 测试金字塔三层架构 (53+21+15=89 测试用例) - 本地/WSL2/Docker 测试环境设置 - 单元/集成/E2E 测试详细示例 - Make/npm 脚本快速执行 - 覆盖率目标和 CI/CD 集成 - GitHub Actions 配置示例 部署文档 (DEPLOYMENT.md): - 部署架构和系统要求 - Ubuntu 服务器环境准备 - PM2 本地部署流程 - Docker Compose 容器化部署 - Nginx 反向代理和 SSL 配置 - 数据库备份和日志管理 - 监控告警和故障排查 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/services/admin-service/docs/API.md | 910 +++++++++++++ .../admin-service/docs/ARCHITECTURE.md | 685 ++++++++++ .../services/admin-service/docs/DEPLOYMENT.md | 1078 +++++++++++++++ .../admin-service/docs/DEVELOPMENT.md | 1061 +++++++++++++++ backend/services/admin-service/docs/README.md | 305 +++++ .../services/admin-service/docs/TESTING.md | 1196 +++++++++++++++++ 6 files changed, 5235 insertions(+) create mode 100644 backend/services/admin-service/docs/API.md create mode 100644 backend/services/admin-service/docs/ARCHITECTURE.md create mode 100644 backend/services/admin-service/docs/DEPLOYMENT.md create mode 100644 backend/services/admin-service/docs/DEVELOPMENT.md create mode 100644 backend/services/admin-service/docs/README.md create mode 100644 backend/services/admin-service/docs/TESTING.md diff --git a/backend/services/admin-service/docs/API.md b/backend/services/admin-service/docs/API.md new file mode 100644 index 00000000..ffd7ecb0 --- /dev/null +++ b/backend/services/admin-service/docs/API.md @@ -0,0 +1,910 @@ +# Admin Service API 文档 + +## 目录 + +- [1. API 概述](#1-api-概述) +- [2. 认证](#2-认证) +- [3. 通用响应格式](#3-通用响应格式) +- [4. 错误处理](#4-错误处理) +- [5. API 端点](#5-api-端点) +- [6. 数据模型](#6-数据模型) +- [7. 使用示例](#7-使用示例) + +--- + +## 1. API 概述 + +### 1.1 基本信息 + +| 项目 | 值 | +|-----|---| +| **Base URL** | `http://localhost:3005/api/v1` | +| **协议** | HTTP/HTTPS | +| **数据格式** | JSON | +| **字符编码** | UTF-8 | +| **API 版本** | v1 | + +### 1.2 API 分类 + +| 分类 | 端点数 | 说明 | +|-----|-------|------| +| 版本管理 | 5 | 创建、启用、禁用、查询版本 | +| 版本检查 | 1 | 移动端检查更新 | + +--- + +## 2. 认证 + +### 2.1 认证方式 (待实现) + +当前版本 API **未实现认证机制**,生产环境需要添加 JWT 认证。 + +**计划认证方案**: +```http +Authorization: Bearer +``` + +**获取 Token** (待实现): +```http +POST /api/v1/auth/login +Content-Type: application/json + +{ + "username": "admin", + "password": "password123" +} +``` + +**响应**: +```json +{ + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "expiresIn": 7200 +} +``` + +### 2.2 权限级别 (待实现) + +| 角色 | 权限 | +|-----|------| +| **admin** | 完全权限:创建、启用、禁用、删除版本 | +| **developer** | 创建、查询版本 | +| **public** | 仅检查更新 (无需认证) | + +--- + +## 3. 通用响应格式 + +### 3.1 成功响应 + +**200 OK** - 查询成功: +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "platform": "android", + "versionCode": 100, + "versionName": "1.0.0", + "buildNumber": "1", + "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk", + "fileSize": 52428800, + "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "changelog": "Initial release", + "isEnabled": true, + "isForceUpdate": false, + "createdBy": "admin", + "createdAt": "2025-01-02T10:00:00.000Z", + "updatedBy": "admin", + "updatedAt": "2025-01-02T10:00:00.000Z" +} +``` + +**201 Created** - 创建成功: +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "platform": "android", + "versionCode": 101, + ... +} +``` + +**204 No Content** - 操作成功无返回内容 + +### 3.2 分页响应 (待实现) + +```json +{ + "data": [...], + "meta": { + "total": 50, + "page": 1, + "pageSize": 10, + "totalPages": 5 + } +} +``` + +--- + +## 4. 错误处理 + +### 4.1 错误响应格式 + +```json +{ + "statusCode": 400, + "message": "Invalid version code", + "error": "Bad Request", + "timestamp": "2025-01-02T10:00:00.000Z", + "path": "/api/v1/version" +} +``` + +### 4.2 HTTP 状态码 + +| 状态码 | 说明 | 常见场景 | +|-------|------|---------| +| **200** | 成功 | 查询成功 | +| **201** | 已创建 | 创建版本成功 | +| **204** | 无内容 | 启用/禁用成功 | +| **400** | 请求错误 | 参数验证失败 | +| **401** | 未认证 | Token 缺失或无效 | +| **403** | 禁止访问 | 权限不足 | +| **404** | 未找到 | 版本不存在 | +| **409** | 冲突 | 版本号重复 | +| **500** | 服务器错误 | 内部异常 | + +### 4.3 业务错误码 (待实现) + +| 错误码 | 说明 | +|-------|------| +| `VERSION_ALREADY_EXISTS` | 版本已存在 | +| `INVALID_VERSION_CODE` | 版本号格式错误 | +| `INVALID_VERSION_NAME` | 版本名称格式错误 | +| `INVALID_SHA256` | SHA256 格式错误 | +| `VERSION_NOT_FOUND` | 版本不存在 | +| `FILE_SIZE_INVALID` | 文件大小无效 | + +--- + +## 5. API 端点 + +### 5.1 创建版本 + +**端点**: `POST /api/v1/version` + +**权限**: 需要认证 (待实现) + +**请求体**: +```json +{ + "platform": "android", + "versionCode": 100, + "versionName": "1.0.0", + "buildNumber": "1", + "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk", + "fileSize": 52428800, + "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "changelog": "Initial release", + "isEnabled": true, + "isForceUpdate": false, + "createdBy": "admin" +} +``` + +**字段说明**: + +| 字段 | 类型 | 必填 | 说明 | 验证规则 | +|-----|------|-----|------|---------| +| `platform` | string | ✅ | 平台 | `android` 或 `ios` | +| `versionCode` | number | ✅ | 版本号 | 正整数 | +| `versionName` | string | ✅ | 版本名称 | 语义化版本 (x.y.z) | +| `buildNumber` | string | ✅ | 构建号 | 非空字符串 | +| `downloadUrl` | string | ✅ | 下载链接 | 有效 URL | +| `fileSize` | number | ✅ | 文件大小 (字节) | > 0 | +| `fileSha256` | string | ✅ | SHA256 哈希 | 64 位十六进制 | +| `changelog` | string | ✅ | 更新日志 | 非空字符串 | +| `isEnabled` | boolean | ❌ | 是否启用 | 默认 `true` | +| `isForceUpdate` | boolean | ❌ | 是否强制更新 | 默认 `false` | +| `createdBy` | string | ✅ | 创建者 | 非空字符串 | + +**响应**: `201 Created` +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "platform": "android", + "versionCode": 100, + "versionName": "1.0.0", + "buildNumber": "1", + "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk", + "fileSize": 52428800, + "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "changelog": "Initial release", + "isEnabled": true, + "isForceUpdate": false, + "createdBy": "admin", + "createdAt": "2025-01-02T10:00:00.000Z", + "updatedBy": "admin", + "updatedAt": "2025-01-02T10:00:00.000Z" +} +``` + +**错误响应**: +```json +// 400 Bad Request - 版本号无效 +{ + "statusCode": 400, + "message": "Version code must be a positive integer", + "error": "Bad Request" +} + +// 409 Conflict - 版本已存在 +{ + "statusCode": 409, + "message": "Version already exists for this platform", + "error": "Conflict" +} +``` + +**cURL 示例**: +```bash +curl -X POST http://localhost:3005/api/v1/version \ + -H "Content-Type: application/json" \ + -d '{ + "platform": "android", + "versionCode": 100, + "versionName": "1.0.0", + "buildNumber": "1", + "downloadUrl": "https://cdn.example.com/app-v1.0.0.apk", + "fileSize": 52428800, + "fileSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "changelog": "Initial release", + "isEnabled": true, + "isForceUpdate": false, + "createdBy": "admin" + }' +``` + +--- + +### 5.2 查询所有版本 + +**端点**: `GET /api/v1/version` + +**权限**: 需要认证 (待实现) + +**查询参数**: + +| 参数 | 类型 | 必填 | 说明 | 示例 | +|-----|------|-----|------|------| +| `platform` | string | ❌ | 过滤平台 | `android` | +| `isEnabled` | boolean | ❌ | 过滤启用状态 | `true` | +| `page` | number | ❌ | 页码 (待实现) | `1` | +| `pageSize` | number | ❌ | 每页数量 (待实现) | `10` | + +**请求示例**: +```http +GET /api/v1/version?platform=android&isEnabled=true +``` + +**响应**: `200 OK` +```json +[ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "platform": "android", + "versionCode": 101, + "versionName": "1.0.1", + ... + }, + { + "id": "550e8400-e29b-41d4-a716-446655440001", + "platform": "android", + "versionCode": 100, + "versionName": "1.0.0", + ... + } +] +``` + +**cURL 示例**: +```bash +curl -X GET "http://localhost:3005/api/v1/version?platform=android&isEnabled=true" +``` + +--- + +### 5.3 查询单个版本 + +**端点**: `GET /api/v1/version/:id` + +**权限**: 需要认证 (待实现) + +**路径参数**: + +| 参数 | 类型 | 说明 | +|-----|------|------| +| `id` | string (UUID) | 版本 ID | + +**请求示例**: +```http +GET /api/v1/version/550e8400-e29b-41d4-a716-446655440000 +``` + +**响应**: `200 OK` +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "platform": "android", + "versionCode": 100, + "versionName": "1.0.0", + ... +} +``` + +**错误响应**: +```json +// 404 Not Found +{ + "statusCode": 404, + "message": "Version not found", + "error": "Not Found" +} +``` + +**cURL 示例**: +```bash +curl -X GET http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440000 +``` + +--- + +### 5.4 启用版本 + +**端点**: `PATCH /api/v1/version/:id/enable` + +**权限**: 需要认证 (待实现) + +**路径参数**: + +| 参数 | 类型 | 说明 | +|-----|------|------| +| `id` | string (UUID) | 版本 ID | + +**请求体**: +```json +{ + "updatedBy": "admin" +} +``` + +**请求示例**: +```http +PATCH /api/v1/version/550e8400-e29b-41d4-a716-446655440000/enable +Content-Type: application/json + +{ + "updatedBy": "admin" +} +``` + +**响应**: `204 No Content` + +**错误响应**: +```json +// 404 Not Found +{ + "statusCode": 404, + "message": "Version not found", + "error": "Not Found" +} +``` + +**cURL 示例**: +```bash +curl -X PATCH http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440000/enable \ + -H "Content-Type: application/json" \ + -d '{"updatedBy": "admin"}' +``` + +--- + +### 5.5 禁用版本 + +**端点**: `PATCH /api/v1/version/:id/disable` + +**权限**: 需要认证 (待实现) + +**路径参数**: + +| 参数 | 类型 | 说明 | +|-----|------|------| +| `id` | string (UUID) | 版本 ID | + +**请求体**: +```json +{ + "updatedBy": "admin" +} +``` + +**请求示例**: +```http +PATCH /api/v1/version/550e8400-e29b-41d4-a716-446655440000/disable +Content-Type: application/json + +{ + "updatedBy": "admin" +} +``` + +**响应**: `204 No Content` + +**业务逻辑**: +- 禁用版本时,会自动将 `isForceUpdate` 设置为 `false` +- 禁用后的版本不会出现在 "检查更新" 结果中 + +**cURL 示例**: +```bash +curl -X PATCH http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440000/disable \ + -H "Content-Type: application/json" \ + -d '{"updatedBy": "admin"}' +``` + +--- + +### 5.6 检查更新 (移动端) + +**端点**: `GET /api/v1/version/check` + +**权限**: 公开 (无需认证) + +**查询参数**: + +| 参数 | 类型 | 必填 | 说明 | 示例 | +|-----|------|-----|------|------| +| `platform` | string | ✅ | 平台 | `android` | +| `versionCode` | number | ✅ | 当前版本号 | `100` | + +**请求示例**: +```http +GET /api/v1/version/check?platform=android&versionCode=100 +``` + +**响应 1**: `200 OK` - 有更新 +```json +{ + "hasUpdate": true, + "latestVersion": "1.0.1", + "downloadUrl": "https://cdn.example.com/app-v1.0.1.apk", + "isForceUpdate": false, + "changelog": "Bug fixes and performance improvements" +} +``` + +**响应 2**: `200 OK` - 无更新 +```json +{ + "hasUpdate": false +} +``` + +**响应 3**: `200 OK` - 强制更新 +```json +{ + "hasUpdate": true, + "latestVersion": "2.0.0", + "downloadUrl": "https://cdn.example.com/app-v2.0.0.apk", + "isForceUpdate": true, + "changelog": "Major security update. Please update immediately!" +} +``` + +**错误响应**: +```json +// 400 Bad Request - 参数缺失 +{ + "statusCode": 400, + "message": ["platform should not be empty", "versionCode must be a number"], + "error": "Bad Request" +} +``` + +**业务逻辑**: +1. 查询指定平台的所有启用版本 (`isEnabled = true`) +2. 按 `versionCode` 降序排序,取第一个作为最新版本 +3. 如果最新版本的 `versionCode` > 当前版本号,返回更新信息 +4. 否则返回 `hasUpdate: false` + +**移动端处理逻辑**: +```typescript +// Flutter 示例 +async function checkForUpdate() { + const response = await fetch( + `${API_BASE}/version/check?platform=android&versionCode=100` + ); + const data = await response.json(); + + if (data.hasUpdate) { + if (data.isForceUpdate) { + // 显示强制更新对话框(无法关闭) + showForceUpdateDialog({ + version: data.latestVersion, + downloadUrl: data.downloadUrl, + changelog: data.changelog, + }); + } else { + // 显示普通更新对话框(可以关闭) + showUpdateDialog({ + version: data.latestVersion, + downloadUrl: data.downloadUrl, + changelog: data.changelog, + }); + } + } +} +``` + +**cURL 示例**: +```bash +curl -X GET "http://localhost:3005/api/v1/version/check?platform=android&versionCode=100" +``` + +--- + +## 6. 数据模型 + +### 6.1 AppVersion (应用版本) + +```typescript +interface AppVersion { + id: string; // UUID + platform: 'android' | 'ios';// 平台 + versionCode: number; // 版本号(整数) + versionName: string; // 版本名称(x.y.z) + buildNumber: string; // 构建号 + downloadUrl: string; // 下载链接 + fileSize: number; // 文件大小(字节) + fileSha256: string; // SHA256 哈希 + changelog: string; // 更新日志 + isEnabled: boolean; // 是否启用 + isForceUpdate: boolean; // 是否强制更新 + createdBy: string; // 创建者 + createdAt: string; // 创建时间(ISO 8601) + updatedBy: string; // 更新者 + updatedAt: string; // 更新时间(ISO 8601) +} +``` + +### 6.2 Platform (平台枚举) + +```typescript +enum Platform { + ANDROID = 'android', + IOS = 'ios', +} +``` + +### 6.3 VersionCheckResult (版本检查结果) + +```typescript +interface VersionCheckResult { + hasUpdate: boolean; // 是否有更新 + latestVersion?: string; // 最新版本名称 + downloadUrl?: string; // 下载链接 + isForceUpdate?: boolean; // 是否强制更新 + changelog?: string; // 更新日志 +} +``` + +--- + +## 7. 使用示例 + +### 7.1 完整发版流程 + +#### 步骤 1: 创建 Android 新版本 + +```bash +curl -X POST http://localhost:3005/api/v1/version \ + -H "Content-Type: application/json" \ + -d '{ + "platform": "android", + "versionCode": 101, + "versionName": "1.0.1", + "buildNumber": "20250102001", + "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.1.apk", + "fileSize": 54525952, + "fileSha256": "a3c5d7e9f1b2c4d6e8f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2", + "changelog": "1. Fixed mining reward calculation bug\n2. Improved UI performance\n3. Added dark mode support", + "isEnabled": true, + "isForceUpdate": false, + "createdBy": "admin" + }' +``` + +#### 步骤 2: 验证版本已创建 + +```bash +curl -X GET "http://localhost:3005/api/v1/version?platform=android&isEnabled=true" +``` + +#### 步骤 3: 移动端检查更新 + +```bash +# 用户当前版本号 100 +curl -X GET "http://localhost:3005/api/v1/version/check?platform=android&versionCode=100" + +# 响应: +{ + "hasUpdate": true, + "latestVersion": "1.0.1", + "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.1.apk", + "isForceUpdate": false, + "changelog": "1. Fixed mining reward calculation bug\n2. Improved UI performance\n3. Added dark mode support" +} +``` + +#### 步骤 4: 发现问题,紧急禁用版本 + +```bash +curl -X PATCH http://localhost:3005/api/v1/version/550e8400-e29b-41d4-a716-446655440001/disable \ + -H "Content-Type: application/json" \ + -d '{"updatedBy": "admin"}' +``` + +#### 步骤 5: 创建修复版本 + +```bash +curl -X POST http://localhost:3005/api/v1/version \ + -H "Content-Type: application/json" \ + -d '{ + "platform": "android", + "versionCode": 102, + "versionName": "1.0.2", + "buildNumber": "20250102002", + "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.2.apk", + "fileSize": 54530048, + "fileSha256": "b4d6e8f0a2c3d5e7f9a1b3c4d6e8f0a2b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1", + "changelog": "Hotfix: Fixed critical security vulnerability", + "isEnabled": true, + "isForceUpdate": true, + "createdBy": "admin" + }' +``` + +### 7.2 iOS 版本发布 + +```bash +curl -X POST http://localhost:3005/api/v1/version \ + -H "Content-Type: application/json" \ + -d '{ + "platform": "ios", + "versionCode": 1, + "versionName": "1.0.0", + "buildNumber": "1", + "downloadUrl": "https://apps.apple.com/app/rwa-durian/id123456789", + "fileSize": 67108864, + "fileSha256": "c5e7f9a1b3c4d6e8f0a2b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2", + "changelog": "Initial iOS release", + "isEnabled": true, + "isForceUpdate": false, + "createdBy": "admin" + }' +``` + +### 7.3 Postman Collection (部分示例) + +```json +{ + "info": { + "name": "Admin Service API", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Create Android Version", + "request": { + "method": "POST", + "header": [{"key": "Content-Type", "value": "application/json"}], + "body": { + "mode": "raw", + "raw": "{\n \"platform\": \"android\",\n \"versionCode\": 100,\n \"versionName\": \"1.0.0\",\n \"buildNumber\": \"1\",\n \"downloadUrl\": \"https://cdn.example.com/app-v1.0.0.apk\",\n \"fileSize\": 52428800,\n \"fileSha256\": \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n \"changelog\": \"Initial release\",\n \"isEnabled\": true,\n \"isForceUpdate\": false,\n \"createdBy\": \"admin\"\n}" + }, + "url": { + "raw": "http://localhost:3005/api/v1/version", + "protocol": "http", + "host": ["localhost"], + "port": "3005", + "path": ["api", "v1", "version"] + } + } + }, + { + "name": "Check For Update", + "request": { + "method": "GET", + "url": { + "raw": "http://localhost:3005/api/v1/version/check?platform=android&versionCode=100", + "protocol": "http", + "host": ["localhost"], + "port": "3005", + "path": ["api", "v1", "version", "check"], + "query": [ + {"key": "platform", "value": "android"}, + {"key": "versionCode", "value": "100"} + ] + } + } + } + ] +} +``` + +--- + +## 8. 版本控制策略 + +### 8.1 版本号规则 + +**VersionCode** (数字版本号): +- 每次发布递增 1 +- Android: 从 1 开始 +- iOS: 从 1 开始 +- 用于版本比较 (机器识别) + +**VersionName** (语义化版本): +- 格式: `MAJOR.MINOR.PATCH` (例如: `1.2.3`) +- 用于用户展示 (人类可读) + +**BuildNumber** (构建号): +- 格式: 自定义 (建议: `YYYYMMDDXXX`) +- 例如: `20250102001` = 2025年1月2日第1次构建 + +### 8.2 更新策略 + +| 场景 | isForceUpdate | 说明 | +|-----|---------------|------| +| 功能更新 | `false` | 用户可选择更新时机 | +| Bug 修复 | `false` | 建议更新,但不强制 | +| 安全漏洞 | `true` | 必须更新才能继续使用 | +| API 破坏性变更 | `true` | 旧版本无法正常工作 | + +--- + +## 9. 最佳实践 + +### 9.1 文件托管建议 + +1. **使用 CDN**: 加速全球用户下载 +2. **HTTPS**: 确保传输安全 +3. **文件命名**: `app-{platform}-v{versionName}.{ext}` + - Android: `app-android-v1.0.0.apk` + - iOS: `app-ios-v1.0.0.ipa` + +### 9.2 SHA256 校验流程 + +**服务端计算** (发版时): +```bash +# Linux/macOS +sha256sum app-android-v1.0.0.apk + +# Windows +certutil -hashfile app-android-v1.0.0.apk SHA256 +``` + +**移动端校验** (下载后): +```dart +// Flutter 示例 +import 'package:crypto/crypto.dart'; +import 'dart:io'; + +Future verifyApkIntegrity(String filePath, String expectedSha256) async { + final file = File(filePath); + final bytes = await file.readAsBytes(); + final digest = sha256.convert(bytes); + return digest.toString() == expectedSha256.toLowerCase(); +} + +// 使用 +final isValid = await verifyApkIntegrity( + '/storage/emulated/0/Download/app.apk', + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' +); + +if (!isValid) { + throw Exception('File integrity check failed! Possible tampering detected.'); +} +``` + +### 9.3 更新日志编写规范 + +**推荐格式**: +``` +1. 新功能:添加暗黑模式支持 +2. 优化:挖矿页面性能提升 30% +3. 修复:交易历史加载失败问题 +4. 安全:修复账户导入漏洞 +``` + +**避免**: +- ❌ "Bug fixes and improvements" (太笼统) +- ❌ 技术术语 (普通用户不理解) +- ✅ 简洁明了,面向用户 + +--- + +## 10. 常见问题 + +### Q1: 如何回滚版本? + +**方案 1**: 禁用问题版本,启用旧版本 +```bash +# 禁用 v1.0.1 +curl -X PATCH http://localhost:3005/api/v1/version/{v1.0.1-id}/disable \ + -H "Content-Type: application/json" \ + -d '{"updatedBy": "admin"}' + +# 启用 v1.0.0 +curl -X PATCH http://localhost:3005/api/v1/version/{v1.0.0-id}/enable \ + -H "Content-Type: application/json" \ + -d '{"updatedBy": "admin"}' +``` + +**方案 2**: 创建新版本,使用更高的 versionCode +```bash +# 创建 v1.0.0-hotfix (versionCode = 103) +curl -X POST http://localhost:3005/api/v1/version \ + -H "Content-Type: application/json" \ + -d '{ + "platform": "android", + "versionCode": 103, + "versionName": "1.0.0", + "buildNumber": "20250102003", + ... + }' +``` + +### Q2: 如何处理多渠道包 (Google Play, 自建服务器)? + +当前版本不支持,建议通过 `buildNumber` 区分: + +```bash +# Google Play 渠道 +{ + "versionCode": 100, + "versionName": "1.0.0", + "buildNumber": "100-gplay", + "downloadUrl": "https://play.google.com/store/apps/details?id=com.rwa.durian", + ... +} + +# 自建渠道 +{ + "versionCode": 100, + "versionName": "1.0.0", + "buildNumber": "100-self", + "downloadUrl": "https://cdn.rwadurian.com/android/app-v1.0.0.apk", + ... +} +``` + +### Q3: 如何实现灰度发布? + +当前版本不支持,未来可扩展: + +```typescript +// 计划实现 +interface AppVersion { + ... + releaseType: 'full' | 'gray'; // 发布类型 + grayRatio?: number; // 灰度比例 (0-100) + grayUserIds?: string[]; // 灰度用户列表 +} +``` + +--- + +**最后更新**: 2025-12-03 +**版本**: 1.0.0 +**维护者**: RWA Durian Team diff --git a/backend/services/admin-service/docs/ARCHITECTURE.md b/backend/services/admin-service/docs/ARCHITECTURE.md new file mode 100644 index 00000000..91249c9d --- /dev/null +++ b/backend/services/admin-service/docs/ARCHITECTURE.md @@ -0,0 +1,685 @@ +# Admin Service 架构文档 + +## 目录 + +- [1. 服务概述](#1-服务概述) +- [2. 架构设计](#2-架构设计) +- [3. 领域设计](#3-领域设计) +- [4. 技术栈](#4-技术栈) +- [5. 目录结构](#5-目录结构) +- [6. 数据流](#6-数据流) + +--- + +## 1. 服务概述 + +### 1.1 服务职责 + +Admin Service 是 RWA Durian 项目的**应用版本管理服务**,负责: + +- 📱 **版本发布管理**: 管理 Android/iOS 应用版本的创建、更新、启用/禁用 +- 🔄 **版本检查**: 为移动端提供版本检查 API,支持强制更新和普通更新 +- 📊 **版本查询**: 支持按平台、版本号、启用状态等条件查询版本信息 +- 🔐 **SHA256 校验**: 确保 APK/IPA 文件完整性和安全性 + +### 1.2 核心功能 + +| 功能 | 说明 | API 端点 | +|-----|------|---------| +| 创建版本 | 发布新版本(Android/iOS) | POST /api/v1/version | +| 检查更新 | 移动端检查是否有新版本 | GET /api/v1/version/check | +| 查询版本 | 查询所有版本或特定版本 | GET /api/v1/version | +| 启用/禁用版本 | 控制版本可用性 | PATCH /api/v1/version/:id/enable
PATCH /api/v1/version/:id/disable | + +--- + +## 2. 架构设计 + +### 2.1 架构模式 + +Admin Service 采用 **DDD (领域驱动设计) + Hexagonal Architecture (六边形架构)** 的混合架构模式。 + +``` +┌─────────────────────────────────────────────────────────┐ +│ API Layer (NestJS) │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Controllers │ │ DTOs │ │ Guards │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ Application Layer (Handlers) │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Commands │ │ Queries │ │ Events │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ Domain Layer │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Entities │ │ Value Objects│ │ Services │ │ +│ │ │ │ │ │ │ │ +│ │ AppVersion │ │VersionCode │ │VersionCheck │ │ +│ │ │ │VersionName │ │ Service │ │ +│ │ │ │ FileSize │ │ │ │ +│ │ │ │ FileSha256 │ │ │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ Repository Interfaces (Port) │ │ +│ └──────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────┐ +│ Infrastructure Layer (Adapters) │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Repositories │ │ Mappers │ │ Prisma │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ + ▼ + ┌──────────┐ + │PostgreSQL│ + └──────────┘ +``` + +### 2.2 分层职责 + +#### API Layer (接口层) +- **Controllers**: 处理 HTTP 请求,路由分发 +- **DTOs**: 定义请求/响应数据传输对象 +- **Guards**: 身份验证、权限控制 (暂未实现) +- **依赖方向**: → Application Layer + +#### Application Layer (应用层) +- **Command Handlers**: 处理写操作命令 (Create, Update, Delete) +- **Query Handlers**: 处理读操作查询 (Get, List, Find) +- **Event Handlers**: 处理领域事件 (暂未实现) +- **依赖方向**: → Domain Layer + +#### Domain Layer (领域层) +- **Entities**: 聚合根,包含业务逻辑 (`AppVersion`) +- **Value Objects**: 不可变值对象 (`VersionCode`, `VersionName`, `FileSize`, `FileSha256`) +- **Domain Services**: 跨实体的业务逻辑 (`VersionCheckService`) +- **Repository Interfaces**: 持久化端口定义 +- **依赖方向**: 无外部依赖 (核心层) + +#### Infrastructure Layer (基础设施层) +- **Repositories**: Repository 接口的 Prisma 实现 +- **Mappers**: 领域对象 ↔ 持久化对象转换 +- **Prisma Client**: 数据库 ORM +- **依赖方向**: → Domain Layer (依赖倒置) + +--- + +## 3. 领域设计 + +### 3.1 领域模型 + +#### 聚合根: AppVersion + +```typescript +class AppVersion { + // 标识 + private readonly _id: string; + private readonly _platform: Platform; + + // 版本信息 + private readonly _versionCode: VersionCode; + private readonly _versionName: VersionName; + private readonly _buildNumber: string; + + // 文件信息 + private _downloadUrl: string; + private readonly _fileSize: FileSize; + private readonly _fileSha256: FileSha256; + + // 更新信息 + private _changelog: string; + private _isEnabled: boolean; + private _isForceUpdate: boolean; + + // 审计信息 + private readonly _createdBy: string; + private readonly _createdAt: Date; + private _updatedBy: string; + private _updatedAt: Date; +} +``` + +**业务不变式**: +1. `versionCode` 必须是正整数 +2. `versionName` 必须符合语义化版本格式 (x.y.z) +3. `fileSize` 必须大于 0 +4. `fileSha256` 必须是有效的 64 位十六进制字符串 +5. 同一平台同一版本号的版本只能有一个启用 + +#### 值对象 + +**VersionCode (版本号)** +```typescript +class VersionCode { + constructor(private readonly value: number) { + if (!Number.isInteger(value) || value < 1) { + throw new DomainException('Version code must be a positive integer'); + } + } + + isGreaterThan(other: VersionCode): boolean + isLessThan(other: VersionCode): boolean + equals(other: VersionCode): boolean +} +``` + +**VersionName (版本名称)** +```typescript +class VersionName { + private readonly SEMVER_REGEX = /^\d+\.\d+\.\d+$/; + + constructor(private readonly value: string) { + if (!this.SEMVER_REGEX.test(value)) { + throw new DomainException('Invalid semantic version format'); + } + } + + get major(): number + get minor(): number + get patch(): number +} +``` + +**FileSize (文件大小)** +```typescript +class FileSize { + constructor(private readonly bytes: bigint) { + if (bytes < 0n) { + throw new DomainException('File size cannot be negative'); + } + } + + toHumanReadable(): string // "1.50 MB" + toMegabytes(): string // "1.50" +} +``` + +**FileSha256 (SHA256 哈希)** +```typescript +class FileSha256 { + private readonly SHA256_REGEX = /^[a-f0-9]{64}$/; + + constructor(private readonly hash: string) { + if (!this.SHA256_REGEX.test(hash.toLowerCase())) { + throw new DomainException('Invalid SHA256 hash format'); + } + } +} +``` + +### 3.2 领域服务 + +**VersionCheckService** +```typescript +class VersionCheckService { + async checkForUpdate( + platform: Platform, + currentVersionCode: number, + ): Promise { + // 1. 查找最新启用的版本 + const latestVersion = await this.repository.findLatestEnabledVersion(platform); + + // 2. 比较版本号 + if (!latestVersion || latestVersion.versionCode.value <= currentVersionCode) { + return VersionCheckResult.noUpdate(); + } + + // 3. 返回更新信息 + return VersionCheckResult.hasUpdate({ + latestVersion: latestVersion.versionName.value, + downloadUrl: latestVersion.downloadUrl, + isForceUpdate: latestVersion.isForceUpdate, + changelog: latestVersion.changelog, + }); + } +} +``` + +### 3.3 业务规则 + +| 规则 | 实现位置 | 验证时机 | +|-----|---------|---------| +| 版本号必须唯一 | `AppVersionRepository` | 创建版本时 | +| 禁用版本不能强制更新 | `AppVersion.disable()` | 禁用操作时 | +| 文件大小必须 > 0 | `FileSize` VO | 值对象创建时 | +| SHA256 必须 64 位十六进制 | `FileSha256` VO | 值对象创建时 | +| 版本名称必须符合 semver | `VersionName` VO | 值对象创建时 | + +--- + +## 4. 技术栈 + +### 4.1 核心框架 + +| 技术 | 版本 | 用途 | +|-----|------|------| +| NestJS | 10.0.0 | Web 框架 | +| TypeScript | 5.1.3 | 编程语言 | +| Node.js | 20.x | 运行时 | +| Prisma | 5.7.0 | ORM | +| PostgreSQL | 16 | 数据库 | + +### 4.2 开发工具 + +| 工具 | 版本 | 用途 | +|-----|------|------| +| Jest | 29.5.0 | 测试框架 | +| ts-jest | 29.1.0 | TypeScript + Jest | +| Supertest | 6.3.3 | HTTP 测试 | +| ESLint | 8.42.0 | 代码检查 | +| Prettier | 3.0.0 | 代码格式化 | + +### 4.3 部署工具 + +| 工具 | 用途 | +|-----|------| +| Docker | 容器化 | +| Docker Compose | 多容器编排 | +| Makefile | 自动化脚本 | + +--- + +## 5. 目录结构 + +``` +admin-service/ +├── src/ +│ ├── api/ # API 层 +│ │ ├── controllers/ # 控制器 +│ │ │ └── version.controller.ts +│ │ └── dtos/ # 数据传输对象 +│ │ ├── create-version.dto.ts +│ │ ├── update-version.dto.ts +│ │ ├── check-version.dto.ts +│ │ └── version-response.dto.ts +│ │ +│ ├── application/ # 应用层 +│ │ ├── commands/ # 命令 +│ │ │ ├── create-version.command.ts +│ │ │ ├── enable-version.command.ts +│ │ │ └── disable-version.command.ts +│ │ ├── handlers/ # 处理器 +│ │ │ ├── create-version.handler.ts +│ │ │ ├── enable-version.handler.ts +│ │ │ └── disable-version.handler.ts +│ │ └── queries/ # 查询 +│ │ ├── find-version-by-id.query.ts +│ │ └── find-all-versions.query.ts +│ │ +│ ├── domain/ # 领域层 +│ │ ├── entities/ # 实体 +│ │ │ └── app-version.entity.ts +│ │ ├── value-objects/ # 值对象 +│ │ │ ├── version-code.vo.ts +│ │ │ ├── version-name.vo.ts +│ │ │ ├── file-size.vo.ts +│ │ │ └── file-sha256.vo.ts +│ │ ├── repositories/ # 仓储接口 +│ │ │ └── app-version.repository.ts +│ │ ├── services/ # 领域服务 +│ │ │ └── version-check.service.ts +│ │ └── enums/ # 枚举 +│ │ └── platform.enum.ts +│ │ +│ ├── infrastructure/ # 基础设施层 +│ │ ├── persistence/ # 持久化 +│ │ │ ├── repositories/ # 仓储实现 +│ │ │ │ └── app-version.repository.impl.ts +│ │ │ └── mappers/ # 映射器 +│ │ │ └── app-version.mapper.ts +│ │ └── prisma/ # Prisma +│ │ └── prisma.service.ts +│ │ +│ ├── shared/ # 共享模块 +│ │ ├── exceptions/ # 异常 +│ │ │ ├── domain.exception.ts +│ │ │ └── application.exception.ts +│ │ └── utils/ # 工具 +│ │ +│ ├── app.module.ts # 根模块 +│ └── main.ts # 入口文件 +│ +├── prisma/ +│ ├── schema.prisma # Prisma Schema +│ └── migrations/ # 数据库迁移 +│ +├── test/ # 测试 +│ ├── unit/ # 单元测试 +│ ├── integration/ # 集成测试 +│ └── e2e/ # E2E 测试 +│ +├── database/ # 数据库初始化 +│ ├── init.sql # 初始化脚本 +│ └── README.md +│ +├── docs/ # 文档 +│ ├── ARCHITECTURE.md # 本文档 +│ ├── API.md # API 文档 +│ ├── DEVELOPMENT.md # 开发指南 +│ ├── TESTING.md # 测试文档 +│ └── DEPLOYMENT.md # 部署文档 +│ +├── scripts/ # 脚本 +│ ├── test-in-wsl.sh +│ ├── run-wsl-tests.ps1 +│ └── test-with-docker-db.sh +│ +├── docker-compose.yml # Docker Compose +├── Dockerfile # Dockerfile +├── Makefile # Make 命令 +├── package.json # NPM 配置 +├── tsconfig.json # TypeScript 配置 +└── README.md # 项目说明 +``` + +--- + +## 6. 数据流 + +### 6.1 创建版本流程 + +``` +Client Request (POST /api/v1/version) + │ + ▼ +┌─────────────────────────────────────┐ +│ VersionController.createVersion() │ ← API Layer +└─────────────────────────────────────┘ + │ CreateVersionDto + ▼ +┌─────────────────────────────────────┐ +│ CreateVersionHandler.execute() │ ← Application Layer +│ 1. Create Command │ +│ 2. Validate Business Rules │ +│ 3. Call Repository │ +└─────────────────────────────────────┘ + │ CreateVersionCommand + ▼ +┌─────────────────────────────────────┐ +│ AppVersion.create() │ ← Domain Layer +│ 1. Create Value Objects │ +│ - VersionCode │ +│ - VersionName │ +│ - FileSize │ +│ - FileSha256 │ +│ 2. Create Entity │ +│ 3. Apply Business Rules │ +└─────────────────────────────────────┘ + │ AppVersion Entity + ▼ +┌─────────────────────────────────────┐ +│ AppVersionRepositoryImpl.save() │ ← Infrastructure Layer +│ 1. Map Entity → Prisma Model │ +│ 2. Save to Database │ +│ 3. Return Persisted Entity │ +└─────────────────────────────────────┘ + │ + ▼ + PostgreSQL +``` + +### 6.2 检查更新流程 + +``` +Mobile Client (GET /api/v1/version/check?platform=android&versionCode=100) + │ + ▼ +┌─────────────────────────────────────┐ +│ VersionController.checkForUpdate() │ ← API Layer +└─────────────────────────────────────┘ + │ CheckVersionDto + ▼ +┌─────────────────────────────────────┐ +│ VersionCheckService.checkForUpdate()│ ← Domain Service +│ 1. Query Latest Enabled Version │ +│ 2. Compare Version Codes │ +│ 3. Build Update Result │ +└─────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────┐ +│ AppVersionRepository │ ← Repository +│ .findLatestEnabledVersion() │ +└─────────────────────────────────────┘ + │ + ▼ + PostgreSQL + │ + ▼ +┌─────────────────────────────────────┐ +│ VersionCheckResult │ ← Response +│ - hasUpdate: boolean │ +│ - latestVersion: string │ +│ - downloadUrl: string │ +│ - isForceUpdate: boolean │ +│ - changelog: string │ +└─────────────────────────────────────┘ +``` + +### 6.3 依赖方向 + +``` +API Layer + ↓ depends on +Application Layer + ↓ depends on +Domain Layer (Core) + ↑ implemented by +Infrastructure Layer +``` + +**核心原则**: +- Domain Layer 不依赖任何外部层 +- Infrastructure Layer 通过接口依赖 Domain Layer (依赖倒置原则) +- Application Layer 协调 Domain 和 Infrastructure +- API Layer 仅依赖 Application Layer + +--- + +## 7. 设计原则 + +### 7.1 SOLID 原则应用 + +| 原则 | 应用实例 | +|-----|---------| +| **S** (单一职责) | 每个值对象只负责一个验证逻辑
每个 Handler 只处理一个命令/查询 | +| **O** (开闭原则) | 新增平台类型无需修改现有代码
通过 enum 扩展实现 | +| **L** (里氏替换) | Repository 接口可被不同实现替换
(Prisma, TypeORM, InMemory) | +| **I** (接口隔离) | Repository 接口仅定义必要方法
不强制实现不需要的功能 | +| **D** (依赖倒置) | Domain Layer 定义 Repository 接口
Infrastructure Layer 实现接口 | + +### 7.2 DDD 战术模式 + +| 模式 | 应用 | +|-----|------| +| **Entity** | `AppVersion` 聚合根 | +| **Value Object** | `VersionCode`, `VersionName`, `FileSize`, `FileSha256` | +| **Aggregate** | `AppVersion` 作为聚合边界 | +| **Repository** | `AppVersionRepository` 接口及实现 | +| **Domain Service** | `VersionCheckService` 处理跨实体逻辑 | +| **Factory Method** | `AppVersion.create()` 静态工厂方法 | + +--- + +## 8. 扩展性设计 + +### 8.1 新增平台支持 + +当需要支持新平台(如 HarmonyOS)时: + +1. **枚举扩展** (`domain/enums/platform.enum.ts`): +```typescript +export enum Platform { + ANDROID = 'android', + IOS = 'ios', + HARMONYOS = 'harmonyos', // 新增 +} +``` + +2. **无需修改**: + - Entity 逻辑 + - Repository 实现 + - Controller/Handler + +### 8.2 新增版本检查策略 + +当需要支持灰度发布、A/B 测试时: + +1. **新增领域服务**: +```typescript +class GrayReleaseService { + async checkEligibility(userId: string, version: AppVersion): Promise +} +``` + +2. **修改 VersionCheckService**: +```typescript +async checkForUpdate( + platform: Platform, + currentVersionCode: number, + userId?: string, // 新增参数 +): Promise +``` + +--- + +## 9. 性能考量 + +### 9.1 数据库索引 + +```sql +-- 平台 + 版本号唯一索引 +CREATE UNIQUE INDEX idx_platform_versioncode +ON "AppVersion" (platform, "versionCode"); + +-- 启用状态 + 平台 + 版本号索引(查询最新版本) +CREATE INDEX idx_enabled_platform_versioncode +ON "AppVersion" ("isEnabled", platform, "versionCode" DESC); +``` + +### 9.2 缓存策略 + +**建议实现** (当前未实现): +```typescript +@Injectable() +export class CachedVersionCheckService { + constructor( + private readonly versionCheckService: VersionCheckService, + private readonly cacheManager: Cache, + ) {} + + async checkForUpdate(platform: Platform, versionCode: number) { + const cacheKey = `version:${platform}:${versionCode}`; + const cached = await this.cacheManager.get(cacheKey); + if (cached) return cached; + + const result = await this.versionCheckService.checkForUpdate(platform, versionCode); + await this.cacheManager.set(cacheKey, result, { ttl: 300 }); // 5分钟 + return result; + } +} +``` + +--- + +## 10. 安全性 + +### 10.1 文件校验 + +- **SHA256 验证**: 确保下载文件未被篡改 +- **下载 URL**: 建议使用 HTTPS + CDN +- **文件大小**: 防止异常大文件攻击 + +### 10.2 API 安全 (待实现) + +```typescript +@Controller('api/v1/version') +@UseGuards(JwtAuthGuard) // 管理端需要认证 +export class VersionController { + @Post() + @UseGuards(RolesGuard) + @Roles('admin', 'developer') // 仅管理员和开发者可创建版本 + async createVersion(@Body() dto: CreateVersionDto) {} + + @Get('check') + // 公开端点,无需认证 + async checkForUpdate(@Query() dto: CheckVersionDto) {} +} +``` + +--- + +## 11. 监控和日志 + +### 11.1 关键指标 + +| 指标 | 说明 | 监控方式 | +|-----|------|---------| +| 版本检查 QPS | 每秒查询次数 | Prometheus + Grafana | +| 创建版本成功率 | 创建操作成功/失败比例 | Application Logs | +| 数据库查询延迟 | 查询耗时 | Prisma Metrics | +| 强制更新触发率 | 强制更新用户占比 | Business Metrics | + +### 11.2 日志记录 + +```typescript +@Injectable() +export class CreateVersionHandler { + private readonly logger = new Logger(CreateVersionHandler.name); + + async execute(command: CreateVersionCommand): Promise { + this.logger.log(`Creating version: ${command.platform} v${command.versionName}`); + + try { + const version = await this.repository.save(appVersion); + this.logger.log(`Version created successfully: ${version.id}`); + return version; + } catch (error) { + this.logger.error(`Failed to create version: ${error.message}`, error.stack); + throw error; + } + } +} +``` + +--- + +## 12. 未来改进 + +### 12.1 短期 (1-3 个月) + +- [ ] 实现 JWT 认证和 RBAC 权限控制 +- [ ] 添加版本删除功能(软删除) +- [ ] 实现分页查询 +- [ ] 添加 Redis 缓存层 + +### 12.2 中期 (3-6 个月) + +- [ ] 实现灰度发布功能 +- [ ] 添加版本回滚机制 +- [ ] 实现版本发布审批流程 +- [ ] 集成 CDN 文件上传 + +### 12.3 长期 (6-12 个月) + +- [ ] 实现多渠道版本管理(Google Play, App Store, 自建服务器) +- [ ] 添加 A/B 测试支持 +- [ ] 实现版本使用统计和分析 +- [ ] 集成 Sentry 错误监控 + +--- + +**最后更新**: 2025-12-03 +**版本**: 1.0.0 +**维护者**: RWA Durian Team diff --git a/backend/services/admin-service/docs/DEPLOYMENT.md b/backend/services/admin-service/docs/DEPLOYMENT.md new file mode 100644 index 00000000..f72ff624 --- /dev/null +++ b/backend/services/admin-service/docs/DEPLOYMENT.md @@ -0,0 +1,1078 @@ +# Admin Service 部署文档 + +## 目录 + +- [1. 部署概述](#1-部署概述) +- [2. 环境准备](#2-环境准备) +- [3. 本地部署](#3-本地部署) +- [4. Docker 部署](#4-docker-部署) +- [5. 生产环境部署](#5-生产环境部署) +- [6. 监控和维护](#6-监控和维护) +- [7. 故障排查](#7-故障排查) + +--- + +## 1. 部署概述 + +### 1.1 部署架构 + +``` +┌─────────────────────────────────────────────────┐ +│ Load Balancer │ +│ (Nginx / AWS ALB / etc.) │ +└───────────────────┬─────────────────────────────┘ + │ + ┌───────────┼───────────┐ + │ │ │ + ▼ ▼ ▼ +┌──────────┐ ┌──────────┐ ┌──────────┐ +│ Admin │ │ Admin │ │ Admin │ +│ Service │ │ Service │ │ Service │ +│ Instance │ │ Instance │ │ Instance │ +└────┬─────┘ └────┬─────┘ └────┬─────┘ + │ │ │ + └─────────────┼─────────────┘ + │ + ▼ + ┌──────────────────┐ + │ PostgreSQL │ + │ (Primary + │ + │ Replicas) │ + └──────────────────┘ +``` + +### 1.2 部署环境 + +| 环境 | 说明 | 数据库 | 实例数 | +|-----|------|--------|-------| +| **Development** | 开发环境 | 本地/Docker | 1 | +| **Staging** | 预发布环境 | 独立数据库 | 1-2 | +| **Production** | 生产环境 | 高可用集群 | 3+ | + +### 1.3 系统要求 + +#### 最低配置 + +| 资源 | 要求 | +|-----|------| +| **CPU** | 2 核心 | +| **内存** | 2 GB | +| **硬盘** | 20 GB (SSD) | +| **网络** | 100 Mbps | + +#### 推荐配置 (生产环境) + +| 资源 | 要求 | +|-----|------| +| **CPU** | 4 核心 | +| **内存** | 4-8 GB | +| **硬盘** | 50 GB (SSD) | +| **网络** | 1 Gbps | + +--- + +## 2. 环境准备 + +### 2.1 服务器准备 + +```bash +# Ubuntu 22.04 LTS 示例 + +# 1. 更新系统 +sudo apt update && sudo apt upgrade -y + +# 2. 安装基础工具 +sudo apt install -y \ + curl \ + wget \ + git \ + build-essential \ + ca-certificates \ + gnupg \ + lsb-release + +# 3. 安装 Node.js 20.x +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt install -y nodejs + +# 验证 +node --version # v20.x.x +npm --version # 10.x.x + +# 4. 安装 PM2 (进程管理器) +sudo npm install -g pm2 + +# 5. 安装 PostgreSQL 16 +sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - +sudo apt update +sudo apt install -y postgresql-16 +``` + +### 2.2 数据库配置 + +```bash +# 1. 切换到 postgres 用户 +sudo -u postgres psql + +# 2. 创建数据库和用户 +CREATE DATABASE admin_service_prod; +CREATE USER admin_service WITH ENCRYPTED PASSWORD 'your_secure_password'; +GRANT ALL PRIVILEGES ON DATABASE admin_service_prod TO admin_service; + +# 3. 退出 psql +\q + +# 4. 配置 PostgreSQL 允许远程连接 (如果需要) +sudo nano /etc/postgresql/16/main/postgresql.conf +# 修改: listen_addresses = '*' + +sudo nano /etc/postgresql/16/main/pg_hba.conf +# 添加: host all all 0.0.0.0/0 md5 + +# 5. 重启 PostgreSQL +sudo systemctl restart postgresql +``` + +### 2.3 防火墙配置 + +```bash +# UFW 防火墙配置 +sudo ufw allow 22/tcp # SSH +sudo ufw allow 3005/tcp # Admin Service (或通过 Nginx 反向代理) +sudo ufw allow 5432/tcp # PostgreSQL (仅内网) + +sudo ufw enable +sudo ufw status +``` + +--- + +## 3. 本地部署 + +### 3.1 克隆代码 + +```bash +cd /opt +sudo git clone https://github.com/your-org/rwa-durian.git +cd rwa-durian/backend/services/admin-service + +# 设置权限 +sudo chown -R $USER:$USER /opt/rwa-durian +``` + +### 3.2 安装依赖 + +```bash +npm ci --omit=dev +``` + +### 3.3 环境配置 + +创建 `.env.production`: + +```env +# 应用配置 +NODE_ENV=production +APP_PORT=3005 +API_PREFIX=api/v1 + +# 数据库配置 +DATABASE_URL=postgresql://admin_service:your_secure_password@localhost:5432/admin_service_prod?schema=public + +# 日志配置 +LOG_LEVEL=info + +# CORS 配置 +CORS_ORIGIN=https://admin.rwadurian.com,https://app.rwadurian.com + +# 安全配置 (待实现) +JWT_SECRET=your_super_secret_jwt_key_change_in_production +``` + +### 3.4 数据库迁移 + +```bash +# 生成 Prisma Client +npm run prisma:generate + +# 运行迁移 +npm run prisma:migrate:deploy + +# (可选) 运行初始化脚本 +psql -U admin_service -d admin_service_prod -f database/init.sql +``` + +### 3.5 构建应用 + +```bash +npm run build +``` + +### 3.6 使用 PM2 启动 + +创建 `ecosystem.config.js`: + +```javascript +module.exports = { + apps: [ + { + name: 'admin-service', + script: 'dist/main.js', + instances: 2, // CPU 核心数 + exec_mode: 'cluster', + env: { + NODE_ENV: 'production', + APP_PORT: 3005, + }, + env_file: '.env.production', + error_file: 'logs/error.log', + out_file: 'logs/out.log', + log_date_format: 'YYYY-MM-DD HH:mm:ss', + merge_logs: true, + autorestart: true, + max_memory_restart: '500M', + watch: false, + }, + ], +}; +``` + +启动服务: + +```bash +# 启动 +pm2 start ecosystem.config.js + +# 查看状态 +pm2 status + +# 查看日志 +pm2 logs admin-service + +# 重启 +pm2 restart admin-service + +# 停止 +pm2 stop admin-service + +# 删除 +pm2 delete admin-service +``` + +### 3.7 设置开机自启动 + +```bash +# 保存 PM2 进程列表 +pm2 save + +# 生成启动脚本 +pm2 startup systemd + +# 执行输出的命令 (类似): +# sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u your_user --hp /home/your_user +``` + +### 3.8 验证部署 + +```bash +# 检查服务状态 +curl http://localhost:3005/api/v1/health + +# 预期响应 +{"status": "ok"} + +# 检查版本查询 +curl http://localhost:3005/api/v1/version/check?platform=android&versionCode=1 + +# PM2 状态 +pm2 status +``` + +--- + +## 4. Docker 部署 + +### 4.1 Dockerfile + +**Dockerfile**: +```dockerfile +# 构建阶段 +FROM node:20-alpine AS builder + +WORKDIR /app + +# 安装 OpenSSL (Prisma 需要) +RUN apk add --no-cache openssl + +# 复制 package.json 和 package-lock.json +COPY package*.json ./ +COPY prisma ./prisma/ + +# 安装依赖 +RUN npm ci + +# 生成 Prisma Client +RUN npx prisma generate + +# 复制源代码 +COPY . . + +# 构建 +RUN npm run build + +# 生产阶段 +FROM node:20-alpine + +WORKDIR /app + +RUN apk add --no-cache openssl + +# 复制依赖 +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package*.json ./ +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/prisma ./prisma + +# 暴露端口 +EXPOSE 3005 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \ + CMD wget -q --spider http://localhost:3005/api/v1/health || exit 1 + +# 启动命令 +CMD ["node", "dist/main.js"] +``` + +### 4.2 Docker Compose + +**docker-compose.yml**: +```yaml +version: '3.8' + +services: + admin-service: + build: + context: . + dockerfile: Dockerfile + container_name: admin-service + restart: unless-stopped + ports: + - "3005:3005" + environment: + - NODE_ENV=production + - APP_PORT=3005 + - API_PREFIX=api/v1 + - DATABASE_URL=postgresql://postgres:password@postgres:5432/admin_service_prod + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://localhost:3005/api/v1/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + networks: + - admin-network + + postgres: + image: postgres:16-alpine + container_name: admin-postgres + restart: unless-stopped + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=password + - POSTGRES_DB=admin_service_prod + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + - ./database/init.sql:/docker-entrypoint-initdb.d/init.sql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 10 + networks: + - admin-network + +volumes: + postgres_data: + +networks: + admin-network: + driver: bridge +``` + +### 4.3 Docker 部署步骤 + +```bash +# 1. 构建镜像 +docker-compose build + +# 2. 启动服务 +docker-compose up -d + +# 3. 运行数据库迁移 +docker-compose exec admin-service npx prisma migrate deploy + +# 4. 查看日志 +docker-compose logs -f admin-service + +# 5. 查看状态 +docker-compose ps + +# 6. 停止服务 +docker-compose down + +# 7. 清理 (包括数据) +docker-compose down -v +``` + +### 4.4 Docker 健康检查 + +```bash +# 检查容器健康状态 +docker ps + +# 查看健康检查日志 +docker inspect admin-service | jq '.[0].State.Health' + +# 手动健康检查 +docker exec admin-service wget -q -O - http://localhost:3005/api/v1/health +``` + +--- + +## 5. 生产环境部署 + +### 5.1 Nginx 反向代理 + +**安装 Nginx**: +```bash +sudo apt install -y nginx +``` + +**配置文件** (`/etc/nginx/sites-available/admin-service`): +```nginx +upstream admin_service { + least_conn; + server 127.0.0.1:3005; + # server 127.0.0.1:3006; # 多实例负载均衡 + # server 127.0.0.1:3007; +} + +server { + listen 80; + listen [::]:80; + server_name admin-api.rwadurian.com; + + # 重定向到 HTTPS + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name admin-api.rwadurian.com; + + # SSL 证书 + ssl_certificate /etc/letsencrypt/live/admin-api.rwadurian.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/admin-api.rwadurian.com/privkey.pem; + + # SSL 配置 + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # 日志 + access_log /var/log/nginx/admin-service-access.log; + error_log /var/log/nginx/admin-service-error.log; + + # 代理配置 + location /api/v1/ { + proxy_pass http://admin_service; + proxy_http_version 1.1; + + # 请求头 + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + 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_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # 缓存禁用 (API 不需要) + proxy_cache_bypass $http_upgrade; + } + + # 健康检查端点 + location /health { + proxy_pass http://admin_service/api/v1/health; + access_log off; + } +} +``` + +**启用配置**: +```bash +sudo ln -s /etc/nginx/sites-available/admin-service /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl reload nginx +``` + +### 5.2 SSL 证书 (Let's Encrypt) + +```bash +# 安装 Certbot +sudo apt install -y certbot python3-certbot-nginx + +# 获取证书 +sudo certbot --nginx -d admin-api.rwadurian.com + +# 自动续期测试 +sudo certbot renew --dry-run + +# 自动续期 (crontab) +sudo crontab -e +# 添加: 0 3 * * * certbot renew --quiet +``` + +### 5.3 日志管理 + +#### 日志轮转 + +创建 `/etc/logrotate.d/admin-service`: + +``` +/opt/rwa-durian/backend/services/admin-service/logs/*.log { + daily + rotate 30 + compress + delaycompress + notifempty + create 0640 your_user your_user + sharedscripts + postrotate + pm2 reloadLogs + endscript +} +``` + +#### 查看日志 + +```bash +# PM2 日志 +pm2 logs admin-service + +# 实时日志 +pm2 logs admin-service --lines 100 + +# 错误日志 +pm2 logs admin-service --err + +# Nginx 日志 +sudo tail -f /var/log/nginx/admin-service-access.log +sudo tail -f /var/log/nginx/admin-service-error.log +``` + +### 5.4 数据库备份 + +#### 自动备份脚本 + +创建 `/opt/scripts/backup-admin-db.sh`: + +```bash +#!/bin/bash + +# 配置 +DB_NAME="admin_service_prod" +DB_USER="admin_service" +BACKUP_DIR="/opt/backups/admin-service" +DATE=$(date +%Y%m%d_%H%M%S) +RETENTION_DAYS=30 + +# 创建备份目录 +mkdir -p $BACKUP_DIR + +# 执行备份 +pg_dump -U $DB_USER -d $DB_NAME -F c -b -v -f "$BACKUP_DIR/admin_service_$DATE.backup" + +# 压缩 +gzip "$BACKUP_DIR/admin_service_$DATE.backup" + +# 删除旧备份 +find $BACKUP_DIR -name "*.backup.gz" -mtime +$RETENTION_DAYS -delete + +echo "Backup completed: admin_service_$DATE.backup.gz" +``` + +#### 设置定时任务 + +```bash +chmod +x /opt/scripts/backup-admin-db.sh + +# 添加到 crontab +crontab -e +# 每天凌晨 2 点备份 +0 2 * * * /opt/scripts/backup-admin-db.sh >> /var/log/admin-service-backup.log 2>&1 +``` + +#### 恢复数据库 + +```bash +# 解压备份 +gunzip admin_service_20250103_020000.backup.gz + +# 恢复 +pg_restore -U admin_service -d admin_service_prod -v admin_service_20250103_020000.backup +``` + +### 5.5 监控告警 + +#### PM2 监控 + +```bash +# 安装 PM2 Plus (可选) +pm2 install pm2-logrotate +pm2 install pm2-server-monit + +# 查看监控 +pm2 monit +``` + +#### 健康检查脚本 + +创建 `/opt/scripts/health-check.sh`: + +```bash +#!/bin/bash + +HEALTH_URL="http://localhost:3005/api/v1/health" +ALERT_EMAIL="admin@rwadurian.com" + +response=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL) + +if [ "$response" != "200" ]; then + echo "Admin Service health check failed! HTTP code: $response" | \ + mail -s "Admin Service Alert" $ALERT_EMAIL + + # 自动重启 (可选) + pm2 restart admin-service +fi +``` + +#### 设置监控定时任务 + +```bash +crontab -e +# 每 5 分钟检查一次 +*/5 * * * * /opt/scripts/health-check.sh +``` + +--- + +## 6. 监控和维护 + +### 6.1 性能监控 + +#### 应用指标 + +```bash +# CPU 和内存使用 +pm2 monit + +# 详细指标 +pm2 describe admin-service + +# 进程列表 +pm2 list +``` + +#### 数据库监控 + +```bash +# 连接数 +sudo -u postgres psql -c "SELECT count(*) FROM pg_stat_activity WHERE datname = 'admin_service_prod';" + +# 慢查询 +sudo -u postgres psql -d admin_service_prod -c "SELECT query, calls, total_time, mean_time FROM pg_stat_statements ORDER BY mean_time DESC LIMIT 10;" + +# 数据库大小 +sudo -u postgres psql -c "SELECT pg_size_pretty(pg_database_size('admin_service_prod'));" +``` + +### 6.2 日常维护 + +#### 更新应用 + +```bash +cd /opt/rwa-durian/backend/services/admin-service + +# 1. 备份当前版本 +cp -r dist dist.backup.$(date +%Y%m%d) + +# 2. 拉取最新代码 +git pull origin main + +# 3. 安装依赖 +npm ci --omit=dev + +# 4. 运行迁移 +npm run prisma:migrate:deploy + +# 5. 构建 +npm run build + +# 6. 重启服务 +pm2 restart admin-service + +# 7. 验证 +curl http://localhost:3005/api/v1/health + +# 8. 查看日志 +pm2 logs admin-service --lines 50 +``` + +#### 数据库维护 + +```bash +# 1. 分析表 +sudo -u postgres psql -d admin_service_prod -c "ANALYZE;" + +# 2. 清理死元组 +sudo -u postgres psql -d admin_service_prod -c "VACUUM ANALYZE;" + +# 3. 重建索引 +sudo -u postgres psql -d admin_service_prod -c "REINDEX DATABASE admin_service_prod;" +``` + +### 6.3 扩容方案 + +#### 垂直扩容 (增加资源) + +```bash +# 1. 调整 PM2 实例数 +pm2 scale admin-service 4 # 增加到 4 个实例 + +# 2. 调整内存限制 +# 编辑 ecosystem.config.js +max_memory_restart: '1G' # 增加到 1GB + +pm2 restart admin-service +``` + +#### 水平扩容 (增加服务器) + +1. 在新服务器上重复本地部署步骤 +2. 配置 Nginx 负载均衡: + +```nginx +upstream admin_service { + least_conn; + server 192.168.1.10:3005 weight=1; + server 192.168.1.11:3005 weight=1; + server 192.168.1.12:3005 weight=1; +} +``` + +3. 重新加载 Nginx: +```bash +sudo nginx -t +sudo systemctl reload nginx +``` + +--- + +## 7. 故障排查 + +### 7.1 常见问题 + +#### 问题 1: 服务无法启动 + +**症状**: +```bash +pm2 logs admin-service +# Error: Cannot find module '@prisma/client' +``` + +**解决方案**: +```bash +npm run prisma:generate +pm2 restart admin-service +``` + +#### 问题 2: 数据库连接失败 + +**症状**: +``` +Error: P1001: Can't reach database server +``` + +**排查步骤**: +```bash +# 1. 检查 PostgreSQL 状态 +sudo systemctl status postgresql + +# 2. 测试数据库连接 +psql -U admin_service -h localhost -d admin_service_prod + +# 3. 检查 DATABASE_URL 配置 +cat .env.production | grep DATABASE_URL + +# 4. 检查防火墙 +sudo ufw status +``` + +#### 问题 3: 内存泄漏 + +**症状**: +```bash +pm2 list +# admin-service 内存持续增长 +``` + +**排查步骤**: +```bash +# 1. 查看内存使用 +pm2 describe admin-service + +# 2. 分析堆内存 +node --inspect dist/main.js +# 访问 chrome://inspect + +# 3. 临时解决 - 重启 +pm2 restart admin-service + +# 4. 调整内存限制 +# ecosystem.config.js +max_memory_restart: '500M' +``` + +#### 问题 4: 高并发性能下降 + +**症状**: 响应时间变长,超时增加 + +**优化方案**: + +1. **增加实例数**: +```bash +pm2 scale admin-service +2 +``` + +2. **数据库连接池**: +```javascript +// prisma/schema.prisma +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" + previewFeatures = ["metrics"] +} + +// src/infrastructure/prisma/prisma.service.ts +@Injectable() +export class PrismaService extends PrismaClient { + constructor() { + super({ + datasources: { + db: { + url: process.env.DATABASE_URL, + }, + }, + connectionLimit: 10, // 增加连接池 + }); + } +} +``` + +3. **添加缓存** (Redis): +```bash +# 安装 Redis +sudo apt install -y redis-server + +# 配置缓存 +npm install @nestjs/cache-manager cache-manager cache-manager-redis-store +``` + +### 7.2 日志分析 + +#### 错误日志 + +```bash +# 查看最近的错误 +pm2 logs admin-service --err --lines 100 + +# 搜索特定错误 +pm2 logs admin-service --err | grep "Error" + +# Nginx 错误日志 +sudo tail -100 /var/log/nginx/admin-service-error.log +``` + +#### 性能分析 + +```bash +# PM2 性能监控 +pm2 monit + +# Node.js profiler +node --prof dist/main.js +# 生成 isolate-*.log + +# 分析 profile +node --prof-process isolate-*.log > profile.txt +``` + +### 7.3 回滚策略 + +#### 应用回滚 + +```bash +# 1. 停止服务 +pm2 stop admin-service + +# 2. 恢复备份代码 +rm -rf dist +mv dist.backup.20250103 dist + +# 3. 回滚数据库迁移 (谨慎!) +DATABASE_URL="..." npx prisma migrate resolve --rolled-back 20250103100000_add_new_field + +# 4. 重启服务 +pm2 start admin-service + +# 5. 验证 +curl http://localhost:3005/api/v1/health +``` + +#### 数据库回滚 + +```bash +# 恢复数据库备份 +pg_restore -U admin_service -d admin_service_prod -c admin_service_20250103_020000.backup +``` + +--- + +## 8. 安全加固 + +### 8.1 应用安全 + +```bash +# 1. 限制 Node.js 进程权限 +# 创建专用用户 +sudo useradd -r -s /bin/false admin_service + +# 2. 设置文件权限 +sudo chown -R admin_service:admin_service /opt/rwa-durian/backend/services/admin-service +sudo chmod -R 750 /opt/rwa-durian/backend/services/admin-service + +# 3. 使用环境变量管理敏感信息 +# .env.production 权限 +chmod 600 .env.production +``` + +### 8.2 数据库安全 + +```bash +# 1. 修改默认密码 +sudo -u postgres psql +ALTER USER admin_service WITH PASSWORD 'new_strong_password'; + +# 2. 限制网络访问 +# /etc/postgresql/16/main/pg_hba.conf +host admin_service_prod admin_service 127.0.0.1/32 md5 + +# 3. 启用 SSL +# postgresql.conf +ssl = on +``` + +### 8.3 Nginx 安全 + +```nginx +# 隐藏版本号 +server_tokens off; + +# 限流 +limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; + +server { + # ... + location /api/v1/ { + limit_req zone=api_limit burst=20; + proxy_pass http://admin_service; + } +} +``` + +--- + +## 9. 快速参考 + +### 9.1 常用命令 + +```bash +# PM2 管理 +pm2 start admin-service +pm2 stop admin-service +pm2 restart admin-service +pm2 reload admin-service # 零停机重启 +pm2 delete admin-service +pm2 logs admin-service +pm2 monit + +# 数据库 +npm run prisma:migrate:deploy +npm run prisma:generate +npm run prisma:studio + +# 构建 +npm run build +npm run start:prod + +# 健康检查 +curl http://localhost:3005/api/v1/health + +# Nginx +sudo systemctl status nginx +sudo systemctl reload nginx +sudo nginx -t +``` + +### 9.2 检查清单 + +#### 部署前 + +- [ ] 代码已通过所有测试 +- [ ] 环境变量已正确配置 +- [ ] 数据库迁移已准备 +- [ ] SSL 证书已配置 +- [ ] 备份策略已设置 +- [ ] 监控告警已配置 + +#### 部署后 + +- [ ] 服务健康检查通过 +- [ ] 数据库连接正常 +- [ ] API 端点可访问 +- [ ] 日志正常输出 +- [ ] 性能指标正常 +- [ ] 备份自动执行 + +--- + +**最后更新**: 2025-12-03 +**版本**: 1.0.0 +**维护者**: RWA Durian Team diff --git a/backend/services/admin-service/docs/DEVELOPMENT.md b/backend/services/admin-service/docs/DEVELOPMENT.md new file mode 100644 index 00000000..b8e0beba --- /dev/null +++ b/backend/services/admin-service/docs/DEVELOPMENT.md @@ -0,0 +1,1061 @@ +# Admin Service 开发指南 + +## 目录 + +- [1. 开发环境设置](#1-开发环境设置) +- [2. 项目初始化](#2-项目初始化) +- [3. 开发流程](#3-开发流程) +- [4. 代码规范](#4-代码规范) +- [5. 调试技巧](#5-调试技巧) +- [6. 常见开发任务](#6-常见开发任务) + +--- + +## 1. 开发环境设置 + +### 1.1 系统要求 + +| 工具 | 版本要求 | 说明 | +|-----|---------|------| +| **Node.js** | >= 20.x | 推荐使用 LTS 版本 | +| **npm** | >= 10.x | 或使用 yarn/pnpm | +| **PostgreSQL** | >= 16.x | 本地开发或 Docker | +| **Docker** | >= 24.x | (可选) 容器化开发 | +| **Git** | >= 2.x | 版本控制 | +| **VSCode** | 最新版 | 推荐 IDE | + +### 1.2 VSCode 推荐插件 + +```json +{ + "recommendations": [ + "dbaeumer.vscode-eslint", // ESLint + "esbenp.prettier-vscode", // Prettier + "prisma.prisma", // Prisma + "firsttris.vscode-jest-runner", // Jest Runner + "orta.vscode-jest", // Jest + "ms-vscode.vscode-typescript-next", // TypeScript + "usernamehw.errorlens", // Error Lens + "eamodio.gitlens" // GitLens + ] +} +``` + +保存到 `.vscode/extensions.json` + +### 1.3 VSCode 工作区设置 + +```json +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "typescript.preferences.importModuleSpecifier": "relative", + "jest.autoRun": "off", + "[prisma]": { + "editor.defaultFormatter": "Prisma.prisma" + } +} +``` + +保存到 `.vscode/settings.json` + +--- + +## 2. 项目初始化 + +### 2.1 克隆项目 + +```bash +git clone https://github.com/your-org/rwa-durian.git +cd rwa-durian/backend/services/admin-service +``` + +### 2.2 安装依赖 + +```bash +# 使用 npm +npm install + +# 或使用 yarn +yarn install + +# 或使用 pnpm +pnpm install +``` + +### 2.3 环境配置 + +创建 `.env.development` 文件: + +```env +# 应用配置 +NODE_ENV=development +APP_PORT=3005 +API_PREFIX=api/v1 + +# 数据库配置 +DATABASE_URL=postgresql://postgres:password@localhost:5432/admin_service_dev?schema=public + +# 日志配置 +LOG_LEVEL=debug + +# CORS 配置 +CORS_ORIGIN=http://localhost:3000,http://localhost:3001 +``` + +**注意**: 不要提交 `.env.*` 文件到 Git!已添加到 `.gitignore`。 + +### 2.4 数据库初始化 + +#### 方案 1: 本地 PostgreSQL + +```bash +# 1. 创建数据库 +psql -U postgres -c "CREATE DATABASE admin_service_dev;" + +# 2. 运行迁移 +npm run prisma:migrate:dev + +# 3. 生成 Prisma Client +npm run prisma:generate +``` + +#### 方案 2: Docker PostgreSQL + +```bash +# 1. 启动数据库容器 +docker run -d \ + --name admin-dev-db \ + -e POSTGRES_USER=postgres \ + -e POSTGRES_PASSWORD=password \ + -e POSTGRES_DB=admin_service_dev \ + -p 5432:5432 \ + postgres:16-alpine + +# 2. 运行迁移 +npm run prisma:migrate:dev + +# 3. 生成 Prisma Client +npm run prisma:generate +``` + +### 2.5 验证环境 + +```bash +# 检查数据库连接 +npm run prisma:studio + +# 运行测试 +npm run test:unit + +# 启动开发服务器 +npm run start:dev +``` + +访问 `http://localhost:3005/api/v1/health` 应返回: +```json +{"status": "ok"} +``` + +--- + +## 3. 开发流程 + +### 3.1 Git 工作流 + +#### 分支策略 + +``` +main (生产) + ↑ +develop (开发) + ↑ +feature/xxx (功能分支) +hotfix/xxx (紧急修复) +``` + +#### 创建功能分支 + +```bash +# 从 develop 创建功能分支 +git checkout develop +git pull origin develop +git checkout -b feature/add-version-delete + +# 开发... + +# 提交 +git add . +git commit -m "feat(version): add delete version functionality" + +# 推送 +git push origin feature/add-version-delete + +# 创建 Pull Request +``` + +#### Commit Message 规范 + +遵循 [Conventional Commits](https://www.conventionalcommits.org/): + +``` +(): + + + +