|
@@ -0,0 +1,301 @@
|
|
|
|
|
+# Story 015.002: 人才用户认证API扩展
|
|
|
|
|
+
|
|
|
|
|
+## Status
|
|
|
|
|
+Approved
|
|
|
|
|
+
|
|
|
|
|
+## Story
|
|
|
|
|
+**作为** 人才用户,
|
|
|
|
|
+**我希望** 能够使用身份证号/残疾证号和密码登录系统,
|
|
|
|
|
+**以便** 安全地访问我的个人信息、就业记录和薪资数据。
|
|
|
|
|
+
|
|
|
|
|
+## Acceptance Criteria
|
|
|
|
|
+1. 人才用户可使用身份证号/残疾证号和密码成功登录
|
|
|
|
|
+2. 人才用户登录后可获取包含人才详情的用户信息
|
|
|
|
|
+3. 人才用户可成功退出登录
|
|
|
|
|
+4. 认证中间件正确识别人才用户身份
|
|
|
|
|
+5. 人才用户权限验证逻辑正确
|
|
|
|
|
+6. 所有新增接口通过单元测试和集成测试
|
|
|
|
|
+7. API文档完整,包含OpenAPI定义和TypeScript类型
|
|
|
|
|
+
|
|
|
|
|
+## Tasks / Subtasks
|
|
|
|
|
+- [ ] 任务1:扩展auth-module,添加人才用户登录接口 (AC: 1)
|
|
|
|
|
+ - [ ] 创建人才登录Schema验证(支持身份证号/残疾证号+密码登录)
|
|
|
|
|
+ - [ ] 创建人才登录服务方法(验证身份证号/残疾证号和密码)
|
|
|
|
|
+ - [ ] 创建人才登录路由 `POST /api/v1/rencai/auth/login`
|
|
|
|
|
+ - [ ] 基于users2表的person_id字段关联disabled_person表验证
|
|
|
|
|
+ - [ ] 生成JWT token并返回用户基本信息
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务2:添加人才用户退出登录接口 (AC: 3)
|
|
|
|
|
+ - [ ] 创建退出登录路由 `POST /api/v1/rencai/auth/logout`
|
|
|
|
|
+ - [ ] 实现token失效处理(可选:Redis黑名单或延长过期时间)
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务3:添加获取人才用户信息接口 (AC: 2)
|
|
|
|
|
+ - [ ] 创建获取用户信息路由 `GET /api/v1/rencai/auth/me`
|
|
|
|
|
+ - [ ] 关联查询disabled_person表获取人才详情
|
|
|
|
|
+ - [ ] 返回用户基本信息和人才详细信息
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务4:更新认证中间件,支持人才用户身份识别 (AC: 4)
|
|
|
|
|
+ - [ ] 扩展现有auth.middleware.ts,识别UserType.TALENT
|
|
|
|
|
+ - [ ] 确保人才用户token验证逻辑正确
|
|
|
|
|
+ - [ ] 添加人才用户权限验证逻辑
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务5:编写单元测试和集成测试 (AC: 6)
|
|
|
|
|
+ - [ ] 测试人才用户登录成功场景(身份证号登录)
|
|
|
|
|
+ - [ ] 测试人才用户登录成功场景(残疾证号登录)
|
|
|
|
|
+ - [ ] 测试登录失败场景(错误的身份证号/残疾证号或密码)
|
|
|
|
|
+ - [ ] 测试获取用户信息接口
|
|
|
|
|
+ - [ ] 测试认证中间件识别人才用户
|
|
|
|
|
+ - [ ] 测试权限验证逻辑
|
|
|
|
|
+
|
|
|
|
|
+- [ ] 任务6:添加OpenAPI文档和TypeScript类型 (AC: 7)
|
|
|
|
|
+ - [ ] 为所有新接口添加OpenAPI元数据
|
|
|
|
|
+ - [ ] 定义请求/响应Schema
|
|
|
|
|
+ - [ ] 确保类型安全导出
|
|
|
|
|
+
|
|
|
|
|
+## Dev Notes
|
|
|
|
|
+
|
|
|
|
|
+### 先前故事见解
|
|
|
|
|
+- **故事015.001**:已完成数据库schema扩展,UserType枚举新增talent类型,users2表添加person_id字段关联disabled_person表 [Source: docs/stories/015.001.story.md#L130-L141]
|
|
|
|
|
+- **UserType枚举位置**:定义在`@d8d/shared-types`中,包含admin、employer、talent三种类型 [Source: docs/stories/015.001.story.md#L132-L133]
|
|
|
|
|
+- **personId字段关系**:UserEntity中使用字符串引用避免循环依赖 [Source: packages/core-module/user-module/src/entities/user.entity.ts#L57-L60]
|
|
|
|
|
+
|
|
|
|
|
+### 技术栈要求
|
|
|
|
|
+- **后端框架**:Hono 4.8.5 [Source: docs/architecture/tech-stack.md#L12]
|
|
|
|
|
+- **数据库**:PostgreSQL 17 [Source: docs/architecture/tech-stack.md#L15]
|
|
|
|
|
+- **ORM**:TypeORM 0.3.25 [Source: docs/architecture/tech-stack.md#L16]
|
|
|
|
|
+- **认证**:JWT 9.0.2 [Source: docs/architecture/tech-stack.md#L19]
|
|
|
|
|
+- **测试框架**:Vitest 2.x [Source: docs/architecture/tech-stack.md#L24]
|
|
|
|
|
+
|
|
|
|
|
+### 数据模型规范
|
|
|
|
|
+- **用户实体位置**:`packages/core-module/user-module/src/entities/user.entity.ts` [Source: 通过项目结构确认]
|
|
|
|
|
+- **残疾人实体位置**:`allin-packages/disability-module/src/entities/disabled-person.entity.ts` [Source: 通过项目结构确认]
|
|
|
|
|
+- **UserType枚举**:`@d8d/shared-types`包中定义 [Source: docs/stories/015.001.story.md#L132]
|
|
|
|
|
+
|
|
|
|
|
+**users2表关键字段**:
|
|
|
|
|
+- `id`: 用户ID(主键)
|
|
|
|
|
+- `username`: 用户名
|
|
|
|
|
+- `password`: 密码(bcrypt哈希)
|
|
|
|
|
+- `user_type`: 用户类型(admin/employer/talent)
|
|
|
|
|
+- `person_id`: 残疾人ID(外键,可为空)[Source: packages/core-module/user-module/src/entities/user.entity.ts#L54-L55]
|
|
|
|
|
+
|
|
|
|
|
+**disabled_person表关键字段**:
|
|
|
|
|
+- `person_id`: 残疾人ID(主键)
|
|
|
|
|
+- `name`: 姓名
|
|
|
|
|
+- `id_card`: 身份证号(唯一索引)
|
|
|
|
|
+- `disability_id`: 残疾证号(唯一索引)
|
|
|
|
|
+- `phone`: 联系方式
|
|
|
|
|
+- `gender`: 性别
|
|
|
|
|
+- `disability_type`: 残疾类型
|
|
|
|
|
+- `disability_level`: 残疾等级
|
|
|
|
|
+- 其他详细字段见实体定义 [Source: allin-packages/disability-module/src/entities/disabled-person.entity.ts#L8-L238]
|
|
|
|
|
+
|
|
|
|
|
+### API路径约定
|
|
|
|
|
+- **人才小程序API前缀**:`/api/v1/rencai` [Source: docs/prd/epic-015-talent-mini-program-api-support.md#L53-L61]
|
|
|
|
|
+- **模块包内路由定义**:不应包含API前缀,前缀在server包注册时统一添加 [Source: docs/prd/epic-015-talent-mini-program-api-support.md#L335-L337]
|
|
|
|
|
+
|
|
|
|
|
+**具体接口路径**:
|
|
|
|
|
+- 人才用户登录:`POST /api/v1/rencai/auth/login`
|
|
|
|
|
+- 退出登录:`POST /api/v1/rencai/auth/logout`
|
|
|
|
|
+- 获取用户信息:`GET /api/v1/rencai/auth/me`
|
|
|
|
|
+
|
|
|
|
|
+### 认证机制设计
|
|
|
|
|
+**JWT Token认证**:
|
|
|
|
|
+- 使用现有JWT认证机制 [Source: docs/architecture/tech-stack.md#L19]
|
|
|
|
|
+- Token包含用户ID和用户类型信息
|
|
|
|
|
+- 人才用户使用`UserType.TALENT`标识
|
|
|
|
|
+
|
|
|
|
|
+**登录验证逻辑**:
|
|
|
|
|
+1. 接收身份证号或残疾证号 + 密码
|
|
|
|
|
+2. 在disabled_person表中查找匹配的person_id
|
|
|
|
|
+3. 在users2表中通过person_id查找对应用户
|
|
|
|
|
+4. 验证密码(bcrypt比较)
|
|
|
|
|
+5. 生成JWT token(包含userType: 'talent')
|
|
|
|
|
+6. 返回用户基本信息和token
|
|
|
|
|
+
|
|
|
|
|
+**认证中间件扩展**:
|
|
|
|
|
+- 扩展现有auth.middleware.ts
|
|
|
|
|
+- 识别UserType.TALENT
|
|
|
|
|
+- 确保人才用户只能访问`/api/v1/rencai`路径下的接口
|
|
|
|
|
+
|
|
|
|
|
+### 项目结构指南
|
|
|
|
|
+**模块位置**:
|
|
|
|
|
+- auth-module:`packages/core-module/auth-module/` [Source: docs/architecture/source-tree.md#L109-L129]
|
|
|
|
|
+- user-module:`packages/core-module/user-module/` [Source: docs/architecture/source-tree.md#L92-L108]
|
|
|
|
|
+- disability-module:`allin-packages/disability-module/` [Source: 通过项目结构确认]
|
|
|
|
|
+
|
|
|
|
|
+**路由文件结构**:
|
|
|
|
|
+```
|
|
|
|
|
+packages/core-module/auth-module/src/routes/
|
|
|
|
|
+├── rencai/
|
|
|
|
|
+│ ├── login.route.ts # 人才登录路由
|
|
|
|
|
+│ ├── logout.route.ts # 退出登录路由
|
|
|
|
|
+│ └── me.route.ts # 获取用户信息路由
|
|
|
|
|
+└── rencai-auth.routes.ts # 人才认证路由聚合
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Schema文件位置**:
|
|
|
|
|
+```
|
|
|
|
|
+packages/core-module/auth-module/src/schemas/
|
|
|
|
|
+└── rencai-auth.schema.ts # 人才认证Schema
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Schema验证规范
|
|
|
|
|
+**人才登录请求Schema**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+const TalentLoginSchema = z.object({
|
|
|
|
|
+ identifier: z.string().min(1), // 身份证号或残疾证号
|
|
|
|
|
+ password: z.string().min(6),
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**登录响应Schema**:
|
|
|
|
|
+```typescript
|
|
|
|
|
+const TalentLoginResponseSchema = z.object({
|
|
|
|
|
+ success: z.boolean(),
|
|
|
|
|
+ data: z.object({
|
|
|
|
|
+ token: z.string(),
|
|
|
|
|
+ user: z.object({
|
|
|
|
|
+ id: z.number(),
|
|
|
|
|
+ userType: z.nativeEnum(UserType),
|
|
|
|
|
+ username: z.string(),
|
|
|
|
|
+ personId: z.number(),
|
|
|
|
|
+ }),
|
|
|
|
|
+ }),
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 只读设计原则
|
|
|
|
|
+遵循与用人方小程序相同的设计原则,人才用户认证API支持登录和获取用户信息,个人信息修改由管理员在管理后台统一处理 [Source: docs/prd/epic-015-talent-mini-program-api-support.md#L50-L52]
|
|
|
|
|
+
|
|
|
|
|
+**人才用户创建**:人才用户账户统一由管理员在后台用户管理中配置(与企业用户模式相同),不提供自助注册功能。管理员创建人才用户时需要:
|
|
|
|
|
+1. 选择用户类型为"talent"
|
|
|
|
|
+2. 关联对应的残疾人记录(person_id)
|
|
|
|
|
+3. 设置登录密码
|
|
|
|
|
+
|
|
|
|
|
+### 测试要求
|
|
|
|
|
+**测试位置**:
|
|
|
|
|
+- 单元测试:`packages/core-module/auth-module/tests/unit/**/*.test.ts` [Source: docs/architecture/testing-strategy.md#L42]
|
|
|
|
|
+- 集成测试:`packages/core-module/auth-module/tests/integration/**/*.test.ts` [Source: docs/architecture/testing-strategy.md#L53]
|
|
|
|
|
+
|
|
|
|
|
+**测试覆盖率目标**:
|
|
|
|
|
+- 单元测试:≥ 80% [Source: docs/architecture/testing-strategy.md#L169]
|
|
|
|
|
+- 集成测试:≥ 60% [Source: docs/architecture/testing-strategy.md#L169]
|
|
|
|
|
+
|
|
|
|
|
+**测试场景**:
|
|
|
|
|
+1. **登录成功场景**:
|
|
|
|
|
+ - 使用身份证号+密码登录成功
|
|
|
|
|
+ - 使用残疾证号+密码登录成功
|
|
|
|
|
+ - 返回正确的token和用户信息
|
|
|
|
|
+ - personId字段正确关联
|
|
|
|
|
+
|
|
|
|
|
+2. **登录失败场景**:
|
|
|
|
|
+ - 身份证号不存在
|
|
|
|
|
+ - 残疾证号不存在
|
|
|
|
|
+ - 密码错误
|
|
|
|
|
+ - 用户不存在(disabled_person存在但users2无记录)
|
|
|
|
|
+ - 用户类型不是talent
|
|
|
|
|
+
|
|
|
|
|
+3. **获取用户信息场景**:
|
|
|
|
|
+ - 成功获取用户基本信息
|
|
|
|
|
+ - 成功获取关联的disabled_person详细信息
|
|
|
|
|
+ - 未登录时返回401
|
|
|
|
|
+
|
|
|
|
|
+4. **认证中间件场景**:
|
|
|
|
|
+ - 人才用户token正确验证通过
|
|
|
|
|
+ - 人才用户可访问`/api/v1/rencai`路径
|
|
|
|
|
+ - 人才用户无法访问其他路径
|
|
|
|
|
+
|
|
|
|
|
+### 安全要求
|
|
|
|
|
+**密码处理**:
|
|
|
|
|
+- 使用bcrypt哈希存储密码
|
|
|
|
|
+- 登录时使用bcrypt比较验证
|
|
|
|
|
+
|
|
|
|
|
+**JWT Token**:
|
|
|
|
|
+- 包含用户ID、用户类型、过期时间
|
|
|
|
|
+- 使用环境变量配置的密钥签名
|
|
|
|
|
+
|
|
|
|
|
+**输入验证**:
|
|
|
|
|
+- 身份证号格式验证(18位)
|
|
|
|
|
+- 残疾证号格式验证
|
|
|
|
|
+- 密码最小长度要求
|
|
|
|
|
+
|
|
|
|
|
+### 技术约束
|
|
|
|
|
+- **依赖管理**:auth-module可能需要添加对disability-module的依赖(或使用ID引用解耦)[Source: docs/architecture/backend-module-package-standards.md#L314-L328]
|
|
|
|
|
+- **循环依赖处理**:避免直接实体引用导致的循环依赖,考虑使用ID引用模式 [Source: docs/architecture/backend-module-package-standards.md#L314-L328]
|
|
|
|
|
+- **模块包命名**:如果创建新包,使用`@d8d/allin-{name}-module`格式 [Source: docs/architecture/backend-module-package-standards.md#L39-L42]
|
|
|
|
|
+
|
|
|
|
|
+### 参考实现
|
|
|
|
|
+- **企业用户认证**:参考史诗012中的企业用户认证实现模式 [Source: docs/prd/epic-012-api-supplement-for-employer-mini-program.md]
|
|
|
|
|
+- **现有认证中间件**:参考`packages/core-module/auth-module/src/middleware/auth.middleware.ts` [Source: docs/architecture/source-tree.md#L125-L127]
|
|
|
|
|
+- **枚举定义模式**:参考UserType枚举定义 [Source: docs/stories/015.001.story.md#L132-L133]
|
|
|
|
|
+
|
|
|
|
|
+### 文件位置
|
|
|
|
|
+**需要创建/修改的文件**:
|
|
|
|
|
+- `packages/core-module/auth-module/src/routes/rencai/login.route.ts` - 人才登录路由
|
|
|
|
|
+- `packages/core-module/auth-module/src/routes/rencai/logout.route.ts` - 退出登录路由
|
|
|
|
|
+- `packages/core-module/auth-module/src/routes/rencai/me.route.ts` - 获取用户信息路由
|
|
|
|
|
+- `packages/core-module/auth-module/src/routes/rencai-auth.routes.ts` - 路由聚合
|
|
|
|
|
+- `packages/core-module/auth-module/src/schemas/rencai-auth.schema.ts` - Schema定义
|
|
|
|
|
+- `packages/core-module/auth-module/src/services/rencai-auth.service.ts` - 认证服务(可选)
|
|
|
|
|
+- `packages/core-module/auth-module/src/middleware/auth.middleware.ts` - 扩展认证中间件
|
|
|
|
|
+- `packages/core-module/auth-module/tests/integration/rencai-auth.integration.test.ts` - 集成测试
|
|
|
|
|
+
|
|
|
|
|
+### 错误处理规范
|
|
|
|
|
+**HTTP状态码** [Source: docs/architecture/backend-module-package-standards.md#L442-L449]:
|
|
|
|
|
+- `200 OK`:操作成功
|
|
|
|
|
+- `400 Bad Request`:请求参数错误
|
|
|
|
|
+- `401 Unauthorized`:未授权或token无效
|
|
|
|
|
+- `404 Not Found`:资源不存在
|
|
|
|
|
+
|
|
|
|
|
+**错误响应格式** [Source: docs/architecture/backend-module-package-standards.md#L450-L458]:
|
|
|
|
|
+```typescript
|
|
|
|
|
+{
|
|
|
|
|
+ success: false,
|
|
|
|
|
+ message: "身份证号或密码错误",
|
|
|
|
|
+ code: "INVALID_CREDENTIALS",
|
|
|
|
|
+ timestamp: "2025-12-24T10:30:00Z"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 项目结构注意事项
|
|
|
|
|
+- **模块依赖关系**:auth-module可能需要添加对disability-module的依赖来查询disabled_person表
|
|
|
|
|
+- **包配置更新**:如果添加新依赖,需要更新package.json和pnpm-workspace.yaml
|
|
|
|
|
+- **类型导出**:确保新增的Schema和类型正确导出供其他模块使用
|
|
|
|
|
+- **路由注册**:在server包中正确注册rencai路由并添加`/api/v1/rencai`前缀
|
|
|
|
|
+
|
|
|
|
|
+### Testing
|
|
|
|
|
+
|
|
|
|
|
+#### 测试文件位置
|
|
|
|
|
+- 单元测试:`packages/core-module/auth-module/tests/unit/**/*.test.ts`
|
|
|
|
|
+- 集成测试:`packages/core-module/auth-module/tests/integration/rencai-auth.integration.test.ts`
|
|
|
|
|
+
|
|
|
|
|
+#### 测试框架
|
|
|
|
|
+- Vitest 2.x [Source: docs/architecture/testing-strategy.md#L45-L46]
|
|
|
|
|
+- hono/testing用于API测试 [Source: docs/architecture/tech-stack.md#L26]
|
|
|
|
|
+
|
|
|
|
|
+#### 测试覆盖率要求
|
|
|
|
|
+- 核心业务逻辑 > 80% [Source: docs/architecture/coding-standards.md#L18]
|
|
|
|
|
+
|
|
|
|
|
+#### 测试策略
|
|
|
|
|
+- 单元测试:测试登录验证逻辑、token生成逻辑
|
|
|
|
|
+- 集成测试:测试完整登录流程、获取用户信息流程、认证中间件
|
|
|
|
|
+
|
|
|
|
|
+## Change Log
|
|
|
|
|
+| Date | Version | Description | Author |
|
|
|
|
|
+|------|---------|-------------|--------|
|
|
|
|
|
+| 2025-12-24 | 1.0 | 初始故事创建 | Scrum Master |
|
|
|
|
|
+| 2025-12-24 | 1.1 | 移除自助注册功能,明确人才用户由管理员创建 | Scrum Master |
|
|
|
|
|
+
|
|
|
|
|
+## Dev Agent Record
|
|
|
|
|
+*此部分由开发代理在实施过程中填写*
|
|
|
|
|
+
|
|
|
|
|
+### Agent Model Used
|
|
|
|
|
+
|
|
|
|
|
+### Debug Log References
|
|
|
|
|
+
|
|
|
|
|
+### Completion Notes List
|
|
|
|
|
+
|
|
|
|
|
+### File List
|
|
|
|
|
+
|
|
|
|
|
+## QA Results
|
|
|
|
|
+*此部分由QA代理在审查完成后填写*
|