# Story 008.002: 移植渠道管理UI（channel → @d8d/allin-channel-management-ui）

## Status
Ready for Review

## Story
**As a** 开发者，
**I want** 将channel管理页面从allin_system-master/client移植为独立UI包@d8d/allin-channel-management-ui，完成技术栈转换并验证功能完整性，
**so that** 我们可以将Allin系统的渠道管理UI模块集成到当前项目中，遵循现有的UI包结构和编码标准。

## Acceptance Criteria
1. 创建`allin-packages/channel-management-ui`目录结构
2. 完成组件转换：从Ant Design转换为@d8d/shared-ui-components组件
3. 完成API客户端转换：从自定义fetch API转换为Hono RPC (rpcClient + ClientManager模式)
4. 完成状态管理转换：从Jotai转换为React Query
5. 完成表单转换：从Ant Design Form转换为React Hook Form + Zod
6. 配置package.json：使用`@d8d/allin-channel-management-ui`包名，workspace依赖
7. 编写集成测试：覆盖完整CRUD流程
8. 通过类型检查和基本测试验证
9. 与`@d8d/allin-channel-module`后端模块集成验证
10. 创建渠道选择器组件，参照平台选择器组件模式，作为可复用组件供其他UI包使用

**集成测试要求**：
- 测试文件：`tests/integration/channel.integration.test.tsx`
- 测试覆盖：完整CRUD流程、错误处理、搜索功能、表单验证
- 验证：数据渲染、用户交互、API调用、状态管理
- 遵循现有集成测试模式

## Tasks / Subtasks
- [x] 任务1：创建渠道管理UI包基础结构 (AC: 1, 6)
  - [x] 创建目录：`allin-packages/channel-management-ui/`
  - [x] 复制并修改package.json：参考`allin-packages/platform-management-ui/package.json`，更新包名为`@d8d/allin-channel-management-ui`
  - [x] 复制并修改tsconfig.json：参考`allin-packages/platform-management-ui/tsconfig.json`
  - [x] 复制并修改vitest.config.ts：参考`allin-packages/platform-management-ui/vitest.config.ts`
  - [x] 创建基础目录结构：`src/`、`src/components/`、`src/api/`、`src/hooks/`、`src/types/`、`tests/`

- [x] 任务2：移植源系统渠道管理页面 (AC: 2)
  - [x] 分析源文件：`allin_system-master/client/app/admin/dashboard/channel/page.tsx`
  - [x] 参考对照文件：`allin-packages/platform-management-ui/src/components/PlatformManagement.tsx`
  - [x] 创建主组件：`src/components/ChannelManagement.tsx`
  - [x] 转换Ant Design组件为@d8d/shared-ui-components组件
  - [x] 转换Jotai状态管理为React Query
  - [x] 转换Ant Design Form为React Hook Form + Zod
  - [x] **API路径映射（基于渠道模块路由定义）**：
    - [x] `POST /createChannel` → `client.createChannel.$post`
    - [x] `POST /deleteChannel` → `client.deleteChannel.$post`
    - [x] `POST /updateChannel` → `client.updateChannel.$post`
    - [x] `GET /getAllChannels` → `client.getAllChannels.$get`
    - [x] `GET /getChannel/{id}` → `client.getChannel.$get`
    - [x] `GET /searchChannels` → `client.searchChannels.$get`
    - [x] **注意**：渠道模块使用自定义路由，没有`batchDeleteChannel`路由
  - [x] **RPC API调用实现（在页面组件中使用ClientManager）**：
    - [x] 创建渠道：`channelClientManager.get().createChannel.$post({ json: channelData })`
    - [x] 删除渠道：`channelClientManager.get().deleteChannel.$post({ json: { id } })`
    - [x] 更新渠道：`channelClientManager.get().updateChannel.$post({ json: channelData })`
    - [x] 获取渠道列表：`channelClientManager.get().getAllChannels.$get({ query: { skip, take } })`
    - [x] 获取渠道详情：`channelClientManager.get().getChannel.$get({ param: { id } })`
    - [x] 搜索渠道：`channelClientManager.get().searchChannels.$get({ query: { name, skip, take } })`
    - [x] **注意**：渠道模块使用自定义路由，没有批量删除功能

- [x] 任务3：实现RPC客户端 (AC: 3)
  - [x] 参考对照文件：`allin-packages/platform-management-ui/src/api/platformClient.ts`
  - [x] 创建RPC客户端：`src/api/channelClient.ts`
  - [x] 实现ClientManager单例模式
  - [x] 导出channelClient和channelClientManager
  - [x] 创建API导出文件：`src/api/index.ts`

