007.005.transplant-order-management-module.story.md 14 KB

Story 007.005: 移植订单管理模块(order → @d8d/allin-order-module)

Status

Ready for Development

Story

As a 开发者, I want 将order模块从allin_system-master移植为独立包@d8d/allin-order-module,完成实体重构、文件模块集成和循环依赖处理, so that 我们可以将Allin系统的订单管理功能集成到当前项目中,遵循现有的模块化架构和编码标准,并实现与@d8d/file-module的文件集成和与@d8d/allin-disability-module的依赖解耦。

Acceptance Criteria

  1. 创建allin-packages/order-module目录结构
  2. 完成实体转换:3个实体(EmploymentOrder、OrderPerson、OrderPersonAsset)转换
  3. 枚举常量集成:使用@d8d/allin-enums包中的OrderStatusWorkStatus枚举
  4. 文件实体集成:修改OrderPersonAsset实体,添加fileId字段引用File实体
  5. 解决循环依赖:与disability-module的相互引用处理
  6. 完成服务层转换:订单业务逻辑,包含资产文件关联处理
  7. 完成路由层转换:Hono路由实现,API接收fileId参数
  8. 完成验证系统转换:订单相关验证,包含文件类型验证和枚举值验证
  9. 配置package.json:依赖管理,包含对@d8d/file-module@d8d/allin-enums的依赖
  10. 编写API集成测试:覆盖订单全生命周期,包含资产文件关联测试和枚举值测试
  11. 通过类型检查和基本测试验证
  12. 验证循环依赖解决方案的有效性

Tasks / Subtasks

