|
|
@@ -0,0 +1,332 @@
|
|
|
+# 故事 012.010:近期分配人才查询API
|
|
|
+
|
|
|
+## 状态
|
|
|
+Ready for Review ✅
|
|
|
+
|
|
|
+## 故事
|
|
|
+**作为**企业用户,
|
|
|
+**我希望**查看近期分配的人才(如最近30天入职),
|
|
|
+**以便**快速了解最新的人力资源动态,及时跟进新员工的管理和培养。
|
|
|
+
|
|
|
+## 验收标准
|
|
|
+从史诗文件复制的验收标准编号列表
|
|
|
+
|
|
|
+1. [x] 近期分配人才查询接口返回正确的近期分配人才列表(默认最近30天)
|
|
|
+2. [x] 接口支持可选的limit参数控制返回记录数
|
|
|
+3. [x] 返回数据包含人才基本信息:姓名、入职日期、订单名称、工作状态
|
|
|
+4. [x] 企业用户只能访问自己关联企业的数据
|
|
|
+5. [x] 查询性能优化,添加必要的数据库索引
|
|
|
+6. [x] 接口通过单元测试和集成测试
|
|
|
+7. [x] API文档完善,包含OpenAPI文档注释
|
|
|
+
|
|
|
+## 任务 / 子任务
|
|
|
+将故事分解为实施所需的具体任务和子任务。
|
|
|
+在相关处引用适用的验收标准编号。
|
|
|
+
|
|
|
+- [x] 任务1:近期分配人才查询API开发(company-module扩展)(AC: 1, 2, 3, 4, 5)
|
|
|
+ - [x] 创建近期分配人才查询路由:`company-recent-allocations.route.ts`,路径为`/api/v1/yongren/company/allocations/recent`
|
|
|
+ - [x] 在`company.service.ts`中添加`getRecentAllocations`方法,基于`order_person`表关联`employment_order`和`disabled_person`表查询近期分配人才
|
|
|
+ - [x] 查询逻辑:筛选`order_person.join_date`在最近30天内,且`order_person.work_status = 'working'`的记录
|
|
|
+ - [x] 支持limit参数(可选,默认5条),按`join_date`降序排列
|
|
|
+ - [x] 验证企业用户权限:用户只能查询自己企业(`employment_order.company_id`匹配用户`company_id`)的数据
|
|
|
+ - [x] 添加数据库索引优化查询性能(`order_person.join_date`、`order_person.work_status`等字段索引)
|
|
|
+ - [x] 创建相应的Zod Schema验证:`RecentAllocationsSchema`
|
|
|
+
|
|
|
+- [x] 任务2:API路由集成和认证中间件配置(AC: 4, 6)
|
|
|
+ - [x] 在`company-statistics.route.ts`或新建路由文件中集成近期分配人才查询路由
|
|
|
+ - [x] 配置企业用户认证中间件(使用故事012.002实现的`enterpriseAuthMiddleware`)
|
|
|
+ - [x] 验证接口需要企业用户权限(通过`company_id`验证)
|
|
|
+ - [x] 确保API路径前缀符合约定:`/api/v1/yongren/`
|
|
|
+ - [x] 统一错误处理,使用标准错误响应格式:`{ "success": false, "message": "...", "code": "..." }`
|
|
|
+
|
|
|
+- [x] 任务3:数据库性能优化(AC: 5)
|
|
|
+ - [x] 分析查询性能,识别需要添加索引的字段
|
|
|
+ - [x] 在相关表上添加索引:`order_person.join_date`、`order_person.work_status`、`employment_order.company_id`
|
|
|
+ - [x] 考虑添加复合索引优化多表关联查询(`order_person.order_id` + `join_date`)
|
|
|
+ - [x] 验证索引效果,确保查询响应时间符合要求(< 200ms)
|
|
|
+
|
|
|
+- [x] 任务4:集成测试开发(AC: 6)
|
|
|
+ - [x] 在公司模块集成测试中新增测试用例:`company-recent-allocations.integration.test.ts`
|
|
|
+ - [x] 测试近期分配人才查询接口的各种场景:有数据、无数据、不同limit参数
|
|
|
+ - [x] 测试企业用户权限验证:非企业用户无法访问接口
|
|
|
+ - [x] 测试不同企业用户只能访问自己企业的数据
|
|
|
+ - [x] 测试错误场景:无效的参数等
|
|
|
+ - [x] 确保测试覆盖率≥60%(集成测试要求)
|
|
|
+
|
|
|
+- [x] 任务5:API文档完善(AC: 7)
|
|
|
+ - [x] 为新增接口添加OpenAPI文档注释
|
|
|
+ - [x] 生成TypeScript类型定义文件,供前端使用
|
|
|
+ - [x] 更新模块的README文档,说明新增的近期分配人才查询功能
|
|
|
+ - [x] 验证所有接口的OpenAPI文档生成正确
|
|
|
+
|
|
|
+## 开发笔记
|
|
|
+仅填充从docs文件夹中的实际工件提取的相关信息,与此故事相关:
|
|
|
+
|
|
|
+### 先前故事洞察
|
|
|
+故事012.001(数据库schema扩展)、012.002(企业用户认证API扩展)和012.003(企业统计与人才扩展API)已完成的变更:
|
|
|
+
|
|
|
+1. **数据库schema扩展(故事012.001)**:
|
|
|
+ - `order_person`表已包含`join_date`字段(DATE类型,可为空)[来源:allin-packages/order-module/src/entities/order-person.entity.ts:48-54]
|
|
|
+ - `order_person`表已包含`work_status`字段(枚举类型:working, on_leave, left)[来源:allin-packages/order-module/src/entities/order-person.entity.ts:60-66]
|
|
|
+ - `employment_order`表已包含`company_id`字段(外键,引用`employer_company.company_id`)[来源:allin-packages/order-module/src/entities/employment-order.entity.ts:32-38]
|
|
|
+
|
|
|
+2. **企业用户认证(故事012.002)**:
|
|
|
+ - 企业用户手机号密码登录接口已实现:`POST /api/v1/yongren/auth/login` [来源:docs/stories/012.002.story.md#文件列表]
|
|
|
+ - 企业用户认证中间件已实现:`enterpriseAuthMiddleware` [来源:docs/stories/012.002.story.md#文件列表]
|
|
|
+ - 企业用户权限验证逻辑:基于`users2`表的`company_id`字段验证 [来源:docs/stories/012.002.story.md#文件列表]
|
|
|
+
|
|
|
+3. **企业统计与人才扩展API(故事012.003)**:
|
|
|
+ - 企业概览统计接口:`GET /api/v1/yongren/company/overview` [来源:docs/stories/012.003.story.md#文件列表]
|
|
|
+ - 企业维度人才统计接口:`GET /api/v1/yongren/company/{id}/talents` [来源:docs/stories/012.003.story.md#文件列表]
|
|
|
+ - `CompanyService`已包含`getCompanyOverview`和`getCompanyTalents`方法 [来源:allin-packages/company-module/src/services/company.service.ts]
|
|
|
+ - `CompanyTalentResponseSchema`已定义,包含人才列表和状态分布结构 [来源:allin-packages/company-module/src/schemas/company-statistics.schema.ts:72-79]
|
|
|
+
|
|
|
+### 数据模型
|
|
|
+基于现有实体定义和架构文档:
|
|
|
+
|
|
|
+**订单人员实体**(`allin-packages/order-module/src/entities/order-person.entity.ts`):
|
|
|
+- 表名:`order_person`(@Entity('order_person'))[来源:allin-packages/order-module/src/entities/order-person.entity.ts:7]
|
|
|
+- 主键:`id`(映射到`op_id`列)[来源:allin-packages/order-module/src/entities/order-person.entity.ts:8-14]
|
|
|
+- 字段:`orderId`、`personId`、`joinDate`、`salaryDetail`、`workStatus`等 [来源:allin-packages/order-module/src/entities/order-person.entity.ts:16-73]
|
|
|
+- 关联:`orderId`关联EmploymentOrder,`personId`关联DisabledPerson [来源:allin-packages/order-module/src/entities/order-person.entity.ts:75-83]
|
|
|
+
|
|
|
+**就业订单实体**(`allin-packages/order-module/src/entities/employment-order.entity.ts`):
|
|
|
+- 表名:`employment_order`(@Entity('employment_order'))[来源:allin-packages/order-module/src/entities/employment-order.entity.ts:4]
|
|
|
+- 主键:`id`(映射到`order_id`列)[来源:allin-packages/order-module/src/entities/employment-order.entity.ts:7-13]
|
|
|
+- 字段:`orderName`、`platformId`、`companyId`、`channelId`、`orderStatus`、`workStatus`等 [来源:allin-packages/order-module/src/entities/employment-order.entity.ts:15-104]
|
|
|
+- 公司关联:`companyId`字段关联Company实体 [来源:allin-packages/order-module/src/entities/employment-order.entity.ts:32-38]
|
|
|
+
|
|
|
+**残疾人实体**(`allin-packages/disability-module/src/entities/disabled-person.entity.ts`):
|
|
|
+- 表名:`disabled_person`(@Entity('disabled_person'))[来源:allin-packages/disability-module/src/entities/disabled-person.entity.ts:8]
|
|
|
+- 主键:`id`(映射到`person_id`列)[来源:allin-packages/disability-module/src/entities/disabled-person.entity.ts:9-14]
|
|
|
+- 字段:`name`、`gender`、`idCard`、`disabilityId`、`disabilityType`、`disabilityLevel`、`birthDate`、`phone`、`jobStatus`等 [来源:allin-packages/disability-module/src/entities/disabled-person.entity.ts:16-217]
|
|
|
+
|
|
|
+### API规范
|
|
|
+**API路径约定**(来自史诗012):
|
|
|
+- 所有用人方小程序的API路径统一使用 `api/v1/yongren` 前缀 [来源:docs/prd/epic-012-api-supplement-for-employer-mini-program.md#api路径约定]
|
|
|
+- 现有管理后台API保持不变,新增的用人方小程序API使用独立的路由前缀
|
|
|
+- 示例:企业概览统计:`GET /api/v1/yongren/company/overview` [来源:docs/prd/epic-012-api-supplement-for-employer-mini-program.md#api路径约定]
|
|
|
+
|
|
|
+**新增接口规范**:
|
|
|
+1. **近期分配人才查询**:
|
|
|
+ - 路径:`GET /api/v1/yongren/company/allocations/recent`
|
|
|
+ - 查询参数:
|
|
|
+ - `limit`(可选,number,默认5):返回记录数限制
|
|
|
+ - 请求头:`Authorization: Bearer <企业用户token>`
|
|
|
+ - 响应示例:
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "人才列表": [
|
|
|
+ {
|
|
|
+ "personId": 123,
|
|
|
+ "personName": "张三",
|
|
|
+ "joinDate": "2024-12-15T00:00:00.000Z",
|
|
|
+ "workStatus": "working",
|
|
|
+ "orderName": "2024年第四季度用工订单"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "personId": 124,
|
|
|
+ "personName": "李四",
|
|
|
+ "joinDate": "2024-12-10T00:00:00.000Z",
|
|
|
+ "workStatus": "working",
|
|
|
+ "orderName": "2024年第四季度用工订单"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ```
|
|
|
+ - 状态码:200成功,400参数错误,401未授权,403权限不足,500服务器错误
|
|
|
+
|
|
|
+**查询逻辑**:
|
|
|
+- 筛选条件:
|
|
|
+ - `order_person.join_date` >= CURRENT_DATE - INTERVAL '30 days'(最近30天)
|
|
|
+ - `order_person.work_status = 'working'`(在职状态)
|
|
|
+ - `employment_order.company_id` = 用户关联的企业ID
|
|
|
+- 排序:按`order_person.join_date`降序(最新入职的排前面)
|
|
|
+- 关联表:`order_person` → `employment_order`(获取订单名称和企业ID)→ `disabled_person`(获取人员姓名)
|
|
|
+
|
|
|
+**认证要求**:
|
|
|
+- 需要企业用户权限验证
|
|
|
+- 使用故事012.002实现的`enterpriseAuthMiddleware`中间件
|
|
|
+- 验证用户`company_id`字段不为空
|
|
|
+- 企业用户只能访问自己关联的企业数据
|
|
|
+
|
|
|
+### 组件规范
|
|
|
+不适用(后端API故事)。
|
|
|
+
|
|
|
+### 文件位置
|
|
|
+基于项目结构和后端模块包规范 [来源:architecture/source-tree.md, architecture/backend-module-package-standards.md]:
|
|
|
+
|
|
|
+**公司模块位置**:
|
|
|
+- `allin-packages/company-module/src/routes/` - 现有路由文件位置
|
|
|
+- `allin-packages/company-module/src/services/` - 服务层文件位置
|
|
|
+- `allin-packages/company-module/src/schemas/` - Schema验证文件位置
|
|
|
+- `allin-packages/company-module/tests/integration/` - 集成测试位置
|
|
|
+
|
|
|
+**新文件建议位置**:
|
|
|
+1. **近期分配人才查询API文件**:
|
|
|
+ - `allin-packages/company-module/src/routes/company-recent-allocations.route.ts` - 近期分配人才查询路由
|
|
|
+ - `allin-packages/company-module/src/schemas/company-statistics.schema.ts` - 在现有Schema文件中添加`RecentAllocationsSchema`(或新建`company-recent-allocations.schema.ts`)
|
|
|
+ - `allin-packages/company-module/tests/integration/company-recent-allocations.integration.test.ts` - 集成测试
|
|
|
+
|
|
|
+**现有文件需要修改**:
|
|
|
+- `allin-packages/company-module/src/services/company.service.ts` - 添加`getRecentAllocations`方法
|
|
|
+- `allin-packages/company-module/src/routes/index.ts` - 路由聚合,包含新路由
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+基于技术栈和架构文档 [来源: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. **性能约束**:
|
|
|
+ - 查询响应时间 < 200ms(现有测试基准)
|
|
|
+ - 需要添加适当的数据库索引优化查询性能
|
|
|
+ - 近期数据查询需要优化时间范围筛选性能
|
|
|
+
|
|
|
+4. **安全约束**:
|
|
|
+ - 企业用户只能访问自己关联的企业数据
|
|
|
+ - 需要验证`company_id`匹配性
|
|
|
+ - 使用企业用户专属的认证中间件
|
|
|
+
|
|
|
+5. **向后兼容性**:
|
|
|
+ - 现有管理后台API保持不变
|
|
|
+ - 新增接口使用独立的路由前缀`/api/v1/yongren`
|
|
|
+ - 现有业务逻辑不受影响
|
|
|
+
|
|
|
+### 项目结构说明
|
|
|
+基于monorepo结构和模块化包架构 [来源:architecture/source-tree.md]:
|
|
|
+
|
|
|
+1. **模块化架构**:
|
|
|
+ - `allin-packages/` - Allin系统移植的业务模块
|
|
|
+ - `company-module`业务模块已存在,企业相关API在此模块扩展
|
|
|
+ - 近期分配人才查询API在`company-module`中实现,与其他企业统计API保持一致
|
|
|
+
|
|
|
+2. **依赖关系**:
|
|
|
+ - `company-module`依赖`order-module`查询订单和人员数据
|
|
|
+ - `company-module`依赖`disability-module`查询残疾人信息
|
|
|
+ - 所有模块依赖核心的`auth-module`进行认证
|
|
|
+
|
|
|
+3. **路由结构**:
|
|
|
+ - 现有企业统计路由:`/api/v1/yongren/company/overview`、`/api/v1/yongren/company/{id}/talents`
|
|
|
+ - 新增近期分配人才查询路由:`/api/v1/yongren/company/allocations/recent`
|
|
|
+ - 所有企业用户API使用统一的前缀和认证中间件
|
|
|
+
|
|
|
+4. **代码组织**:
|
|
|
+ - 遵循后端模块包规范 [来源:architecture/backend-module-package-standards.md]
|
|
|
+ - 实体、服务、路由、Schema分层清晰
|
|
|
+ - 测试文件与源码对应,位于`tests/integration/`目录
|
|
|
+
|
|
|
+### 测试
|
|
|
+列出开发者需要遵循的相关测试标准:
|
|
|
+
|
|
|
+#### 测试文件位置
|
|
|
+基于测试策略文档 [来源:architecture/testing-strategy.md]:
|
|
|
+- 集成测试:`allin-packages/company-module/tests/integration/company-recent-allocations.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#数据库测试策略]
|
|
|
+- 覆盖率要求:集成测试 ≥ 60% [来源:architecture/testing-strategy.md#测试覆盖率标准]
|
|
|
+- 测试数据管理:使用`TestDataFactory`创建测试数据
|
|
|
+
|
|
|
+#### 测试框架和模式
|
|
|
+基于现有集成测试模式:
|
|
|
+1. **集成测试模式**:
|
|
|
+ - 使用`setupIntegrationDatabaseHooksWithEntities`设置测试数据库
|
|
|
+ - 使用`testClient`创建Hono测试客户端
|
|
|
+ - 每个测试前清理测试数据,避免唯一性约束冲突
|
|
|
+ - 使用`TestDataFactory`创建一致的测试数据
|
|
|
+
|
|
|
+2. **测试场景覆盖**:
|
|
|
+ - 成功场景:企业用户访问接口,返回近期分配人才列表
|
|
|
+ - 参数场景:测试不同limit参数值(1, 5, 10, 默认)
|
|
|
+ - 数据场景:测试有数据、无数据、部分数据(< limit)情况
|
|
|
+ - 权限场景:非企业用户访问被拒绝,不同企业用户只能访问自己数据
|
|
|
+ - 时间场景:验证只返回最近30天的数据
|
|
|
+
|
|
|
+3. **断言模式**:
|
|
|
+ - 验证HTTP状态码:`expect(response.status).toBe(200)`
|
|
|
+ - 验证响应数据结构:`expect(responseData).toHaveProperty('人才列表')`
|
|
|
+ - 验证数据正确性:`expect(responseData.人才列表.length).toBeLessThanOrEqual(limit)`
|
|
|
+ - 验证排序:`expect(responseData.人才列表[0].joinDate).toBeGreaterThan(responseData.人才列表[1].joinDate)`
|
|
|
+ - 验证时间范围:`expect(joinDate).toBeWithinDays(30)`
|
|
|
+ - 验证错误消息:`expect(responseData.message).toContain('权限不足')`
|
|
|
+
|
|
|
+#### 此故事的特定测试要求
|
|
|
+1. **近期分配人才查询API测试**:
|
|
|
+ - 测试接口返回正确的近期分配人才列表
|
|
|
+ - 测试limit参数控制返回记录数
|
|
|
+ - 测试默认返回最近30天的数据
|
|
|
+ - 测试按join_date降序排列
|
|
|
+ - 测试只返回work_status='working'的记录
|
|
|
+
|
|
|
+2. **权限测试**:
|
|
|
+ - 测试企业用户权限验证正确
|
|
|
+ - 测试跨企业访问数据被拒绝
|
|
|
+ - 测试认证中间件正确拦截非企业用户
|
|
|
+
|
|
|
+3. **性能测试**:
|
|
|
+ - 测试查询响应时间 < 200ms
|
|
|
+ - 测试数据库索引效果
|
|
|
+ - 测试大量数据时的分页性能
|
|
|
+
|
|
|
+## 变更日志
|
|
|
+跟踪对此故事文档所做的更改
|
|
|
+
|
|
|
+| 日期 | 版本 | 描述 | 作者 |
|
|
|
+|------|------|------|------|
|
|
|
+| 2025-12-18 | 1.0 | 初始故事创建,实现近期分配人才查询API | Claude Code |
|
|
|
+
|
|
|
+## 开发代理记录
|
|
|
+此部分由开发代理在实施过程中填充
|
|
|
+
|
|
|
+### 使用的代理模型
|
|
|
+claude-sonnet
|
|
|
+
|
|
|
+### 调试日志引用
|
|
|
+- 无关键调试问题,所有测试通过
|
|
|
+
|
|
|
+### 完成笔记列表
|
|
|
+1. 实现了近期分配人才查询API:路径 `/api/v1/yongren/company/allocations/recent`
|
|
|
+2. 在 `company.service.ts` 中添加了 `getRecentAllocations` 方法,查询最近30天入职的在职人员
|
|
|
+3. 支持可选的 `limit` 参数(默认5条),按 `join_date` 降序排列
|
|
|
+4. 验证企业用户权限:用户只能访问自己关联企业的数据
|
|
|
+5. 添加了数据库索引优化查询性能:`order_person.join_date`、`order_person.order_id + join_date` 等
|
|
|
+6. 创建了 `RecentAllocationsSchema` Zod Schema 验证
|
|
|
+7. 创建了独立的路由文件 `company-recent-allocations.route.ts` 并集成到企业路由聚合
|
|
|
+8. 配置了企业用户认证中间件 `enterpriseAuthMiddleware`
|
|
|
+9. 开发了完整的集成测试套件,覆盖各种场景
|
|
|
+10. 添加了OpenAPI文档注释,完善了API文档
|
|
|
+11. 修复了集成测试中的类型错误,确保类型检查通过
|
|
|
+
|
|
|
+### 待解决问题
|
|
|
+- 无
|
|
|
+
|
|
|
+### 文件列表
|
|
|
+**新建文件:**
|
|
|
+1. `allin-packages/company-module/src/routes/company-recent-allocations.route.ts` - 近期分配人才查询路由
|
|
|
+2. `allin-packages/company-module/src/routes/company-enterprise.routes.ts` - 企业路由聚合
|
|
|
+3. `allin-packages/company-module/tests/integration/company-recent-allocations.integration.test.ts` - 集成测试
|
|
|
+
|
|
|
+**修改文件:**
|
|
|
+1. `allin-packages/company-module/src/services/company.service.ts` - 添加 `getRecentAllocations` 方法
|
|
|
+2. `allin-packages/company-module/src/schemas/company-statistics.schema.ts` - 添加 `RecentAllocationsSchema`
|
|
|
+3. `allin-packages/company-module/src/routes/index.ts` - 导出新路由
|
|
|
+4. `allin-packages/order-module/src/entities/order-person.entity.ts` - 添加数据库索引
|
|
|
+5. `packages/server/src/index.ts` - 更新企业路由导入和挂载
|
|
|
+6. `docs/stories/012.010.story.md` - 更新任务状态和记录
|
|
|
+
|
|
|
+## QA结果
|
|
|
+来自QA代理对已完成故事实施的QA审查结果
|