Parcourir la source

feat(story): 添加故事015.002 - 人才用户认证API扩展

- 创建人才用户登录接口(支持身份证号/残疾证号登录)
- 创建退出登录和获取用户信息接口
- 扩展认证中间件支持UserType.TALENT
- 人才用户由管理员统一创建,不提供自助注册
- 包含完整的测试要求和OpenAPI文档规范

🤖 Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname il y a 3 semaines
Parent
commit
7e5e6e1785
1 fichiers modifiés avec 301 ajouts et 0 suppressions
  1. 301 0
      docs/stories/015.002.story.md

+ 301 - 0
docs/stories/015.002.story.md

@@ -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代理在审查完成后填写*