- [x] 任务4：实现类型定义 (AC: 3, 8)
  - [x] 参考对照文件：`allin-packages/platform-management-ui/src/api/types.ts`
  - [x] 创建类型文件：`src/types/index.ts`
  - [x] 使用RPC推导类型：参考`typeof channelClient[':id']['$put']`语法
  - [x] 定义ChannelResponse、CreateChannelRequest、UpdateChannelRequest等类型

- [x] 任务5：实现表单验证Schema (AC: 5)
  - [x] 分析源系统表单字段
  - [x] 创建Zod验证Schema：`src/schemas/channel.schema.ts`
  - [x] 实现创建和更新表单的验证规则
  - [x] 集成到React Hook Form中

- [x] 任务6：编写集成测试 (AC: 7)
  - [x] 参考对照文件：`allin-packages/platform-management-ui/tests/integration/platform-management.integration.test.tsx`
  - [x] 创建集成测试：`tests/integration/channel.integration.test.tsx`
  - [x] 实现mock响应工具函数
  - [x] 测试完整CRUD流程和错误处理
  - [x] 添加test ID到所有交互元素（基于故事008.001经验）

- [x] 任务7：验证与后端模块集成 (AC: 9)
  - [x] 检查后端模块路由定义：`allin-packages/channel-module/src/routes/`目录
  - [x] 检查后端模块集成测试：`allin-packages/channel-module/tests/integration/`目录
  - [x] 确保API路径一致性（基于故事008.001经验：不能假设为标准CRUD模式）
  - [x] 验证Schema设计一致性（基于故事008.001经验：必须查看后端模块的集成测试和路由定义）
  - [x] **基于渠道模块集成测试的验证点**：
    - [x] 验证`CreateChannelSchema`字段：`channelName`（渠道名称）、`channelType`（渠道类型）、`contactPerson`（联系人）、`contactPhone`（联系电话）、`description`（描述）
    - [x] 验证`UpdateChannelSchema`字段：`id`（渠道ID）、`channelName`（渠道名称）、`channelType`（渠道类型）、`contactPerson`（联系人）、`contactPhone`（联系电话）、`description`（描述）
    - [x] 验证`DeleteChannelSchema`字段：`id`（渠道ID）
    - [x] 验证`SearchChannelSchema`字段：`name`（渠道名称）
    - [x] **注意**：没有`BatchDeleteChannelSchema`，渠道模块使用自定义路由
    - [x] 验证`GetAllChannelsQuerySchema`字段：`skip`（跳过记录数）、`take`（获取记录数）
    - [x] 验证`GetChannelParamSchema`字段：`id`（渠道ID）
    - [x] 验证`SearchChannelsQuerySchema`字段：`name`（渠道名称）、`skip`（跳过记录数）、`take`（获取记录数）
  - [x] **基于渠道模块路由定义的验证点**：
    - [x] 验证路由路径：`POST /createChannel`、`POST /deleteChannel`、`POST /updateChannel`、`GET /getAllChannels`、`GET /getChannel/{id}`、`GET /searchChannels`
    - [x] 验证路由处理函数：`createChannel`、`deleteChannel`、`updateChannel`、`getAllChannels`、`getChannel`、`searchChannels`
    - [x] 验证路由Schema引用：确保前端Schema与后端Schema定义一致

- [x] 任务8：运行测试和类型检查 (AC: 8)
  - [x] 运行组件测试：`pnpm test`（8个测试全部通过）
  - [x] 运行类型检查：`pnpm typecheck`（修复了所有类型错误）
  - [x] 修复测试失败和类型错误（修复了测试选择器冲突、路由名称问题、类型推导错误）
  - [x] 验证测试覆盖率（集成测试全部通过，类型检查通过）

- [x] 任务9：创建渠道选择器组件 (AC: 10)
  - [x] 创建`src/components/ChannelSelector.tsx`组件
    - **参考文件**：`allin-packages/platform-management-ui/src/components/PlatformSelector.tsx`
    - **架构**：使用React Query获取渠道列表，使用@d8d/shared-ui-components的Select组件
    - **功能**：渠道选择器，支持value/onChange等标准props，显示渠道名称
    - **用途**：作为可复用组件供其他UI包使用（如广告管理、内容管理等需要选择渠道的场景）
  - [x] 创建渠道选择器集成测试
    - **参考文件**：`allin-packages/platform-management-ui/tests/integration/platform-selector.integration.test.tsx`
    - **测试内容**：数据加载、选择功能、错误处理、禁用状态
  - [x] 更新package.json导出配置
    - **导出**：在`src/index.ts`中导出ChannelSelector组件
    - **依赖**：确保组件可被其他模块导入使用

## Dev Notes

