Procházet zdrojové kódy

docs(story): 补充史诗007系列完整经验教训到订单管理模块故事

基于史诗007所有已完成故事(001-007)的经验教训:
1. 从007.001(渠道模块)吸取:布尔返回值处理、软删除考虑、路由聚合模式
2. 从007.002(公司模块)吸取:模块间依赖处理、复合唯一性检查、关联关系配置
3. 从007.003(枚举包)吸取:枚举值一致性、数字枚举处理、注释完整性
4. 从007.006(平台模块)吸取:基础依赖包设计、唯一性索引、错误信息明确
5. 更新关键经验教训总结为33条,分类为6个方面
6. 添加更多实施建议和代码示例

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname před 1 měsícem
rodič
revize
a285bc4857

+ 157 - 14
docs/stories/007.005.transplant-order-management-module.story.md

@@ -218,33 +218,80 @@ Ready for Development
 11. **枚举使用**:通过`@d8d/allin-enums`包导入OrderStatus和WorkStatus枚举
 12. **区域包集成经验**:参考salary-module与geo-areas的集成方式处理外部依赖
 
-### 关键经验教训总结(基于007.004和007.007):
+#### 从故事007.001(渠道管理模块)吸取的经验教训:
+1. **实体主键命名**:主键属性名应直接定义为`id`(而不是`channelId`)以遵循GenericCrudService约定
+2. **布尔返回值处理**:需要正确处理布尔返回值转换,保持与原始API兼容
+3. **软删除考虑**:考虑使用`status`字段实现软删除,而不是硬删除
+4. **路由聚合模式**:使用`.route('/', customRoutes).route('/', crudRoutes)`聚合自定义路由和CRUD路由
+5. **默认值设置**:创建时设置合理的默认值(contact_person, contact_phone等)
+
+#### 从故事007.002(公司管理模块)吸取的经验教训:
+1. **模块间依赖处理**:正确配置对`@d8d/allin-platform-module`的依赖
+2. **复合唯一性检查**:公司名称在同一平台下唯一性检查(`company_name`和`platform_id`组合)
+3. **关联关系配置**:正确配置与Platform实体的关联关系`@ManyToOne(() => Platform, { eager: true })`
+4. **跨模块业务逻辑**:处理跨模块的业务逻辑,如平台ID验证
+5. **排序配置**:默认按`company_id`降序排列
+
+#### 从故事007.003(枚举常量包)吸取的经验教训:
+1. **枚举值一致性**:保持与原始数据库值一致(小写字符串,下划线分隔)
+2. **数字枚举处理**:残疾等级使用数字枚举(1, 2, 3, 4)
+3. **注释完整性**:为每个枚举值添加中文注释说明和业务含义
+4. **包配置优化**:枚举常量包直接引用源码,避免不必要的构建步骤
+5. **类型安全**:提供类型安全的枚举常量,提高代码可读性和维护性
+
+#### 从故事007.006(平台管理模块)吸取的经验教训:
+1. **基础依赖包设计**:作为基础包,不需要依赖其他allin模块
+2. **唯一性索引配置**:平台名称唯一性索引配置
+3. **返回值格式**:成功返回`{ success: true }`,失败返回`{ success: false, message: "..." }`
+4. **错误信息明确**:提供明确的错误信息,如"平台不存在或名称重复"
+5. **路由模式参考**:参考channel-module的路由模式实现
+
+### 关键经验教训总结(基于史诗007所有已完成故事):
 
 #### 数据库和类型相关:
 1. **PostgreSQL类型兼容**:注意tinyint → smallint,datetime → timestamp的类型转换
 2. **Decimal字段处理**:数据库返回的decimal字段可能是字符串格式,需要使用z.coerce.number()处理
 3. **Schema一致性**:确保实体字段名与Schema定义完全匹配,特别注意时间字段命名
+4. **枚举值一致性**:保持与原始数据库值一致(小写字符串,下划线分隔)
+5. **数字枚举处理**:残疾等级等使用数字枚举(1, 2, 3, 4)
+
+#### 实体设计相关:
+6. **实体主键命名**:主键属性名应直接定义为`id`以遵循GenericCrudService约定
+7. **唯一性约束**:配置正确的唯一性索引(单字段或复合字段)
+8. **关联关系配置**:正确配置实体间关联关系,如`@ManyToOne(() => Platform, { eager: true })`
+9. **软删除考虑**:考虑使用`status`字段实现软删除,而不是硬删除
+10. **默认值设置**:创建时设置合理的默认值
 
 #### 测试相关:
-4. **测试数据完整性**:确保测试数据包含所有必填字段(如subBankName、operatorId等)
-5. **唯一性约束**:测试数据避免创建违反唯一性约束的记录
-6. **测试期望值**:根据实际数据调整测试断言期望值
-7. **调试信息**:在路由中添加console.debug便于问题排查
+11. **测试数据完整性**:确保测试数据包含所有必填字段
+12. **唯一性约束**:测试数据避免创建违反唯一性约束的记录
+13. **测试期望值**:根据实际数据调整测试断言期望值
+14. **调试信息**:在路由中添加console.debug便于问题排查
 
 #### 路由和API相关:
