Files
plates-server/.kilocode/rules/memory-bank/tech.md
richarjiang 1fe969aa97 feat(diet-records): 修复营养成分分析记录查询参数验证和类型转换
修复GET请求查询参数验证装饰器缺失问题,添加正确的class-validator装饰器
在控制器中实现查询参数类型转换,确保数字参数正确处理
更新技术文档,添加DTO验证装饰器编写规范和GET请求参数处理指南
2025-10-16 16:26:58 +08:00

431 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 技术栈与开发环境
## 核心技术栈
### 后端框架
- **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<RecordsResponseDto> {
// 转换查询参数中的字符串为数字
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**: 自动化构建和部署流水线