1. 创建包结构和配置文件 (AC: 1)

  • 创建目录:allin-packages/order-module/
  • 初始化package.json:参考allin-packages/salary-module/package.json
    • 参考文件: allin-packages/salary-module/package.json
    • 修改点: 包名改为@d8d/allin-order-module,添加对@d8d/file-module@d8d/allin-enums的依赖
    • 关键依赖: @d8d/file-module, @d8d/allin-enums, @d8d/core-module, @d8d/shared-crud, @d8d/shared-utils
    • 注意吸取经验: 根据故事007.006的经验,需要在pnpm-workspace.yaml中添加allin-packages/*配置
  • 配置tsconfig.json:参考allin-packages/salary-module/tsconfig.json
    • 参考文件: allin-packages/salary-module/tsconfig.json
  • 配置vitest.config.ts:参考allin-packages/salary-module/vitest.config.ts
    • 参考文件: allin-packages/salary-module/vitest.config.ts
  • 配置workspace:在根目录pnpm-workspace.yaml中添加allin-packages/order-module
    • 修改文件: /mnt/code/188-179-template-6/pnpm-workspace.yaml
    • 添加内容: 'allin-packages/order-module'

2. 迁移实体文件 (AC: 2, 3, 4)

2.1 迁移EmploymentOrder实体

源文件路径: allin_system-master/server/src/order/employment_order.entity.ts 目标文件路径: allin-packages/order-module/src/entities/employment-order.entity.ts 参考对照文件:

  • allin-packages/salary-module/src/entities/salary-level.entity.ts(实体结构)
  • allin-packages/enums/src/enums/order-status.enum.ts(枚举引用)
  • allin-packages/enums/src/enums/work-status.enum.ts(枚举引用)

修改要点:

  1. 将主键字段名从orderId改为id以遵循GenericCrudService约定
  2. orderStatus字段类型从string改为OrderStatus枚举
  3. 添加workStatus字段,使用WorkStatus枚举
  4. 将下划线字段名转换为驼峰命名:order_nameorderName, platform_idplatformId
  5. 添加详细的TypeORM装饰器配置
  6. 保持数据库表名不变:@Entity('employment_order')

2.2 迁移OrderPerson实体

源文件路径: allin_system-master/server/src/order/order_person.entity.ts 目标文件路径: allin-packages/order-module/src/entities/order-person.entity.ts 参考对照文件:

  • allin-packages/disability-module/src/entities/disabled-person.entity.ts(实体结构)
  • 注意循环依赖: 原实体引用DisabledPerson实体,需要解耦处理

修改要点:

  1. 将主键字段名从opId改为id
  2. personId字段类型保持为number(不直接引用DisabledPerson实体)
  3. 将下划线字段名转换为驼峰命名
  4. 添加详细的TypeORM装饰器配置
  5. 保持数据库表名不变:@Entity('order_person')
  6. 循环依赖处理: 移除对DisabledPerson的直接引用,改为使用personId: number

2.3 迁移OrderPersonAsset实体

源文件路径: allin_system-master/server/src/order/order_person_asset.entity.ts 目标文件路径: allin-packages/order-module/src/entities/order-person-asset.entity.ts 参考对照文件:

  • allin-packages/disability-module/src/entities/disabled-photo.entity.ts(文件实体集成)
  • packages/file-module/src/entities/file.entity.ts(文件实体引用)

修改要点:

  1. 将主键字段名从opId改为id
  2. 文件模块集成: 移除assetUrl: string字段,添加fileId: number字段
  3. 添加与File实体的关联关系:@ManyToOne(() => File)
  4. 循环依赖处理: 移除对DisabledPerson的直接引用,改为使用personId: number
  5. AssetTypeAssetFileType枚举移到实体文件中(模块内部枚举)
  6. 将下划线字段名转换为驼峰命名
  7. 添加详细的TypeORM装饰器配置
  8. 保持数据库表名不变:@Entity('order_person_asset')

3. 创建DTO和Schema文件 (AC: 8)

目标文件路径:

  • allin-packages/order-module/src/dto/create-order.dto.ts
  • allin-packages/order-module/src/dto/update-order.dto.ts
  • allin-packages/order-module/src/dto/create-order-person.dto.ts
  • allin-packages/order-module/src/dto/create-order-person-asset.dto.ts
  • allin-packages/order-module/src/schemas/order.schema.ts

参考对照文件:

  • allin-packages/salary-module/src/dto/create-salary.dto.ts(DTO结构)
  • allin-packages/salary-module/src/dto/update-salary.dto.ts
  • allin-packages/salary-module/src/schemas/salary.schema.ts(Zod schema)
  • allin-packages/disability-module/src/schemas/disabled-person.schema.ts(文件ID验证)

修改要点:

  1. 将class-validator DTO转换为Zod Schema
  2. 在OrderPersonAsset的Schema中添加fileId验证
  3. 添加枚举值验证:使用OrderStatusWorkStatus枚举
  4. 保持与原始API相同的字段名和验证规则

4. 迁移控制器和服务 (AC: 6, 7)

4.1 迁移OrderService

源文件路径: allin_system-master/server/src/order/order.service.ts 目标文件路径: allin-packages/order-module/src/services/order.service.ts 参考对照文件:

  • allin-packages/salary-module/src/services/salary.service.ts(服务层结构)
  • allin-packages/disability-module/src/services/disabled-person.service.ts(文件验证逻辑)

修改要点:

  1. 将NestJS服务转换为继承GenericCrudService<EmploymentOrder>
  2. 循环依赖处理: 移除对DisabledPersonRepository的直接依赖
  3. 文件验证: 在创建/更新OrderPersonAsset时验证fileId的有效性
  4. 将业务逻辑从NestJS风格转换为Hono风格
  5. 保持原始的业务逻辑和错误处理

4.2 迁移OrderController为Hono路由

源文件路径: allin_system-master/server/src/order/order.controller.ts 目标文件路径: allin-packages/order-module/src/routes/order.routes.ts 参考对照文件:

  • allin-packages/salary-module/src/routes/salary.routes.ts(Hono路由结构)
  • allin-packages/disability-module/src/routes/disabled-person.routes.ts(文件ID参数处理)

修改要点:

  1. 将NestJS控制器转换为Hono路由
  2. 将class-validator管道验证转换为Zod验证
  3. 更新API端点路径,保持与原始API兼容
  4. 在OrderPersonAsset路由中添加fileId参数处理
  5. 配置OpenAPI文档

5. 创建模块主文件 (AC: 1)

目标文件路径:

  • allin-packages/order-module/src/index.ts
  • allin-packages/order-module/src/order.module.ts

参考对照文件:

  • allin-packages/salary-module/src/index.ts(导出结构)
  • allin-packages/salary-module/src/salary.module.ts(模块定义)

6. 创建测试文件 (AC: 10)

目标文件路径:

  • allin-packages/order-module/tests/unit/order.controller.test.ts
  • allin-packages/order-module/tests/unit/order.service.test.ts
  • allin-packages/order-module/tests/integration/order.integration.test.ts

参考对照文件:

  • allin-packages/salary-module/tests/unit/salary.controller.test.ts(单元测试结构)
  • allin-packages/salary-module/tests/integration/salary.integration.test.ts(集成测试结构)
  • allin-packages/disability-module/tests/integration/disability.integration.test.ts(文件集成测试)

测试重点:

  1. 枚举测试: 验证OrderStatusWorkStatus枚举的正确使用
  2. 文件集成测试: 测试OrderPersonAsset与File实体的关联
  3. 循环依赖测试: 验证与disability-module的解耦效果
  4. API兼容性测试: 验证与原始NestJS API的兼容性

7. 处理循环依赖 (AC: 5)

问题: 订单模块与disability-module存在相互引用 源文件分析:

  • 订单模块引用: DisabledPerson实体
  • 残疾人模块引用: EmploymentOrderOrderPerson实体

解决方案:

  1. 接口抽象: 在订单模块中创建PersonReference接口,避免直接引用DisabledPerson实体
  2. ID引用: 使用personId: number代替直接的实体引用
  3. 事件解耦: 通过事件或消息队列处理跨模块业务逻辑
  4. 参考处理: 参考allin-packages/salary-module@d8d/geo-areas的集成方式

实施步骤:

  1. 在订单模块中定义PersonReference类型
  2. 修改OrderPerson实体,使用personId: number代替person: DisabledPerson
  3. 修改OrderPersonAsset实体,使用personId: number代替person: DisabledPerson
  4. 在服务层通过ID验证人员存在性(可选:通过API调用验证)
  5. 更新残疾人管理模块,移除对订单实体的直接引用

8. 集成测试和验证 (AC: 11, 12)

  • 运行单元测试:pnpm test
  • 运行集成测试:pnpm test:integration
  • 类型检查:pnpm typecheck
  • 构建验证:pnpm build
  • 循环依赖验证:检查模块间导入关系

Dev Notes

从之前故事吸取的经验教训:

  1. 实体主键命名:确保所有实体使用id作为主键字段名,而不是orderIdopId等特定名称
  2. workspace配置:在根目录pnpm-workspace.yaml中添加新包路径'allin-packages/order-module'
  3. 测试依赖:集成测试需要配置测试数据库,参考salary-module的tests/integration/setup.ts
  4. 类型检查问题:使用pnpm typecheck检查类型错误,特别注意枚举导入和循环依赖
  5. API兼容性:保持与原始NestJS API相同的请求/响应格式
  6. 文件实体集成:正确配置与@d8d/file-module的关联关系,参考disabled-photo.entity.ts
  7. 枚举使用:通过@d8d/allin-enums包导入OrderStatus和WorkStatus枚举
  8. 区域包集成经验:参考salary-module与geo-areas的集成方式处理外部依赖

技术细节:

  1. OrderStatus和WorkStatus枚举集成

    import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
    
    @Column({
     name: 'order_status',
     type: 'enum',
     enum: OrderStatus,
     default: OrderStatus.DRAFT,
     comment: '订单状态'
    })
    orderStatus!: OrderStatus;
    
    @Column({
     name: 'work_status',
     type: 'enum',
     enum: WorkStatus,
     default: WorkStatus.NOT_WORKING,
     comment: '工作状态'
    })
    workStatus!: WorkStatus;
    
  2. OrderPersonAsset实体文件集成

    import { File } from '@d8d/file-module/entities';
    
    @Column({
     name: 'file_id',
     type: 'int',
     nullable: false,
     comment: '文件ID,引用files表'
    })
    fileId!: number;
    
    @ManyToOne(() => File)
    @JoinColumn({ name: 'file_id' })
    file!: File;
    
  3. 循环依赖处理方案

    // 原代码(有循环依赖):
    // @ManyToOne(() => DisabledPerson)
    // person!: DisabledPerson;
    
    // 新代码(解耦):
    @Column({
     name: 'person_id',
     type: 'int',
     nullable: false,
     comment: '人员ID'
    })
    personId!: number;
    
    // 可选:定义引用接口
    export interface PersonReference {
     id: number;
     name: string;
     idCard: string;
    }
    
  4. AssetType和AssetFileType枚举

    • 这些是模块内部枚举,不需要移到enums包
    • order-person-asset.entity.ts中定义即可
    • 保持与原始值一致:TAX = 'tax', SALARY = 'salary'

文件模块集成步骤:

  1. 安装依赖:@d8d/file-module
  2. 在OrderPersonAsset实体中建立与File实体的关联
  3. 在DTO中验证fileId的有效性
  4. 在服务层处理文件关联逻辑
  5. 在集成测试中模拟文件上传和关联

测试策略:

  1. 单元测试:覆盖所有控制器和服务方法
  2. 集成测试:测试数据库操作和API端点
  3. 枚举验证测试:测试OrderStatus和WorkStatus枚举的正确使用
  4. 文件关联测试:测试OrderPersonAsset与File实体的关联
  5. 循环依赖测试:验证解耦方案的有效性
  6. API兼容性测试:验证与原始NestJS API的兼容性

Dependencies

  • @d8d/allin-enums
  • @d8d/file-module
  • @d8d/shared-crud
  • @d8d/shared-utils
  • @d8d/shared-types
  • @d8d/auth-module
  • @d8d/user-module
  • typeorm
  • zod
  • hono
  • vitest (dev dependency)
  • @d8d/shared-test-util (dev dependency)

Test Plan

  1. 单元测试:覆盖所有控制器和服务方法
  2. 集成测试:测试数据库操作和API端点
  3. 枚举验证:测试OrderStatus和WorkStatus枚举的正确使用
  4. 文件关联测试:测试OrderPersonAsset与File实体的关联
  5. 循环依赖测试:验证与disability-module的解耦效果
  6. API兼容性测试:验证与原始NestJS API的兼容性

Definition of Done

  • 所有实体成功迁移并转换为TypeORM + Zod
  • 完整的CRUD API端点可用
  • 集成@d8d/allin-enums包中的枚举
  • 集成@d8d/file-module包,正确处理文件关联
  • 解决与disability-module的循环依赖
  • 所有测试通过(单元测试、集成测试)
  • 类型检查通过
  • 构建成功
  • 代码符合项目代码规范
  • 文档完整(README、API文档)

Dev Agent Record

将在开发完成后填写


故事创建时间:2025-12-02 创建者:Bob (Scrum Master) 更新说明:重新创建故事,吸取之前移植故事的经验教训,在任务中标注迁移文件的路径和参考对照文件的路径