# Story 007.002: 移植公司管理模块（company → @d8d/allin-company-module）

## Status
Completed

## 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]
- **故事007.006**：已完成平台管理模块移植，提供了基础依赖包 [Source: docs/stories/007.006.transplant-platform-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的布尔返回值格式
  6. **平台模块依赖**：platform-module已可用，可作为基础依赖包使用

### 数据模型
- **源实体结构**：`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) |
| 2025-12-02 | 1.1 | 更新状态为Ready for Development，添加平台模块依赖说明 | James (Developer) |
| 2025-12-02 | 1.2 | 完成公司管理模块移植，所有测试通过，记录开发经验 | Claude Code |

## Dev Agent Record
*此部分由开发代理在实现过程中填写*

### Agent Model Used
- Claude Code (d8d-model)

### Debug Log References
1. **类型检查错误修复**：
   - 索引文件导出冲突：`Module './schemas/index.js' has already exported a member named 'Company'`
   - 修复：修改`src/index.ts`，将实体导出重命名为`CompanyEntity`

   - GenericCrudService配置问题：`'searchFields' does not exist in type`
   - 修复：将searchFields改为类的私有属性，而不是构造函数参数

   - Platform实体字段错误：`'platformCode' does not exist in type 'DeepPartial<Platform>'`
   - 修复：根据实际的Platform实体结构，使用正确的字段（contactPerson、contactPhone等）

2. **测试类型安全问题**：
   - 用户反馈：`const data = await response.json() as any[];`不应该用any
   - 修复：将响应包在if的状态码判断为200之内

3. **集成测试失败分析**：
   - 4个测试失败，主要与公司名称唯一性检查相关
   - 错误信息显示：数据库唯一约束`idx_company_name_platform`被违反
   - 根本原因：实体索引配置错误，只检查`company_name`字段，而不是`(company_name, platform_id)`组合
   - 修复：将`@Index('idx_company_name_platform', { unique: true })`从字段级别移到实体级别，配置为复合索引：`@Index('idx_company_name_platform', ['companyName', 'platformId'], { unique: true })`

4. **服务层错误处理问题**：
   - 问题：`createCompany`和`updateCompany`方法捕获错误并返回`false`，但路由层期望捕获错误
   - 修复：让服务层方法重新抛出错误，让路由层处理

5. **路由层逻辑问题**：
   - 问题：更新路由中检查`success`为`false`时返回404，但根据修改后的服务层，现在会抛出错误
   - 修复：移除不必要的`success`检查，让错误处理逻辑处理所有错误

6. **测试逻辑错误**：
   - 问题：测试"应该允许更新到不同平台下的相同名称"逻辑错误
   - 原逻辑：将公司B的名称改为"公司A"，同时将平台改为平台1（但平台1下已有"公司A"）
   - 正确逻辑：将公司B的名称改为"公司A"，但保持平台2不变（不同平台下可以有相同名称）
   - 修复：修改测试逻辑，保持平台ID不变

### Completion Notes List
1. **成功完成所有9个验收标准**：
   - ✅ 创建目录结构
   - ✅ 完成实体转换
   - ✅ 处理模块依赖
   - ✅ 完成服务层转换
   - ✅ 完成路由层转换
   - ✅ 完成验证系统转换
   - ✅ 配置package.json
   - ✅ 编写API集成测试
   - ✅ 通过类型检查和基本测试验证

2. **关键实现细节**：
   - 实体主键属性名直接定义为`id`（遵循GenericCrudService约定）
   - 正确处理对`@d8d/allin-platform-module`的workspace依赖
   - 服务层继承`GenericCrudService`，覆盖`create`、`update`方法实现业务逻辑
   - 路由层保持原始API的布尔返回值格式
   - 验证系统从class-validator转换为Zod Schema
   - 集成测试包含15个测试用例，特别测试跨模块依赖

3. **技术要点**：
   - 复合索引配置：`@Index('idx_company_name_platform', ['companyName', 'platformId'], { unique: true })`
   - 错误处理模式：服务层抛出错误，路由层捕获并返回适当的HTTP状态码
   - 测试类型安全：避免使用`as any`，将响应包在状态码判断内
   - 跨模块测试：验证与platform-module的集成，确保关联查询正常工作

### File List
**创建的文件**：
1. `allin-packages/company-module/package.json` - 包配置
2. `allin-packages/company-module/tsconfig.json` - TypeScript配置
3. `allin-packages/company-module/vitest.config.ts` - 测试配置
4. `allin-packages/company-module/src/index.ts` - 模块导出
5. `allin-packages/company-module/src/entities/company.entity.ts` - 公司实体
6. `allin-packages/company-module/src/services/company.service.ts` - 公司服务
7. `allin-packages/company-module/src/routes/company.routes.ts` - 主路由
8. `allin-packages/company-module/src/routes/company-crud.routes.ts` - CRUD路由
9. `allin-packages/company-module/src/routes/company-custom.routes.ts` - 自定义路由
10. `allin-packages/company-module/src/schemas/company.schema.ts` - Zod Schema
11. `allin-packages/company-module/tests/integration/company.integration.test.ts` - 集成测试

**修改的文件**：
1. `docs/stories/007.002.transplant-company-management-module.story.md` - 更新状态和记录开发经验

## QA Results
Results from QA Agent QA review of the completed story implementation