### 从前一个故事学到的关键经验（故事008.001）：
1. **Schema设计一致性验证**：必须查看后端模块的集成测试和路由定义来确保Schema设计正确，不能仅凭前端使用场景假设。
2. **API路径一致性验证**：必须根据后端实际路由设计前端API调用，不能假设为标准CRUD模式。
3. **测试精度优化**：在测试中使用test ID比文本查找更精确可靠。
4. **类型推导优化**：遵循现有UI包的模式，使用正确的RPC类型推导语法。
5. **选择器组件模式**：创建可复用的选择器组件供其他UI包使用，遵循平台选择器组件的架构模式。

### 技术栈规范 [Source: docs/architecture/ui-package-standards.md]
- **包结构规范**：标准目录结构，包含components、api、hooks、types目录
- **RPC客户端实现规范**：必须使用ClientManager单例模式管理RPC客户端生命周期
- **组件开发规范**：使用@d8d/shared-ui-components组件库，React Query进行状态管理
- **类型定义规范**：使用RPC推导类型，避免重新定义类型
- **测试规范**：集成测试、组件测试、单元测试分层结构

### 项目结构信息 [Source: docs/architecture/source-tree.md]
- **UI包位置**：`allin-packages/channel-management-ui/`（Allin系统专属包目录）
- **参考实现**：`allin-packages/platform-management-ui/`（已完成的平台管理UI包）
- **后端模块**：`allin-packages/channel-module/`（对应的后端模块）

### 源系统文件路径
- **需要移植的源文件**：`allin_system-master/client/app/admin/dashboard/channel/page.tsx`
- **需要对照参考的文件**：
  - `allin-packages/platform-management-ui/src/components/PlatformManagement.tsx`
  - `allin-packages/platform-management-ui/src/api/platformClient.ts`
  - `allin-packages/platform-management-ui/src/api/types.ts`
  - `allin-packages/platform-management-ui/tests/integration/platform.integration.test.tsx`

### 渠道模块RPC API调用信息（基于集成测试）
- **RPC客户端调用方式**（来自`allin-packages/channel-module/tests/integration/channel.integration.test.ts`）：
  - `client.createChannel.$post({ json: channelData })` - 创建渠道
  - `client.deleteChannel.$post({ json: { id } })` - 删除渠道
  - `client.updateChannel.$post({ json: channelData })` - 更新渠道
  - `client.channels.$get({ query: { page, pageSize, name } })` - 获取渠道列表
  - `client.channel[':id'].$get({ param: { id } })` - 获取渠道详情
  - `client.searchChannel.$post({ json: { name } })` - 搜索渠道
  - `client.batchDeleteChannel.$post({ json: { ids } })` - 批量删除渠道

- **API路径映射**（来自`allin-packages/channel-module/src/routes/channel-custom.routes.ts`）：
  - `POST /createChannel` → `client.createChannel.$post`
  - `POST /deleteChannel` → `client.deleteChannel.$post`
  - `POST /updateChannel` → `client.updateChannel.$post`
  - `GET /channels` → `client.channels.$get`
  - `GET /channel/:id` → `client.channel[':id'].$get`
  - `POST /searchChannel` → `client.searchChannel.$post`
  - `POST /batchDeleteChannel` → `client.batchDeleteChannel.$post`

- **Schema字段定义**（来自`allin-packages/channel-module/src/schemas/channel.schema.ts`）：
  - `CreateChannelSchema`：`name`（渠道名称）、`description`（描述）、`status`（状态）
  - `UpdateChannelSchema`：`id`（渠道ID）、`name`（渠道名称）、`description`（描述）、`status`（状态）
  - `DeleteChannelSchema`：`id`（渠道ID）
  - `SearchChannelSchema`：`name`（渠道名称）
  - `BatchDeleteChannelSchema`：`ids`（渠道ID数组）
  - `GetChannelListSchema`：`page`（页码）、`pageSize`（每页数量）、`name`（渠道名称）
  - `GetChannelDetailSchema`：`id`（渠道ID）

### 后端模块集成验证点
- **路由定义**：检查`allin-packages/channel-module/src/routes/`目录中的实际路由
- **集成测试**：检查`allin-packages/channel-module/tests/integration/`目录中的测试用例
- **Schema定义**：检查后端模块的Schema定义，确保前后端Schema一致

### 技术栈转换要求
1. **Ant Design组件 → @d8d/shared-ui-components组件**：重写所有UI组件
2. **Jotai状态 → React Query + React状态**：重构状态管理
3. **Ant Design Form → React Hook Form + Zod**：转换表单逻辑
4. **自定义fetch API → Hono RPC (rpcClient + ClientManager模式)**：重构API客户端

### 文件路径和命名规范
- **包名**：`@d8d/allin-channel-management-ui`
- **目录名**：`channel-management-ui`
- **主组件**：`src/components/ChannelManagement.tsx`
- **RPC客户端**：`src/api/channelClient.ts`
- **类型文件**：`src/types/index.ts`
- **测试文件**：`tests/integration/channel.integration.test.tsx`

