Prechádzať zdrojové kódy

docs(epic): 更新史诗012进度并添加故事012.002

- 更新史诗012最近更新日期为2025-12-16
- 添加故事012.002(企业用户认证API扩展)的提及
- 记录故事012.001完成状态和012.002草稿状态

🤖 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 1 týždeň pred
rodič
commit
1ea4bb196e

+ 1 - 1
docs/prd/epic-012-api-supplement-for-employer-mini-program.md

@@ -246,7 +246,7 @@
 
 **总体进度**:1/7 故事完成(14%)
 
-**最近更新**:2025-12-13 - 故事012.001完成,所有测试通过,代码已提交
+**最近更新**:2025-12-16 - 故事012.001完成,所有测试通过;故事012.002已创建(草稿状态)
 
 ---
 

+ 304 - 0
docs/stories/012.002.story.md

@@ -0,0 +1,304 @@
+# 故事 012.002:企业用户认证API扩展
+
+## 状态
+Draft
+
+## 故事
+**作为**企业用户,
+**我希望**使用手机号和密码登录,并获取关联的企业信息,
+**以便**能够安全访问用人方小程序的企业管理功能。
+
+## 验收标准
+从史诗文件复制的验收标准编号列表
+
+1. [ ] 企业用户可使用手机号和密码成功登录
+2. [ ] 企业用户登录后可获取包含企业详情的用户信息
+3. [ ] 企业用户可成功退出登录
+4. [ ] 认证中间件正确识别企业用户身份
+5. [ ] 企业用户权限验证逻辑正确
+6. [ ] 所有新增接口通过集成测试
+7. [ ] API文档完整,包含OpenAPI定义和TypeScript类型
+
+## 任务 / 子任务
+将故事分解为实施所需的具体任务和子任务。
+在相关处引用适用的验收标准编号。
+
+- [ ] 任务1:扩展auth-module,添加企业用户手机号密码登录接口(AC:1)
+  - [ ] 创建新的企业用户登录schema:`EnterpriseLoginSchema`,包含手机号和密码字段
+  - [ ] 创建新的企业用户登录路由:`enterprise-login.route.ts`,路径为`/api/v1/yongren/auth/login`
+  - [ ] 在`auth.service.ts`中添加`enterpriseLogin`方法,支持手机号密码验证
+  - [ ] 验证用户`company_id`字段不为空,确保是企业用户
+  - [ ] 生成JWT令牌,包含企业用户身份标识
+- [ ] 任务2:添加企业用户退出登录接口(AC:3)
+  - [ ] 创建企业用户退出登录路由:`enterprise-logout.route.ts`,路径为`/api/v1/yongren/auth/logout`
+  - [ ] 在`auth.service.ts`中扩展`logout`方法或创建新的`enterpriseLogout`方法
+  - [ ] 实现令牌失效逻辑(可选:添加到Redis黑名单)
+- [ ] 任务3:添加获取企业用户信息接口,包含关联的企业详情(AC:2)
+  - [ ] 创建获取企业用户信息路由:`enterprise-me.route.ts`,路径为`/api/v1/yongren/auth/me`
+  - [ ] 扩展`UserResponseSchema`或创建新的`EnterpriseUserResponseSchema`,包含`company`字段详情
+  - [ ] 在服务层添加方法,通过`company_id`关联查询`employer_company`表数据
+  - [ ] 返回包含企业详情(公司名称、联系人、联系方式等)的用户信息
+- [ ] 任务4:基于`users2`表的`company_id`字段验证企业用户权限(AC:5)
+  - [ ] 在`auth.service.ts`中添加`verifyEnterpriseUser`方法,验证用户是否有`company_id`
+  - [ ] 在企业用户登录逻辑中添加权限检查:只有`company_id`不为空的用户才能使用企业登录接口
+  - [ ] 创建企业用户专属的权限验证工具函数
+- [ ] 任务5:更新认证中间件,支持企业用户身份识别(AC:4)
+  - [ ] 扩展`auth.middleware.ts`中的`authMiddleware`函数,支持识别企业用户令牌
+  - [ ] 在企业用户令牌验证时,检查`company_id`字段存在性
+  - [ ] 为需要企业用户权限的接口创建专门的中间件:`enterpriseAuthMiddleware`
+- **企业用户创建方式说明**:企业用户不需要专门的注册接口。企业用户的创建是在管理后台的用户管理功能中完成的:管理员为用户配置企业关联(设置`company_id`字段),用户就被标记为企业用户。没有关联企业的用户就是普通用户。
+- [ ] 任务7:编写集成测试(AC:6)
+  - [ ] 创建企业用户认证的集成测试文件:`enterprise-auth.integration.test.ts`
+  - [ ] 测试各种场景:成功登录、错误密码、不存在的手机号、非企业用户登录等
+  - [ ] 测试企业用户信息接口返回正确的企业详情
+  - [ ] 测试认证中间件正确识别企业用户身份
+- [ ] 任务8:完善API文档和类型定义(AC:7)
+  - [ ] 为所有新增接口添加OpenAPI文档注释
+  - [ ] 生成TypeScript类型定义文件,供前端使用
+  - [ ] 更新模块的README文档,说明新增的企业用户认证功能
+
+## 开发笔记
+仅填充从docs文件夹中的实际工件提取的相关信息,与此故事相关:
+
+### 先前故事洞察
+故事012.001(数据库schema扩展)已完成的变更:
+1. **`users2`表已添加`company_id`字段**:可为空的外键字段,引用`employer_company.company_id` [来源:docs/stories/012.001.story.md#数据模型]
+2. **`UserEntity`已更新**:添加了`companyId`字段和`@ManyToOne`关联到`Company`实体 [来源:packages/core-module/user-module/src/entities/user.entity.ts:37-42]
+3. **`user.schema.ts`已更新**:在`UserSchemaMt`、`CreateUserDtoMt`、`UpdateUserDtoMt`中添加了`companyId`字段验证 [来源:packages/core-module/user-module/src/schemas/user.schema.ts:46-49, 118-121, 158-161]
+4. **依赖关系已建立**:相关模块已添加对`@d8d/allin-company-module`的依赖 [来源:docs/stories/012.001.story.md#文件列表]
+5. **向后兼容性保障**:所有新字段可为空,现有admin用户的`company_id`为NULL,不影响现有功能 [来源:docs/prd/epic-012-api-supplement-for-employer-mini-program.md#兼容性要求]
+
+### 数据模型
+基于现有实体定义和架构文档:
+
+**用户实体**(`packages/core-module/user-module/src/entities/user.entity.ts`):
+- 表名:`users2`(@Entity({ name: 'users2' }))[来源:packages/core-module/user-module/src/entities/user.entity.ts:7]
+- 主键:`id`(映射到用户ID列)[来源:packages/core-module/user-module/src/entities/user.entity.ts:9-10]
+- `companyId`字段:`@Column({ name: 'company_id', type: 'int', unsigned: true, nullable: true, comment: '公司ID,引用employer_company.company_id' })` [来源:packages/core-module/user-module/src/entities/user.entity.ts:37-38]
+- `company`关联:`@ManyToOne(() => Company, { nullable: true })`,`@JoinColumn({ name: 'company_id', referencedColumnName: 'id' })` [来源:packages/core-module/user-module/src/entities/user.entity.ts:40-42]
+- 认证相关字段:`username`、`password`、`phone`、`email`、`isDisabled`等 [来源:packages/core-module/user-module/src/entities/user.entity.ts:12-68]
+
+**公司实体**(`allin-packages/company-module/src/entities/company.entity.ts`):
+- 表名:`employer_company`(@Entity('employer_company'))[来源:allin-packages/company-module/src/entities/company.entity.ts:4]
+- 主键:`id`(映射到`company_id`列)[来源:allin-packages/company-module/src/entities/company.entity.ts:7-13]
+- 平台关联:`platformId`字段,关联到Platform实体 [来源:allin-packages/company-module/src/entities/company.entity.ts:15-22, 94-96]
+- 企业详情字段:
+  - `companyName`:公司名称(varchar(100),必填)[来源:allin-packages/company-module/src/entities/company.entity.ts:24-31]
+  - `contactPerson`:联系人(varchar(50),可为空)[来源:allin-packages/company-module/src/entities/company.entity.ts:33-40]
+  - `contactPhone`:联系电话(varchar(20),可为空)[来源:allin-packages/company-module/src/entities/company.entity.ts:42-49]
+  - `contactEmail`:联系邮箱(varchar(100),可为空)[来源:allin-packages/company-module/src/entities/company.entity.ts:51-58]
+  - `address`:地址(varchar(200),可为空)[来源:allin-packages/company-module/src/entities/company.entity.ts:60-67]
+  - `status`:状态(int,默认1,1-正常,0-禁用)[来源:allin-packages/company-module/src/entities/company.entity.ts:69-75]
+  - `createTime`:创建时间(timestamp,默认CURRENT_TIMESTAMP)[来源:allin-packages/company-module/src/entities/company.entity.ts:77-83]
+  - `updateTime`:更新时间(timestamp,默认CURRENT_TIMESTAMP,onUpdate更新)[来源:allin-packages/company-module/src/entities/company.entity.ts:85-92]
+- 唯一性约束:`companyName`和`platformId`组合唯一(@Index('idx_company_name_platform', ['companyName', 'platformId'], { unique: true }))[来源:allin-packages/company-module/src/entities/company.entity.ts:5]
+
+**用户Schema验证**(`packages/core-module/user-module/src/schemas/user.schema.ts`):
+- `UserSchemaMt`:已包含`companyId`字段验证(`z.number().int().positive().nullable()`)[来源:packages/core-module/user-module/src/schemas/user.schema.ts:46-49]
+- `CreateUserDtoMt`:已包含`companyId`字段验证(可选)[来源:packages/core-module/user-module/src/schemas/user.schema.ts:118-121]
+- `UpdateUserDtoMt`:已包含`companyId`字段验证(可选)[来源:packages/core-module/user-module/src/schemas/user.schema.ts:158-161]
+
+**认证Schema**(`packages/core-module/auth-module/src/schemas/auth.schema.ts`):
+- 现有`LoginSchema`:使用`username`和`password`字段 [来源:packages/core-module/auth-module/src/schemas/auth.schema.ts:3-12]
+- 需要新增`EnterpriseLoginSchema`:使用`phone`和`password`字段,或`phone`和`password`组合
+- `UserResponseSchema`:当前不包含`company`字段详情,需要扩展 [来源:packages/core-module/auth-module/src/schemas/auth.schema.ts:40-117]
+
+### API规范
+**API路径约定**(来自史诗012):
+- 所有用人方小程序的API路径统一使用 `api/v1/yongren` 前缀 [来源:docs/prd/epic-012-api-supplement-for-employer-mini-program.md#api路径约定]
+- 现有管理后台API保持不变,新增的用人方小程序API使用独立的路由前缀
+- 示例:企业用户登录:`POST /api/v1/yongren/auth/login` [来源:docs/prd/epic-012-api-supplement-for-employer-mini-program.md#api路径约定]
+
+**新增接口规范**:
+1. **企业用户手机号密码登录**:
+   - 路径:`POST /api/v1/yongren/auth/login`
+   - 请求体:`{ "phone": "13800138000", "password": "password123" }`
+   - 响应:`{ "token": "jwt.token", "user": { ...包含企业详情 } }`
+   - 状态码:200成功,401认证失败
+
+2. **企业用户退出登录**:
+   - 路径:`POST /api/v1/yongren/auth/logout`
+   - 请求头:`Authorization: Bearer <token>`
+   - 响应:`{ "message": "登出成功" }`
+   - 状态码:200成功
+
+3. **获取企业用户信息**:
+   - 路径:`GET /api/v1/yongren/auth/me`
+   - 请求头:`Authorization: Bearer <token>`
+   - 响应:包含完整用户信息和企业详情
+   - 状态码:200成功,401未授权
+
+**企业用户创建方式说明**:企业用户不需要专门的注册接口。企业用户的创建是在管理后台的用户管理功能中完成的:管理员为用户配置企业关联(设置`company_id`字段),用户就被标记为企业用户。没有关联企业的用户就是普通用户。
+
+**现有接口保持不变**:
+- 现有管理后台登录:`POST /auth/login`(使用username/password)
+- 现有用户信息:`GET /auth/me`
+- 现有退出登录:`POST /auth/logout`
+
+### 组件规范
+不适用(后端API故事)。
+
+### 文件位置
+基于项目结构和后端模块包规范 [来源:architecture/source-tree.md, architecture/backend-module-package-standards.md]:
+
+**核心认证模块位置**:
+- `packages/core-module/auth-module/src/routes/` - 现有路由文件位置
+- `packages/core-module/auth-module/src/services/` - 服务层文件位置
+- `packages/core-module/auth-module/src/schemas/` - Schema验证文件位置
+- `packages/core-module/auth-module/src/middleware/` - 中间件文件位置
+
+**新文件建议位置**:
+- `packages/core-module/auth-module/src/routes/enterprise-login.route.ts` - 企业用户登录路由
+- `packages/core-module/auth-module/src/routes/enterprise-logout.route.ts` - 企业用户退出登录路由
+- `packages/core-module/auth-module/src/routes/enterprise-me.route.ts` - 企业用户信息路由
+- `packages/core-module/auth-module/src/routes/enterprise-register.route.ts` - 企业用户注册路由(如需要)
+- `packages/core-module/auth-module/src/schemas/enterprise-auth.schema.ts` - 企业用户认证Schema
+- `packages/core-module/auth-module/src/middleware/enterprise-auth.middleware.ts` - 企业用户认证中间件
+
+**测试文件位置**:
+- `packages/core-module/auth-module/tests/integration/enterprise-auth.integration.test.ts` - 企业用户认证集成测试
+- `packages/core-module/auth-module/tests/unit/enterprise-auth.service.test.ts` - 企业用户认证服务单元测试
+
+**公司模块位置**:
+- `allin-packages/company-module/src/entities/company.entity.ts` - Company实体定义
+- `allin-packages/company-module/src/services/company.service.ts` - Company服务层
+
+### 技术约束
+基于技术栈和架构文档 [来源:architecture/tech-stack.md, architecture/backend-module-package-standards.md]:
+
+1. **技术栈约束**:
+   - 后端框架:Hono 4.8.5 [来源:architecture/tech-stack.md#现有技术栈维护]
+   - 数据库ORM:TypeORM 0.3.25 [来源:architecture/tech-stack.md#现有技术栈维护]
+   - 数据库:PostgreSQL 17 [来源:architecture/tech-stack.md#现有技术栈维护]
+   - 认证:JWT 9.0.2 [来源:architecture/tech-stack.md#现有技术栈维护]
+   - 测试框架:Vitest [来源:architecture/tech-stack.md#新技术添加]
+
+2. **API设计约束**:
+   - 使用Zod OpenAPI进行Schema验证和文档生成 [来源:architecture/backend-module-package-standards.md#验证系统规范]
+   - 遵循现有的路由聚合模式 [来源:architecture/backend-module-package-standards.md#路由层规范]
+   - 错误响应格式统一:`{ "success": false, "message": "...", "code": "..." }` [来源:architecture/backend-module-package-standards.md#错误处理规范]
+
+3. **安全约束**:
+   - JWT令牌必须包含必要的最小用户信息
+   - 密码必须加密存储(现有`UserService.verifyPassword`方法)
+   - 企业用户必须通过`company_id`验证
+   - 令牌过期时间配置合理
+
+4. **性能约束**:
+   - 登录响应时间 < 200ms(现有测试基准)[来源:packages/core-module/auth-module/tests/integration/auth.integration.test.ts:381-397]
+   - 数据库查询需要适当的索引优化
+
+5. **向后兼容性**:
+   - 现有管理后台认证功能不受影响
+   - 新增接口使用独立的路由前缀`/api/v1/yongren`
+   - 现有用户数据保持不变
+
+### 项目结构说明
+基于monorepo结构和模块化包架构 [来源:architecture/source-tree.md]:
+
+1. **模块化架构**:
+   - `packages/core-module/` - 核心模块,包含auth-module、user-module等
+   - `allin-packages/` - Allin系统移植的业务模块
+   - 认证模块位于`packages/core-module/auth-module/`,是企业用户认证的基础
+
+2. **依赖关系**:
+   - `auth-module`依赖`user-module`进行用户数据操作
+   - `user-module`已添加对`@d8d/allin-company-module`的依赖(故事012.001完成)
+   - 企业用户认证需要查询`Company`实体,通过`company_id`关联
+
+3. **路由结构**:
+   - 现有认证路由:`/auth/login`, `/auth/logout`, `/auth/me`等
+   - 新增企业认证路由:`/api/v1/yongren/auth/login`, `/api/v1/yongren/auth/logout`, `/api/v1/yongren/auth/me`
+   - 需要在服务器层配置路由前缀,或在新路由文件中定义完整路径
+
+4. **代码组织**:
+   - 遵循后端模块包规范 [来源:architecture/backend-module-package-standards.md]
+   - 实体、服务、路由、Schema分层清晰
+   - 测试文件与源码对应,位于`tests/`目录
+
+### 测试
+列出开发者需要遵循的相关测试标准:
+
+#### 测试文件位置
+基于测试策略文档 [来源:architecture/testing-strategy.md]:
+- 单元测试:`packages/core-module/auth-module/tests/unit/**/*.test.ts` [来源:architecture/testing-strategy.md#单元测试](此故事不需要)
+- 集成测试:`packages/core-module/auth-module/tests/integration/**/*.test.ts` [来源:architecture/testing-strategy.md#集成测试]
+- 测试基础设施:使用`@d8d/shared-test-util`提供的工具 [来源:architecture/testing-strategy.md#集成测试]
+
+#### 测试标准
+基于测试策略文档 [来源:architecture/testing-strategy.md]:
+- 测试框架:Vitest [来源:architecture/testing-strategy.md#单元测试]
+- API测试:使用`hono/testing`进行API端点测试 [来源:architecture/testing-strategy.md#集成测试]
+- 数据库测试:使用测试数据库和事务回滚 [来源:architecture/testing-strategy.md#数据库测试策略]
+- 覆盖率要求:单元测试 ≥ 80%,集成测试 ≥ 60% [来源:architecture/testing-strategy.md#测试覆盖率标准](注意:此故事仅要求集成测试)
+- 测试数据管理:使用`TestDataFactory`创建测试数据 [来源:packages/core-module/auth-module/tests/integration/auth.integration.test.ts:12]
+
+#### 测试框架和模式
+基于现有认证集成测试模式 [来源:packages/core-module/auth-module/tests/integration/auth.integration.test.ts]:
+1. **集成测试模式**:
+   - 使用`setupIntegrationDatabaseHooksWithEntities`设置测试数据库
+   - 使用`testClient`创建Hono测试客户端
+   - 每个测试前清理测试数据,避免唯一性约束冲突
+   - 使用`TestDataFactory`创建一致的测试数据
+
+2. **测试场景覆盖**:
+   - 成功场景:正确凭据登录、获取用户信息、退出登录
+   - 失败场景:错误密码、不存在的用户、禁用账户、无效令牌
+   - 权限场景:企业用户权限验证、非企业用户访问限制
+   - 性能场景:响应时间基准测试
+
+3. **断言模式**:
+   - 验证HTTP状态码:`expect(response.status).toBe(200)`
+   - 验证响应数据结构:`expect(responseData).toHaveProperty('token')`
+   - 验证业务逻辑:`expect(responseData.user.companyId).toBe(1)`
+   - 验证错误消息:`expect(responseData.message).toContain('用户名或密码错误')`
+
+#### 此故事的特定测试要求
+1. **企业用户登录测试**:
+   - 测试企业用户使用手机号和密码成功登录
+   - 测试非企业用户(`company_id`为NULL)无法使用企业登录接口
+   - 测试错误密码、不存在的手机号等失败场景
+   - 测试响应包含企业详情信息
+
+2. **企业用户信息测试**:
+   - 测试企业用户信息接口返回正确的企业详情
+   - 测试非企业用户信息接口不返回企业详情
+   - 测试企业详情包含公司名称、联系人等字段
+
+3. **认证中间件测试**:
+   - 测试企业用户中间件正确识别企业用户身份
+   - 测试企业用户中间件拒绝非企业用户访问
+   - 测试现有中间件不受影响
+
+4. **权限验证测试**:
+   - 测试企业用户权限验证逻辑正确
+   - 测试只有关联了企业的用户才能访问企业相关接口
+   - 测试权限错误返回正确的HTTP状态码
+
+5. **API文档测试**:
+   - 验证OpenAPI文档生成正确
+   - 验证TypeScript类型定义完整
+
+## 变更日志
+跟踪对此故事文档所做的更改
+
+| 日期 | 版本 | 描述 | 作者 |
+|------|------|------|------|
+| 2025-12-14 | 1.0 | 初始故事创建 | Bob(Scrum Master) |
+| 2025-12-14 | 1.1 | 添加Company实体字段详细信息 | Bob(Scrum Master) |
+| 2025-12-14 | 1.2 | 澄清企业用户创建方式,移除注册接口需求 | Bob(Scrum Master) |
+| 2025-12-14 | 1.3 | 更新测试要求:仅需要集成测试,移除单元测试要求 | Bob(Scrum Master) |
+
+## 开发代理记录
+此部分由开发代理在实施过程中填充
+
+### 使用的代理模型
+
+### 调试日志引用
+
+### 完成笔记列表
+
+### 文件列表
+
+## QA结果
+来自QA代理对已完成故事实施的QA审查结果