-8. **路由冲突**:CRUD路由可能与自定义路由冲突,需要合理设计路由结构
-9. **错误响应**:确保DELETE返回200(成功)而不是404,GET聚合端点正确处理404场景
-10. **API兼容性**:保持与原始NestJS API相同的请求/响应格式
+15. **路由冲突**:CRUD路由可能与自定义路由冲突,需要合理设计路由结构
+16. **路由聚合模式**:使用`.route('/', customRoutes).route('/', crudRoutes)`聚合路由
+17. **错误响应**:确保DELETE返回200(成功)而不是404,GET聚合端点正确处理404场景
+18. **API兼容性**:保持与原始NestJS API相同的请求/响应格式
+19. **布尔返回值处理**:需要正确处理布尔返回值转换
+20. **错误信息明确**:提供明确的错误信息,如"平台不存在或名称重复"
 
 #### 模块集成相关:
-11. **文件模块集成**:正确使用fileId字段而不是URL字段,建立与File实体的关联
-12. **循环依赖处理**:使用ID引用代替直接实体引用,避免模块间循环依赖
-13. **枚举集成**:通过@d8d/allin-enums包导入共享枚举
+21. **文件模块集成**:正确使用fileId字段而不是URL字段,建立与File实体的关联
+22. **循环依赖处理**:使用ID引用代替直接实体引用,避免模块间循环依赖
+23. **枚举集成**:通过@d8d/allin-enums包导入共享枚举
+24. **模块间依赖处理**:正确配置模块间依赖关系
+25. **跨模块业务逻辑**:处理跨模块的业务逻辑,如平台ID验证
+26. **基础依赖包设计**:基础包不需要依赖其他allin模块
+27. **区域包集成**:参考salary-module与geo-areas的集成方式
 
 #### 开发流程相关:
-14. **workspace配置**:及时在pnpm-workspace.yaml中添加新包路径
-15. **类型检查**:使用pnpm typecheck检查类型错误,特别注意枚举导入
-16. **测试依赖**:集成测试需要正确配置测试数据库和实体
+28. **workspace配置**:及时在pnpm-workspace.yaml中添加新包路径
+29. **类型检查**:使用pnpm typecheck检查类型错误,特别注意枚举导入
+30. **测试依赖**:集成测试需要正确配置测试数据库和实体
+31. **包配置优化**:枚举常量包直接引用源码,避免不必要的构建步骤
+32. **排序配置**:默认按主键降序排列
+33. **注释完整性**:为枚举值添加中文注释说明和业务含义
 
 ### 技术细节:
 1. **OrderStatus和WorkStatus枚举集成**:
@@ -447,6 +494,102 @@ app.post('/create', async (c) => {
 });
 ```
 
+### 7. 布尔返回值处理(基于007.001和007.006)
+```typescript
+// 正确处理布尔返回值,保持与原始API兼容
+app.post('/create', async (c) => {
+  try {
+    const result = await service.create(data);
+    return c.json({ success: true }, 200);
+  } catch (error) {
+    return c.json({
+      success: false,
+      message: error.message || '创建失败'
+    }, 400);
+  }
+});
+```
+
+### 8. 软删除实现(基于007.001和007.002)
+```typescript
+// 考虑使用status字段实现软删除
+@Column({
+  name: 'status',
+  type: 'tinyint',
+  default: 1,
+  comment: '状态:0-删除,1-正常'
+})
+status!: number;
+
+// 在服务层实现软删除
+async delete(id: number): Promise<boolean> {
+  const entity = await this.repository.findOne({ where: { id } });
+  if (!entity) return false;
+
+  entity.status = 0; // 软删除
+  entity.updateTime = new Date();
+  await this.repository.save(entity);
+  return true;
+}
+```
+
+### 9. 复合唯一性检查(基于007.002)
+```typescript
+// 公司名称在同一平台下唯一性检查
+async create(data: CreateCompanyDto): Promise<Company> {
+  // 检查(companyName, platformId)组合是否已存在
+  const existing = await this.repository.findOne({
+    where: {
+      companyName: data.companyName,
+      platformId: data.platformId,
+      status: 1 // 只检查正常状态的记录
+    }
+  });
+
+  if (existing) {
+    throw new Error('同一平台下公司名称已存在');
+  }
+
+  return super.create(data);
+}
+```
+
+### 10. 枚举使用规范(基于007.003)
+```typescript
+// 保持与数据库值一致的小写字符串枚举
+import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
+
+// 在实体中使用
+@Column({
+  name: 'order_status',
+  type: 'enum',
+  enum: OrderStatus,
+  default: OrderStatus.DRAFT,
+  comment: '订单状态:draft-草稿, confirmed-已确认, in_progress-进行中, completed-已完成, cancelled-已取消'
+})
+orderStatus!: OrderStatus;
+
+// 在Schema中验证
+const CreateOrderSchema = z.object({
+  orderStatus: z.nativeEnum(OrderStatus).default(OrderStatus.DRAFT),
+  workStatus: z.nativeEnum(WorkStatus).default(WorkStatus.NOT_WORKING),
+});
+```
+
+### 11. 路由聚合模式(基于007.001和007.006)
+```typescript
+// 合理聚合自定义路由和CRUD路由
+import customRoutes from './order-custom.routes';
+import crudRoutes from './order-crud.routes';
+
+const orderRoutes = new Hono()
+  .basePath('/orders')
+  .route('/', customRoutes)   // 自定义业务逻辑路由
+  .route('/', crudRoutes);    // 标准CRUD路由(readOnly: true)
+
+export default orderRoutes;
+```
+
 ## Dev Agent Record
 *将在开发完成后填写*