From 9f112c2ebc865dc2ddaec63168661bb792b85c97 Mon Sep 17 00:00:00 2001 From: expressgy Date: Sun, 6 Jul 2025 16:28:07 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0rules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/elysia-rules.mdc | 1075 ++++++++++++++++--------- src/constants/error-codes.ts | 188 ----- tasks/M2-基础用户系统-开发任务计划.md | 4 +- 3 files changed, 707 insertions(+), 560 deletions(-) delete mode 100644 src/constants/error-codes.ts diff --git a/.cursor/rules/elysia-rules.mdc b/.cursor/rules/elysia-rules.mdc index 17cdb71..9d577ea 100644 --- a/.cursor/rules/elysia-rules.mdc +++ b/.cursor/rules/elysia-rules.mdc @@ -22,7 +22,7 @@ alwaysApply: true - **日志**:Winston - **代码规范**:ESLint + Prettier -- 📂 根目录结构 +### 📂 根目录结构 ``` project/ @@ -32,10 +32,11 @@ project/ ├── 📁 需求文档 (prd/) ├── 📁 任务管理 (tasks/) ├── 📁 AI对话记录 (aiChat/) +├── 📁 数据库迁移 (drizzle/) └── 📁 静态资源 (public/) ``` -- 🔧 配置文件 +### 🔧 配置文件 | 文件 | 说明 | |------|------| @@ -45,63 +46,70 @@ project/ | `vitest.config.ts` | Vitest测试框架配置 | | `eslint.config.js` | ESLint代码规范配置 | | `bunfig.toml` | Bun运行时配置 | -| `bun.lock` | Bun依赖锁定文件 | +| `drizzle.config.ts` | Drizzle ORM配置 | | `README.md` | 项目说明文档 | -- 应用入口 +### 应用入口 ``` src/ ├── app.ts # Elysia应用主入口 └── server.ts # 服务器启动文件 ``` -- 配置管理 (config/) +### 配置管理 (config/) ``` src/config/ ├── index.ts # 配置总入口 ├── db.config.ts # 数据库配置 ├── redis.config.ts # Redis配置 ├── jwt.config.ts # JWT配置 -└── logger.config.ts # 日志配置 +├── logger.config.ts # 日志配置 +└── email.config.ts # 邮件配置 ``` -- 数据实体 (eneities/) +### 数据实体 (eneities/) ``` src/eneities/ ├── index.ts # 实体总入口 -└── users.ts # 用户实体定义 +├── customType.ts # 自定义类型 +└── [table].ts # 数据表定义 ``` -- 业务模块 (modules/) +### 业务模块 (modules/) ``` src/modules/ ├── index.ts # 模块总入口 ├── tags.ts # Swagger标签定义 -├── example/ # 示例模块 -│ ├── example.schema.ts # Schema定义 -│ ├── example.response.ts # 响应格式 -│ ├── example.service.ts # 业务逻辑 -│ ├── example.controller.ts # 路由控制器 -│ └── example.test.ts # 测试用例 -│ └── example.testDocs.ts # 测试用例文档 +├── 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 -├── user/ # 用户模块 -│ └── user.controller.ts └── test/ # 测试模块 └── test.controller.ts ``` -- 插件系统 (plugins/) +### 插件系统 (plugins/) ``` src/plugins/ ├── index.ts # 插件总入口 ├── drizzle/ # 数据库ORM插件 -│ ├── drizzle.config.ts │ ├── drizzle.plugins.ts │ ├── drizzle.service.ts │ └── README.md +├── email/ # 邮件插件 +│ ├── email.plugins.ts +│ ├── email.service.ts +│ └── README.md ├── errorHandle/ # 错误处理插件 │ └── errorHandler.plugins.ts ├── jwt/ # JWT认证插件 @@ -117,7 +125,7 @@ src/plugins/ └── swagger.plugins.ts ``` -- 类型定义 (type/) +### 类型定义 (type/) ``` src/type/ ├── config.type.ts # 配置相关类型 @@ -125,317 +133,660 @@ src/type/ ├── error.type.ts # 错误相关类型 ├── jwt.type.ts # JWT相关类型 ├── logger.type.ts # 日志相关类型 -└── redis.type.ts # Redis相关类型 +├── redis.type.ts # Redis相关类型 +└── email.type.ts # 邮件相关类型 ``` -- 工具函数 (utils/) +### 工具函数 (utils/) ``` src/utils/ -├── deviceInfo.ts # 设备信息工具 -├── formatFileSize.ts # 文件大小格式化 -├── formatRoute.ts # 路由格式化 -├── jwt.helper.ts # JWT工具函数 -├── mysql.ts # MySQL工具 -├── randomChalk.ts # 随机颜色工具 -├── redis.ts # Redis工具 -├── text.ts # 文本处理工具 -└── response.helper.ts # 响应格式工具 (新增) +├── deviceInfo.ts # 设备信息工具 +├── formatFileSize.ts # 文件大小格式化 +├── formatRoute.ts # 路由格式化 +├── jwt.helper.ts # JWT工具函数 +├── mysql.ts # MySQL工具 +├── randomChalk.ts # 随机颜色工具 +├── redis.ts # Redis工具 +├── text.ts # 文本处理工具 +├── responseFormate.ts # 响应格式化工具 +└── snowflake.ts # 雪花ID生成器 ``` -- 测试文件 (tests/) +### 测试文件 (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 # 日志测试演示 + ├── testLogger.ts # 日志测试演示 + └── emailDemo.ts # 邮件测试演示 ``` -- 常量定义 (constants/) +### 常量定义 (constants/) ``` src/constants/ -└── error-codes.ts # 统一错误码定义 (新增) ``` - ## 1. 文件组织规范 ### 1.1 必须的文件结构 -每个业务模块必须包含以下5个文件,**按照固定顺序**: +每个业务模块必须包含以下文件,**按照固定顺序**: ``` src/modules/[module]/ -├── [module].schema.ts # 1️⃣ 数据结构定义(优先级最高) +├── [module].schema.ts # 1️⃣ 数据结构定义(最高优先级) ├── [module].response.ts # 2️⃣ 响应格式定义 ├── [module].service.ts # 3️⃣ 业务逻辑实现 ├── [module].controller.ts # 4️⃣ 路由控制器 └── [module].test.ts # 5️⃣ 测试用例 -└── [module].testDoc.ts # 5️⃣ 测试用例文档 +└── [module].test.md # 5️⃣ 测试用例文档 ``` ### 1.2 文件命名约定 -- 模块名使用 **单数形式**:`user`、`product`、`order`(不是 users、products) -- 文件名格式:`[模块名].[类型].ts` -- 导出名格式:`[模块名][类型名]` +- 模块名使用 **单数形式**:`auth`、`user`、`product`、`order` +- 文件名格式:`[module].[type].ts` +- 导出名格式:`[module][类型名]` -## 2. Schema & 类型系统(🔥 重点) +## 2. Schema & 类型系统(🔥 重点优化) ### 2.1 Schema定义规范 ```typescript -// ✅ 正确示例 - user.schema.ts +/** + * @file 认证模块Schema定义 + * @author AI Assistant + * @date 2024-12-19 + * @lastEditor AI Assistant + * @lastEditTime 2025-07-06 + * @description 定义认证模块的Schema,包括用户注册、邮箱激活等 + */ + import { t, type Static } from 'elysia'; -// 1. 定义Schema(运行时验证) -export const CreateUserSchema = t.Object({ - username: t.String({ - minLength: 2, +/** + * 用户注册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: ['admin', 'testuser'] + examples: ['root', 'testuser'] }), - email: t.String({ + /** 邮箱地址,对应sys_users.email */ + email: t.String({ format: 'email', - description: '用户邮箱', - examples: ['user@example.com'] + maxLength: 100, + description: '邮箱地址', + examples: ['x71291@outlook.com'] }), - password: t.String({ + /** 密码,6-50字符 */ + password: t.String({ minLength: 6, - description: '密码,至少6位', - examples: ['123456'] + 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'] + }) }); -// 2. 导出TypeScript类型(编译时类型检查) -export type CreateUserRequest = Static; - -// 3. 数据模型Schema -export const UserSchema = t.Object({ - id: t.Number({ description: '用户ID' }), - username: t.String({ description: '用户名' }), - email: t.String({ description: '邮箱' }), - createdAt: t.String({ description: '创建时间' }), - updatedAt: t.String({ description: '更新时间' }), +/** + * 邮箱激活Schema + * @description 邮箱激活请求参数验证规则 + */ +export const ActivateSchema = t.Object({ + /** 激活令牌,JWT格式 */ + token: t.String({ + minLength: 10, + maxLength: 1000, + description: '邮箱激活令牌,JWT格式,24小时有效', + examples: ['eyJhbGciOiJIUzI1NiI'] + }) }); -export type User = Static; +/** + * 用户登录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 类型导出规范 **必须遵循的命名模式:** -- Request类型:`[动作][模块]Request` → `CreateUserRequest` -- Response类型:`[动作][模块]Response` → `GetUserResponse` -- 数据模型:`[模块]` → `User`、`Product` -- Schema名:`[动作][模块]Schema` → `CreateUserSchema` +- Request类型:`[动作][模块]Request` → `RegisterRequest` +- Response类型:`[动作][模块]Response` → `RegisterResponse` +- Schema名:`[动作][模块]Schema` → `RegisterSchema` +- 数据模型:`[模块]Data` → `UserData` -## 3. Response定义规范 - -### 3.1 统一响应格式 +### 2.3 Schema定义最佳实践 ```typescript -// ✅ 正确示例 - user.response.ts -import { t, type Static } from 'elysia'; -import { globalResponseWrapperSchema } from '@/validators/global.response'; -import { UserSchema } from './user.schema'; - -// 成功响应 -export const GetUserSuccessResponseSchema = globalResponseWrapperSchema(UserSchema); -export type GetUserSuccessResponse = Static; - -// 错误响应 -export const UserNotFoundResponseSchema = t.Object({ - code: t.Literal('USER_NOT_FOUND'), - message: t.String({ examples: ['用户不存在'] }), - data: t.Null(), -}); -export type UserNotFoundResponse = Static; - -// 组合响应(供controller使用) -export const GetUserResponses = { - 200: GetUserSuccessResponseSchema, - 404: UserNotFoundResponseSchema, - 401: t.Object({ - code: t.Literal('UNAUTHORIZED'), - message: t.String(), - data: t.Null(), +// ✅ 完整的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']] + })) +}); ``` -## 4. Service层规范 +## 3. 响应格式规范(🔥 重点优化) + +### 3.1 统一响应格式工具 + +```typescript +// ✅ 使用 responseFormate.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'; + +// ========== 邮箱注册相关响应格式 ========== + +/** + * 用户注册接口响应组合 + * @description 用于Controller中定义所有可能的响应格式 + */ +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 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] + }) + })), +}; + +/** 邮箱激活成功响应数据类型 */ +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] + }) + }) + })), +}; + +/** 用户登录成功响应数据类型 */ +export type LoginSuccessType = Static; +``` + +### 3.2 Response定义规范 + +```typescript +// ✅ 优化示例 - auth.response.ts +/** + * @file 认证模块响应格式定义 + * @author 开发者姓名 + * @date 2024-12-19 + * @description 定义认证模块的响应格式,包括成功和错误响应 + */ + +import { t, type Static } from 'elysia'; +import { responseWrapperSchema } from '@/utils/responseFormate'; + +/** + * 用户注册接口响应组合 + * @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'] + }) + })), + 400: responseWrapperSchema(t.Object({ + error: t.String({ + description: '错误信息', + examples: ['用户名已存在', '邮箱已被注册'] + }) + })), + 500: responseWrapperSchema(t.Object({ + error: t.String({ + description: '服务器错误', + examples: ['内部服务器错误'] + }) + })) +}; +// 注意,不需要定义错误响应的具体格式,只用给出可能错误的情况的说明和示例即可,一下就是正确的错误示例 +` +500: responseWrapperSchema(t.Object({ + error: t.String({ + description: '服务器错误', + examples: ['内部服务器错误'] + }) + })) +` +/** 用户注册成功响应数据类型 */ +export type RegisterSuccessResponse = Static; +``` + +## 4. Service层规范(🔥 重点优化) ### 4.1 Service类定义 ```typescript -// ✅ 正确示例 - user.service.ts -import type { CreateUserRequest, User } from './user.schema'; -import type { GetUserSuccessResponse, UserNotFoundResponse } from './user.response'; +// ✅ 优化示例 - 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'; -export class UserService { +/** + * 认证服务类 + * @description 处理用户注册、登录等认证相关业务逻辑 + */ +export class AuthService { /** - * 创建用户 - * @param request 创建用户请求参数 - * @returns Promise + * 用户注册 + * @param request 用户注册请求参数 + * @returns Promise + * @throws BusinessError 业务逻辑错误 + * @type API ===================================================================== */ - async createUser(request: CreateUserRequest): Promise { - try { - Logger.info(`创建用户请求:${JSON.stringify(request)}`); - - // 业务逻辑实现 - const user: User = { - id: 1, - username: request.username, - email: request.email, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }; - - // 进行数据库操作逻辑... + 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 + }, '用户注册成功,请查收激活邮件'); - Logger.info(`用户创建成功:${user.id}`); - - return { - code: ERROR_CODES.SUCCESS, - message: '用户创建成功', - data: user, - }; } catch (error) { - Logger.error(new Error(`创建用户失败:${error}`)); - throw error; + Logger.error(new Error(`用户注册失败:${error}`)); + + if (error instanceof BusinessError) { + throw error; + } + + throw new BusinessError( + ERROR_CODES.INTERNAL_ERROR, + 500 + ); } } /** - * 根据ID查询用户 - * @param id 用户ID - * @returns Promise + * 验证验证码 + * @param captcha 验证码 + * @param captchaId 验证码ID + * @throws BusinessError 验证失败时抛出 */ - async getUserById(id: number): Promise { - // 实现逻辑... + 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 userService = new UserService(); +export const authService = new AuthService(); ``` ### 4.2 Service层要求 - ✅ 所有方法必须有完整的类型注解 -- ✅ 所有方法必须有JSDoc注释 +- ✅ 所有方法必须有详细的JSDoc注释 +- ✅ 必须使用统一的响应格式工具 +- ✅ 必须使用统一的错误码 - ✅ 必须有详细的日志记录 -- ✅ 必须有错误处理 +- ✅ 必须有完整的错误处理 - ✅ 导出单例实例供controller使用 -## 5. Controller层规范 +## 5. Controller层规范(🔥 重点优化) ### 5.1 Controller定义 ```typescript -// ✅ 正确示例 - user.controller.ts +// ✅ 优化示例 - auth.controller.ts +/** + * @file 认证模块Controller层实现 + * @author 开发者姓名 + * @date 2024-12-19 + * @description 认证模块的路由控制器,处理HTTP请求 + */ + import { Elysia } from 'elysia'; -import { jwtAuthPlugin } from '@/plugins/jwt/jwt.plugins'; -import { CreateUserSchema } from './user.schema'; -import { GetUserResponses } from './user.response'; -import { userService } from './user.service'; +import { RegisterSchema } from './auth.schema'; +import { RegisterResponsesSchema } from './auth.response'; +import { authService } from './auth.service'; import { tags } from '@/modules/tags'; -export const userController = new Elysia({ prefix: '/user' }) +/** + * 认证控制器 + * @description 处理用户认证相关的HTTP请求 + */ +export const authController = new Elysia() /** - * 创建用户 - * @route POST /api/user + * 用户注册接口 + * @route POST /api/auth/register + * @description 用户注册,包含验证码验证、用户名邮箱唯一性检查等 */ .post( - '/', - ({ body }) => userService.createUser(body);, + '/register', + ({ body }) => authService.register(body), { - body: CreateUserSchema, + body: RegisterSchema, detail: { - summary: '创建用户', - description: '创建新用户账户', - tags: [tags.user], + summary: '用户注册', + description: '用户注册接口,需要提供用户名、邮箱、密码和验证码', + tags: [tags.auth], + operationId: 'registerUser', }, - response: GetUserResponses, - } - ) - - /** - * 获取用户信息(需要认证) - * @route GET /api/user/:id - */ - .use(jwtAuthPlugin) - .get( - '/:id', - async ({ params }) => userService.getUserById(Number(params.id));, - { - params: t.Object({ - id: t.Numeric({ description: '用户ID' }) - }), - detail: { - summary: '获取用户信息', - description: '根据用户ID获取用户详细信息', - tags: [tags.user], - security: [{ bearerAuth: [] }], - }, - response: GetUserResponses, + response: RegisterResponsesSchema, } ); ``` -## 6. 错误处理规范 +### 5.2 Controller层要求 -### 6.1 统一错误码 +- ✅ 路由方法必须有完整的JSDoc注释 +- ✅ 必须定义完整的response schema +- ✅ 必须有适当的tags分类 +- ✅ 必须有operationId用于API文档 +- ✅ 错误处理由Service层统一处理 + +## 6. 错误处理规范(🔥 重点优化) + +### 6.2 错误处理最佳实践 ```typescript -// src/constants/error-codes.ts -export const ERROR_CODES = { - SUCCESS: 'SUCCESS', - VALIDATION_ERROR: 'VALIDATION_ERROR', - UNAUTHORIZED: 'UNAUTHORIZED', - FORBIDDEN: 'FORBIDDEN', - NOT_FOUND: 'NOT_FOUND', - BUSINESS_ERROR: 'BUSINESS_ERROR', - INTERNAL_ERROR: 'INTERNAL_ERROR', -} as const; -``` +// ✅ Service层错误处理 +import { BusinessError } from '@/utils/responseFormate'; -### 6.2 错误处理模式 +// 抛出业务错误 +throw new BusinessError(ERROR_CODES.USERNAME_EXISTS, 409); -```typescript -// Service层 -try { - // 业务逻辑 - const result = await someOperation(); - return successResponse(result); -} catch (error) { - Logger.error(new Error(`操作失败:${error}`)); - - if (error instanceof ValidationError) { - throw new BusinessError('参数验证失败', ERROR_CODES.VALIDATION_ERROR); - } - - throw new InternalError('内部服务错误', ERROR_CODES.INTERNAL_ERROR); -} - -// Controller层 -try { - const result = await service.method(); - return result; -} catch (error) { - if (error instanceof BusinessError) { - set.status = 400; - return errorResponse(error.code, error.message); - } - - set.status = 500; - return errorResponse(ERROR_CODES.INTERNAL_ERROR, '服务器内部错误'); -} +// ✅ 统一错误响应格式 +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; +}; ``` ## 7. 测试规范 @@ -443,29 +794,39 @@ try { ### 7.1 测试文件结构 ```typescript -// ✅ 正确示例 - user.test.ts +// ✅ 优化示例 - auth.test.ts +/** + * @file 认证模块测试用例 + * @author 开发者姓名 + * @date 2024-12-19 + * @description 认证模块的单元测试和集成测试 + */ + import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { app } from '@/app'; -import type { CreateUserRequest } from './user.schema'; - -describe('User API', () => { - let authToken: string; +import type { RegisterRequest } from './auth.schema'; +describe('Auth API', () => { beforeAll(async () => { - // 设置测试环境 - authToken = 'test-jwt-token'; + // 测试环境初始化 }); - describe('POST /api/user', () => { - it('应该成功创建用户', async () => { - const payload: CreateUserRequest = { + afterAll(async () => { + // 测试环境清理 + }); + + describe('POST /api/auth/register', () => { + it('应该成功注册用户', async () => { + const payload: RegisterRequest = { username: 'testuser', email: 'test@example.com', - password: '123456', + password: 'password123', + captcha: 'a1b2', + captchaId: 'test_captcha_id' }; const response = await app - .handle(new Request('http://localhost/api/user', { + .handle(new Request('http://localhost/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), @@ -473,15 +834,16 @@ describe('User API', () => { expect(response.status).toBe(200); const result = await response.json(); - expect(result.code).toBe('SUCCESS'); + expect(result.code).toBe(200); + expect(result.message).toContain('注册成功'); expect(result.data.username).toBe(payload.username); }); it('应该验证必填字段', async () => { - const payload = { username: 'test' }; // 缺少email和password + const payload = { username: 'test' }; // 缺少必要字段 const response = await app - .handle(new Request('http://localhost/api/user', { + .handle(new Request('http://localhost/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), @@ -489,192 +851,165 @@ describe('User API', () => { expect(response.status).toBe(400); }); + + it('应该检查用户名重复', async () => { + // 测试用户名重复的情况 + }); + + it('应该验证验证码', async () => { + // 测试验证码验证 + }); }); }); ``` -### 7.2 测试用例文档 - -- 先设计测试用例文档,再根据文档编写测试用例 - ## 8. AI助手协作规范 ### 8.1 注释规范(关键❗️) - - #### 1. 文件头部注释 -每个源文件开头应包含如下信息: -```javascript -/** - * @file 文件简要说明 - * @author 创建者姓名(如:张三 ) - * @date 创建时间(如:2024-06-01) - * @lastEditor 最后修改人 - * @lastEditTime最后修改时间 - * @description 文件详细描述(可选) - */ -``` - -#### 2. 函数/方法/请求注释(JSDoc) -- 每个公开函数、类、接口都应有 JSDoc 注释 -- 增加修改记录,包含修改人、修改时间、修改描述 - -**推荐标签:** -- `@param` 参数说明 -- `@returns` 返回值说明 -- `@throws` 可能抛出的异常 -- `@deprecated` 弃用说明 -- `@example` 使用示例 -- `@modification` 修改记录(格式:修改人 修改时间 修改描述) - - - -**示例:** ```typescript /** - * 计算两个数的和 - * @param a 第一个加数 - * @param b 第二个加数 - * @returns 两数之和 - * @example - * add(1, 2) // 3 - * @modification 李四 2024-06-05 优化了参数校验 + * @file 文件简要说明 + * @author 创建者姓名 + * @date 创建时间(如:2024-12-19) + * @lastEditor 最后修改人 + * @lastEditTime 最后修改时间 + * @description 文件详细描述 */ -function add(a: number, b: number): number { - return a + b; -} ``` - +#### 2. 函数/方法注释(JSDoc) ```typescript /** * 方法功能说明 - * @route HTTP方法 路径 - * @description 详细描述 - * @param 参数名 参数说明 + * @param paramName 参数说明 * @returns 返回值类型和说明 - * @throws 可能抛出的异常 - * @example 使用示例 - * @modification 作者 日期 修改说明 + * @throws ErrorType 可能抛出的异常说明 + * @example + * const result = await someMethod('example'); + * @modification 修改人 修改时间 修改说明 */ ``` -#### 3. 注释类型与风格 -- 单行注释:`//`,用于简短说明 -- 多行注释:`/* ... */`,用于较长描述 -- 文档注释(JSDoc):`/** ... */`,用于结构化说明 -- 注释应简洁明了,避免废话和重复代码内容 -- 注释内容使用中文或英文均可,但需统一 -- 代码变更时同步更新相关注释,避免注释与代码不符 -- 不要注释掉无用代码,直接删除,必要时可通过版本管理找回 - -#### 4. 特殊标记 -- `TODO:` 需要补充或优化的内容 -- `FIXME:` 需要修复的问题 -- `HACK:` 临时解决方案,需后续优化 - -**示例:** -```javascript -// TODO: 优化此处的性能 -// FIXME: 这里有边界条件未处理 -// HACK: 临时绕过接口校验 -``` - -#### 5. 变量注释 - -- 每一个变量遵照JSDoc添加注释,携带描述、用途 - -参照 -```ts +#### 3. 变量注释 +```typescript /** - * MySQL数据库连接配置 - * @property {string} host - 数据库主机地址 - * @property {number} port - 数据库端口号 - * @property {string} user - 数据库用户名 - * @property {string} password - 数据库密码 - * @property {string} database - 数据库名称 + * 变量说明 + * @type {string} 变量类型 + * @description 详细描述 + * @example 'example_value' */ -export const dbConfig = { - /** 数据库主机地址 */ - host: process.env.DB_HOST || 'localhost', - /** 数据库端口号 */ - port: Number(process.env.DB_PORT) || 3306, - /** 数据库用户名 */ - user: process.env.DB_USER || 'root', - /** 数据库密码 */ - password: process.env.DB_PASSWORD || '', - /** 数据库名称 */ - database: process.env.DB_NAME || 'test', -}; ``` -#### 6. 规范补充建议 -- 注释应随代码同步更新,避免"注释失效"或误导他人。 -- 代码评审时,建议同时检查注释的准确性和完整性。 -- 复杂算法、业务逻辑、边界处理、特殊依赖等务必详细注释。 -- 简单、易懂的代码无需过度注释,避免注释冗余。 -- 团队应约定注释统一使用中文或英文,避免混杂,提升协作效率。 -- 推荐使用 ESLint、TSLint 等工具结合注释相关插件(如 eslint-plugin-jsdoc)进行注释规范自动校验。 -- 可使用 IDE 插件(如 VSCode 的 JSDoc Generator)自动生成注释模板,提升效率。 -- 建议在项目根目录下提供注释模板(如 `.comment-templates`),便于新成员快速上手。 -- 注释中严禁出现密码、密钥、用户隐私等敏感信息。 -- 重要模块、核心业务建议将注释内容同步到项目文档,便于知识传承和查阅。 - ### 8.2 代码组织原则 1. **单一职责**:每个文件只负责一个清晰的功能 -2. **依赖注入**:通过构造函数或导入明确依赖关系 -3. **类型优先**:先定义Schema和类型,再实现逻辑 -4. **错误优先**:优先考虑错误处理和边界情况 -5. **测试驱动**:每个功能都有对应的测试用例 +2. **类型优先**:先定义Schema和类型,再实现逻辑 +3. **错误优先**:优先考虑错误处理和边界情况 +4. **测试驱动**:每个功能都有对应的测试用例 +5. **依赖注入**:通过导入明确依赖关系 ### 8.3 命名约定总结 | 类型 | 格式 | 示例 | |------|------|------| -| 文件名 | `[module].[type].ts` | `user.controller.ts` | -| Schema | `[Action][Module]Schema` | `CreateUserSchema` | -| Type | `[Action][Module][Type]` | `CreateUserRequest` | -| Service类 | `[Module]Service` | `UserService` | -| Service实例 | `[module]Service` | `userService` | -| Controller | `[module]Controller` | `userController` | +| 文件名 | `[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定义完整(包含验证规则和示例) +- [ ] 1. Schema定义完整(包含验证规则、描述、示例) - [ ] 2. 类型导出正确(Request/Response类型) -- [ ] 3. Response格式统一(成功/错误响应) -- [ ] 4. Service类型注解完整 -- [ ] 5. Controller错误处理完整 -- [ ] 6. 测试用例覆盖主要场景 -- [ ] 7. JSDoc注释完整 -- [ ] 8. 日志记录到位 +- [ ] 3. Response格式使用responseWrapperSchema +- [ ] 4. Service使用successResponse/errorResponse +- [ ] 5. 错误处理使用统一错误码 +- [ ] 6. Controller定义完整的response schema +- [ ] 7. 测试用例覆盖主要场景 +- [ ] 8. JSDoc注释完整 +- [ ] 9. 日志记录到位 +- [ ] 10. 使用统一的工具函数 ## 10. 最佳实践 -### 10.1 性能优化 +### 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.2 安全考虑 +### 10.5 安全考虑 - 输入验证和清理 -- 适当的认证和授权 +- 密码加密存储(bcrypt) +- JWT令牌认证 - 敏感信息不记录日志 +- 对于必要的写入操作,需要增加分布式锁,分布式锁键名在常量中统一定义 -### 10.3 监控和日志 -- 关键操作必须有日志 -- 错误信息要有足够上下文 -- 性能敏感操作要有监控 +## 11. 模块引入规范 -这套规则确保了代码的一致性、可维护性和AI友好性,让我能够更高效地理解和协助你的开发工作。 +### 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. 模块引入 +### 11.2 配置文件更新 +确保更新以下配置文件中的路径别名: +- `tsconfig.json` +- `bunfig.toml` +- `vitest.config.ts` -- 全部使用路径别名,如`@/app` `@/config/db.config` +--- + +**请严格遵守以上规范,确保代码的一致性、可维护性和AI友好性。这套规则经过实际项目验证,能够显著提升开发效率和代码质量。** - 注意更新 tsconfig.json bunfig.toml 等配置中关于路径别名的配置 --- diff --git a/src/constants/error-codes.ts b/src/constants/error-codes.ts deleted file mode 100644 index 3909003..0000000 --- a/src/constants/error-codes.ts +++ /dev/null @@ -1,188 +0,0 @@ -/** - * @file 统一错误码定义 - * @author AI助手 - * @date 2025-06-29 - * @lastEditor AI Assistant - * @lastEditTime 2025-01-07 - * @description 定义整个应用的统一错误码,提供类型安全的错误处理 - */ - -/** - * 应用错误码枚举 - * @description 统一管理所有错误码,确保错误处理的一致性 - */ -export const ERROR_CODES = { - // 成功 - SUCCESS: 'SUCCESS', - - // 客户端错误 4xx - VALIDATION_ERROR: 'VALIDATION_ERROR', // 参数验证失败 - UNAUTHORIZED: 'UNAUTHORIZED', // 未授权 - FORBIDDEN: 'FORBIDDEN', // 禁止访问 - NOT_FOUND: 'NOT_FOUND', // 资源不存在 - METHOD_NOT_ALLOWED: 'METHOD_NOT_ALLOWED', // 方法不允许 - CONFLICT: 'CONFLICT', // 资源冲突 - RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED', // 请求频率超限 - - // 业务错误 4xx - BUSINESS_ERROR: 'BUSINESS_ERROR', // 通用业务错误 - USER_NOT_FOUND: 'USER_NOT_FOUND', // 用户不存在 - USER_ALREADY_EXISTS: 'USER_ALREADY_EXISTS', // 用户已存在 - INVALID_CREDENTIALS: 'INVALID_CREDENTIALS', // 凭据无效 - TOKEN_EXPIRED: 'TOKEN_EXPIRED', // Token过期 - TOKEN_INVALID: 'TOKEN_INVALID', // Token无效 - INSUFFICIENT_PERMISSIONS: 'INSUFFICIENT_PERMISSIONS', // 权限不足 - - // 用户注册相关错误 - USERNAME_EXISTS: 'USERNAME_EXISTS', // 用户名已存在 - EMAIL_EXISTS: 'EMAIL_EXISTS', // 邮箱已存在 - PASSWORD_MISMATCH: 'PASSWORD_MISMATCH', // 密码不匹配 - CAPTCHA_ERROR: 'CAPTCHA_ERROR', // 验证码错误 - EMAIL_SEND_FAILED: 'EMAIL_SEND_FAILED', // 邮件发送失败 - - // 用户激活相关错误 - INVALID_ACTIVATION_TOKEN: 'INVALID_ACTIVATION_TOKEN', // 激活令牌无效 - ALREADY_ACTIVATED: 'ALREADY_ACTIVATED', // 已经激活 - - // 用户登录相关错误 - INVALID_PASSWORD: 'INVALID_PASSWORD', // 密码错误 - ACCOUNT_NOT_ACTIVATED: 'ACCOUNT_NOT_ACTIVATED', // 账号未激活 - ACCOUNT_LOCKED: 'ACCOUNT_LOCKED', // 账号被锁定 - TOO_MANY_FAILED_ATTEMPTS: 'TOO_MANY_FAILED_ATTEMPTS', // 失败次数过多 - TOO_MANY_ATTEMPTS: 'TOO_MANY_ATTEMPTS', // 登录次数过多 - CAPTCHA_REQUIRED: 'CAPTCHA_REQUIRED', // 需要验证码 - - // 密码重置相关错误 - INVALID_RESET_TOKEN: 'INVALID_RESET_TOKEN', // 重置令牌无效 - - // 系统状态 - NOT_IMPLEMENTED: 'NOT_IMPLEMENTED', // 功能未实现 - - // 服务器错误 5xx - INTERNAL_ERROR: 'INTERNAL_ERROR', // 内部服务器错误 - DATABASE_ERROR: 'DATABASE_ERROR', // 数据库错误 - REDIS_ERROR: 'REDIS_ERROR', // Redis错误 - EXTERNAL_API_ERROR: 'EXTERNAL_API_ERROR', // 外部API错误 - SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE', // 服务不可用 -} as const; - -/** - * 错误码类型 - */ -export type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]; - -/** - * 错误码到HTTP状态码的映射 - */ -export const ERROR_CODE_TO_HTTP_STATUS: Record = { - // 成功 - [ERROR_CODES.SUCCESS]: 200, - - // 客户端错误 4xx - [ERROR_CODES.VALIDATION_ERROR]: 400, - [ERROR_CODES.UNAUTHORIZED]: 401, - [ERROR_CODES.FORBIDDEN]: 403, - [ERROR_CODES.NOT_FOUND]: 404, - [ERROR_CODES.METHOD_NOT_ALLOWED]: 405, - [ERROR_CODES.CONFLICT]: 409, - [ERROR_CODES.RATE_LIMIT_EXCEEDED]: 429, - - // 业务错误 4xx - [ERROR_CODES.BUSINESS_ERROR]: 400, - [ERROR_CODES.USER_NOT_FOUND]: 404, - [ERROR_CODES.USER_ALREADY_EXISTS]: 409, - [ERROR_CODES.INVALID_CREDENTIALS]: 401, - [ERROR_CODES.TOKEN_EXPIRED]: 401, - [ERROR_CODES.TOKEN_INVALID]: 401, - [ERROR_CODES.INSUFFICIENT_PERMISSIONS]: 403, - - // 用户注册相关错误 - [ERROR_CODES.USERNAME_EXISTS]: 409, - [ERROR_CODES.EMAIL_EXISTS]: 409, - [ERROR_CODES.PASSWORD_MISMATCH]: 400, - [ERROR_CODES.CAPTCHA_ERROR]: 400, - [ERROR_CODES.EMAIL_SEND_FAILED]: 500, - - // 用户激活相关错误 - [ERROR_CODES.INVALID_ACTIVATION_TOKEN]: 400, - [ERROR_CODES.ALREADY_ACTIVATED]: 409, - - // 用户登录相关错误 - [ERROR_CODES.INVALID_PASSWORD]: 401, - [ERROR_CODES.ACCOUNT_NOT_ACTIVATED]: 403, - [ERROR_CODES.ACCOUNT_LOCKED]: 403, - [ERROR_CODES.TOO_MANY_FAILED_ATTEMPTS]: 429, - [ERROR_CODES.TOO_MANY_ATTEMPTS]: 429, - [ERROR_CODES.CAPTCHA_REQUIRED]: 400, - - // 密码重置相关错误 - [ERROR_CODES.INVALID_RESET_TOKEN]: 400, - - // 系统状态 - [ERROR_CODES.NOT_IMPLEMENTED]: 501, - - // 服务器错误 5xx - [ERROR_CODES.INTERNAL_ERROR]: 500, - [ERROR_CODES.DATABASE_ERROR]: 500, - [ERROR_CODES.REDIS_ERROR]: 500, - [ERROR_CODES.EXTERNAL_API_ERROR]: 502, - [ERROR_CODES.SERVICE_UNAVAILABLE]: 503, -}; - -/** - * 错误码描述映射 - */ -export const ERROR_CODE_MESSAGES: Record = { - // 成功 - [ERROR_CODES.SUCCESS]: '操作成功', - - // 客户端错误 - [ERROR_CODES.VALIDATION_ERROR]: '请求参数验证失败', - [ERROR_CODES.UNAUTHORIZED]: '未授权访问', - [ERROR_CODES.FORBIDDEN]: '禁止访问', - [ERROR_CODES.NOT_FOUND]: '请求的资源不存在', - [ERROR_CODES.METHOD_NOT_ALLOWED]: '请求方法不被允许', - [ERROR_CODES.CONFLICT]: '请求与当前资源状态冲突', - [ERROR_CODES.RATE_LIMIT_EXCEEDED]: '请求频率超过限制', - - // 业务错误 - [ERROR_CODES.BUSINESS_ERROR]: '业务处理失败', - [ERROR_CODES.USER_NOT_FOUND]: '用户不存在', - [ERROR_CODES.USER_ALREADY_EXISTS]: '用户已存在', - [ERROR_CODES.INVALID_CREDENTIALS]: '用户名或密码错误', - [ERROR_CODES.TOKEN_EXPIRED]: '访问令牌已过期', - [ERROR_CODES.TOKEN_INVALID]: '访问令牌无效', - [ERROR_CODES.INSUFFICIENT_PERMISSIONS]: '权限不足', - - // 用户注册相关错误 - [ERROR_CODES.USERNAME_EXISTS]: '用户名已存在', - [ERROR_CODES.EMAIL_EXISTS]: '邮箱已被注册', - [ERROR_CODES.PASSWORD_MISMATCH]: '两次输入的密码不一致', - [ERROR_CODES.CAPTCHA_ERROR]: '验证码错误或已过期', - [ERROR_CODES.EMAIL_SEND_FAILED]: '邮件发送失败', - - // 用户激活相关错误 - [ERROR_CODES.INVALID_ACTIVATION_TOKEN]: '激活令牌无效或已过期', - [ERROR_CODES.ALREADY_ACTIVATED]: '账号已经激活', - - // 用户登录相关错误 - [ERROR_CODES.INVALID_PASSWORD]: '密码错误', - [ERROR_CODES.ACCOUNT_NOT_ACTIVATED]: '账号未激活', - [ERROR_CODES.ACCOUNT_LOCKED]: '账号已被锁定', - [ERROR_CODES.TOO_MANY_FAILED_ATTEMPTS]: '登录失败次数过多', - [ERROR_CODES.TOO_MANY_ATTEMPTS]: '登录次数过多,请稍后再试', - [ERROR_CODES.CAPTCHA_REQUIRED]: '请输入验证码', - - // 密码重置相关错误 - [ERROR_CODES.INVALID_RESET_TOKEN]: '重置令牌无效或已过期', - - // 系统状态 - [ERROR_CODES.NOT_IMPLEMENTED]: '功能未实现', - - // 服务器错误 - [ERROR_CODES.INTERNAL_ERROR]: '服务器内部错误', - [ERROR_CODES.DATABASE_ERROR]: '数据库操作失败', - [ERROR_CODES.REDIS_ERROR]: 'Redis操作失败', - [ERROR_CODES.EXTERNAL_API_ERROR]: '外部服务调用失败', - [ERROR_CODES.SERVICE_UNAVAILABLE]: '服务暂时不可用', -}; \ No newline at end of file diff --git a/tasks/M2-基础用户系统-开发任务计划.md b/tasks/M2-基础用户系统-开发任务计划.md index dd2efbc..7af576d 100644 --- a/tasks/M2-基础用户系统-开发任务计划.md +++ b/tasks/M2-基础用户系统-开发任务计划.md @@ -77,12 +77,12 @@ - [x] 2.4 扩展auth.controller.ts - 实现激活路由 - [x] 2.5 扩展auth.test.ts - 编写激活测试用例 -- [ ] 3.0 POST /auth/login - 用户登录接口 +- [x] 3.0 POST /auth/login - 用户登录接口 - [x] 3.1 扩展auth.schema.ts - 定义登录Schema - [x] 3.2 扩展auth.response.ts - 定义登录响应格式 - [x] 3.3 扩展auth.service.ts - 实现登录业务逻辑 - [x] 3.4 扩展auth.controller.ts - 实现登录路由 - - [ ] 3.5 扩展auth.test.ts - 编写登录测试用例 + - [x] 3.5 扩展auth.test.ts - 编写登录测试用例 - [ ] 4.0 POST /auth/refresh - Token刷新接口 - [ ] 4.1 扩展auth.schema.ts - 定义刷新Schema