012.002.story.md 22 KB

故事 012.002:企业用户认证API扩展

状态

Ready for Review

故事

作为企业用户, 我希望使用手机号和密码登录,并获取关联的企业信息, 以便能够安全访问用人方小程序的企业管理功能。

验收标准

从史诗文件复制的验收标准编号列表

  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已更新:在UserSchemaMtCreateUserDtoMtUpdateUserDtoMt中添加了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]
  • 认证相关字段:usernamepasswordphoneemailisDisabled等 [来源: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]
  • 唯一性约束:companyNameplatformId组合唯一(@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]

认证Schemapackages/core-module/auth-module/src/schemas/auth.schema.ts):

  • 现有LoginSchema:使用usernamepassword字段 [来源:packages/core-module/auth-module/src/schemas/auth.schema.ts:3-12]
  • 需要新增EnterpriseLoginSchema:使用phonepassword字段,或phonepassword组合
  • 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)

开发代理记录

此部分由开发代理在实施过程中填充

使用的代理模型

Claude Sonnet (2025-12-16) - 作为James开发人员实施故事012.002的所有任务

调试日志引用

完成笔记列表

  1. 企业用户认证功能完整实现:成功为企业用户添加了手机号和密码登录、退出登录、获取企业信息等功能
  2. 认证中间件扩展:创建了专门的企业用户认证中间件enterpriseAuthMiddleware,验证用户是否关联企业
  3. 数据库查询优化:在UserService中添加了getUserWithCompany方法,通过company_id关联查询企业详情
  4. 权限验证逻辑:实现了verifyEnterpriseUser方法,基于users2表的company_id字段验证企业用户权限
  5. API文档完整:所有新增接口都包含OpenAPI文档注释,TypeScript类型定义完整
  6. 集成测试覆盖全面:创建了12个集成测试用例,覆盖所有验收标准和各种场景
  7. 依赖管理:添加了必要的@d8d/allin-platform-module依赖,确保Company实体能正确关联Platform实体
  8. 测试通过:所有12个集成测试用例全部通过,包含成功场景和失败场景测试
  9. 向后兼容性保障:现有管理后台认证功能不受影响,新增接口使用独立的路由前缀/api/v1/yongren

文件列表

新建文件

  1. packages/core-module/auth-module/src/schemas/auth.schema.ts - 添加了EnterpriseLoginSchema, EnterpriseUserResponseSchema, EnterpriseTokenResponseSchema等企业用户认证Schema
  2. packages/core-module/auth-module/src/routes/enterprise-login.route.ts - 企业用户手机号密码登录路由,路径为POST /api/v1/yongren/auth/login
  3. packages/core-module/auth-module/src/routes/enterprise-logout.route.ts - 企业用户退出登录路由,路径为POST /api/v1/yongren/auth/logout
  4. packages/core-module/auth-module/src/routes/enterprise-me.route.ts - 获取企业用户信息路由,路径为GET /api/v1/yongren/auth/me,返回包含企业详情的用户信息
  5. packages/core-module/auth-module/src/middleware/enterprise-auth.middleware.ts - 企业用户认证中间件,验证用户是否是企业用户
  6. packages/core-module/auth-module/tests/integration/enterprise-auth.integration.test.ts - 企业用户认证集成测试,包含12个测试用例覆盖所有验收标准

修改的现有文件

  1. packages/core-module/auth-module/src/services/auth.service.ts - 添加enterpriseLoginverifyEnterpriseUser方法
  2. packages/core-module/user-module/src/services/user.service.ts - 添加getUserWithCompany方法,通过company_id关联查询企业详情
  3. packages/core-module/auth-module/src/routes/index.ts - 导入并注册新的企业用户认证路由
  4. packages/core-module/auth-module/src/middleware/index.ts - 导出enterpriseAuthMiddleware
  5. packages/core-module/auth-module/src/schemas/index.ts - 导出企业用户认证相关的Schema
  6. packages/core-module/package.json - 添加@d8d/allin-platform-module依赖,以支持Company实体关联Platform实体

依赖更新

  • packages/core-module/package.json中添加了@d8d/allin-platform-module: "workspace:*"依赖
  • 运行pnpm install安装了新的依赖包

QA结果

来自QA代理对已完成故事实施的QA审查结果