## Testing

### 测试标准 [Source: docs/architecture/testing-strategy.md]
- **测试框架**：使用 Vitest + Testing Library
- **测试位置**：`tests/integration/`目录（集成测试），`tests/components/`目录（组件测试）
- **测试类型**：集成测试验证完整CRUD流程和错误处理
- **覆盖率要求**：集成测试 ≥ 60%

### 本故事特定测试要求
1. **完整CRUD流程测试**：必须验证创建 → 查询 → 更新 → 删除的完整流程
2. **错误处理测试**：测试API错误、网络错误、验证错误的处理
3. **搜索功能测试**：测试按名称搜索和分页查询
4. **表单验证测试**：测试Zod验证规则和错误提示
5. **状态管理测试**：验证React Query数据获取和更新
6. **API集成测试**：验证RPC客户端调用正确性
7. **用户交互测试**：测试点击、输入、表单提交等交互
8. **渠道选择器组件测试**：测试渠道选择器的数据加载、选择功能、错误处理和禁用状态

### 测试执行流程
1. 设置测试环境，配置必要的mock
2. 编写完整CRUD流程测试，模拟用户操作
3. 编写错误处理测试，验证错误场景
4. 编写搜索功能测试，验证筛选和分页
5. 测试表单验证和提交逻辑
6. 验证API调用和状态更新
7. 编写渠道选择器组件测试，验证数据加载和选择功能
8. 检查测试覆盖率和通过率

### 测试精度优化（基于故事008.001经验）
- 在组件中添加test ID到所有交互元素
- 测试中使用test ID而非文本查找
- 提高测试的稳定性和可维护性

## Change Log
| Date | Version | Description | Author |
|------|---------|-------------|--------|
| 2025-12-03 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
| 2025-12-03 | 1.1 | 添加渠道选择器组件任务，参照平台选择器组件模式 | John (PM) |

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

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

### 关键修复经验记录
1. **路由名称一致性验证**：发现故事中描述的路由名称与实际路由定义不一致，先更新故事文件再修复代码
2. **测试选择器优化**：使用test ID代替文本查找，避免选择器冲突
3. **类型推导修复**：根据实际路由结构修复类型定义，正确处理混合路由模式（自定义路由+CRUD路由）
4. **表单组件模式**：参考PlatformManagement.tsx，使用条件渲染两个独立的Form组件
5. **API调用修正**：根据实际路由名称修正API调用：`index.$get` → `getAllChannels.$get`，`searchChannel` → `searchChannels`
6. **路由结构验证**：通过查看后台模块集成测试确认正确的路由结构：`getChannel[':id'].$get`而不是`getChannel.$get`
7. **类型推断优化**：参考广告管理UI模式，使用RPC推断类型`ChannelListItem = ChannelListResponse['data'][0]`，避免直接导入schema类型

### Completion Notes List
1. ✅ 前8个任务已完成
2. ✅ 8个集成测试全部通过
3. ✅ 类型检查通过（channel-management-ui包无错误）
4. ✅ 前后端Schema一致性验证完成
5. ✅ API路径映射正确性验证完成
6. ✅ 技术栈转换完成（Ant Design → @d8d/shared-ui-components，Jotai → React Query，Ant Form → React Hook Form + Zod）
7. ✅ 第9个任务（渠道选择器组件）已完成

### File List
1. `allin-packages/channel-management-ui/package.json` - 包配置
2. `allin-packages/channel-management-ui/tsconfig.json` - TypeScript配置
3. `allin-packages/channel-management-ui/vitest.config.ts` - 测试配置
4. `allin-packages/channel-management-ui/src/components/ChannelManagement.tsx` - 主组件
5. `allin-packages/channel-management-ui/src/api/channelClient.ts` - RPC客户端
6. `allin-packages/channel-management-ui/src/api/index.ts` - API导出
7. `allin-packages/channel-management-ui/src/types/index.ts` - 类型定义
8. `allin-packages/channel-management-ui/tests/integration/channel.integration.test.tsx` - 集成测试
9. `allin-packages/channel-management-ui/src/schemas/channel.schema.ts` - 表单验证Schema
10. `allin-packages/channel-management-ui/src/components/ChannelSelector.tsx` - 渠道选择器组件
11. `allin-packages/channel-management-ui/tests/integration/channel-selector.integration.test.tsx` - 渠道选择器集成测试
12. `allin-packages/channel-management-ui/src/components/index.ts` - 组件导出文件
13. `allin-packages/channel-management-ui/src/index.ts` - 包主导出文件

## QA Results
*此部分由QA代理在QA审查后填写*