diff --git a/.cursor/rules/README.mdc b/.cursor/rules/README.mdc deleted file mode 100644 index e39ecd8..0000000 --- a/.cursor/rules/README.mdc +++ /dev/null @@ -1,379 +0,0 @@ ---- -description: "全局规则" -globs: ["**/*"] -alwaysApply: true ---- - -# 🤖 AI友好的Elysia开发规则体系 - -## 快速开始 🚀 - -### 1. 对于开发者 - -**首次使用:** -1. 阅读 `ai-friendly-elysia-rules.md` 了解规范 -2. 查看 `ai-development-workflow.md` 学习如何与AI协作 -3. 在项目中导入支持文件 - -**日常开发:** -```typescript -// 使用标准错误码 -import { ERROR_CODES } from '@/constants/error-codes'; - -// 使用响应工具 -import { successResponse, errorResponse, BusinessError } from '@/utils/response.helper'; -``` - -### 2. 对于AI助手 - -**工作原则:** -- 严格遵循 `ai-friendly-elysia-rules.md` 规范 -- 按照 `ai-development-workflow.md` 工作流程 -- 确保代码质量和一致性 - -**开发顺序:** -1. Schema定义(最高优先级) -2. Response格式 -3. Service层实现 -4. Controller层实现 -5. 测试用例 - -## 核心优势 💪 - -### 1. 一致性 -- 统一的文件结构 -- 标准的命名规范 -- 一致的错误处理 - -### 2. 类型安全 -- TypeBox Schema + TypeScript类型 -- 编译时类型检查 -- 运行时参数验证 - -### 3. 可维护性 -- 清晰的模块划分 -- 完整的文档注释 -- 系统化的测试 - -### 4. AI友好 -- 语义清晰的代码结构 -- 明确的依赖关系 -- 标准化的模式 - -## 使用示例 📝 - -### 创建新模块 - -当你需要创建新的业务模块时,告诉AI助手: - -``` -功能:用户管理 -模块:user -接口:注册、登录、获取个人信息、修改个人信息 -认证:登录后的接口需要JWT认证 -特殊要求:密码需要加密存储 -``` - -AI助手会自动创建: -- `src/modules/user/user.schema.ts` -- `src/modules/user/user.response.ts` -- `src/modules/user/user.service.ts` -- `src/modules/user/user.controller.ts` -- `src/modules/user/user.test.ts` - -### 修改现有功能 - -``` -修改用户查询接口,添加分页功能,每页最多50条记录 -``` - -AI助手会: -1. 分析现有代码 -2. 更新Schema定义 -3. 修改Service逻辑 -4. 更新Controller -5. 补充测试用例 - -## 代码质量保证 ✅ - -### 自动检查项 -- [ ] TypeScript类型正确性 -- [ ] Schema验证完整性 -- [ ] 错误处理覆盖 -- [ ] 响应格式一致性 -- [ ] 命名规范符合标准 -- [ ] 文档注释完整 - -### 人工Review项 -- [ ] 业务逻辑正确性 -- [ ] 安全性考虑 -- [ ] 性能优化 -- [ ] 用户体验 - -## 最佳实践 🌟 - -### 1. 需求描述 -``` -✅ 清晰:实现用户注册接口,包含邮箱验证和密码强度检查 -❌ 模糊:做一个用户功能 -``` - -### 2. 错误处理 -```typescript -// ✅ 使用标准错误类 -throw new BusinessError('用户名已存在', ERROR_CODES.USER_ALREADY_EXISTS); - -// ❌ 直接抛出Error -throw new Error('用户名已存在'); -``` - -### 3. 响应格式 -```typescript -// ✅ 使用工具函数 -return successResponse(userData, '查询成功'); - -// ❌ 手动构造 -return { code: 'SUCCESS', message: '查询成功', data: userData }; -``` - -## 性能考虑 ⚡ - -### 数据库优化 -- 使用索引优化查询 -- 避免N+1查询问题 -- 合理使用连接池 - -### 缓存策略 -- 热点数据Redis缓存 -- 适当的缓存过期时间 -- 缓存穿透防护 - -### 并发处理 -- 避免阻塞操作 -- 合理的超时设置 -- 资源清理 - -## 故障排除 🔧 - -### 常见问题 - -1. **类型错误** - - 检查Schema定义 - - 确认类型导出 - - 验证导入路径 - -2. **运行时错误** - - 查看错误日志 - - 检查参数验证 - - 确认业务逻辑 - -3. **性能问题** - - 分析慢查询 - - 检查缓存命中率 - - 监控资源使用 - -### 调试技巧 - -```typescript -// 添加调试日志 -Logger.debug(`处理用户请求: ${JSON.stringify(params)}`); - -// 性能监控 -const startTime = Date.now(); -// ... 业务逻辑 -Logger.info(`操作耗时: ${Date.now() - startTime}ms`); -``` - -## 版本历史 📚 - -- **v1.0.0** - 初始版本,包含核心规范 -- **v1.1.0** - 添加AI协作指南 -- **v1.2.0** - 完善错误处理和响应格式 - -记住:好的规范不是限制,而是让团队更高效协作的基础! 🎯 # 🤖 AI友好的Elysia开发规则体系 - -## 快速开始 🚀 - -### 1. 对于开发者 - -**首次使用:** -1. 阅读 `ai-friendly-elysia-rules.md` 了解规范 -2. 查看 `ai-development-workflow.md` 学习如何与AI协作 -3. 在项目中导入支持文件 - -**日常开发:** -```typescript -// 使用标准错误码 -import { ERROR_CODES } from '@/constants/error-codes'; - -// 使用响应工具 -import { successResponse, errorResponse, BusinessError } from '@/utils/response.helper'; -``` - -### 2. 对于AI助手 - -**工作原则:** -- 严格遵循 `ai-friendly-elysia-rules.md` 规范 -- 按照 `ai-development-workflow.md` 工作流程 -- 确保代码质量和一致性 - -**开发顺序:** -1. Schema定义(最高优先级) -2. Response格式 -3. Service层实现 -4. Controller层实现 -5. 测试用例 - -## 核心优势 💪 - -### 1. 一致性 -- 统一的文件结构 -- 标准的命名规范 -- 一致的错误处理 - -### 2. 类型安全 -- TypeBox Schema + TypeScript类型 -- 编译时类型检查 -- 运行时参数验证 - -### 3. 可维护性 -- 清晰的模块划分 -- 完整的文档注释 -- 系统化的测试 - -### 4. AI友好 -- 语义清晰的代码结构 -- 明确的依赖关系 -- 标准化的模式 - -## 使用示例 📝 - -### 创建新模块 - -当你需要创建新的业务模块时,告诉AI助手: - -``` -功能:用户管理 -模块:user -接口:注册、登录、获取个人信息、修改个人信息 -认证:登录后的接口需要JWT认证 -特殊要求:密码需要加密存储 -``` - -AI助手会自动创建: -- `src/modules/user/user.schema.ts` -- `src/modules/user/user.response.ts` -- `src/modules/user/user.service.ts` -- `src/modules/user/user.controller.ts` -- `src/modules/user/user.test.ts` - -### 修改现有功能 - -``` -修改用户查询接口,添加分页功能,每页最多50条记录 -``` - -AI助手会: -1. 分析现有代码 -2. 更新Schema定义 -3. 修改Service逻辑 -4. 更新Controller -5. 补充测试用例 - -## 代码质量保证 ✅ - -### 自动检查项 -- [ ] TypeScript类型正确性 -- [ ] Schema验证完整性 -- [ ] 错误处理覆盖 -- [ ] 响应格式一致性 -- [ ] 命名规范符合标准 -- [ ] 文档注释完整 - -### 人工Review项 -- [ ] 业务逻辑正确性 -- [ ] 安全性考虑 -- [ ] 性能优化 -- [ ] 用户体验 - -## 最佳实践 🌟 - -### 1. 需求描述 -``` -✅ 清晰:实现用户注册接口,包含邮箱验证和密码强度检查 -❌ 模糊:做一个用户功能 -``` - -### 2. 错误处理 -```typescript -// ✅ 使用标准错误类 -throw new BusinessError('用户名已存在', ERROR_CODES.USER_ALREADY_EXISTS); - -// ❌ 直接抛出Error -throw new Error('用户名已存在'); -``` - -### 3. 响应格式 -```typescript -// ✅ 使用工具函数 -return successResponse(userData, '查询成功'); - -// ❌ 手动构造 -return { code: 'SUCCESS', message: '查询成功', data: userData }; -``` - -## 性能考虑 ⚡ - -### 数据库优化 -- 使用索引优化查询 -- 避免N+1查询问题 -- 合理使用连接池 - -### 缓存策略 -- 热点数据Redis缓存 -- 适当的缓存过期时间 -- 缓存穿透防护 - -### 并发处理 -- 避免阻塞操作 -- 合理的超时设置 -- 资源清理 - -## 故障排除 🔧 - -### 常见问题 - -1. **类型错误** - - 检查Schema定义 - - 确认类型导出 - - 验证导入路径 - -2. **运行时错误** - - 查看错误日志 - - 检查参数验证 - - 确认业务逻辑 - -3. **性能问题** - - 分析慢查询 - - 检查缓存命中率 - - 监控资源使用 - -### 调试技巧 - -```typescript -// 添加调试日志 -Logger.debug(`处理用户请求: ${JSON.stringify(params)}`); - -// 性能监控 -const startTime = Date.now(); -// ... 业务逻辑 -Logger.info(`操作耗时: ${Date.now() - startTime}ms`); -``` - -## 版本历史 📚 - -- **v1.0.0** - 初始版本,包含核心规范 -- **v1.1.0** - 添加AI协作指南 -- **v1.2.0** - 完善错误处理和响应格式 - -记住:好的规范不是限制,而是让团队更高效协作的基础! 🎯 \ No newline at end of file diff --git a/.cursor/rules/ai-development-workflow.mdc b/.cursor/rules/ai-development-workflow.mdc deleted file mode 100644 index e2129ec..0000000 --- a/.cursor/rules/ai-development-workflow.mdc +++ /dev/null @@ -1,294 +0,0 @@ ---- -description: "全局规则" -globs: ["**/*"] -alwaysApply: true ---- - -# AI助手开发工作流程指南 🤖 - -## 快速开始 - -当你需要我帮你开发新功能时,请按照以下格式提供信息: - -``` -功能:[功能名称] -模块:[模块名,如 user、product] -接口:[接口列表,如 创建用户、查询用户列表] -认证:[是否需要JWT认证] -特殊要求:[任何特殊要求] -``` - -## 我的工作流程 - -### 1. 分析阶段(30秒内) -- 理解功能需求 -- 分析现有代码结构 -- 确定模块依赖关系 -- 制定开发计划 - -### 2. 设计阶段(按优先级) -1. **Schema设计**(最优先) - - 定义请求参数Schema - - 定义响应数据Schema - - 导出TypeScript类型 - -2. **Response格式设计** - - 成功响应格式 - - 错误响应格式 - - 组合响应定义 - -3. **Service层设计** - - 业务逻辑接口 - - 数据访问逻辑 - - 错误处理逻辑 - -4. **Controller层设计** - - 路由定义 - - 参数验证 - - 错误处理 - -5. **测试用例设计** - - 正常流程测试 - - 异常流程测试 - - 边界条件测试 - -### 3. 实现阶段(批量操作) - -我会同时创建/修改多个文件: - -```typescript -// 1. 同时读取相关文件了解现状 -// 2. 并行创建所有必需的文件 -// 3. 更新路由和导出文件 -// 4. 验证代码完整性 -``` - -### 4. 验证阶段 - -- 检查类型安全性 -- 确认错误处理完整性 -- 验证响应格式一致性 -- 检查测试覆盖率 - -## 交互模式 - -### 快速开发模式 ⚡ -适用于:标准CRUD操作、常见业务场景 - -**你只需要说:** -``` -"帮我实现用户模块的CRUD接口" -"添加产品管理功能" -"实现订单状态查询" -``` - -**AI会自动:** -- 按照规范创建完整的5个文件 -- 集成到现有路由系统 -- 提供完整的类型安全 -- 包含基础测试用例 - -### 定制开发模式 🔧 -适用于:复杂业务逻辑、特殊需求 - -**你需要提供:** -- 详细的业务规则 -- 特殊的验证要求 -- 复杂的数据关联 -- 性能要求 - -**AI会:** -- 详细分析需求 -- 提供设计方案 -- 征求确认后实现 -- 优化性能和安全性 - -## 我擅长处理的场景 - -### ✅ 高效处理 -- 标准REST API开发 -- CRUD操作实现 -- 数据验证和类型安全 -- 错误处理和响应格式 -- JWT认证集成 -- 数据库操作(Drizzle ORM) -- Redis缓存集成 -- 测试用例编写 -- API文档生成 - -### ⚡ 批量操作 -- 多文件同时创建/修改 -- 路由批量注册 -- 类型定义批量导出 -- 测试用例批量生成 - -### 🔍 代码分析 -- 现有代码结构理解 -- 依赖关系分析 -- 潜在问题识别 -- 优化建议提供 - -## 沟通最佳实践 - -### 清晰描述需求 -``` -❌ "做一个用户功能" -✅ "实现用户注册、登录、个人信息查询和修改功能,需要JWT认证" - -❌ "这个接口有问题" -✅ "用户登录接口返回401错误,但是用户名密码正确" -``` - -### 提供上下文信息 -``` -✅ "在现有的用户模块基础上添加头像上传功能" -✅ "这个接口需要管理员权限才能访问" -✅ "数据需要缓存到Redis,缓存时间1小时" -``` - -### 明确期望结果 -``` -✅ "创建完整的用户CRUD接口,包含测试" -✅ "只需要修改现有的查询接口,添加分页功能" -✅ "优化这个接口的性能,响应时间控制在100ms内" -``` - -## 错误处理和调试 - -### 当代码出现问题时 - -1. **我会主动分析** - - 检查类型错误 - - 验证语法正确性 - - 确认导入导出关系 - -2. **提供修复方案** - - 直接修复简单问题 - - 解释复杂问题的原因 - - 提供多种解决方案 - -3. **验证修复结果** - - 确保修复后代码可运行 - - 检查是否引入新问题 - - 验证功能完整性 - -### 性能优化建议 - -我会在适当时候提供: -- 数据库查询优化 -- 缓存策略建议 -- 并发处理优化 -- 内存使用优化 - -## 质量保证 - -### 代码质量检查 -- [ ] 类型安全性 -- [ ] 错误处理完整性 -- [ ] 响应格式一致性 -- [ ] 命名规范符合标准 -- [ ] 注释文档完整 - -### 功能完整性检查 -- [ ] Schema定义完整 -- [ ] Response格式正确 -- [ ] Service逻辑完整 -- [ ] Controller路由正确 -- [ ] 测试用例覆盖 - -### 安全性检查 -- [ ] 参数验证到位 -- [ ] 认证授权正确 -- [ ] 敏感信息保护 -- [ ] SQL注入防护 -- [ ] XSS攻击防护 - -记住:我的目标是让你专注于业务逻辑,而我来确保代码的规范性、安全性和可维护性! 🎯 # AI助手开发工作流程指南 🤖 - -## 快速开始 - -当你需要我帮你开发新功能时,请按照以下格式提供信息: - -``` -功能:[功能名称] -模块:[模块名,如 user、product] -接口:[接口列表,如 创建用户、查询用户列表] -认证:[是否需要JWT认证] -特殊要求:[任何特殊要求] -``` - -## 我的工作流程 - -### 1. 分析阶段(30秒内) -- 理解功能需求 -- 分析现有代码结构 -- 确定模块依赖关系 -- 制定开发计划 - -### 2. 设计阶段(按优先级) -1. **Schema设计**(最优先) - - 定义请求参数Schema - - 定义响应数据Schema - - 导出TypeScript类型 - -2. **Response格式设计** - - 成功响应格式 - - 错误响应格式 - - 组合响应定义 - -3. **Service层设计** - - 业务逻辑接口 - - 数据访问逻辑 - - 错误处理逻辑 - -4. **Controller层设计** - - 路由定义 - - 参数验证 - - 错误处理 - -5. **测试用例设计** - - 正常流程测试 - - 异常流程测试 - - 边界条件测试 - -### 3. 实现阶段(批量操作) - -我会同时创建/修改多个文件: - -```typescript -// 1. 同时读取相关文件了解现状 -// 2. 并行创建所有必需的文件 -// 3. 更新路由和导出文件 -// 4. 验证代码完整性 -``` - -### 4. 验证阶段 - -- 检查类型安全性 -- 确认错误处理完整性 -- 验证响应格式一致性 -- 检查测试覆盖率 - - -### 代码质量检查 -- [ ] 类型安全性 -- [ ] 错误处理完整性 -- [ ] 响应格式一致性 -- [ ] 命名规范符合标准 -- [ ] 注释文档完整 - -### 功能完整性检查 -- [ ] Schema定义完整 -- [ ] Response格式正确 -- [ ] Service逻辑完整 -- [ ] Controller路由正确 -- [ ] 测试用例覆盖 - -### 安全性检查 -- [ ] 参数验证到位 -- [ ] 认证授权正确 -- [ ] 敏感信息保护 -- [ ] SQL注入防护 -- [ ] XSS攻击防护 - -记住:我的目标是让你专注于业务逻辑,而我来确保代码的规范性、安全性和可维护性! 🎯 \ No newline at end of file diff --git a/.cursor/rules/global-rules/generate-task.mdc b/.cursor/rules/create-prd.mdc similarity index 98% rename from .cursor/rules/global-rules/generate-task.mdc rename to .cursor/rules/create-prd.mdc index 528d33c..957cd02 100644 --- a/.cursor/rules/global-rules/generate-task.mdc +++ b/.cursor/rules/create-prd.mdc @@ -1,61 +1,61 @@ ---- -description: "全局规则" -globs: ["**/*"] -alwaysApply: true ---- -# 规则:生成产品需求文档 (PRD) - -## 目标 (Goal) - -指导 AI 助手基于用户的初始提示创建详细的产品需求文档 (PRD)(Markdown 格式)。PRD 应清晰、可操作,并适合初级开发人员理解和实施该功能。 - -## 流程 (Process) - -1. **接收初始提示:** 用户提供新功能或功能的简要描述或请求。 -2. **提出澄清性问题:** 在编写 PRD *之前*,AI *必须*提出澄清性问题以收集足够的细节。目标是理解功能的“是什么”和“为什么”,而不是“如何做”(开发人员将负责解决)。务必以字母/数字列表的形式提供选项,以便我可以用选择轻松回复。 -3. **生成 PRD:** 基于初始提示和用户对澄清性问题的回答,使用下面概述的结构生成 PRD。 -4. **保存 PRD:** 将生成的文档保存为 `/tasks` 目录中的 `prd-[功能名称].md`。 - -## 澄清性问题 (示例) (Clarifying Questions (Examples)) - -AI 应根据提示调整其问题,但以下是一些常见的探索领域: - -* **问题/目标:** “这个功能为用户解决了什么问题?” 或 “我们希望通过这个功能实现的主要目标是什么?” -* **目标用户:** “这个功能的主要用户是谁?” -* **核心功能:** “您能描述用户应该能够使用此功能执行的关键操作吗?” -* **用户故事:** “您能提供一些用户故事吗?(例如:作为 [用户类型],我希望 [执行操作],以便 [获得收益]。)” -* **验收标准:** “我们如何知道此功能已成功实施?关键的成功标准是什么?” -* **范围/边界:** “有没有此功能*不应该*做的特定事情(非目标)?” -* **数据需求:** “此功能需要显示或操作什么类型的数据?” -* **设计/UI:** “是否有现有的设计稿或 UI 指南需要遵循?” 或 “您能描述期望的外观和感觉吗?” -* **边界情况:** “是否有任何潜在的边界情况或错误条件我们需要考虑?” - -## PRD 结构 (PRD Structure) - -生成的 PRD 应包含以下部分: - -1. **引言/概述:** 简要描述该功能及其解决的问题。陈述目标。 -2. **目标:** 列出此功能的具体、可衡量的目标。 -3. **用户故事:** 详细描述描述功能使用和收益的用户叙事。 -4. **功能需求:** 列出该功能必须具备的具体功能。使用清晰、简洁的语言(例如:“系统必须允许用户上传个人资料图片。”)。对这些需求进行编号。 -5. **非目标(范围之外):** 明确说明此功能*不会*包含的内容,以管理范围。 -6. **设计考虑(可选):** 如果适用,链接到设计稿,描述 UI/UX 要求,或提及相关组件/样式。 -7. **技术考虑(可选):** 提及任何已知的技术限制、依赖项或建议(例如:“应与现有的 Auth 模块集成”)。 -8. **成功指标:** 如何衡量此功能的成功?(例如:“用户参与度提高 10%”、“减少与 X 相关的支持工单”)。 -9. **待解决问题:** 列出任何剩余问题或需要进一步澄清的领域。 - -## 目标受众 (Target Audience) - -假设 PRD 的主要读者是**初级开发人员**。因此,需求应明确、无歧义,并尽可能避免行话。提供足够的细节供他们理解功能的目的和核心逻辑。 - -## 输出 (Output) - -* **格式:** Markdown (`.md`) -* **位置:** `/tasks/` -* **文件名:** `prd-[功能名称].md` - -## 最终指令 (Final instructions) - -1. 不要开始实施 PRD。 -2. 务必向用户提出澄清性问题。 +--- +description: "全局规则" +globs: ["**/*"] +alwaysApply: true +--- +# 规则:生成产品需求文档 (PRD) + +## 目标 (Goal) + +指导 AI 助手基于用户的初始提示创建详细的产品需求文档 (PRD)(Markdown 格式)。PRD 应清晰、可操作,并适合初级开发人员理解和实施该功能。 + +## 流程 (Process) + +1. **接收初始提示:** 用户提供新功能或功能的简要描述或请求。 +2. **提出澄清性问题:** 在编写 PRD *之前*,AI *必须*提出澄清性问题以收集足够的细节。目标是理解功能的“是什么”和“为什么”,而不是“如何做”(开发人员将负责解决)。务必以字母/数字列表的形式提供选项,以便我可以用选择轻松回复。 +3. **生成 PRD:** 基于初始提示和用户对澄清性问题的回答,使用下面概述的结构生成 PRD。 +4. **保存 PRD:** 将生成的文档保存为 `/tasks` 目录中的 `prd-[功能名称].md`。 + +## 澄清性问题 (示例) (Clarifying Questions (Examples)) + +AI 应根据提示调整其问题,但以下是一些常见的探索领域: + +* **问题/目标:** “这个功能为用户解决了什么问题?” 或 “我们希望通过这个功能实现的主要目标是什么?” +* **目标用户:** “这个功能的主要用户是谁?” +* **核心功能:** “您能描述用户应该能够使用此功能执行的关键操作吗?” +* **用户故事:** “您能提供一些用户故事吗?(例如:作为 [用户类型],我希望 [执行操作],以便 [获得收益]。)” +* **验收标准:** “我们如何知道此功能已成功实施?关键的成功标准是什么?” +* **范围/边界:** “有没有此功能*不应该*做的特定事情(非目标)?” +* **数据需求:** “此功能需要显示或操作什么类型的数据?” +* **设计/UI:** “是否有现有的设计稿或 UI 指南需要遵循?” 或 “您能描述期望的外观和感觉吗?” +* **边界情况:** “是否有任何潜在的边界情况或错误条件我们需要考虑?” + +## PRD 结构 (PRD Structure) + +生成的 PRD 应包含以下部分: + +1. **引言/概述:** 简要描述该功能及其解决的问题。陈述目标。 +2. **目标:** 列出此功能的具体、可衡量的目标。 +3. **用户故事:** 详细描述描述功能使用和收益的用户叙事。 +4. **功能需求:** 列出该功能必须具备的具体功能。使用清晰、简洁的语言(例如:“系统必须允许用户上传个人资料图片。”)。对这些需求进行编号。 +5. **非目标(范围之外):** 明确说明此功能*不会*包含的内容,以管理范围。 +6. **设计考虑(可选):** 如果适用,链接到设计稿,描述 UI/UX 要求,或提及相关组件/样式。 +7. **技术考虑(可选):** 提及任何已知的技术限制、依赖项或建议(例如:“应与现有的 Auth 模块集成”)。 +8. **成功指标:** 如何衡量此功能的成功?(例如:“用户参与度提高 10%”、“减少与 X 相关的支持工单”)。 +9. **待解决问题:** 列出任何剩余问题或需要进一步澄清的领域。 + +## 目标受众 (Target Audience) + +假设 PRD 的主要读者是**初级开发人员**。因此,需求应明确、无歧义,并尽可能避免行话。提供足够的细节供他们理解功能的目的和核心逻辑。 + +## 输出 (Output) + +* **格式:** Markdown (`.md`) +* **位置:** `/tasks/` +* **文件名:** `prd-[功能名称].md` + +## 最终指令 (Final instructions) + +1. 不要开始实施 PRD。 +2. 务必向用户提出澄清性问题。 3. 获取用户对澄清性问题的答案,并据此改进 PRD。 \ No newline at end of file diff --git a/.cursor/rules/global-rules/create-prd.mdc b/.cursor/rules/create-task.mdc similarity index 95% rename from .cursor/rules/global-rules/create-prd.mdc rename to .cursor/rules/create-task.mdc index e268a67..20f65bb 100644 --- a/.cursor/rules/global-rules/create-prd.mdc +++ b/.cursor/rules/create-task.mdc @@ -1,54 +1,54 @@ ---- -description: "全局规则" -globs: ["**/*"] -alwaysApply: true ---- -# 规则:从PRD生成任务清单 - -## 目标 (Goal) - -指导AI助手基于现有的产品需求文档(PRD)创建一个详细的、逐步执行的任务清单(Markdown格式)。该任务清单应指导开发人员进行实现。 - -## 输出 (Output) - -* **格式:** Markdown (`.md`) -* **位置:** `/tasks/` -* **文件名:** `tasks-[prd文件名].md` (例如:`tasks-prd-user-profile-editing.md`) - -## 流程 (Process) - -1. **接收PRD引用:** 用户指定一个特定的PRD文件。 -2. **分析PRD:** AI阅读并分析指定PRD中的功能需求、用户故事和其他部分。 -3. **阶段1:生成父任务:** 基于PRD分析,创建文件并生成实现该功能所需的主要、高级别任务。根据你的判断决定使用多少高级别任务(大约5个)。以指定格式(尚未包含子任务)将这些任务呈现给用户。通知用户:“我已根据PRD生成了高级别任务。准备好生成子任务了吗?请回复 'Go' 以继续。” -4. **等待确认:** 暂停并等待用户回复“Go”。 -5. **阶段2:生成子任务:** 一旦用户确认,将每个父任务分解为完成父任务所需的更小、可操作的子任务。确保子任务逻辑上源自父任务,并涵盖PRD中隐含的实现细节。 -6. **识别相关文件:** 基于任务和PRD,识别需要创建或修改的潜在文件。在 `Relevant Files` 部分列出这些文件,如果适用,包括对应的测试文件。 -7. **生成最终输出:** 将父任务、子任务、相关文件和备注合并到最终的Markdown结构中。 -8. **保存任务清单:** 将生成的文档保存在 `/tasks/` 目录中,文件名为 `tasks-[prd文件名].md`,其中 `[prd文件名]` 与输入PRD文件的基本名称匹配(例如,如果输入是 `prd-user-profile-editing.md`,则输出为 `tasks-prd-user-profile-editing.md`)。 - -## 输出格式 (Output Format) - -生成的任务清单*必须*遵循以下结构: - -```markdown -## 相关文件 (Relevant Files) - -- `path/to/potential/file1.ts` - 该文件相关性的简要说明(例如:包含此功能的主要组件)。 -- `path/to/file1.test.ts` - `file1.ts` 的单元测试。 -- `path/to/another/file.tsx` - 简要说明(例如:用于数据提交的API路由处理器)。 -- `path/to/another/file.test.tsx` - `another/file.tsx` 的单元测试。 -- `lib/utils/helpers.ts` - 简要说明(例如:计算所需的工具函数)。 -- `lib/utils/helpers.test.ts` - `helpers.ts` 的单元测试。 - -### 备注 (Notes) - -- 单元测试通常应放置在与它们测试的代码文件相同的目录中(例如:在同一目录下的 `MyComponent.tsx` 和 `MyComponent.test.tsx`)。 - -## 任务 (Tasks) - -- [ ] 1.0 父任务标题 - - [ ] 1.1 [子任务描述 1.1] - - [ ] 1.2 [子任务描述 1.2] -- [ ] 2.0 父任务标题 - - [ ] 2.1 [子任务描述 2.1] +--- +description: "全局规则" +globs: ["**/*"] +alwaysApply: true +--- +# 从PRD生成任务清单 + +## 目标 (Goal) + +指导AI助手基于现有的产品需求文档(PRD)创建一个详细的、逐步执行的任务清单(Markdown格式)。该任务清单应指导开发人员进行实现。 + +## 输出 (Output) + +* **格式:** Markdown (`.md`) +* **位置:** `/tasks/` +* **文件名:** `tasks-[prd文件名].md` (例如:`tasks-prd-user-profile-editing.md`) + +## 流程 (Process) + +1. **接收PRD引用:** 用户指定一个特定的PRD文件。 +2. **分析PRD:** AI阅读并分析指定PRD中的功能需求、用户故事和其他部分。 +3. **阶段1:生成父任务:** 基于PRD分析,创建文件并生成实现该功能所需的主要、高级别任务。根据你的判断决定使用多少高级别任务(大约5个)。以指定格式(尚未包含子任务)将这些任务呈现给用户。通知用户:“我已根据PRD生成了高级别任务。准备好生成子任务了吗?请回复 'Go' 以继续。” +4. **等待确认:** 暂停并等待用户回复“Go”。 +5. **阶段2:生成子任务:** 一旦用户确认,将每个父任务分解为完成父任务所需的更小、可操作的子任务。确保子任务逻辑上源自父任务,并涵盖PRD中隐含的实现细节。 +6. **识别相关文件:** 基于任务和PRD,识别需要创建或修改的潜在文件。在 `Relevant Files` 部分列出这些文件,如果适用,包括对应的测试文件。 +7. **生成最终输出:** 将父任务、子任务、相关文件和备注合并到最终的Markdown结构中。 +8. **保存任务清单:** 将生成的文档保存在 `/tasks/` 目录中,文件名为 `tasks-[prd文件名].md`,其中 `[prd文件名]` 与输入PRD文件的基本名称匹配(例如,如果输入是 `prd-user-profile-editing.md`,则输出为 `tasks-prd-user-profile-editing.md`)。 + +## 输出格式 (Output Format) + +生成的任务清单*必须*遵循以下结构: + +```markdown +## 相关文件 (Relevant Files) + +- `path/to/potential/file1.ts` - 该文件相关性的简要说明(例如:包含此功能的主要组件)。 +- `path/to/file1.test.ts` - `file1.ts` 的单元测试。 +- `path/to/another/file.tsx` - 简要说明(例如:用于数据提交的API路由处理器)。 +- `path/to/another/file.test.tsx` - `another/file.tsx` 的单元测试。 +- `lib/utils/helpers.ts` - 简要说明(例如:计算所需的工具函数)。 +- `lib/utils/helpers.test.ts` - `helpers.ts` 的单元测试。 + +### 备注 (Notes) + +- 单元测试通常应放置在与它们测试的代码文件相同的目录中(例如:在同一目录下的 `MyComponent.tsx` 和 `MyComponent.test.tsx`)。 + +## 任务 (Tasks) + +- [ ] 1.0 父任务标题 + - [ ] 1.1 [子任务描述 1.1] + - [ ] 1.2 [子任务描述 1.2] +- [ ] 2.0 父任务标题 + - [ ] 2.1 [子任务描述 2.1] - [ ] 3.0 父任务标题 (如果纯粹是结构性的或配置性的,则可能不需要子任务) \ No newline at end of file diff --git a/.cursor/rules/elysia-rules.mdc b/.cursor/rules/elysia-rules.mdc index 9d577ea..3c7ff5f 100644 --- a/.cursor/rules/elysia-rules.mdc +++ b/.cursor/rules/elysia-rules.mdc @@ -1,11 +1,4 @@ ---- -description: "Bun Elysia框架业务开发规则" -globs: ["**/*"] -alwaysApply: true ---- - -# Bun Elysia框架业务开发规则 - +# ElysiaAPI开发流程 ## 0. 概览 @@ -22,22 +15,46 @@ alwaysApply: true - **日志**:Winston - **代码规范**:ESLint + Prettier -### 📂 根目录结构 +使用的技术和库 + +- **数据库**:`"mysql2": "^3.14.1"`, `"drizzle-orm": "^0.44.2"` +- **token验证**:`"jsonwebtoken": "^9.0.2"` +- **密码加密**:`"bcrypt": "^6.0.0"` + +## 1. 相关目录结构和描述 + +### 1.0 整体目录结构 ``` project/ ├── 📋 配置文件(config/) ├── 📁 源代码 (src/) +├───└───config +├───├───eneities +├───├───modules +│ ├───├───auth +│ ├───├───captcha +│ ├───├───health +│ ├───├───test +│ ├───└───user +├───├───plugins +│ ├───├───drizzle +│ ├───├───email +│ ├───├───errorHandle +│ ├───├───jwt +│ ├───├───logger +│ ├───├───redis +│ ├───└───swagger +├───└───tests +│ └───demo +├───type +├───utils ├── 📁 文档 (docs/) ├── 📁 需求文档 (prd/) ├── 📁 任务管理 (tasks/) ├── 📁 AI对话记录 (aiChat/) ├── 📁 数据库迁移 (drizzle/) └── 📁 静态资源 (public/) -``` - -### 🔧 配置文件 - | 文件 | 说明 | |------|------| | `package.json` | 项目依赖和脚本配置 | @@ -48,57 +65,33 @@ project/ | `bunfig.toml` | Bun运行时配置 | | `drizzle.config.ts` | Drizzle ORM配置 | | `README.md` | 项目说明文档 | - -### 应用入口 -``` -src/ -├── app.ts # Elysia应用主入口 -└── server.ts # 服务器启动文件 ``` -### 配置管理 (config/) -``` -src/config/ -├── index.ts # 配置总入口 -├── db.config.ts # 数据库配置 -├── redis.config.ts # Redis配置 -├── jwt.config.ts # JWT配置 -├── logger.config.ts # 日志配置 -└── email.config.ts # 邮件配置 -``` +### 1.1 接口目录结构 -### 数据实体 (eneities/) -``` -src/eneities/ -├── index.ts # 实体总入口 -├── customType.ts # 自定义类型 -└── [table].ts # 数据表定义 -``` - -### 业务模块 (modules/) ``` src/modules/ -├── index.ts # 模块总入口 -├── tags.ts # Swagger标签定义 -├── auth/ # 认证模块 -│ ├── auth.schema.ts # Schema定义 -│ ├── auth.response.ts # 响应格式 -│ ├── auth.service.ts # 业务逻辑 -│ ├── auth.controller.ts # 路由控制器 -│ └── auth.test.ts # 测试用例 -├── captcha/ # 验证码模块 -│ ├── captcha.schema.ts -│ ├── captcha.service.ts -│ ├── captcha.controller.ts -│ └── captcha.test.ts -├── health/ # 健康检查模块 -│ ├── health.controller.ts -│ └── health.service.ts -└── test/ # 测试模块 - └── test.controller.ts +├── index.ts # API总入口:所有的模块文件都由此导出给主程序 +├── [moduleName]/ # 模块目录:每个模块的名称做目录名 +│ ├── [moduleName].docs.md # 接口逻辑规则 +│ ├── [moduleName].schema.ts # Schema定义 +│ ├── [moduleName].response.ts # 响应格式 +│ ├── [moduleName].service.ts # 业务逻辑 +│ ├── [moduleName].controller.ts # 路由控制器 +│ └── [moduleName].test.doc # 测试用例文档 ``` -### 插件系统 (plugins/) +### 1.2 接口目录功能 + +- 每个模块目录下的文件,都需要有对应的功能,不能只有docs.md,其他文件缺一不可 +- [moduleName].docs.md:需要包含接口开发的业务逻辑,包括schema的注意点,response格式的注意点,接口的业务流程,分析相关的数据库,性能问题,安全问题等等需要考虑的地方和注意点 +- [moduleName].schema.ts:定义接口的输入参数,包括参数的类型、参数的必填、参数的默认值、参数的描述、参数的示例 +- [moduleName].response.ts:接口返回数据的格式定义文件 +- [moduleName].service.ts:接口的具体业务逻辑方法 +- [moduleName].controller.ts:接口路由定义文件,在这里组合接口的请求方式、参数类型、响应格式 + +### 1.3 插件目录结构 + ``` src/plugins/ ├── index.ts # 插件总入口 @@ -125,7 +118,7 @@ src/plugins/ └── swagger.plugins.ts ``` -### 类型定义 (type/) +### 1.4 类型定义 (type/) ``` src/type/ ├── config.type.ts # 配置相关类型 @@ -137,441 +130,192 @@ src/type/ └── email.type.ts # 邮件相关类型 ``` -### 工具函数 (utils/) +### 1.5 工具函数 (utils/) ``` src/utils/ ├── deviceInfo.ts # 设备信息工具 +├── distributedLock.ts # 分布式锁工具 ├── formatFileSize.ts # 文件大小格式化 ├── formatRoute.ts # 路由格式化 ├── jwt.helper.ts # JWT工具函数 ├── mysql.ts # MySQL工具 +├── pagination.ts # 分页请求参数工厂函数工具 ├── randomChalk.ts # 随机颜色工具 ├── redis.ts # Redis工具 -├── text.ts # 文本处理工具 -├── responseFormate.ts # 响应格式化工具 -└── snowflake.ts # 雪花ID生成器 +├── responseFormate.ts # 响应统一格式化处理工具 +├── snowflake.ts # 雪花ID生成器 +└── text.ts # 文本处理工具 ``` -### 测试文件 (tests/) -``` -src/tests/ -├── app.test.ts # 应用测试 -├── health.test.ts # 健康检查测试 -├── mysql.test.ts # MySQL测试 -├── redis.test.ts # Redis测试 -├── email.test.ts # 邮件测试 -├── swagger.test.ts # Swagger测试 -└── demo/ - ├── testLogger.ts # 日志测试演示 - └── emailDemo.ts # 邮件测试演示 -``` - -### 常量定义 (constants/) +### 1.6 常量定义 (constants/) ``` src/constants/ +├── swaggerTags.ts # Swagger标签定义:所有模块的tag应该集中在此定义 +└── 其他常量 ``` - -## 1. 文件组织规范 - -### 1.1 必须的文件结构 -每个业务模块必须包含以下文件,**按照固定顺序**: +### 1.7 数据库实体 ``` -src/modules/[module]/ -├── [module].schema.ts # 1️⃣ 数据结构定义(最高优先级) -├── [module].response.ts # 2️⃣ 响应格式定义 -├── [module].service.ts # 3️⃣ 业务逻辑实现 -├── [module].controller.ts # 4️⃣ 路由控制器 -└── [module].test.ts # 5️⃣ 测试用例 -└── [module].test.md # 5️⃣ 测试用例文档 +src/eneities/ +├── index.ts # 实体总入口 +├── customType.ts # 自定义类型 +└── [table].ts # 数据表定义 ``` -### 1.2 文件命名约定 +### 1.8 文件命名约定 - 模块名使用 **单数形式**:`auth`、`user`、`product`、`order` - 文件名格式:`[module].[type].ts` - 导出名格式:`[module][类型名]` -## 2. Schema & 类型系统(🔥 重点优化) +## 2. Schema(请求参数类型) + +**主要指请求参数验证工具,不包括响应** ### 2.1 Schema定义规范 -```typescript -/** - * @file 认证模块Schema定义 - * @author AI Assistant - * @date 2024-12-19 - * @lastEditor AI Assistant - * @lastEditTime 2025-07-06 - * @description 定义认证模块的Schema,包括用户注册、邮箱激活等 - */ - -import { t, type Static } from 'elysia'; - -/** - * 用户注册Schema - * @description 用户注册请求参数验证规则,基于sys_users表结构 - */ -export const RegisterSchema = t.Object({ - /** 用户名,2-50字符,对应sys_users.username */ - username: t.String({ - minLength: 2, - maxLength: 50, - description: '用户名,2-50字符', - examples: ['root', 'testuser'] - }), - /** 邮箱地址,对应sys_users.email */ - email: t.String({ - format: 'email', - maxLength: 100, - description: '邮箱地址', - examples: ['x71291@outlook.com'] - }), - /** 密码,6-50字符 */ - password: t.String({ - minLength: 6, - maxLength: 50, - description: '密码,6-50字符', - examples: ['password123'] - }), - /** 图形验证码 */ - captcha: t.String({ - minLength: 4, - maxLength: 6, - description: '图形验证码', - examples: ['a1b2'] - }), - /** 验证码会话ID */ - captchaId: t.String({ - description: '验证码会话ID', - examples: ['cap'] - }) -}); - -/** - * 邮箱激活Schema - * @description 邮箱激活请求参数验证规则 - */ -export const ActivateSchema = t.Object({ - /** 激活令牌,JWT格式 */ - token: t.String({ - minLength: 10, - maxLength: 1000, - description: '邮箱激活令牌,JWT格式,24小时有效', - examples: ['eyJhbGciOiJIUzI1NiI'] - }) -}); - -/** - * 用户登录Schema - * @description 用户登录请求参数验证规则 - */ -export const LoginSchema = t.Object({ - /** 用户名/邮箱地址,2-50字符,对应sys_users.username */ - identifier: t.String({ - minLength: 2, - maxLength: 100, - description: '用户名/邮箱地址,100字符', - examples: ['root', 'testuser', 'x71291@outlook.com'] - }), - /** 图形验证码(可选) */ - captcha: t.Optional(t.String({ - minLength: 4, - maxLength: 6, - description: '图形验证码,登录失败次数过多时需要', - examples: ['a1b2'] - })), - /** 密码,6-50字符 */ - password: t.String({ - minLength: 6, - maxLength: 50, - description: '密码,6-50字符', - examples: ['password123'] - }), - /** 验证码会话ID(可选) */ - captchaId: t.Optional(t.String({ - description: '验证码会话ID,与captcha配对使用', - examples: ['cap'] - })), - /** 是否记住登录状态 */ - rememberMe: t.Optional(t.Boolean({ - description: '是否记住登录状态,影响token过期时间', - examples: [true, false], - default: false - })) -}); - -/** 用户注册请求类型 */ -export type RegisterRequest = Static; - -/** 邮箱激活请求类型 */ -export type ActivateRequest = Static; - -/** 用户登录请求类型 */ -export type LoginRequest = Static; -``` - -### 2.2 类型导出规范 +- 一个模块的所有schema都在一个文件中 +- 使用elysia自带的类型共据`t` +- 参数一定要明确是必填还是选填,是否有默认值 +- 对必要的数据进行转化,如用户名全小写并且去除两端空格 +- 必须有描述和示例参数 +- 导出类型 +- 注意已经存在的工具函数,比如分页有现成的简化工具,且能够统一请求格式 +### 2.2 特别注意点 **必须遵循的命名模式:** - Request类型:`[动作][模块]Request` → `RegisterRequest` -- Response类型:`[动作][模块]Response` → `RegisterResponse` - Schema名:`[动作][模块]Schema` → `RegisterSchema` -- 数据模型:`[模块]Data` → `UserData` -### 2.3 Schema定义最佳实践 -```typescript -// ✅ 完整的Schema定义示例 -export const CreateUserSchema = t.Object({ - username: t.String({ - minLength: 2, - maxLength: 50, - pattern: '^[a-zA-Z0-9_-]+$', // 添加正则验证 - description: '用户名,2-50字符,仅允许字母、数字、下划线、连字符', - examples: ['admin', 'user123', 'test_user'] - }), - email: t.String({ - format: 'email', - maxLength: 100, - description: '邮箱地址', - examples: ['user@example.com', 'admin@company.com'] - }), - age: t.Optional(t.Number({ - minimum: 0, - maximum: 150, - description: '年龄,可选字段', - examples: [25, 30, 35] - })), - tags: t.Optional(t.Array(t.String({ - maxLength: 20 - }), { - description: '标签列表', - examples: [['developer', 'admin'], ['user']] - })) -}); -``` +### 2.3 代码示例 -## 3. 响应格式规范(🔥 重点优化) - -### 3.1 统一响应格式工具 - -```typescript -// ✅ 使用 responseFormate.ts 中的工具 +```ts /** - * @file 认证模块响应格式定义 + * @file 用户模块Schema定义 * @author AI Assistant * @date 2024-12-19 * @lastEditor AI Assistant * @lastEditTime 2025-01-07 - * @description 定义认证模块的响应格式,包括用户注册、邮箱激活、用户登录等 + * @description 定义用户模块的Schema,包括获取当前用户信息、用户列表查询等 */ import { t, type Static } from 'elysia'; -import { responseWrapperSchema } from '@/utils/responseFormate'; - -// ========== 邮箱注册相关响应格式 ========== +import { createQuerySchema } from '@/utils/pagination'; /** - * 用户注册接口响应组合 - * @description 用于Controller中定义所有可能的响应格式 + * 用户列表查询参数Schema + * @description 用户列表查询的请求参数验证规则 */ -export const RegisterResponsesSchema = { - 200: responseWrapperSchema(t.Object({ - /** 用户ID */ - id: t.String({ - description: '用户ID(bigint类型以字符串形式返回防止精度丢失)', - examples: ['1', '2', '3'] - }), - /** 用户名 */ - username: t.String({ - description: '用户名', - examples: ['admin', 'testuser'] - }), - /** 邮箱地址 */ - email: t.String({ - description: '邮箱地址', - examples: ['user@example.com'] - }), - /** 账号状态 */ - status: t.String({ - description: '账号状态', - examples: ['pending', 'active'] - }), - /** 创建时间 */ - createdAt: t.String({ - description: '创建时间', - examples: ['2024-12-19T10:30:00Z'] - }) +export const UserListQuerySchema = createQuerySchema(t.Object({ + // 用户特有参数 + keyword: t.Optional(t.String({ + minLength: 1, + maxLength: 100, + description: '搜索关键词,支持用户名、邮箱模糊搜索', + examples: ['admin', 'test@example.com'] })), -}; -/** 用户注册成功响应数据类型 */ -export type RegisterResponsesType = Static; - -// ========== 邮箱激活相关响应格式 ========== - -/** - * 邮箱激活接口响应组合 - * @description 用于Controller中定义所有可能的响应格式 - */ -export const ActivateResponsesSchema = { - 200: responseWrapperSchema(t.Object({ - /** 用户ID */ - id: t.String({ - description: '用户ID(bigint类型以字符串形式返回防止精度丢失)', - examples: ['1', '2', '3'] - }), - /** 用户名 */ - username: t.String({ - description: '用户名', - examples: ['admin', 'testuser'] - }), - /** 邮箱地址 */ - email: t.String({ - description: '邮箱地址', - examples: ['user@example.com'] - }), - /** 账号状态 */ - status: t.String({ - description: '账号状态', - examples: ['active'] - }), - /** 激活时间 */ - updatedAt: t.String({ - description: '激活时间', - examples: ['2024-12-19T10:30:00Z'] - }), - /** 激活成功标识 */ - activated: t.Boolean({ - description: '是否已激活', - examples: [true] - }) + status: t.Optional(t.Union([ + t.Literal('active'), + t.Literal('inactive'), + t.Literal('pending') + ], { + description: '用户状态筛选', + examples: ['active', 'inactive', 'pending'] })), -}; - -/** 邮箱激活成功响应数据类型 */ -export type ActivateSuccessType = Static; - -// ========== 用户登录相关响应格式 ========== - -/** - * 用户登录接口响应组合 - * @description 用于Controller中定义所有可能的响应格式 - */ -export const LoginResponsesSchema = { - 200: responseWrapperSchema(t.Object({ - /** 用户基本信息 */ - user: t.Object({ - /** 用户ID */ - id: t.String({ - description: '用户ID(bigint类型以字符串形式返回防止精度丢失)', - examples: ['1', '2', '3'] - }), - /** 用户名 */ - username: t.String({ - description: '用户名', - examples: ['admin', 'testuser'] - }), - /** 邮箱地址 */ - email: t.String({ - description: '邮箱地址', - examples: ['user@example.com'] - }), - /** 账号状态 */ - status: t.String({ - description: '账号状态', - examples: ['active'] - }), - /** 最后登录时间 */ - lastLoginAt: t.Union([t.String(), t.Null()], { - description: '最后登录时间', - examples: ['2024-12-19T10:30:00Z', null] - }) - }), - /** 认证令牌信息 */ - tokens: t.Object({ - /** 访问令牌 */ - accessToken: t.String({ - description: 'JWT访问令牌', - examples: ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'] - }), - /** 刷新令牌 */ - refreshToken: t.String({ - description: 'JWT刷新令牌', - examples: ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'] - }), - /** 令牌类型 */ - tokenType: t.String({ - description: '令牌类型', - examples: ['Bearer'] - }), - /** 过期时间(秒) */ - expiresIn: t.String({ - description: '访问令牌过期时间(秒)', - examples: [7200, 86400] - }), - /** 刷新令牌过期时间(秒) */ - refreshExpiresIn: t.String({ - description: '刷新令牌过期时间(秒)', - examples: [2592000] - }) - }) + gender: t.Optional(t.Union([ + t.Literal(0), + t.Literal(1), + t.Literal(2), + t.Literal('0'), + t.Literal('1'), + t.Literal('2'), + ], { + description: '性别筛选:0-未知,1-男,2-女', + examples: [0, 1, 2] })), -}; + isRoot: t.Optional(t.Boolean({ + description: '是否超级管理员筛选', + examples: [true, false] + })) +})); -/** 用户登录成功响应数据类型 */ -export type LoginSuccessType = Static; +/** 用户列表查询参数类型 */ +export type UserListQueryRequest = Static; ``` -### 3.2 Response定义规范 +## 3. Response(响应数据类型) -```typescript -// ✅ 优化示例 - auth.response.ts +### 3.1 响应格式定义规范 + +- 使用统一的相应格式工具`responseWrapperSchema` +- 错误相应只提供示例和描述 +- 导出响应成功类型 + + +### 3.2 特别注意点 +**必须遵循的命名模式:** +- Response格式定义:`[动作][模块]Response` → `RegisterResponse` +- Response成功类型:`[动作][模块]SuccessType ` → `RegisterSuccessType ` + +### 3.3 代码示例 + +```ts /** - * @file 认证模块响应格式定义 - * @author 开发者姓名 + * @file 用户模块响应格式定义 + * @author AI Assistant * @date 2024-12-19 - * @description 定义认证模块的响应格式,包括成功和错误响应 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 定义用户模块的响应格式,包括获取当前用户信息、用户列表查询等 */ import { t, type Static } from 'elysia'; import { responseWrapperSchema } from '@/utils/responseFormate'; +import { createPaginationResponseSchema } from '@/utils/pagination'; + + /** - * 用户注册接口响应组合 + * 用户列表项Schema + * @description 用户列表中单个用户的数据结构 + */ +export const UserListItemSchema = t.Object({ + /** 用户ID */ + id: t.String({ + description: '用户ID(bigint类型以字符串形式返回防止精度丢失)', + examples: ['1', '2', '3'] + }), + /** 用户名 */ + username: t.String({ + description: '用户名', + examples: ['admin', 'testuser'] + }), + + /** 更多字段... */ + + /** 更新时间 */ + updatedAt: t.String({ + description: '更新时间', + examples: ['2024-12-19T10:30:00Z'] + }) +}); + +/** + * 获取用户列表接口响应组合 * @description 用于Controller中定义所有可能的响应格式 */ -export const RegisterResponsesSchema = { - 200: responseWrapperSchema(t.Object({ - /** 用户ID,以字符串形式返回避免精度丢失 */ - id: t.String({ - description: '用户ID', - examples: ['1', '2', '3'] - }), - /** 用户名 */ - username: t.String({ - description: '用户名', - examples: ['admin', 'testuser'] - }), - /** 邮箱地址 */ - email: t.String({ - description: '邮箱地址', - examples: ['user@example.com'] - }), - /** 账号状态 */ - status: t.String({ - description: '账号状态', - examples: ['pending', 'active'] - }), - /** 创建时间 */ - createdAt: t.String({ - description: '创建时间', - examples: ['2024-12-19T10:30:00Z'] +export const GetUserListResponsesSchema = { + 200: responseWrapperSchema(createPaginationResponseSchema(UserListItemSchema)), + 401: responseWrapperSchema(t.Object({ + error: t.String({ + description: '认证失败', + examples: ['未提供有效的认证令牌', '令牌已过期'] }) })), 400: responseWrapperSchema(t.Object({ error: t.String({ - description: '错误信息', - examples: ['用户名已存在', '邮箱已被注册'] + description: '参数错误', + examples: ['分页参数无效', '搜索关键词格式错误'] }) })), 500: responseWrapperSchema(t.Object({ @@ -581,155 +325,134 @@ export const RegisterResponsesSchema = { }) })) }; -// 注意,不需要定义错误响应的具体格式,只用给出可能错误的情况的说明和示例即可,一下就是正确的错误示例 -` -500: responseWrapperSchema(t.Object({ - error: t.String({ - description: '服务器错误', - examples: ['内部服务器错误'] - }) - })) -` -/** 用户注册成功响应数据类型 */ -export type RegisterSuccessResponse = Static; + +/** 获取用户列表成功响应数据类型 */ +export type GetUserListSuccessType = Static; ``` -## 4. Service层规范(🔥 重点优化) +## 4. Service(业务逻辑层) -### 4.1 Service类定义 - -```typescript -// ✅ 优化示例 - auth.service.ts -/** - * @file 认证模块Service层实现 - * @author 开发者姓名 - * @date 2024-12-19 - * @description 认证模块的业务逻辑实现,包括用户注册、登录等 - */ - -import { Logger } from '@/plugins/logger/logger.service'; -import { successResponse, errorResponse, BusinessError } from '@/utils/responseFormate'; -import { ERROR_CODES } from '@/constants/error-codes'; -import type { RegisterRequest } from './auth.schema'; -import type { RegisterSuccessResponse } from './auth.response'; - -/** - * 认证服务类 - * @description 处理用户注册、登录等认证相关业务逻辑 - */ -export class AuthService { - /** - * 用户注册 - * @param request 用户注册请求参数 - * @returns Promise - * @throws BusinessError 业务逻辑错误 - * @type API ===================================================================== - */ - public async register(request: RegisterRequest): Promise { - Logger.info(`用户注册请求:${JSON.stringify({ ...request, password: '***' })}`); - - try { - // 1. 验证验证码 - await this.validateCaptcha(request.captcha, request.captchaId); - - // 2. 检查用户名是否已存在 - await this.checkUsernameExists(request.username); - - // 3. 检查邮箱是否已存在 - await this.checkEmailExists(request.email); - - // 4. 创建用户 - const user = await this.createUser(request); - - Logger.info(`用户注册成功:${user.id} - ${user.username}`); - - return successResponse({ - id: user.id, - username: user.username, - email: user.email, - status: user.status, - createdAt: user.createdAt - }, '用户注册成功,请查收激活邮件'); - - } catch (error) { - Logger.error(new Error(`用户注册失败:${error}`)); - - if (error instanceof BusinessError) { - throw error; - } - - throw new BusinessError( - ERROR_CODES.INTERNAL_ERROR, - 500 - ); - } - } - - /** - * 验证验证码 - * @param captcha 验证码 - * @param captchaId 验证码ID - * @throws BusinessError 验证失败时抛出 - */ - private async validateCaptcha(captcha: string, captchaId: string): Promise { - // 验证逻辑... - if (!isValidCaptcha) { - throw new BusinessError( - ERROR_CODES.CAPTCHA_ERROR, - 400 - ); - } - } - - /** - * 检查用户名是否已存在 - * @param username 用户名 - * @throws BusinessError 用户名已存在时抛出 - */ - private async checkUsernameExists(username: string): Promise { - // 检查逻辑... - if (exists) { - throw new BusinessError( - ERROR_CODES.USERNAME_EXISTS, - 409 - ); - } - } -} - -// 导出单例实例 -export const authService = new AuthService(); -``` - -### 4.2 Service层要求 +### 4.1 Service层要求 - ✅ 所有方法必须有完整的类型注解 - ✅ 所有方法必须有详细的JSDoc注释 - ✅ 必须使用统一的响应格式工具 - ✅ 必须使用统一的错误码 -- ✅ 必须有详细的日志记录 -- ✅ 必须有完整的错误处理 +- ✅ 必须有详细的日志记录,接口有请求响应记录,无需记录每次请求 +- ✅ 需要有完整的错误处理,服务错误有拦截器处理可以不管,只判断逻辑上的错误 - ✅ 导出单例实例供controller使用 -## 5. Controller层规范(🔥 重点优化) +### 4.2 注意点 -### 5.1 Controller定义 +- 开发逻辑时,注意数据库实体,必须严格按照数据库字段进行开发,不能出错 +- 更新时间数据库一般会自动天写,不用手动设置或更新 +- 数据库id一般为bigint,注意类型和精度问题 +- 在写入数据时,必要的增加分布式锁 +- 逻辑要清晰,代码要简洁 -```typescript -// ✅ 优化示例 - auth.controller.ts +### 4.3 代码示例 + +```ts /** - * @file 认证模块Controller层实现 - * @author 开发者姓名 + * @file 用户模块Service层实现 + * @author AI Assistant * @date 2024-12-19 - * @description 认证模块的路由控制器,处理HTTP请求 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 用户模块的业务逻辑实现,包括获取当前用户信息、用户列表查询等 */ -import { Elysia } from 'elysia'; -import { RegisterSchema } from './auth.schema'; -import { RegisterResponsesSchema } from './auth.response'; -import { authService } from './auth.service'; -import { tags } from '@/modules/tags'; +import { Logger } from '@/plugins/logger/logger.service'; +import { db } from '@/plugins/drizzle/drizzle.service'; +import { sysUsers } from '@/eneities'; +import { eq, like, and, desc, asc, sql } from 'drizzle-orm'; +import { successResponse, errorResponse, BusinessError } from '@/utils/responseFormate'; +import { calculatePagination, normalizePaginationParams } from '@/utils/pagination'; +import type { GetCurrentUserSuccessType, GetUserListSuccessType } from './user.response'; +import type { UserListQueryRequest, UserListItem } from './user.schema'; + +/** + * 用户服务类 + * @description 处理用户相关的业务逻辑 + */ +export class UserService { + /** + * 获取当前用户信息 + * @param userId 用户ID + * @returns Promise + * @throws BusinessError 业务逻辑错误 + * @type API ===================================================================== + */ + public async getCurrentUser(userId: string): Promise { + Logger.info(`获取用户信息:${userId}`); + // 查询用户信息 + const user = await db() + .select({ + id: sysUsers.id, + username: sysUsers.username, + email: sysUsers.email, + nickname: sysUsers.nickname, + avatar: sysUsers.avatar, + mobile: sysUsers.mobile, + status: sysUsers.status, + lastLoginAt: sysUsers.lastLoginAt, + createdAt: sysUsers.createdAt, + updatedAt: sysUsers.updatedAt + }) + .from(sysUsers) + .where(eq(sysUsers.id, BigInt(userId))) + .limit(1); + + if (!user || user.length === 0) { + Logger.warn(`用户不存在:${userId}`); + throw new BusinessError( + `用户不存在:${userId}`, + 404 + ); + } + + const userData = user[0]!; + + Logger.info(`获取用户信息成功:${userId} - ${userData.username}`); + + return successResponse({ + id: userId, // 使用传入的字符串ID,避免精度丢失 + username: userData.username, + email: userData.email, + nickname: userData.nickname, + avatar: userData.avatar, + phone: userData.mobile, + status: userData.status, + lastLoginAt: userData.lastLoginAt || null, + createdAt: userData.createdAt, + updatedAt: userData.updatedAt + }, '获取用户信息成功'); + } + +} + +// 导出单例实例 +export const userService = new UserService(); +``` + +## 5. Controllers(接口名称接入) + +### 5.1 Controllers层要求 + +- ✅ 路由方法必须有完整的JSDoc注释 +- ✅ 必须定义完整的response schema +- ✅ 必须有适当的tags分类 +- ✅ 必须有operationId用于API文档 +- ✅ 错误处理由Service层统一处理 + +### 5.2 Controllers层注意点 + +- 使用service时要简洁,如`({ body }) => authService.register(body),` + +### 5.3 Controllers层代码示例 + +```ts /** * 认证控制器 * @description 处理用户认证相关的HTTP请求 @@ -755,263 +478,26 @@ export const authController = new Elysia() } ); ``` +## 6. 错误处理 -### 5.2 Controller层要求 +### 6.1 错误处理规范 -- ✅ 路由方法必须有完整的JSDoc注释 -- ✅ 必须定义完整的response schema -- ✅ 必须有适当的tags分类 -- ✅ 必须有operationId用于API文档 -- ✅ 错误处理由Service层统一处理 +- 统一`import { BusinessError } from '@/utils/responseFormate';`引入错误工具抛出错误 +- 错误处理在errorHandle.plugins中统一处理, -## 6. 错误处理规范(🔥 重点优化) - -### 6.2 错误处理最佳实践 +### 6.2 主动抛出异常示例 ```typescript // ✅ Service层错误处理 import { BusinessError } from '@/utils/responseFormate'; // 抛出业务错误 -throw new BusinessError(ERROR_CODES.USERNAME_EXISTS, 409); - -// ✅ 统一错误响应格式 -export const errorResponse = (code: number, message: string, type: string, data: any = null) => { - const response = { - code, - message, - data, - type, - timestamp: new Date().toISOString(), - }; - Logger.warn(response); - return response; -}; +throw new BusinessError('消息说明...', 409); ``` +## 7. 测试用例文档 -## 7. 测试规范 - -### 7.1 测试文件结构 - -```typescript -// ✅ 优化示例 - auth.test.ts -/** - * @file 认证模块测试用例 - * @author 开发者姓名 - * @date 2024-12-19 - * @description 认证模块的单元测试和集成测试 - */ - -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; -import { app } from '@/app'; -import type { RegisterRequest } from './auth.schema'; - -describe('Auth API', () => { - beforeAll(async () => { - // 测试环境初始化 - }); - - afterAll(async () => { - // 测试环境清理 - }); - - describe('POST /api/auth/register', () => { - it('应该成功注册用户', async () => { - const payload: RegisterRequest = { - username: 'testuser', - email: 'test@example.com', - password: 'password123', - captcha: 'a1b2', - captchaId: 'test_captcha_id' - }; - - const response = await app - .handle(new Request('http://localhost/api/auth/register', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - })); - - expect(response.status).toBe(200); - const result = await response.json(); - expect(result.code).toBe(200); - expect(result.message).toContain('注册成功'); - expect(result.data.username).toBe(payload.username); - }); - - it('应该验证必填字段', async () => { - const payload = { username: 'test' }; // 缺少必要字段 - - const response = await app - .handle(new Request('http://localhost/api/auth/register', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - })); - - expect(response.status).toBe(400); - }); - - it('应该检查用户名重复', async () => { - // 测试用户名重复的情况 - }); - - it('应该验证验证码', async () => { - // 测试验证码验证 - }); - }); -}); -``` - -## 8. AI助手协作规范 - -### 8.1 注释规范(关键❗️) - -#### 1. 文件头部注释 -```typescript -/** - * @file 文件简要说明 - * @author 创建者姓名 - * @date 创建时间(如:2024-12-19) - * @lastEditor 最后修改人 - * @lastEditTime 最后修改时间 - * @description 文件详细描述 - */ -``` - -#### 2. 函数/方法注释(JSDoc) -```typescript -/** - * 方法功能说明 - * @param paramName 参数说明 - * @returns 返回值类型和说明 - * @throws ErrorType 可能抛出的异常说明 - * @example - * const result = await someMethod('example'); - * @modification 修改人 修改时间 修改说明 - */ -``` - -#### 3. 变量注释 -```typescript -/** - * 变量说明 - * @type {string} 变量类型 - * @description 详细描述 - * @example 'example_value' - */ -``` - -### 8.2 代码组织原则 - -1. **单一职责**:每个文件只负责一个清晰的功能 -2. **类型优先**:先定义Schema和类型,再实现逻辑 -3. **错误优先**:优先考虑错误处理和边界情况 -4. **测试驱动**:每个功能都有对应的测试用例 -5. **依赖注入**:通过导入明确依赖关系 - -### 8.3 命名约定总结 - -| 类型 | 格式 | 示例 | -|------|------|------| -| 文件名 | `[module].[type].ts` | `auth.controller.ts` | -| Schema | `[Action][Module]Schema` | `RegisterSchema` | -| Request类型 | `[Action][Module]Request` | `RegisterRequest` | -| Response类型 | `[Action][Module]Response` | `RegisterResponse` | -| Service类 | `[Module]Service` | `AuthService` | -| Service实例 | `[module]Service` | `authService` | -| Controller | `[module]Controller` | `authController` | - -## 9. 快速检查清单 - -开发新功能时,按此顺序检查: - -- [ ] 1. Schema定义完整(包含验证规则、描述、示例) -- [ ] 2. 类型导出正确(Request/Response类型) -- [ ] 3. Response格式使用responseWrapperSchema -- [ ] 4. Service使用successResponse/errorResponse -- [ ] 5. 错误处理使用统一错误码 -- [ ] 6. Controller定义完整的response schema -- [ ] 7. 测试用例覆盖主要场景 -- [ ] 8. JSDoc注释完整 -- [ ] 9. 日志记录到位 -- [ ] 10. 使用统一的工具函数 - -## 10. 最佳实践 - -### 10.1 响应格式优化 -```typescript -// ✅ 使用统一的响应格式 -import { successResponse, errorResponse } from '@/utils/responseFormate'; - -// 成功响应 -return successResponse(data, '操作成功'); - -// 错误响应 -return errorResponse(400, '参数错误', 'VALIDATION_ERROR'); -``` - -### 10.2 错误处理优化 -```typescript -// ✅ 使用BusinessError类 -import { BusinessError } from '@/utils/responseFormate'; -import { ERROR_CODES } from '@/constants/error-codes'; - -throw new BusinessError(ERROR_CODES.USERNAME_EXISTS, 409); -``` - -### 10.3 Schema验证优化 -```typescript -// ✅ 完整的Schema定义 -export const UserSchema = t.Object({ - id: t.String({ description: '用户ID' }), - username: t.String({ - description: '用户名', - examples: ['admin', 'user123'] - }), - email: t.String({ - format: 'email', - description: '邮箱地址', - examples: ['user@example.com'] - }) -}); -``` - -### 10.4 性能优化 -- 使用连接池管理数据库连接 -- 实现合理的缓存策略(Redis) -- 避免N+1查询问题 -- 使用雪花ID算法生成唯一ID - -### 10.5 安全考虑 -- 输入验证和清理 -- 密码加密存储(bcrypt) -- JWT令牌认证 -- 敏感信息不记录日志 -- 对于必要的写入操作,需要增加分布式锁,分布式锁键名在常量中统一定义 - -## 11. 模块引入规范 - -### 11.1 路径别名 -```typescript -// ✅ 使用路径别名 -import { Logger } from '@/plugins/logger/logger.service'; -import { db } from '@/plugins/drizzle/drizzle.service'; -import { ERROR_CODES } from '@/constants/error-codes'; -import { successResponse } from '@/utils/responseFormate'; -``` - -### 11.2 配置文件更新 -确保更新以下配置文件中的路径别名: -- `tsconfig.json` -- `bunfig.toml` -- `vitest.config.ts` - ---- - -**请严格遵守以上规范,确保代码的一致性、可维护性和AI友好性。这套规则经过实际项目验证,能够显著提升开发效率和代码质量。** -- 注意更新 tsconfig.json bunfig.toml 等配置中关于路径别名的配置 - ---- - -**请所有开发者严格遵守以上规范,保障 Elysia 接口的一致性、后端服务的健壮性、安全性与可维护性。** \ No newline at end of file +1. 分模块 +2. 分接口 +3. 测试名称 +4. 场景 +5. 方法 \ No newline at end of file diff --git a/.cursor/rules/global-rules/global.mdc b/.cursor/rules/global-rules/global.mdc deleted file mode 100644 index 6efd233..0000000 --- a/.cursor/rules/global-rules/global.mdc +++ /dev/null @@ -1,10 +0,0 @@ ---- -description: "全局规则" -globs: ["**/*"] -alwaysApply: true ---- -# 特殊要求 - -1. 删除文件时一定要请求确认 - -2. **不允许执行脚本和命令,告诉我命令即可,由我手动执行** \ No newline at end of file diff --git a/.cursor/rules/global-rules/process-list-task.mdc b/.cursor/rules/global-rules/process-list-task.mdc deleted file mode 100644 index 8e48779..0000000 --- a/.cursor/rules/global-rules/process-list-task.mdc +++ /dev/null @@ -1,59 +0,0 @@ ---- -description: "全局规则" -globs: ["**/*"] -alwaysApply: true ---- -描述 (description): -全局模式 (globs): -始终应用 (alwaysApply): false ---- -# 任务清单管理 - -管理Markdown文件中的任务清单以跟踪完成PRD进度的指南。 - -## 任务实施 (Task Implementation) -* **一次处理一个子任务:** 在询问用户并获得“yes”或“y”的许可之前,**不要**开始下一个子任务。********非常重要必须执行********* -* **完成协议 (Completion protocol):** - 1. 当你完成一个**子任务**时,立即通过将 `[ ]` 改为 `[x]` 将其标记为已完成。 - 2. 如果一个父任务下的**所有**子任务现在都是 `[x]`,则按以下顺序执行: - * **首先:** 运行完整的测试套件(`pytest`, `npm test`, `bin/rails test` 等)。 - * **仅当所有测试通过时:** 暂存更改 (`git add .`)。 - * **清理:** 提交前删除所有临时文件和临时代码。 - * **提交 (Commit):** 使用描述性的提交消息: - * 采用常规提交格式 (`feat:`, `fix:`, `refactor:`, 等)。 - * 总结父任务中完成的内容。 - * 列出关键的更改和新增。 - * 引用任务编号和PRD上下文。 - * **使用 `-m` 标志将消息格式化为单行命令**,例如: - ``` - git commit -m "feat: 添加支付验证逻辑" -m "- 验证卡类型和有效期" -m "- 为边界情况添加单元测试" -m "关联PRD中的T123" - ``` - 3. 一旦所有子任务标记为完成且更改已提交,将**父任务**标记为完成 (`[x]`)。 -* 完成每个子任务后停止并等待用户的批准 (`go-ahead`)。 - -## 任务清单维护 (Task List Maintenance) - -1. **边工作边更新任务清单:** - * 按照上述协议将任务和子任务标记为完成 (`[x]`)。 - * 添加新出现的任务。 - * **注意,每完成一个子任务时,都要更新任务清单状态** -2. **维护“相关文件”部分:** - * 列出每个创建或修改的文件。 - * 为每个文件提供一行其用途描述。 - -## AI 指令 (AI Instructions) - -当使用任务清单时,AI 必须: - -1. 完成任何重要工作后定期更新任务清单文件。 -2. 遵守完成协议: - * 将每个完成的**子任务**标记为 `[x]`。 - * 一旦其**所有**子任务都是 `[x]`,将**父任务**标记为 `[x]`。 -3. 添加新发现的任务。 -4. 保持“相关文件”准确且最新。 -5. 开始工作前,检查下一个子任务是什么。 -6. 实现一个子任务后,更新文件,然后暂停等待用户批准。 -7. 在执行任务前请扫描项目目录 -8. 完成一个子任务后,提交git -9. 将已完成的任务归档到tasks的归档目录archive并修改文件名,文件名前添加时间 -10. 将需求prd也归档 diff --git a/.cursor/rules/task-execution.mdc b/.cursor/rules/task-execution.mdc new file mode 100644 index 0000000..cddfc1b --- /dev/null +++ b/.cursor/rules/task-execution.mdc @@ -0,0 +1,46 @@ +--- +description: "全局规则" +globs: ["**/*"] +alwaysApply: true +--- +# 任务执行流程 + +管理Markdown文件中的任务清单以跟踪完成PRD进度的指南。 + +## 任务实施 (Task Implementation) + +1. 在执行大任务 `x.0`时先扫描项目,理解AI规则 +2. 每一个大任务包含多个子任务,如 `1.1`、`1.2`、`1.3`等 +3. 在执行子任务之前,要深刻理解任务需求,给出详细的任务执行逻辑,确保执行步骤正确,**必须等待取人才能进行下一步,需要等我的输入,如y和go等** +4. 每一个子任务执行完之后都必须暂停,等待我的验证,坚决不允许任何连续执行多个任务 +6. 每个大任务执行前,给出git commit提交文本 + +* **一次处理一个子任务:** 在询问用户并获得“yes”或“y”的许可之前,**不要**开始下一个子任务。********非常重要必须执行********* +* 完成每个子任务后停止并等待用户的批准 (`go-ahead`)。 + +## 任务清单维护 (Task List Maintenance) + +1. **边工作边更新任务清单:** + * 按照上述协议将任务和子任务标记为完成 (`[x]`)。 + * 添加新出现的任务。 + * **注意,每完成一个子任务时,都要更新任务清单状态** +2. **维护“相关文件”部分:** + * 列出每个创建或修改的文件。 + * 为每个文件提供一行其用途描述。 + +## AI 指令 (AI Instructions) + +当使用任务清单时,AI 必须: + +1. 完成任何重要工作后定期更新任务清单文件。 +2. 遵守完成协议: + * 将每个完成的**子任务**标记为 `[x]`。 + * 一旦其**所有**子任务都是 `[x]`,将**父任务**标记为 `[x]`。 +3. 添加新发现的任务。 +4. 保持“相关文件”准确且最新。 +5. 开始工作前,检查下一个子任务是什么。 +6. 实现一个子任务后,更新文件,然后暂停等待用户批准。 +7. 在执行任务前请扫描项目目录 +8. 完成一个子任务后,提交git +9. 将已完成的任务归档到tasks的归档目录archive并修改文件名,文件名前添加时间 +10. 将需求prd也归档 diff --git a/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc b/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc deleted file mode 100644 index b8100b7..0000000 --- a/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +++ /dev/null @@ -1,111 +0,0 @@ ---- -description: Use Bun instead of Node.js, npm, pnpm, or vite. -globs: "*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json" -alwaysApply: false ---- - -Default to using Bun instead of Node.js. - -- Use `bun ` instead of `node ` or `ts-node ` -- Use `bun test` instead of `jest` or `vitest` -- Use `bun build ` instead of `webpack` or `esbuild` -- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install` -- Use `bun run - - -``` - -With the following `frontend.tsx`: - -```tsx#frontend.tsx -import React from "react"; - -// import .css files directly and it works -import './index.css'; - -import { createRoot } from "react-dom/client"; - -const root = createRoot(document.body); - -export default function Frontend() { - return

