|
|
@@ -0,0 +1,355 @@
|
|
|
+# Story 007.002: 移植公司管理模块(company → @d8d/allin-company-module)
|
|
|
+
|
|
|
+## Status
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 开发者,
|
|
|
+**I want** 将company模块从allin_system-master移植为独立包@d8d/allin-company-module,正确处理对platform-module的依赖并验证功能完整性,
|
|
|
+**so that** 我们可以将Allin系统的公司管理功能集成到当前项目中,遵循现有的模块化架构和编码标准,并保持模块间依赖关系。
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. ✅ 创建`allin-packages/company-module`目录结构
|
|
|
+2. ✅ 完成实体转换:`Company`实体转换
|
|
|
+3. ✅ 处理模块依赖:正确配置对`@d8d/allin-platform-module`的依赖
|
|
|
+4. ✅ 完成服务层转换:处理跨模块业务逻辑
|
|
|
+5. ✅ 完成路由层转换:Hono路由实现
|
|
|
+6. ✅ 完成验证系统转换:Zod Schema定义
|
|
|
+7. ✅ 配置package.json:workspace依赖管理
|
|
|
+8. ✅ 编写API集成测试:验证模块间依赖正常工作
|
|
|
+9. ✅ 通过类型检查和基本测试验证
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] 创建`allin-packages/company-module`目录结构 (AC: 1)
|
|
|
+ - [ ] 创建`allin-packages/company-module/`目录
|
|
|
+ - [ ] 创建`package.json`文件,配置包名`@d8d/allin-company-module`和workspace依赖
|
|
|
+ - **参考文件**: `allin-packages/channel-module/package.json`
|
|
|
+ - **修改点**: 包名改为`@d8d/allin-company-module`,依赖调整
|
|
|
+ - **关键依赖**: 添加对`@d8d/allin-platform-module`的依赖(需要先创建platform-module)
|
|
|
+ - [ ] 创建`tsconfig.json`文件,配置TypeScript编译选项
|
|
|
+ - **参考文件**: `allin-packages/channel-module/tsconfig.json`
|
|
|
+ - [ ] 创建`vitest.config.ts`文件,配置测试环境
|
|
|
+ - **参考文件**: `allin-packages/channel-module/vitest.config.ts`
|
|
|
+ - [ ] 创建`src/`目录结构:`entities/`, `services/`, `routes/`, `schemas/`, `types/`
|
|
|
+ - **参考结构**: `allin-packages/channel-module/src/`目录结构
|
|
|
+- [ ] 完成实体转换:`Company`实体转换 (AC: 2)
|
|
|
+ - [ ] 分析源实体`allin_system-master/server/src/company/company.entity.ts`
|
|
|
+ - **源文件**: `allin_system-master/server/src/company/company.entity.ts`
|
|
|
+ - **关键字段**: `company_id`, `platform_id`, `company_name`, `contact_person`, `contact_phone`, `contact_email`, `address`, `status`, `create_time`, `update_time`
|
|
|
+ - **关系**: `@ManyToOne(() => Platform)` 关联platform实体
|
|
|
+ - [ ] 创建转换后的实体文件`src/entities/company.entity.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/entities/channel.entity.ts`
|
|
|
+ - **转换要点**: 下划线命名 → 驼峰命名,添加详细TypeORM配置
|
|
|
+ - **注意吸取经验**: 根据故事007.001的经验,主键属性名应直接定义为`id`(而不是`companyId`)以遵循GenericCrudService约定
|
|
|
+ - **迁移文件路径**: `allin-packages/company-module/src/entities/company.entity.ts`
|
|
|
+ - [ ] 将下划线字段名转换为驼峰命名:`company_id` → `id`, `platform_id` → `platformId`, `company_name` → `companyName`等
|
|
|
+ - [ ] 添加详细的TypeORM装饰器配置:`@Column({ name: 'company_name', type: 'varchar', length: 100 })`
|
|
|
+ - [ ] 保持数据库表名不变:`@Entity('employer_company')`
|
|
|
+ - [ ] 配置与Platform实体的关联关系:`@ManyToOne(() => Platform, { eager: true })`
|
|
|
+ - [ ] 添加必要的索引和约束配置
|
|
|
+- [ ] 处理模块依赖:正确配置对`@d8d/allin-platform-module`的依赖 (AC: 3)
|
|
|
+ - [ ] 分析源模块依赖`allin_system-master/server/src/company/company.module.ts`
|
|
|
+ - **源文件**: `allin_system-master/server/src/company/company.module.ts`
|
|
|
+ - **依赖**: 依赖`PlatformModule`(需要先创建platform-module)
|
|
|
+ - [ ] 在`package.json`中添加对`@d8d/allin-platform-module`的workspace依赖
|
|
|
+ - **注意**: 需要先创建platform-module(故事007.006),或者临时创建占位包
|
|
|
+ - [ ] 在实体中正确导入Platform实体类型
|
|
|
+ - **导入路径**: `import { Platform } from '@d8d/allin-platform-module/entities';`
|
|
|
+ - [ ] 验证依赖关系:确保company-module可以正确引用platform-module的实体和服务
|
|
|
+- [ ] 完成服务层转换:处理跨模块业务逻辑 (AC: 4)
|
|
|
+ - [ ] 分析源服务`allin_system-master/server/src/company/company.service.ts`
|
|
|
+ - **源文件**: `allin_system-master/server/src/company/company.service.ts`
|
|
|
+ - **关键方法**: `createCompany`, `deleteCompany`, `findAll`, `searchByName`, `findByPlatform`, `findOne`, `updateCompany`
|
|
|
+ - **业务逻辑**: 公司名称在同一平台下唯一性检查,关联平台查询
|
|
|
+ - [ ] 创建转换后的服务文件`src/services/company.service.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/services/channel.service.ts`
|
|
|
+ - **架构**: 继承`GenericCrudService<Company>`
|
|
|
+ - **迁移文件路径**: `allin-packages/company-module/src/services/company.service.ts`
|
|
|
+ - [ ] 继承`GenericCrudService<Company>`,配置搜索字段
|
|
|
+ - **参考**: `packages/shared-crud/src/services/generic-crud.service.ts`
|
|
|
+ - **搜索字段**: `['companyName', 'contactPerson', 'contactPhone']`
|
|
|
+ - [ ] 覆盖`create`方法:添加公司名称在同一平台下唯一性检查
|
|
|
+ - **源逻辑**: `company.service.ts:14-33` - 检查`company_name`和`platform_id`组合是否已存在
|
|
|
+ - **注意吸取经验**: 根据故事007.001的经验,需要正确处理布尔返回值转换
|
|
|
+ - [ ] 覆盖`update`方法:检查公司存在性和名称重复性
|
|
|
+ - **源逻辑**: `company.service.ts:76-110` - 检查公司是否存在,检查更新后的名称是否与同一平台下的其他公司重复
|
|
|
+ - **注意**: 需要处理`platform_id`变更的情况
|
|
|
+ - [ ] 覆盖`delete`方法:当前为硬删除,考虑改为软删除(使用`status`字段)
|
|
|
+ - **源逻辑**: `company.service.ts:35-38` - 直接删除记录
|
|
|
+ - **建议**: 改为软删除,设置`status`为0或删除状态
|
|
|
+ - [ ] 覆盖`findAll`方法:需要返回`{ data: Company[], total: number }`格式并加载平台关联
|
|
|
+ - **源逻辑**: `company.service.ts:40-48` - 使用`findAndCount`返回数据和总数,加载`relations: ['platform']`
|
|
|
+ - **排序**: 默认按`company_id`降序排列
|
|
|
+ - [ ] 自定义`searchByName`方法:按名称模糊搜索
|
|
|
+ - **源逻辑**: `company.service.ts:50-61` - 使用`Like`操作符进行模糊匹配,加载平台关联
|
|
|
+ - [ ] 自定义`findByPlatform`方法:按平台ID查询公司
|
|
|
+ - **源逻辑**: `company.service.ts:63-67` - 根据`platform_id`查询公司列表
|
|
|
+ - [ ] 自定义`findOne`方法:查询单个公司并加载平台关联
|
|
|
+ - **源逻辑**: `company.service.ts:69-74` - 根据ID查询单个公司,加载`relations: ['platform']`
|
|
|
+- [ ] 完成路由层转换:Hono路由实现 (AC: 5)
|
|
|
+ - [ ] 分析源控制器`allin_system-master/server/src/company/company.controller.ts`
|
|
|
+ - **源文件**: `allin_system-master/server/src/company/company.controller.ts`
|
|
|
+ - **API端点**:
|
|
|
+ - `POST /company/createCompany` - 创建公司
|
|
|
+ - `POST /company/deleteCompany` - 删除公司
|
|
|
+ - `POST /company/updateCompany` - 更新公司
|
|
|
+ - `GET /company/getAllCompanies` - 获取所有公司(分页)
|
|
|
+ - `GET /company/searchCompanies` - 搜索公司(按名称)
|
|
|
+ - `GET /company/getCompaniesByPlatform/:platformId` - 按平台获取公司
|
|
|
+ - `GET /company/getCompany/:id` - 获取单个公司详情
|
|
|
+ - **认证**: 所有端点需要JWT认证 (`@UseGuards(JwtAuthGuard)`)
|
|
|
+ - [ ] 创建自定义路由文件`src/routes/company-custom.routes.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/routes/channel-custom.routes.ts`
|
|
|
+ - **迁移文件路径**: `allin-packages/company-module/src/routes/company-custom.routes.ts`
|
|
|
+ - [ ] 自定义`POST /createCompany`路由:处理布尔返回值
|
|
|
+ - **返回格式**: 成功返回`{ success: true }`,失败返回`{ success: false }`
|
|
|
+ - **源逻辑**: `company.controller.ts:11-14`,`company.service.ts:14-33`
|
|
|
+ - **参考模式**: `allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的`createChannelRoute`
|
|
|
+ - [ ] 自定义`POST /deleteCompany`路由:处理布尔返回值
|
|
|
+ - **返回格式**: 成功返回`{ success: true }`,失败返回`{ success: false }`
|
|
|
+ - **源逻辑**: `company.controller.ts:16-19`,`company.service.ts:35-38`
|
|
|
+ - **参考模式**: `allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的`deleteChannelRoute`
|
|
|
+ - [ ] 自定义`POST /updateCompany`路由:处理布尔返回值
|
|
|
+ - **返回格式**: 成功返回`{ success: true }`,失败返回`{ success: false, message: "公司不存在或名称重复" }`
|
|
|
+ - **源逻辑**: `company.controller.ts:21-24`,`company.service.ts:76-110`
|
|
|
+ - **参考模式**: `allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的`updateChannelRoute`
|
|
|
+ - [ ] 自定义`GET /getAllCompanies`路由:处理分页参数和返回格式
|
|
|
+ - **参数**: `skip`, `take`查询参数
|
|
|
+ - **返回格式**: `{ data: Company[], total: number }`
|
|
|
+ - **源逻辑**: `company.controller.ts:26-29`,`company.service.ts:40-48`
|
|
|
+ - **参考模式**: 自定义分页查询路由,参考`allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的`getAllChannelsRoute`
|
|
|
+ - [ ] 自定义`GET /searchCompanies`路由:处理搜索功能
|
|
|
+ - **参数**: `name`(搜索关键词),`skip`, `take`(分页参数)
|
|
|
+ - **返回格式**: `{ data: Company[], total: number }`
|
|
|
+ - **源逻辑**: `company.controller.ts:31-34`,`company.service.ts:50-61`
|
|
|
+ - **参考模式**: 自定义搜索路由,参考`allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的`searchChannelsRoute`
|
|
|
+ - [ ] 自定义`GET /getCompaniesByPlatform/:platformId`路由:按平台查询公司
|
|
|
+ - **参数**: `platformId`路径参数
|
|
|
+ - **返回格式**: `Company[]`数组
|
|
|
+ - **源逻辑**: `company.controller.ts:36-39`,`company.service.ts:63-67`
|
|
|
+ - **参考模式**: 自定义参数路由,参考`allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的参数验证
|
|
|
+ - [ ] 自定义`GET /getCompany/:id`路由:处理单个公司查询
|
|
|
+ - **参数**: `id`路径参数
|
|
|
+ - **返回格式**: `Company`对象或`null`
|
|
|
+ - **源逻辑**: `company.controller.ts:41-44`,`company.service.ts:69-74`
|
|
|
+ - **参考模式**: `allin-packages/channel-module/src/routes/channel-custom.routes.ts`中的参数验证和错误处理
|
|
|
+ - [ ] 创建CRUD路由文件`src/routes/company-crud.routes.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/routes/channel-crud.routes.ts`
|
|
|
+ - **架构**: 使用`createCrudRoutes`生成标准CRUD路由
|
|
|
+ - **配置**: 配置`entity`, `createSchema`, `updateSchema`, `getSchema`, `listSchema`, `searchFields`等参数
|
|
|
+ - **注意**: 设置`readOnly: true`,因为创建、更新、删除操作通过自定义路由处理
|
|
|
+ - [ ] 创建主路由文件`src/routes/company.routes.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/routes/channel.routes.ts`
|
|
|
+ - **功能**: 聚合自定义路由和CRUD路由,导出路由实例
|
|
|
+- [ ] 完成验证系统转换:从class-validator DTO转换为Zod Schema (AC: 6)
|
|
|
+ - [ ] 分析源DTO`allin_system-master/server/src/company/company.dto.ts`
|
|
|
+ - **源文件**: `allin_system-master/server/src/company/company.dto.ts`
|
|
|
+ - **DTO类型**: `CreateCompanyDto`, `UpdateCompanyDto`, `DeleteCompanyDto`
|
|
|
+ - [ ] 创建转换后的Schema文件`src/schemas/company.schema.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/schemas/channel.schema.ts`
|
|
|
+ - **迁移文件路径**: `allin-packages/company-module/src/schemas/company.schema.ts`
|
|
|
+ - [ ] 使用`z.object()`定义`CreateCompanySchema`, `UpdateCompanySchema`, `DeleteCompanySchema`
|
|
|
+ - [ ] 添加详细的验证规则:字符串长度、必填字段、可选字段、邮箱格式验证
|
|
|
+ - [ ] 创建对应的TypeScript类型定义:`CreateCompanyDto`, `UpdateCompanyDto`, `DeleteCompanyDto`
|
|
|
+- [ ] 配置package.json:workspace依赖管理 (AC: 7)
|
|
|
+ - [ ] 配置`package.json`中的`name`字段为`@d8d/allin-company-module`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/package.json`
|
|
|
+ - [ ] 设置`type: "module"`和主入口`src/index.ts`
|
|
|
+ - [ ] 添加workspace依赖:`@d8d/core-module`, `@d8d/shared-crud`, `@d8d/shared-utils`, `@d8d/allin-platform-module`
|
|
|
+ - [ ] 添加外部依赖:`@hono/zod-openapi`, `typeorm`, `zod`
|
|
|
+ - [ ] 配置导出路径:`services`, `schemas`, `routes`, `entities`
|
|
|
+- [ ] 编写API集成测试:验证模块间依赖正常工作 (AC: 8)
|
|
|
+ - [ ] 创建测试文件`tests/integration/company.integration.test.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/tests/integration/channel.integration.test.ts`
|
|
|
+ - **迁移文件路径**: `allin-packages/company-module/tests/integration/company.integration.test.ts`
|
|
|
+ - [ ] 参考`channel-module`的集成测试模式
|
|
|
+ - **测试模式**: 使用`testClient`, `setupIntegrationDatabaseHooksWithEntities`
|
|
|
+ - [ ] 使用`testClient`创建测试客户端
|
|
|
+ - [ ] 使用`setupIntegrationDatabaseHooksWithEntities`设置测试数据库
|
|
|
+ - **工具**: `@d8d/shared-test-util`中的测试基础设施
|
|
|
+ - **注意**: 需要包含Platform实体(来自platform-module)
|
|
|
+ - [ ] 编写测试用例覆盖所有端点:创建、查询、更新、删除、搜索、按平台查询
|
|
|
+ - [ ] 添加认证测试、数据验证测试、错误处理测试
|
|
|
+ - [ ] 包含边界条件和异常场景测试
|
|
|
+ - [ ] 特别测试跨模块依赖:验证与platform-module的集成
|
|
|
+ - **测试场景**: 创建平台 → 创建公司关联该平台 → 查询公司验证平台关联数据
|
|
|
+ - **验证**: 关联查询返回完整的平台信息
|
|
|
+- [ ] 通过类型检查和基本测试验证 (AC: 9)
|
|
|
+ - [ ] 运行`pnpm typecheck`确保无类型错误
|
|
|
+ - [ ] 运行`pnpm test`确保所有测试通过
|
|
|
+ - [ ] 运行`pnpm test:integration`验证集成测试
|
|
|
+ - [ ] 检查测试覆盖率是否满足要求
|
|
|
+ - **标准**: 集成测试 ≥ 60% [Source: architecture/testing-strategy.md#测试覆盖率标准]
|
|
|
+ - [ ] 验证模块可以正确导入和使用
|
|
|
+ - [ ] 验证与platform-module的依赖关系正常工作
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 先前故事洞察
|
|
|
+- **故事007.001**:已完成渠道管理模块移植,提供了完整的参考实现 [Source: docs/stories/007.001.transplant-channel-management-module.story.md]
|
|
|
+- **关键经验教训**:
|
|
|
+ 1. **实体主键命名**:根据用户反馈,主键属性名应直接定义为`id`(而不是`channelId`)以遵循GenericCrudService约定
|
|
|
+ 2. **workspace配置**:需要在`pnpm-workspace.yaml`中添加`allin-packages/*`配置
|
|
|
+ 3. **测试依赖**:需要添加`@d8d/user-module`和`@d8d/file-module`依赖
|
|
|
+ 4. **类型检查**:需要注意导出重复和路由返回类型问题
|
|
|
+ 5. **API兼容性**:需要保持原始API的布尔返回值格式
|
|
|
+
|
|
|
+### 数据模型
|
|
|
+- **源实体结构**:`Company`实体包含以下字段 [Source: allin_system-master/server/src/company/company.entity.ts]:
|
|
|
+ - `company_id: number` (主键,自增)
|
|
|
+ - `platform_id: number` (外键,关联platform表)
|
|
|
+ - `company_name: string` (公司名称)
|
|
|
+ - `contact_person: string` (联系人)
|
|
|
+ - `contact_phone: string` (联系电话)
|
|
|
+ - `contact_email?: string` (联系邮箱,可选)
|
|
|
+ - `address?: string` (地址,可选)
|
|
|
+ - `status: number` (状态,默认1)
|
|
|
+ - `create_time: Date` (创建时间)
|
|
|
+ - `update_time: Date` (更新时间)
|
|
|
+ - `platform?: Platform` (关联的Platform实体)
|
|
|
+- **转换要求**:下划线命名 → 驼峰命名,添加详细TypeORM配置
|
|
|
+- **表名保持**:`employer_company`表名不变
|
|
|
+- **关系配置**:`@ManyToOne(() => Platform)`关联,需要配置`eager: true`或`relations`加载
|
|
|
+
|
|
|
+### 自定义实现分析
|
|
|
+- **需要覆盖GenericCrudService的方法**:
|
|
|
+ - **`create`方法**:需要添加公司名称在同一平台下唯一性检查
|
|
|
+ - **源逻辑**: `company.service.ts:14-33` - 检查`company_name`和`platform_id`组合是否已存在
|
|
|
+ - **默认值设置**: 创建时设置`status`为1,`create_time`和`update_time`为当前时间
|
|
|
+ - **`update`方法**:需要检查公司存在性和名称重复性
|
|
|
+ - **源逻辑**: `company.service.ts:76-110` - 检查公司是否存在,检查更新后的名称是否与同一平台下的其他公司重复
|
|
|
+ - **更新时间**: 自动设置`update_time`为当前时间
|
|
|
+ - **`delete`方法**:当前为硬删除,考虑改为软删除(使用`status`字段)
|
|
|
+ - **源逻辑**: `company.service.ts:35-38` - 直接删除记录
|
|
|
+ - **建议**: 改为软删除,设置`status`为0或删除状态
|
|
|
+ - **`findAll`方法**:需要返回`{ data: Company[], total: number }`格式并加载平台关联
|
|
|
+ - **源逻辑**: `company.service.ts:40-48` - 使用`findAndCount`返回数据和总数,加载`relations: ['platform']`
|
|
|
+ - **排序**: 默认按`company_id`降序排列
|
|
|
+ - **自定义`searchByName`方法**:按名称模糊搜索
|
|
|
+ - **源逻辑**: `company.service.ts:50-61` - 使用`Like`操作符进行模糊匹配,加载平台关联
|
|
|
+ - **自定义`findByPlatform`方法**:按平台ID查询公司
|
|
|
+ - **源逻辑**: `company.service.ts:63-67` - 根据`platform_id`查询公司列表
|
|
|
+ - **自定义`findOne`方法**:查询单个公司并加载平台关联
|
|
|
+ - **源逻辑**: `company.service.ts:69-74` - 根据ID查询单个公司,加载`relations: ['platform']`
|
|
|
+
|
|
|
+- **与GenericCrudService的差异**:
|
|
|
+ - **返回值格式**:源服务返回布尔值或分页对象,GenericCrudService返回实体对象
|
|
|
+ - **验证逻辑**:源服务有自定义的业务验证逻辑(名称在同一平台下唯一性检查)
|
|
|
+ - **关联查询**:源服务自动加载`relations: ['platform']`
|
|
|
+ - **搜索功能**:源服务有专门的按名称搜索和按平台查询功能
|
|
|
+
|
|
|
+### API规范
|
|
|
+- **现有API端点** [Source: allin_system-master/server/src/company/company.controller.ts]:
|
|
|
+ - `POST /company/createCompany` - 创建公司
|
|
|
+ - `POST /company/deleteCompany` - 删除公司
|
|
|
+ - `POST /company/updateCompany` - 更新公司
|
|
|
+ - `GET /company/getAllCompanies` - 获取所有公司(分页)
|
|
|
+ - `GET /company/searchCompanies` - 搜索公司(按名称)
|
|
|
+ - `GET /company/getCompaniesByPlatform/:platformId` - 按平台获取公司
|
|
|
+ - `GET /company/getCompany/:id` - 获取单个公司详情
|
|
|
+- **认证要求**:所有端点需要JWT认证 (`@UseGuards(JwtAuthGuard)`)
|
|
|
+- **转换策略**:NestJS控制器 → Hono路由,保持相同的端点路径和功能
|
|
|
+
|
|
|
+### 服务规范
|
|
|
+- **源服务逻辑** [Source: allin_system-master/server/src/company/company.service.ts]:
|
|
|
+ - `createCompany`: 检查名称在同一平台下重复,设置默认值,插入数据
|
|
|
+ - `deleteCompany`: 根据ID删除
|
|
|
+ - `findAll`: 分页查询,按ID降序排序,加载平台关联
|
|
|
+ - `searchByName`: 按名称模糊搜索,分页查询,加载平台关联
|
|
|
+ - `findByPlatform`: 根据平台ID查询公司列表
|
|
|
+ - `findOne`: 根据ID查询单个,加载平台关联
|
|
|
+ - `updateCompany`: 检查存在性,检查名称在同一平台下重复,更新数据
|
|
|
+- **转换策略**:继承`GenericCrudService`,复用现有CRUD模式,保持业务逻辑
|
|
|
+
|
|
|
+### 验证系统
|
|
|
+- **源DTO结构** [Source: allin_system-master/server/src/company/company.dto.ts]:
|
|
|
+ - `CreateCompanyDto`: `platform_id`(必填), `company_name`(必填), `contact_person`(必填), `contact_phone`(必填), `contact_email`(可选), `address`(可选)
|
|
|
+ - `UpdateCompanyDto`: `company_id`(必填), `platform_id`(可选), `company_name`(可选), `contact_person`(可选), `contact_phone`(可选), `contact_email`(可选), `address`(可选)
|
|
|
+ - `DeleteCompanyDto`: `company_id`(必填)
|
|
|
+- **转换策略**:`class-validator` → `Zod Schema`,添加详细的验证规则
|
|
|
+
|
|
|
+### 文件位置
|
|
|
+- **包目录**:`allin-packages/company-module/` (根据史诗007的目录结构决策)
|
|
|
+- **源文件位置**:
|
|
|
+ - **实体源文件**: `allin_system-master/server/src/company/company.entity.ts`
|
|
|
+ - **服务源文件**: `allin_system-master/server/src/company/company.service.ts`
|
|
|
+ - **控制器源文件**: `allin_system-master/server/src/company/company.controller.ts`
|
|
|
+ - **DTO源文件**: `allin_system-master/server/src/company/company.dto.ts`
|
|
|
+- **目标文件位置**:
|
|
|
+ - **实体文件**: `src/entities/company.entity.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/entities/channel.entity.ts`
|
|
|
+ - **服务文件**: `src/services/company.service.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/services/channel.service.ts`
|
|
|
+ - **主路由文件**: `src/routes/company.routes.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/routes/channel.routes.ts`
|
|
|
+ - **自定义路由文件**: `src/routes/company-custom.routes.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/routes/channel-custom.routes.ts`
|
|
|
+ - **CRUD路由文件**: `src/routes/company-crud.routes.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/routes/channel-crud.routes.ts`
|
|
|
+ - **Schema文件**: `src/schemas/company.schema.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/src/schemas/channel.schema.ts`
|
|
|
+ - **测试文件**: `tests/integration/company.integration.test.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/tests/integration/channel.integration.test.ts`
|
|
|
+ - **包配置**: `package.json`, `tsconfig.json`, `vitest.config.ts`
|
|
|
+ - **参考文件**: `allin-packages/channel-module/`中的对应配置文件
|
|
|
+
|
|
|
+### 测试要求
|
|
|
+- **测试框架**:Vitest [Source: architecture/testing-strategy.md#单元测试]
|
|
|
+- **测试位置**:`tests/integration/`目录 [Source: architecture/testing-strategy.md#测试金字塔策略]
|
|
|
+- **测试类型**:集成测试,验证API端点和数据库交互 [Source: architecture/testing-strategy.md#集成测试]
|
|
|
+- **覆盖率目标**:集成测试 ≥ 60% [Source: architecture/testing-strategy.md#测试覆盖率标准]
|
|
|
+- **测试模式**:参考`channel-module`的集成测试模式 [Source: allin-packages/channel-module/tests/integration/channel.integration.test.ts]
|
|
|
+- **测试工具**:使用`@d8d/shared-test-util`中的测试基础设施 [Source: architecture/testing-strategy.md#包测试架构]
|
|
|
+- **跨模块测试**:需要测试与platform-module的集成,验证关联查询功能
|
|
|
+
|
|
|
+### 技术约束
|
|
|
+- **技术栈**:Node.js 20.19.2, Hono 4.8.5, TypeORM 0.3.25, PostgreSQL 17 [Source: architecture/tech-stack.md]
|
|
|
+- **编码标准**:TypeScript严格模式,一致的缩进和命名 [Source: architecture/coding-standards.md]
|
|
|
+- **API设计**:RESTful API设计,使用Hono框架 [Source: architecture/api-design-integration.md]
|
|
|
+- **包管理**:使用pnpm workspace管理依赖 [Source: architecture/source-tree.md#集成指南]
|
|
|
+- **模块导出**:通过`src/index.ts`统一导出 [Source: architecture/source-tree.md#包结构规范]
|
|
|
+
|
|
|
+### 项目结构注意事项
|
|
|
+- **目录结构冲突**:根据史诗007决策,Allin系统专属包放在`allin-packages/`目录,而非通用的`packages/`目录
|
|
|
+- **命名规范**:使用`@d8d/allin-`前缀,`-module`后缀,非多租户版本
|
|
|
+- **依赖管理**:通过workspace依赖引用`@d8d/core-module`和其他共享包,特别需要添加对`@d8d/allin-platform-module`的依赖
|
|
|
+- **依赖顺序问题**:company-module依赖platform-module,需要先创建platform-module或处理循环依赖
|
|
|
+
|
|
|
+### 测试标准
|
|
|
+1. **API端点测试**:必须覆盖所有7个端点(创建、删除、更新、查询所有、搜索、按平台查询、查询单个)
|
|
|
+2. **认证测试**:验证所有端点需要有效的JWT令牌
|
|
|
+3. **数据验证测试**:测试输入验证规则(必填字段、字符串长度、数据类型、邮箱格式)
|
|
|
+4. **业务逻辑测试**:测试公司名称在同一平台下唯一性检查、分页查询、模糊搜索、按平台查询
|
|
|
+5. **跨模块测试**:测试与platform-module的集成,验证关联查询返回完整的平台信息
|
|
|
+6. **错误处理测试**:测试各种错误场景(无效ID、重复名称、缺失字段、无效平台ID)
|
|
|
+7. **数据库集成测试**:验证数据正确持久化和查询,包括关联数据
|
|
|
+8. **测试数据管理**:使用测试数据工厂模式,每个测试后清理数据
|
|
|
+
|
|
|
+### 测试执行流程
|
|
|
+1. 设置测试数据库,包含必要的实体(Company和Platform)
|
|
|
+2. 创建测试用户和认证令牌
|
|
|
+3. 创建测试平台数据
|
|
|
+4. 为每个端点编写成功场景测试
|
|
|
+5. 为每个端点编写失败场景测试
|
|
|
+6. 验证响应格式和数据正确性
|
|
|
+7. 检查数据库状态变化
|
|
|
+8. 验证跨模块关联查询功能
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-12-02 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实现过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+## QA Results
|
|
|
+Results from QA Agent QA review of the completed story implementation
|