# 技术栈与开发环境 ## 核心技术栈 ### 后端框架 - **NestJS 11.x**: TypeScript 原生支持的企业级 Node.js 框架 - **TypeScript 5.7+**: 类型安全的 JavaScript 超集 - **Express.js**: 底层 HTTP 服务器框架(NestJS 内置) ### 数据库与 ORM - **MySQL 8.0**: 主数据库,支持 JSON 字段和全文索引 - **Sequelize 6.x**: ORM 框架,支持 TypeScript 和迁移 - **Sequelize-typescript**: TypeScript 类型定义和装饰器支持 ### 认证与安全 - **JWT (jsonwebtoken)**: 无状态身份认证 - **Apple Sign-In**: iOS 生态登录集成 - **crypto-js**: 客户端/服务端加密工具 - **AES-256-GCM**: 敏感数据加密标准 ### AI 与机器学习 - **OpenAI SDK**: AI 模型调用统一接口 - **通义千问 (阿里云)**: 主要 AI 模型服务 - **qwen-vl-max**: 视觉识别专用模型 - **qwen-flash**: 快速对话模型 ### 文件存储与云服务 - **腾讯云 COS**: 对象存储服务 - **qcloud-cos-sts**: 临时访问凭证管理 - **APNs (Apple Push Notification)**: iOS 推送服务 - **@parse/node-apn**: APNs 服务端 SDK ## 开发工具与环境 ### 包管理与构建 - **yarn**: 包管理器(支持工作空间) - **npm**: 备用包管理器 - **SWC**: 快速 TypeScript 编译器 - **ts-node**: 开发时 TypeScript 执行 ### 代码质量与规范 - **ESLint 9.x**: 代码质量检查 - **Prettier**: 代码格式化 - **TypeScript**: 静态类型检查 - **Husky**: Git hooks 管理(未配置但推荐) ### 测试框架 - **Jest 29.x**: 单元测试和集成测试 - **Supertest**: HTTP 接口测试 - **ts-jest**: TypeScript 测试支持 ### 部署与运维 - **PM2**: Node.js 进程管理器 - **Docker**: 容器化部署(未完全实现) - **Nginx**: 反向代理和负载均衡 - **Winston**: 结构化日志记录 ## 项目配置文件 ### 核心配置 - `package.json`: 项目依赖和脚本定义 - `tsconfig.json`: TypeScript 编译配置 - `nest-cli.json`: NestJS CLI 配置 - `ecosystem.config.js`: PM2 集群配置 ### 环境配置 - `.env`: 开发环境变量(不提交到版本控制) - `.env.glm.example`: 环境变量模板 - `eslint.config.mjs`: ESLint 配置 ### 部署配置 - `deploy.sh`: 完整部署脚本 - `deploy-optimized.sh`: 优化部署脚本 - `start.sh`: 服务启动脚本 ## 开发环境设置 ### 本地开发要求 - **Node.js**: >= 18.0.0 - **MySQL**: >= 8.0 - **yarn**: 最新稳定版 - **Git**: 版本控制 ### 开发命令 ```bash # 安装依赖 yarn install # 开发模式启动 yarn start:dev # 构建项目 yarn build # 生产模式启动 yarn start:prod # 运行测试 yarn test # 代码检查 yarn lint # 代码格式化 yarn format ``` ### PM2 管理命令 ```bash # 启动开发环境 yarn pm2:start:dev # 启动生产环境 yarn pm2:start # 查看状态 yarn pm2:status # 查看日志 yarn pm2:logs # 重启服务 yarn pm2:restart # 停止服务 yarn pm2:stop ``` ## 环境变量配置 ### 必需的环境变量 ```bash # 数据库配置 DB_HOST=localhost DB_PORT=3306 DB_USERNAME=your_username DB_PASSWORD=your_password DB_DATABASE=pilates_db # JWT 配置 JWT_SECRET=your_jwt_secret_key JWT_EXPIRES_IN=7d REFRESH_TOKEN_SECRET=your_refresh_token_secret REFRESH_TOKEN_EXPIRES_IN=30d # Apple 认证配置 APPLE_BUNDLE_ID=com.yourcompany.pilates APPLE_KEY_ID=your_apple_key_id APPLE_ISSUER_ID=your_apple_issuer_id APPLE_PRIVATE_KEY_PATH=path/to/private/key.p8 APPLE_APP_SHARED_SECRET=your_app_shared_secret # AI 服务配置 DASHSCOPE_API_KEY=your_dashscope_api_key DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 DASHSCOPE_MODEL=qwen-flash DASHSCOPE_VISION_MODEL=qwen-vl-max # 加密配置 ENCRYPTION_KEY=your-32-character-secret-key-here # 腾讯云 COS 配置 COS_SECRET_ID=your_cos_secret_id COS_SECRET_KEY=your_cos_secret_key COS_REGION=your_cos_region COS_BUCKET=your_cos_bucket # RevenueCat 配置 REVENUECAT_PUBLIC_API_KEY=your_revenuecat_public_key REVENUECAT_SECRET_API_KEY=your_revenuecat_secret_key # 服务配置 PORT=3002 NODE_ENV=development ``` ## 数据库架构 ### 字符集和排序规则 - **字符集**: `utf8mb4` (支持完整 Unicode,包括 emoji) - **排序规则**: `utf8mb4_unicode_ci` (不区分大小写) - **时区**: 统一使用 UTC 时间 ### 连接配置 - **连接池**: 最大连接数 10,最小连接数 0 - **超时设置**: 查询超时 30 秒,连接超时 10 秒 - **自动重连**: 启用连接失败自动重连 ### 迁移策略 - **自动同步**: 开发环境使用 `synchronize: true` - **生产环境**: 使用 SQL 脚本手动执行迁移 - **版本控制**: SQL 脚本存储在 `sql-scripts/` 目录 ## API 设计规范 ### RESTful 设计原则 - **资源导向**: 使用名词表示资源 - **HTTP 方法**: GET/POST/PUT/DELETE 对应 CRUD 操作 - **状态码**: 标准 HTTP 状态码 + 业务错误码 - **统一响应**: 使用 `ApiResponseDto` 包装所有响应 ### 接口版本控制 - **路径版本**: `/api/v1/users` (推荐) - **查询参数**: `?version=1` (备选) - **Header 版本**: `Accept: application/vnd.api+json;version=1` (备选) ### 请求响应格式 ```typescript // 成功响应 { "code": 0, "message": "操作成功", "data": { ... } } // 错误响应 { "code": 1, "message": "错误描述", "data": null } ``` ## 日志管理 ### 日志级别 - **ERROR**: 错误信息,需要立即关注 - **WARN**: 警告信息,可能的问题 - **INFO**: 一般信息,重要业务操作 - **DEBUG**: 调试信息,详细的执行流程 ### 日志配置 - **Winston**: 结构化日志记录 - **日志轮转**: 按日期和大小自动轮转 - **多输出**: 同时输出到文件和控制台 - **格式化**: JSON 格式便于分析 ### 日志文件 - `logs/error.log`: 错误日志 - `logs/output.log`: 一般输出日志 - `logs/combined.log`: 合并日志 ## 安全最佳实践 ### 数据加密 - **传输加密**: 强制 HTTPS/TLS 1.3 - **存储加密**: 敏感字段 AES-256-GCM 加密 - **密钥管理**: 环境变量 + 定期轮换 - **哈希算法**: bcrypt 处理密码(如需要) ### 输入验证 - **class-validator**: DTO 数据验证 - **class-transformer**: 数据转换和清理 - **SQL 注入防护**: Sequelize ORM 自动防护 - **XSS 防护**: 输入清理和输出编码 #### DTO 验证装饰器编写规范 **基本原则**: - 所有 DTO 类必须同时包含 `@ApiProperty` 和 `class-validator` 装饰器 - `@ApiProperty` 用于 Swagger 文档生成,`class-validator` 用于数据验证 - 缺少验证装饰器会导致参数校验失败,使 API 端点无法正常工作 **必需要导入的验证装饰器**: ```typescript import { IsOptional, IsDateString, IsNumber, IsString, IsNotEmpty, IsEnum, MaxLength, Min, Max } from 'class-validator'; ``` **常用字段验证规则**: - **分页参数**:在 GET 请求中使用 `@IsOptional()` + `@IsString()`,在控制器中转换为数字;在 POST/PUT 请求中使用 `@IsOptional()` + `@IsNumber()` - **日期参数**:`startDate` 和 `endDate` 使用 `@IsOptional()` + `@IsDateString()` - **字符串参数**:使用 `@IsOptional()` + `@IsString()`,必要时添加 `@MaxLength()` - **枚举参数**:使用 `@IsOptional()` + `@IsEnum(EnumType)` - **必填字段**:使用 `@IsNotEmpty()` 而不是只使用 `@IsString()` #### GET 请求参数特殊处理 **重要说明**:GET 请求的查询参数(Query Parameters)在 HTTP 协议中都是字符串类型,即使看起来是数字(如 `?page=1&limit=20`)。因此需要特殊处理: **GET 请求 DTO 定义**: ```typescript export class GetRecordsQueryDto { @ApiProperty({ description: '页码', example: 1, required: false }) @IsOptional() @IsString() // 注意:GET 请求中使用 @IsString() 而不是 @IsNumber() page?: string; @ApiProperty({ description: '每页数量', example: 20, required: false }) @IsOptional() @IsString() // 注意:GET 请求中使用 @IsString() 而不是 @IsNumber() limit?: string; } ``` **控制器中的类型转换**: ```typescript async getRecords( @Query() query: GetRecordsQueryDto, @CurrentUser() user: AccessTokenPayload, ): Promise { // 转换查询参数中的字符串为数字 const convertedQuery = { page: query.page ? parseInt(query.page, 10) : undefined, limit: query.limit ? parseInt(query.limit, 10) : undefined, // 其他字符串参数保持不变 startDate: query.startDate, endDate: query.endDate, status: query.status, }; const result = await this.service.getRecords(user.sub, convertedQuery); return result; } ``` **POST/PUT 请求 DTO 定义**(对比): ```typescript export class CreateRecordDto { @ApiProperty({ description: '数量', example: 10 }) @IsNumber() // POST/PUT 请求中可以直接使用 @IsNumber() quantity: number; } ``` **正确示例(GET 请求)**: ```typescript export class GetRecordsQueryDto { @ApiProperty({ description: '页码', example: 1, required: false }) @IsOptional() @IsString() // GET 请求中使用 @IsString() page?: string; @ApiProperty({ description: '每页数量', example: 20, required: false }) @IsOptional() @IsString() // GET 请求中使用 @IsString() limit?: string; @ApiProperty({ description: '开始日期', example: '2023-01-01', required: false }) @IsOptional() @IsDateString() startDate?: string; @ApiProperty({ description: '状态', example: 'active', required: false }) @IsOptional() @IsString() status?: string; } ``` **正确示例(POST/PUT 请求)**: ```typescript export class CreateRecordDto { @ApiProperty({ description: '数量', example: 10 }) @IsNumber() // POST/PUT 请求中可以直接使用 @IsNumber() quantity: number; @ApiProperty({ description: '名称', example: '测试' }) @IsString() @IsNotEmpty() name: string; } ``` **常见错误**: - ❌ 只有 `@ApiProperty` 而缺少 `class-validator` 装饰器 - ❌ GET 请求中的数字参数使用 `@IsNumber()` 而不是 `@IsString()` - ❌ 使用 `@IsString()` 但没有 `@IsOptional()` 处理可选参数 - ❌ 日期字段没有使用 `@IsDateString()` 验证 - ❌ GET 请求中忘记在控制器进行类型转换,导致服务层接收到字符串而不是数字 - ❌ 类型转换时没有进行空值检查,可能导致 `parseInt(undefined)` 返回 `NaN` ### 访问控制 - **JWT 认证**: 无状态 Token 认证 - **权限守卫**: 基于角色的访问控制 - **速率限制**: 防止 API 滥用和攻击 - **CORS 配置**: 跨域请求安全控制 ## 性能优化 ### 数据库优化 - **索引策略**: 为常用查询字段添加索引 - **查询优化**: 避免 N+1 查询问题 - **连接池**: 合理配置数据库连接池 - **分页查询**: 大数据集分页处理 ### 缓存策略 - **内存缓存**: 热点数据内存缓存 - **查询缓存**: 数据库查询结果缓存 - **CDN 缓存**: 静态资源 CDN 分发 - **浏览器缓存**: 合理设置 Cache-Control ### 代码优化 - **异步处理**: 使用 async/await 处理异步操作 - **批量操作**: 减少数据库往返次数 - **流式处理**: 大数据量流式处理 - **懒加载**: 按需加载模块和数据 ## 监控与调试 ### 应用监控 - **PM2 监控**: 进程状态和资源使用 - **健康检查**: 应用健康状态接口 - **性能指标**: 响应时间和吞吐量 - **错误追踪**: 异常自动收集和报告 ### 调试工具 - **Source Map**: 生产环境调试支持 - **日志分析**: 结构化日志查询和分析 - **API 文档**: Swagger 自动生成文档 - **数据库工具**: MySQL Workbench/Sequel Pro ## 部署架构 ### 服务器环境 - **操作系统**: Ubuntu 20.04 LTS - **Node.js**: 18.x LTS 版本 - **数据库**: MySQL 8.0 - **Web 服务器**: Nginx 1.18+ ### 部署流程 1. **代码构建**: 本地或服务器端 TypeScript 编译 2. **依赖安装**: 生产依赖安装和锁定 3. **数据库迁移**: SQL 脚本执行和数据迁移 4. **服务启动**: PM2 集群模式启动应用 5. **健康检查**: 验证服务正常运行 ### 容器化部署(未来) - **Docker**: 应用容器化 - **Docker Compose**: 多服务编排 - **Kubernetes**: 容器编排管理 - **CI/CD**: 自动化构建和部署流水线