# Story 015.002: 人才用户认证API扩展

## Status
Ready for Review

## Story
**作为** 人才用户，
**我希望** 能够使用身份证号/残疾证号和密码登录系统，
**以便** 安全地访问我的个人信息、就业记录和薪资数据。

## Acceptance Criteria
1. 人才用户可使用身份证号/残疾证号和密码成功登录
2. 人才用户登录后可获取包含人才详情的用户信息
3. 人才用户可成功退出登录
4. 认证中间件正确识别人才用户身份
5. 人才用户权限验证逻辑正确
6. 所有新增接口通过单元测试和集成测试
7. API文档完整，包含OpenAPI定义和TypeScript类型

## Tasks / Subtasks
- [x] 任务1：扩展auth-module，添加人才用户登录接口 (AC: 1)
  - [x] 创建人才登录Schema验证（支持身份证号/残疾证号+密码登录）
  - [x] 创建人才登录服务方法（验证身份证号/残疾证号和密码）
  - [x] 创建人才登录路由 `POST /api/v1/rencai/auth/login`
  - [x] 基于users2表的person_id字段关联disabled_person表验证
  - [x] 生成JWT token并返回用户基本信息

- [x] 任务2：添加人才用户退出登录接口 (AC: 3)
  - [x] 创建退出登录路由 `POST /api/v1/rencai/auth/logout`
  - [x] 实现token失效处理（可选：Redis黑名单或延长过期时间）

- [x] 任务3：添加获取人才用户信息接口 (AC: 2)
  - [x] 创建获取用户信息路由 `GET /api/v1/rencai/auth/me`
  - [x] 关联查询disabled_person表获取人才详情
  - [x] 返回用户基本信息和人才详细信息

- [x] 任务4：更新认证中间件，支持人才用户身份识别 (AC: 4)
  - [x] 扩展现有auth.middleware.ts，识别UserType.TALENT
  - [x] 确保人才用户token验证逻辑正确
  - [x] 添加人才用户权限验证逻辑

- [x] 任务5：编写单元测试和集成测试 (AC: 6)
  - [x] 测试人才用户登录成功场景（身份证号登录）
  - [x] 测试人才用户登录成功场景（残疾证号登录）
  - [x] 测试登录失败场景（错误的身份证号/残疾证号或密码）
  - [x] 测试获取用户信息接口
  - [x] 测试认证中间件识别人才用户
  - [x] 测试权限验证逻辑

- [x] 任务6：添加OpenAPI文档和TypeScript类型 (AC: 7)
  - [x] 为所有新接口添加OpenAPI元数据
  - [x] 定义请求/响应Schema
  - [x] 确保类型安全导出

## 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 |
| 2025-12-24 | 1.2 | 完成实施 - 添加人才用户认证API | Dev Agent |
| 2025-12-25 | 1.3 | 完成测试验证和DoD检查 - 16/16测试通过 | Dev Agent |

## Dev Agent Record
*此部分由开发代理在实施过程中填写*

### Agent Model Used
claude-sonnet (via BMad Dev Agent)

### Debug Log References
无重大调试问题

### Completion Notes List
1. 创建了人才认证Schema (rencai-auth.schema.ts) - 支持身份证号/残疾证号登录
2. 扩展AuthService添加talentLogin方法
3. 扩展UserService添加残疾人查询方法
4. 创建人才认证路由 (login, logout, me)
5. 创建人才认证中间件 (talent-auth.middleware.ts)
6. 添加core-module对disability-module、order-module和bank-names-module的依赖
7. 创建集成测试框架和测试数据工厂
8. 修正中间件使用方式 - 在createRoute的middleware字段中指定，而非.use()
9. 修复person到personInfo的字段映射问题

注意事项:
- 集成测试需要完整的实体依赖链，由于DisabledPerson实体有多个关联实体（OrderPerson、EmploymentOrder、BankName等），测试setup需要包含所有依赖
- 类型安全：使用RPC推断类型而非直接导入schema类型（遵循UI包开发规范）
- 测试需要实际数据库连接以验证残疾人和用户的关联关系
- Hono中间件应在createRoute定义中使用middleware字段，而非在路由聚合时使用.use()
- UserEntity的person关系需要手动映射为响应中的personInfo字段

### File List
**新增文件:**
- `packages/core-module/auth-module/src/schemas/rencai-auth.schema.ts` - 人才认证Schema定义
- `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/middleware/talent-auth.middleware.ts` - 人才认证中间件
- `packages/core-module/auth-module/tests/integration/talent-auth.integration.test.ts` - 集成测试
- `packages/bank-names-module/src/entities/index.ts` - BankName实体导出文件（用于测试）

**修改文件:**
- `packages/core-module/auth-module/src/schemas/index.ts` - 添加人才Schema导出
- `packages/core-module/auth-module/src/routes/index.ts` - 添加人才路由导出
- `packages/core-module/auth-module/src/middleware/index.ts` - 添加人才中间件导出
- `packages/core-module/auth-module/src/services/auth.service.ts` - 添加talentLogin和verifyTalentUser方法
- `packages/core-module/user-module/src/services/user.service.ts` - 添加残疾人查询相关方法
- `packages/core-module/user-module/src/entities/user.entity.ts` - 添加disability-module导入
- `packages/core-module/package.json` - 添加allin-order-module和bank-names-module依赖
- `packages/core-module/auth-module/tests/utils/test-data-factory.ts` - 添加残疾人测试数据工厂方法
- `packages/core-module/vitest.config.ts` - 临时添加别名配置（后移除）

## QA Results
*此部分由QA代理在审查完成后填写*