Hello, world!

; -} - -root.render(); -``` - -Then, run index.ts - -```sh -bun --hot ./index.ts -``` - -For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`. diff --git a/.trae/rules/project_rules.md b/.trae/rules/project_rules.md new file mode 100644 index 0000000..3c7ff5f --- /dev/null +++ b/.trae/rules/project_rules.md @@ -0,0 +1,503 @@ +# ElysiaAPI开发流程 + +## 0. 概览 + +这是一个基于 **Bun + Elysia** 的现代化后端API项目,采用TypeScript开发,集成了MySQL、Redis、JWT认证、Swagger文档等功能。 + +- **运行时**:Bun +- **框架**:Elysia +- **语言**:TypeScript +- **数据库**:MySQL + Drizzle ORM +- **缓存**:Redis +- **认证**:JWT +- **测试**:Vitest +- **文档**:Swagger +- **日志**:Winston +- **代码规范**:ESLint + Prettier + +使用的技术和库 + +- **数据库**:`"mysql2": "^3.14.1"`, `"drizzle-orm": "^0.44.2"` +- **token验证**:`"jsonwebtoken": "^9.0.2"` +- **密码加密**:`"bcrypt": "^6.0.0"` + +## 1. 相关目录结构和描述 + +### 1.0 整体目录结构 + +``` +project/ +├── 📋 配置文件(config/) +├── 📁 源代码 (src/) +├───└───config +├───├───eneities +├───├───modules +│ ├───├───auth +│ ├───├───captcha +│ ├───├───health +│ ├───├───test +│ ├───└───user +├───├───plugins +│ ├───├───drizzle +│ ├───├───email +│ ├───├───errorHandle +│ ├───├───jwt +│ ├───├───logger +│ ├───├───redis +│ ├───└───swagger +├───└───tests +│ └───demo +├───type +├───utils +├── 📁 文档 (docs/) +├── 📁 需求文档 (prd/) +├── 📁 任务管理 (tasks/) +├── 📁 AI对话记录 (aiChat/) +├── 📁 数据库迁移 (drizzle/) +└── 📁 静态资源 (public/) +| 文件 | 说明 | +|------|------| +| `package.json` | 项目依赖和脚本配置 | +| `tsconfig.json` | TypeScript编译配置 | +| `tsconfig.test.json` | 测试环境TypeScript配置 | +| `vitest.config.ts` | Vitest测试框架配置 | +| `eslint.config.js` | ESLint代码规范配置 | +| `bunfig.toml` | Bun运行时配置 | +| `drizzle.config.ts` | Drizzle ORM配置 | +| `README.md` | 项目说明文档 | +``` + +### 1.1 接口目录结构 + +``` +src/modules/ +├── index.ts # API总入口:所有的模块文件都由此导出给主程序 +├── [moduleName]/ # 模块目录:每个模块的名称做目录名 +│ ├── [moduleName].docs.md # 接口逻辑规则 +│ ├── [moduleName].schema.ts # Schema定义 +│ ├── [moduleName].response.ts # 响应格式 +│ ├── [moduleName].service.ts # 业务逻辑 +│ ├── [moduleName].controller.ts # 路由控制器 +│ └── [moduleName].test.doc # 测试用例文档 +``` + +### 1.2 接口目录功能 + +- 每个模块目录下的文件,都需要有对应的功能,不能只有docs.md,其他文件缺一不可 +- [moduleName].docs.md:需要包含接口开发的业务逻辑,包括schema的注意点,response格式的注意点,接口的业务流程,分析相关的数据库,性能问题,安全问题等等需要考虑的地方和注意点 +- [moduleName].schema.ts:定义接口的输入参数,包括参数的类型、参数的必填、参数的默认值、参数的描述、参数的示例 +- [moduleName].response.ts:接口返回数据的格式定义文件 +- [moduleName].service.ts:接口的具体业务逻辑方法 +- [moduleName].controller.ts:接口路由定义文件,在这里组合接口的请求方式、参数类型、响应格式 + +### 1.3 插件目录结构 + +``` +src/plugins/ +├── index.ts # 插件总入口 +├── drizzle/ # 数据库ORM插件 +│ ├── drizzle.plugins.ts +│ ├── drizzle.service.ts +│ └── README.md +├── email/ # 邮件插件 +│ ├── email.plugins.ts +│ ├── email.service.ts +│ └── README.md +├── errorHandle/ # 错误处理插件 +│ └── errorHandler.plugins.ts +├── jwt/ # JWT认证插件 +│ ├── jwt.plugins.ts +│ └── jwt.service.ts +├── logger/ # 日志插件 +│ ├── logger.plugins.ts +│ └── logger.service.ts +├── redis/ # Redis插件 +│ ├── redis.plugins.ts +│ └── redis.service.ts +└── swagger/ # API文档插件 + └── swagger.plugins.ts +``` + +### 1.4 类型定义 (type/) +``` +src/type/ +├── config.type.ts # 配置相关类型 +├── drizzle.type.ts # 数据库相关类型 +├── error.type.ts # 错误相关类型 +├── jwt.type.ts # JWT相关类型 +├── logger.type.ts # 日志相关类型 +├── redis.type.ts # Redis相关类型 +└── email.type.ts # 邮件相关类型 +``` + +### 1.5 工具函数 (utils/) +``` +src/utils/ +├── deviceInfo.ts # 设备信息工具 +├── distributedLock.ts # 分布式锁工具 +├── formatFileSize.ts # 文件大小格式化 +├── formatRoute.ts # 路由格式化 +├── jwt.helper.ts # JWT工具函数 +├── mysql.ts # MySQL工具 +├── pagination.ts # 分页请求参数工厂函数工具 +├── randomChalk.ts # 随机颜色工具 +├── redis.ts # Redis工具 +├── responseFormate.ts # 响应统一格式化处理工具 +├── snowflake.ts # 雪花ID生成器 +└── text.ts # 文本处理工具 +``` + +### 1.6 常量定义 (constants/) +``` +src/constants/ +├── swaggerTags.ts # Swagger标签定义:所有模块的tag应该集中在此定义 +└── 其他常量 +``` +### 1.7 数据库实体 + +``` +src/eneities/ +├── index.ts # 实体总入口 +├── customType.ts # 自定义类型 +└── [table].ts # 数据表定义 +``` + +### 1.8 文件命名约定 +- 模块名使用 **单数形式**:`auth`、`user`、`product`、`order` +- 文件名格式:`[module].[type].ts` +- 导出名格式:`[module][类型名]` + +## 2. Schema(请求参数类型) + +**主要指请求参数验证工具,不包括响应** + +### 2.1 Schema定义规范 + +- 一个模块的所有schema都在一个文件中 +- 使用elysia自带的类型共据`t` +- 参数一定要明确是必填还是选填,是否有默认值 +- 对必要的数据进行转化,如用户名全小写并且去除两端空格 +- 必须有描述和示例参数 +- 导出类型 +- 注意已经存在的工具函数,比如分页有现成的简化工具,且能够统一请求格式 + +### 2.2 特别注意点 +**必须遵循的命名模式:** +- Request类型:`[动作][模块]Request` → `RegisterRequest` +- Schema名:`[动作][模块]Schema` → `RegisterSchema` + + +### 2.3 代码示例 + +```ts +/** + * @file 用户模块Schema定义 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 定义用户模块的Schema,包括获取当前用户信息、用户列表查询等 + */ + +import { t, type Static } from 'elysia'; +import { createQuerySchema } from '@/utils/pagination'; + +/** + * 用户列表查询参数Schema + * @description 用户列表查询的请求参数验证规则 + */ +export const UserListQuerySchema = createQuerySchema(t.Object({ + // 用户特有参数 + keyword: t.Optional(t.String({ + minLength: 1, + maxLength: 100, + description: '搜索关键词,支持用户名、邮箱模糊搜索', + examples: ['admin', 'test@example.com'] + })), + status: t.Optional(t.Union([ + t.Literal('active'), + t.Literal('inactive'), + t.Literal('pending') + ], { + description: '用户状态筛选', + examples: ['active', 'inactive', 'pending'] + })), + gender: t.Optional(t.Union([ + t.Literal(0), + t.Literal(1), + t.Literal(2), + t.Literal('0'), + t.Literal('1'), + t.Literal('2'), + ], { + description: '性别筛选:0-未知,1-男,2-女', + examples: [0, 1, 2] + })), + isRoot: t.Optional(t.Boolean({ + description: '是否超级管理员筛选', + examples: [true, false] + })) +})); + +/** 用户列表查询参数类型 */ +export type UserListQueryRequest = Static; +``` + +## 3. Response(响应数据类型) + +### 3.1 响应格式定义规范 + +- 使用统一的相应格式工具`responseWrapperSchema` +- 错误相应只提供示例和描述 +- 导出响应成功类型 + + +### 3.2 特别注意点 +**必须遵循的命名模式:** +- Response格式定义:`[动作][模块]Response` → `RegisterResponse` +- Response成功类型:`[动作][模块]SuccessType ` → `RegisterSuccessType ` + +### 3.3 代码示例 + +```ts +/** + * @file 用户模块响应格式定义 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 定义用户模块的响应格式,包括获取当前用户信息、用户列表查询等 + */ + +import { t, type Static } from 'elysia'; +import { responseWrapperSchema } from '@/utils/responseFormate'; +import { createPaginationResponseSchema } from '@/utils/pagination'; + + + +/** + * 用户列表项Schema + * @description 用户列表中单个用户的数据结构 + */ +export const UserListItemSchema = t.Object({ + /** 用户ID */ + id: t.String({ + description: '用户ID(bigint类型以字符串形式返回防止精度丢失)', + examples: ['1', '2', '3'] + }), + /** 用户名 */ + username: t.String({ + description: '用户名', + examples: ['admin', 'testuser'] + }), + + /** 更多字段... */ + + /** 更新时间 */ + updatedAt: t.String({ + description: '更新时间', + examples: ['2024-12-19T10:30:00Z'] + }) +}); + +/** + * 获取用户列表接口响应组合 + * @description 用于Controller中定义所有可能的响应格式 + */ +export const GetUserListResponsesSchema = { + 200: responseWrapperSchema(createPaginationResponseSchema(UserListItemSchema)), + 401: responseWrapperSchema(t.Object({ + error: t.String({ + description: '认证失败', + examples: ['未提供有效的认证令牌', '令牌已过期'] + }) + })), + 400: responseWrapperSchema(t.Object({ + error: t.String({ + description: '参数错误', + examples: ['分页参数无效', '搜索关键词格式错误'] + }) + })), + 500: responseWrapperSchema(t.Object({ + error: t.String({ + description: '服务器错误', + examples: ['内部服务器错误'] + }) + })) +}; + +/** 获取用户列表成功响应数据类型 */ +export type GetUserListSuccessType = Static; +``` + +## 4. Service(业务逻辑层) + +### 4.1 Service层要求 + +- ✅ 所有方法必须有完整的类型注解 +- ✅ 所有方法必须有详细的JSDoc注释 +- ✅ 必须使用统一的响应格式工具 +- ✅ 必须使用统一的错误码 +- ✅ 必须有详细的日志记录,接口有请求响应记录,无需记录每次请求 +- ✅ 需要有完整的错误处理,服务错误有拦截器处理可以不管,只判断逻辑上的错误 +- ✅ 导出单例实例供controller使用 + +### 4.2 注意点 + +- 开发逻辑时,注意数据库实体,必须严格按照数据库字段进行开发,不能出错 +- 更新时间数据库一般会自动天写,不用手动设置或更新 +- 数据库id一般为bigint,注意类型和精度问题 +- 在写入数据时,必要的增加分布式锁 +- 逻辑要清晰,代码要简洁 + +### 4.3 代码示例 + +```ts +/** + * @file 用户模块Service层实现 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 用户模块的业务逻辑实现,包括获取当前用户信息、用户列表查询等 + */ + +import { Logger } from '@/plugins/logger/logger.service'; +import { db } from '@/plugins/drizzle/drizzle.service'; +import { sysUsers } from '@/eneities'; +import { eq, like, and, desc, asc, sql } from 'drizzle-orm'; +import { successResponse, errorResponse, BusinessError } from '@/utils/responseFormate'; + +import { calculatePagination, normalizePaginationParams } from '@/utils/pagination'; +import type { GetCurrentUserSuccessType, GetUserListSuccessType } from './user.response'; +import type { UserListQueryRequest, UserListItem } from './user.schema'; + +/** + * 用户服务类 + * @description 处理用户相关的业务逻辑 + */ +export class UserService { + /** + * 获取当前用户信息 + * @param userId 用户ID + * @returns Promise + * @throws BusinessError 业务逻辑错误 + * @type API ===================================================================== + */ + public async getCurrentUser(userId: string): Promise { + Logger.info(`获取用户信息:${userId}`); + // 查询用户信息 + const user = await db() + .select({ + id: sysUsers.id, + username: sysUsers.username, + email: sysUsers.email, + nickname: sysUsers.nickname, + avatar: sysUsers.avatar, + mobile: sysUsers.mobile, + status: sysUsers.status, + lastLoginAt: sysUsers.lastLoginAt, + createdAt: sysUsers.createdAt, + updatedAt: sysUsers.updatedAt + }) + .from(sysUsers) + .where(eq(sysUsers.id, BigInt(userId))) + .limit(1); + + if (!user || user.length === 0) { + Logger.warn(`用户不存在:${userId}`); + throw new BusinessError( + `用户不存在:${userId}`, + 404 + ); + } + + const userData = user[0]!; + + Logger.info(`获取用户信息成功:${userId} - ${userData.username}`); + + return successResponse({ + id: userId, // 使用传入的字符串ID,避免精度丢失 + username: userData.username, + email: userData.email, + nickname: userData.nickname, + avatar: userData.avatar, + phone: userData.mobile, + status: userData.status, + lastLoginAt: userData.lastLoginAt || null, + createdAt: userData.createdAt, + updatedAt: userData.updatedAt + }, '获取用户信息成功'); + } + +} + +// 导出单例实例 +export const userService = new UserService(); +``` + +## 5. Controllers(接口名称接入) + +### 5.1 Controllers层要求 + +- ✅ 路由方法必须有完整的JSDoc注释 +- ✅ 必须定义完整的response schema +- ✅ 必须有适当的tags分类 +- ✅ 必须有operationId用于API文档 +- ✅ 错误处理由Service层统一处理 + +### 5.2 Controllers层注意点 + +- 使用service时要简洁,如`({ body }) => authService.register(body),` + +### 5.3 Controllers层代码示例 + +```ts +/** + * 认证控制器 + * @description 处理用户认证相关的HTTP请求 + */ +export const authController = new Elysia() + /** + * 用户注册接口 + * @route POST /api/auth/register + * @description 用户注册,包含验证码验证、用户名邮箱唯一性检查等 + */ + .post( + '/register', + ({ body }) => authService.register(body), + { + body: RegisterSchema, + detail: { + summary: '用户注册', + description: '用户注册接口,需要提供用户名、邮箱、密码和验证码', + tags: [tags.auth], + operationId: 'registerUser', + }, + response: RegisterResponsesSchema, + } + ); +``` +## 6. 错误处理 + +### 6.1 错误处理规范 + +- 统一`import { BusinessError } from '@/utils/responseFormate';`引入错误工具抛出错误 +- 错误处理在errorHandle.plugins中统一处理, + +### 6.2 主动抛出异常示例 + +```typescript +// ✅ Service层错误处理 +import { BusinessError } from '@/utils/responseFormate'; + +// 抛出业务错误 +throw new BusinessError('消息说明...', 409); +``` +## 7. 测试用例文档 + +1. 分模块 +2. 分接口 +3. 测试名称 +4. 场景 +5. 方法 \ No newline at end of file diff --git a/bun.lock b/bun.lock index e3d67da..df96b3b 100644 --- a/bun.lock +++ b/bun.lock @@ -5,28 +5,24 @@ "name": "cursor-init", "dependencies": { "@elysiajs/swagger": "^1.3.0", - "@types/ua-parser-js": "^0.7.39", "bcrypt": "^6.0.0", "canvas": "^3.1.2", "chalk": "^5.4.1", "drizzle-orm": "^0.44.2", "jsonwebtoken": "^9.0.2", "mysql2": "^3.14.1", - "nanoid": "^5.1.5", "nodemailer": "^7.0.4", - "picocolors": "^1.1.1", "redis": "^5.5.6", "ua-parser-js": "^2.0.4", - "undici": "^7.11.0", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", }, "devDependencies": { "@types/bcrypt": "^5.0.2", "@types/bun": "^1.0.25", - "@types/jsonwebtoken": "^9.0.10", "@types/nodemailer": "^6.4.17", "@types/redis": "^4.0.11", + "@types/ua-parser-js": "^0.7.39", "@types/winston": "^2.4.4", "@typescript-eslint/eslint-plugin": "^8.35.0", "@typescript-eslint/parser": "^8.35.0", @@ -210,10 +206,6 @@ "@types/json-schema": ["@types/json-schema@7.0.15", "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - "@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.10", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA=="], - - "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@24.0.4", "https://registry.npmmirror.com/@types/node/-/node-24.0.4.tgz", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="], "@types/node-fetch": ["@types/node-fetch@2.6.12", "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.12.tgz", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA=="], @@ -590,7 +582,7 @@ "named-placeholders": ["named-placeholders@1.1.3", "https://registry.npmmirror.com/named-placeholders/-/named-placeholders-1.1.3.tgz", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="], - "nanoid": ["nanoid@5.1.5", "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.5.tgz", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="], + "nanoid": ["nanoid@3.3.11", "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], @@ -752,8 +744,6 @@ "uint8array-extras": ["uint8array-extras@1.4.0", "https://registry.npmmirror.com/uint8array-extras/-/uint8array-extras-1.4.0.tgz", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="], - "undici": ["undici@7.11.0", "https://registry.npmmirror.com/undici/-/undici-7.11.0.tgz", {}, "sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg=="], - "undici-types": ["undici-types@7.8.0", "https://registry.npmmirror.com/undici-types/-/undici-types-7.8.0.tgz", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], "uri-js": ["uri-js@4.4.1", "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -818,8 +808,6 @@ "micromatch/picomatch": ["picomatch@2.3.1", "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "postcss/nanoid": ["nanoid@3.3.11", "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], @@ -868,6 +856,8 @@ "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.2.0", "https://registry.npmmirror.com/@scalar/openapi-types/-/openapi-types-0.2.0.tgz", { "dependencies": { "zod": "^3.23.8" } }, "sha512-waiKk12cRCqyUCWTOX0K1WEVX46+hVUK+zRPzAahDJ7G0TApvbNkuy5wx7aoUyEk++HHde0XuQnshXnt8jsddA=="], + "@scalar/themes/@scalar/types/nanoid": ["nanoid@5.1.5", "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.5.tgz", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="], + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "color/color-convert/color-name": ["color-name@1.1.3", "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], diff --git a/docs/elysiaAPI开发流程.md b/docs/elysiaAPI开发流程.md new file mode 100644 index 0000000..3c7ff5f --- /dev/null +++ b/docs/elysiaAPI开发流程.md @@ -0,0 +1,503 @@ +# ElysiaAPI开发流程 + +## 0. 概览 + +这是一个基于 **Bun + Elysia** 的现代化后端API项目,采用TypeScript开发,集成了MySQL、Redis、JWT认证、Swagger文档等功能。 + +- **运行时**:Bun +- **框架**:Elysia +- **语言**:TypeScript +- **数据库**:MySQL + Drizzle ORM +- **缓存**:Redis +- **认证**:JWT +- **测试**:Vitest +- **文档**:Swagger +- **日志**:Winston +- **代码规范**:ESLint + Prettier + +使用的技术和库 + +- **数据库**:`"mysql2": "^3.14.1"`, `"drizzle-orm": "^0.44.2"` +- **token验证**:`"jsonwebtoken": "^9.0.2"` +- **密码加密**:`"bcrypt": "^6.0.0"` + +## 1. 相关目录结构和描述 + +### 1.0 整体目录结构 + +``` +project/ +├── 📋 配置文件(config/) +├── 📁 源代码 (src/) +├───└───config +├───├───eneities +├───├───modules +│ ├───├───auth +│ ├───├───captcha +│ ├───├───health +│ ├───├───test +│ ├───└───user +├───├───plugins +│ ├───├───drizzle +│ ├───├───email +│ ├───├───errorHandle +│ ├───├───jwt +│ ├───├───logger +│ ├───├───redis +│ ├───└───swagger +├───└───tests +│ └───demo +├───type +├───utils +├── 📁 文档 (docs/) +├── 📁 需求文档 (prd/) +├── 📁 任务管理 (tasks/) +├── 📁 AI对话记录 (aiChat/) +├── 📁 数据库迁移 (drizzle/) +└── 📁 静态资源 (public/) +| 文件 | 说明 | +|------|------| +| `package.json` | 项目依赖和脚本配置 | +| `tsconfig.json` | TypeScript编译配置 | +| `tsconfig.test.json` | 测试环境TypeScript配置 | +| `vitest.config.ts` | Vitest测试框架配置 | +| `eslint.config.js` | ESLint代码规范配置 | +| `bunfig.toml` | Bun运行时配置 | +| `drizzle.config.ts` | Drizzle ORM配置 | +| `README.md` | 项目说明文档 | +``` + +### 1.1 接口目录结构 + +``` +src/modules/ +├── index.ts # API总入口:所有的模块文件都由此导出给主程序 +├── [moduleName]/ # 模块目录:每个模块的名称做目录名 +│ ├── [moduleName].docs.md # 接口逻辑规则 +│ ├── [moduleName].schema.ts # Schema定义 +│ ├── [moduleName].response.ts # 响应格式 +│ ├── [moduleName].service.ts # 业务逻辑 +│ ├── [moduleName].controller.ts # 路由控制器 +│ └── [moduleName].test.doc # 测试用例文档 +``` + +### 1.2 接口目录功能 + +- 每个模块目录下的文件,都需要有对应的功能,不能只有docs.md,其他文件缺一不可 +- [moduleName].docs.md:需要包含接口开发的业务逻辑,包括schema的注意点,response格式的注意点,接口的业务流程,分析相关的数据库,性能问题,安全问题等等需要考虑的地方和注意点 +- [moduleName].schema.ts:定义接口的输入参数,包括参数的类型、参数的必填、参数的默认值、参数的描述、参数的示例 +- [moduleName].response.ts:接口返回数据的格式定义文件 +- [moduleName].service.ts:接口的具体业务逻辑方法 +- [moduleName].controller.ts:接口路由定义文件,在这里组合接口的请求方式、参数类型、响应格式 + +### 1.3 插件目录结构 + +``` +src/plugins/ +├── index.ts # 插件总入口 +├── drizzle/ # 数据库ORM插件 +│ ├── drizzle.plugins.ts +│ ├── drizzle.service.ts +│ └── README.md +├── email/ # 邮件插件 +│ ├── email.plugins.ts +│ ├── email.service.ts +│ └── README.md +├── errorHandle/ # 错误处理插件 +│ └── errorHandler.plugins.ts +├── jwt/ # JWT认证插件 +│ ├── jwt.plugins.ts +│ └── jwt.service.ts +├── logger/ # 日志插件 +│ ├── logger.plugins.ts +│ └── logger.service.ts +├── redis/ # Redis插件 +│ ├── redis.plugins.ts +│ └── redis.service.ts +└── swagger/ # API文档插件 + └── swagger.plugins.ts +``` + +### 1.4 类型定义 (type/) +``` +src/type/ +├── config.type.ts # 配置相关类型 +├── drizzle.type.ts # 数据库相关类型 +├── error.type.ts # 错误相关类型 +├── jwt.type.ts # JWT相关类型 +├── logger.type.ts # 日志相关类型 +├── redis.type.ts # Redis相关类型 +└── email.type.ts # 邮件相关类型 +``` + +### 1.5 工具函数 (utils/) +``` +src/utils/ +├── deviceInfo.ts # 设备信息工具 +├── distributedLock.ts # 分布式锁工具 +├── formatFileSize.ts # 文件大小格式化 +├── formatRoute.ts # 路由格式化 +├── jwt.helper.ts # JWT工具函数 +├── mysql.ts # MySQL工具 +├── pagination.ts # 分页请求参数工厂函数工具 +├── randomChalk.ts # 随机颜色工具 +├── redis.ts # Redis工具 +├── responseFormate.ts # 响应统一格式化处理工具 +├── snowflake.ts # 雪花ID生成器 +└── text.ts # 文本处理工具 +``` + +### 1.6 常量定义 (constants/) +``` +src/constants/ +├── swaggerTags.ts # Swagger标签定义:所有模块的tag应该集中在此定义 +└── 其他常量 +``` +### 1.7 数据库实体 + +``` +src/eneities/ +├── index.ts # 实体总入口 +├── customType.ts # 自定义类型 +└── [table].ts # 数据表定义 +``` + +### 1.8 文件命名约定 +- 模块名使用 **单数形式**:`auth`、`user`、`product`、`order` +- 文件名格式:`[module].[type].ts` +- 导出名格式:`[module][类型名]` + +## 2. Schema(请求参数类型) + +**主要指请求参数验证工具,不包括响应** + +### 2.1 Schema定义规范 + +- 一个模块的所有schema都在一个文件中 +- 使用elysia自带的类型共据`t` +- 参数一定要明确是必填还是选填,是否有默认值 +- 对必要的数据进行转化,如用户名全小写并且去除两端空格 +- 必须有描述和示例参数 +- 导出类型 +- 注意已经存在的工具函数,比如分页有现成的简化工具,且能够统一请求格式 + +### 2.2 特别注意点 +**必须遵循的命名模式:** +- Request类型:`[动作][模块]Request` → `RegisterRequest` +- Schema名:`[动作][模块]Schema` → `RegisterSchema` + + +### 2.3 代码示例 + +```ts +/** + * @file 用户模块Schema定义 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 定义用户模块的Schema,包括获取当前用户信息、用户列表查询等 + */ + +import { t, type Static } from 'elysia'; +import { createQuerySchema } from '@/utils/pagination'; + +/** + * 用户列表查询参数Schema + * @description 用户列表查询的请求参数验证规则 + */ +export const UserListQuerySchema = createQuerySchema(t.Object({ + // 用户特有参数 + keyword: t.Optional(t.String({ + minLength: 1, + maxLength: 100, + description: '搜索关键词,支持用户名、邮箱模糊搜索', + examples: ['admin', 'test@example.com'] + })), + status: t.Optional(t.Union([ + t.Literal('active'), + t.Literal('inactive'), + t.Literal('pending') + ], { + description: '用户状态筛选', + examples: ['active', 'inactive', 'pending'] + })), + gender: t.Optional(t.Union([ + t.Literal(0), + t.Literal(1), + t.Literal(2), + t.Literal('0'), + t.Literal('1'), + t.Literal('2'), + ], { + description: '性别筛选:0-未知,1-男,2-女', + examples: [0, 1, 2] + })), + isRoot: t.Optional(t.Boolean({ + description: '是否超级管理员筛选', + examples: [true, false] + })) +})); + +/** 用户列表查询参数类型 */ +export type UserListQueryRequest = Static; +``` + +## 3. Response(响应数据类型) + +### 3.1 响应格式定义规范 + +- 使用统一的相应格式工具`responseWrapperSchema` +- 错误相应只提供示例和描述 +- 导出响应成功类型 + + +### 3.2 特别注意点 +**必须遵循的命名模式:** +- Response格式定义:`[动作][模块]Response` → `RegisterResponse` +- Response成功类型:`[动作][模块]SuccessType ` → `RegisterSuccessType ` + +### 3.3 代码示例 + +```ts +/** + * @file 用户模块响应格式定义 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 定义用户模块的响应格式,包括获取当前用户信息、用户列表查询等 + */ + +import { t, type Static } from 'elysia'; +import { responseWrapperSchema } from '@/utils/responseFormate'; +import { createPaginationResponseSchema } from '@/utils/pagination'; + + + +/** + * 用户列表项Schema + * @description 用户列表中单个用户的数据结构 + */ +export const UserListItemSchema = t.Object({ + /** 用户ID */ + id: t.String({ + description: '用户ID(bigint类型以字符串形式返回防止精度丢失)', + examples: ['1', '2', '3'] + }), + /** 用户名 */ + username: t.String({ + description: '用户名', + examples: ['admin', 'testuser'] + }), + + /** 更多字段... */ + + /** 更新时间 */ + updatedAt: t.String({ + description: '更新时间', + examples: ['2024-12-19T10:30:00Z'] + }) +}); + +/** + * 获取用户列表接口响应组合 + * @description 用于Controller中定义所有可能的响应格式 + */ +export const GetUserListResponsesSchema = { + 200: responseWrapperSchema(createPaginationResponseSchema(UserListItemSchema)), + 401: responseWrapperSchema(t.Object({ + error: t.String({ + description: '认证失败', + examples: ['未提供有效的认证令牌', '令牌已过期'] + }) + })), + 400: responseWrapperSchema(t.Object({ + error: t.String({ + description: '参数错误', + examples: ['分页参数无效', '搜索关键词格式错误'] + }) + })), + 500: responseWrapperSchema(t.Object({ + error: t.String({ + description: '服务器错误', + examples: ['内部服务器错误'] + }) + })) +}; + +/** 获取用户列表成功响应数据类型 */ +export type GetUserListSuccessType = Static; +``` + +## 4. Service(业务逻辑层) + +### 4.1 Service层要求 + +- ✅ 所有方法必须有完整的类型注解 +- ✅ 所有方法必须有详细的JSDoc注释 +- ✅ 必须使用统一的响应格式工具 +- ✅ 必须使用统一的错误码 +- ✅ 必须有详细的日志记录,接口有请求响应记录,无需记录每次请求 +- ✅ 需要有完整的错误处理,服务错误有拦截器处理可以不管,只判断逻辑上的错误 +- ✅ 导出单例实例供controller使用 + +### 4.2 注意点 + +- 开发逻辑时,注意数据库实体,必须严格按照数据库字段进行开发,不能出错 +- 更新时间数据库一般会自动天写,不用手动设置或更新 +- 数据库id一般为bigint,注意类型和精度问题 +- 在写入数据时,必要的增加分布式锁 +- 逻辑要清晰,代码要简洁 + +### 4.3 代码示例 + +```ts +/** + * @file 用户模块Service层实现 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-01-07 + * @description 用户模块的业务逻辑实现,包括获取当前用户信息、用户列表查询等 + */ + +import { Logger } from '@/plugins/logger/logger.service'; +import { db } from '@/plugins/drizzle/drizzle.service'; +import { sysUsers } from '@/eneities'; +import { eq, like, and, desc, asc, sql } from 'drizzle-orm'; +import { successResponse, errorResponse, BusinessError } from '@/utils/responseFormate'; + +import { calculatePagination, normalizePaginationParams } from '@/utils/pagination'; +import type { GetCurrentUserSuccessType, GetUserListSuccessType } from './user.response'; +import type { UserListQueryRequest, UserListItem } from './user.schema'; + +/** + * 用户服务类 + * @description 处理用户相关的业务逻辑 + */ +export class UserService { + /** + * 获取当前用户信息 + * @param userId 用户ID + * @returns Promise + * @throws BusinessError 业务逻辑错误 + * @type API ===================================================================== + */ + public async getCurrentUser(userId: string): Promise { + Logger.info(`获取用户信息:${userId}`); + // 查询用户信息 + const user = await db() + .select({ + id: sysUsers.id, + username: sysUsers.username, + email: sysUsers.email, + nickname: sysUsers.nickname, + avatar: sysUsers.avatar, + mobile: sysUsers.mobile, + status: sysUsers.status, + lastLoginAt: sysUsers.lastLoginAt, + createdAt: sysUsers.createdAt, + updatedAt: sysUsers.updatedAt + }) + .from(sysUsers) + .where(eq(sysUsers.id, BigInt(userId))) + .limit(1); + + if (!user || user.length === 0) { + Logger.warn(`用户不存在:${userId}`); + throw new BusinessError( + `用户不存在:${userId}`, + 404 + ); + } + + const userData = user[0]!; + + Logger.info(`获取用户信息成功:${userId} - ${userData.username}`); + + return successResponse({ + id: userId, // 使用传入的字符串ID,避免精度丢失 + username: userData.username, + email: userData.email, + nickname: userData.nickname, + avatar: userData.avatar, + phone: userData.mobile, + status: userData.status, + lastLoginAt: userData.lastLoginAt || null, + createdAt: userData.createdAt, + updatedAt: userData.updatedAt + }, '获取用户信息成功'); + } + +} + +// 导出单例实例 +export const userService = new UserService(); +``` + +## 5. Controllers(接口名称接入) + +### 5.1 Controllers层要求 + +- ✅ 路由方法必须有完整的JSDoc注释 +- ✅ 必须定义完整的response schema +- ✅ 必须有适当的tags分类 +- ✅ 必须有operationId用于API文档 +- ✅ 错误处理由Service层统一处理 + +### 5.2 Controllers层注意点 + +- 使用service时要简洁,如`({ body }) => authService.register(body),` + +### 5.3 Controllers层代码示例 + +```ts +/** + * 认证控制器 + * @description 处理用户认证相关的HTTP请求 + */ +export const authController = new Elysia() + /** + * 用户注册接口 + * @route POST /api/auth/register + * @description 用户注册,包含验证码验证、用户名邮箱唯一性检查等 + */ + .post( + '/register', + ({ body }) => authService.register(body), + { + body: RegisterSchema, + detail: { + summary: '用户注册', + description: '用户注册接口,需要提供用户名、邮箱、密码和验证码', + tags: [tags.auth], + operationId: 'registerUser', + }, + response: RegisterResponsesSchema, + } + ); +``` +## 6. 错误处理 + +### 6.1 错误处理规范 + +- 统一`import { BusinessError } from '@/utils/responseFormate';`引入错误工具抛出错误 +- 错误处理在errorHandle.plugins中统一处理, + +### 6.2 主动抛出异常示例 + +```typescript +// ✅ Service层错误处理 +import { BusinessError } from '@/utils/responseFormate'; + +// 抛出业务错误 +throw new BusinessError('消息说明...', 409); +``` +## 7. 测试用例文档 + +1. 分模块 +2. 分接口 +3. 测试名称 +4. 场景 +5. 方法 \ No newline at end of file diff --git a/package.json b/package.json index d602f1b..317e137 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/bun": "^1.0.25", "@types/nodemailer": "^6.4.17", "@types/redis": "^4.0.11", + "@types/ua-parser-js": "^0.7.39", "@types/winston": "^2.4.4", "@typescript-eslint/eslint-plugin": "^8.35.0", "@typescript-eslint/parser": "^8.35.0", @@ -29,21 +30,16 @@ "vitest": "^3.2.4" }, "dependencies": { - "@elysiajs/jwt": "^1.3.1", "@elysiajs/swagger": "^1.3.0", - "@types/ua-parser-js": "^0.7.39", "bcrypt": "^6.0.0", "canvas": "^3.1.2", "chalk": "^5.4.1", "drizzle-orm": "^0.44.2", "jsonwebtoken": "^9.0.2", "mysql2": "^3.14.1", - "nanoid": "^5.1.5", "nodemailer": "^7.0.4", - "picocolors": "^1.1.1", "redis": "^5.5.6", "ua-parser-js": "^2.0.4", - "undici": "^7.11.0", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" }, diff --git a/src/utils/schema.ts b/src/utils/schema.ts deleted file mode 100644 index 0519ecb..0000000 --- a/src/utils/schema.ts +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/tasks/M2-基础用户系统-开发任务计划.md b/tasks/M2-基础用户系统-开发任务计划.md index 8270ed4..41a33d2 100644 --- a/tasks/M2-基础用户系统-开发任务计划.md +++ b/tasks/M2-基础用户系统-开发任务计划.md @@ -141,7 +141,7 @@ - [x] 10.5 扩展user.test.md - 编写用户列表测试用例文档 - [ ] 11.0 POST /users - 创建用户接口 - - [ ] Before 整理输入此接口的逻辑,必须等待用户确认后进行,需要输入go才能进行下一步 + - [ ] 0.0 整理输入此接口的逻辑,必须等待用户确认后进行,需要输入go才能进行下一步 - [ ] 11.1 扩展user.schema.ts - 定义创建用户Schema - [ ] 11.2 扩展user.response.ts - 定义创建用户响应格式 - [ ] 11.3 扩展user.service.ts - 实现创建用户业务逻辑