Przeglądaj źródła

docs: 添加故事 010.012 - 统一广告模块响应格式规范化

创建新故事修复统一广告模块的API响应格式,使其符合项目shared-crud标准规范。

问题:
- 统一广告模块使用非标准响应格式 { code, message, data: { list, ... } }
- 与项目标准格式 { data: [...], pagination: {...} } 不一致

变更范围:
- 4个后端路由文件(admin ads, ad types, user ads, ad types)
- 2个UI hooks文件
- 相关集成测试

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

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 2 tygodni temu
rodzic
commit
b0442bdb09

+ 41 - 0
docs/prd/epic-010-unified-ad-management.md

@@ -24,6 +24,7 @@
 | 1.17 | 2026-01-04 | 完成故事010.010:创建统一文件管理UI包(30个测试,使用RPC推断类型) | Claude (Dev Agent) |
 | 1.18 | 2026-01-04 | 批准故事010.011:集成统一文件模块到统一广告和租户后台 | Bob (Scrum Master) |
 | 1.19 | 2026-01-04 | 完成故事010.011:集成统一文件模块(统一广告模块迁移到UnifiedFile) | Claude (Dev Agent) |
+| 1.20 | 2026-01-04 | 添加故事010.012:统一广告模块响应格式规范化 | James (Dev Agent) |
 
 ## 史诗目标
 
@@ -457,6 +458,46 @@ packages/unified-file-management-ui/
 4. **租户后台集成**: 文件管理菜单和路由已添加
 5. **类型系统扩展**: `AuthContext` 添加 `superAdminId` 字段
 
+### Story 12: 统一广告模块响应格式规范化 🔄 进行中
+
+**标题**: 统一广告模块响应格式规范化
+
+**描述**: 修复统一广告模块的API响应格式,使其符合项目 `shared-crud` 标准格式规范。
+
+**背景说明**:
+- 统一广告模块实施时使用了非标准响应格式(嵌套在 `code/message/data` 结构中)
+- 项目标准格式(`shared-crud/generic-crud.routes.ts`)要求列表响应为 `{ data: [...], pagination: {...} }`
+- 当前格式与UI包的数据处理模式不一致,影响代码可维护性
+
+**任务**:
+- [ ] 修改管理员广告路由响应格式(`admin/unified-advertisements.admin.routes.ts`)
+- [ ] 修改管理员广告类型路由响应格式(`admin/unified-advertisement-types.admin.routes.ts`)
+- [ ] 修改用户端广告路由响应格式(`unified-advertisements.crud.routes.ts`)
+- [ ] 修改用户端广告类型路由响应格式(`unified-advertisement-types.crud.routes.ts`)
+- [ ] 适配统一广告管理UI(hooks和测试)
+- [ ] 更新后端集成测试
+- [ ] 更新Server包集成测试
+
+**响应格式变更**:
+```typescript
+// 列表响应: 当前 → 标准
+{ code: 200, message: 'success', data: { list: [...], total, page, pageSize } }
+→
+{ data: [...], pagination: { total, current, pageSize } }
+
+// 单项响应: 当前 → 标准
+{ code: 200, message: 'success', data: { id, ... } }
+→
+{ id, ... }  // 直接返回资源对象
+
+// 删除响应: 当前 → 标准
+{ code: 200, message: '...' }
+→
+204 No Content  // 空响应
+```
+
+**相关文件**: `docs/stories/010.012.story.md`
+
 ## 兼容性要求
 
 - [x] 现有广告API端点保持向后兼容(或提供适配层)

+ 226 - 0
docs/stories/010.012.story.md

@@ -0,0 +1,226 @@
+# Story 010.012: 统一广告模块响应格式规范化
+
+## Status
+Approved
+
+## Story
+
+**As a** 开发者,
+**I want** 统一广告模块的API响应格式与项目规范(`shared-crud`)保持一致,
+**so that** 前端UI可以使用统一的数据处理模式,确保系统架构的一致性和可维护性。
+
+## Acceptance Criteria
+
+1. 列表查询响应格式修改为标准格式:`{ data: [...], pagination: { total, current, pageSize } }`
+2. 单项查询(get/create/update)响应格式修改为直接返回资源对象:`{ id, ... }`
+3. 删除操作响应修改为 `204 No Content`(空响应)
+4. 统一广告管理UI适配新的响应格式
+5. 所有相关测试通过(模块测试、UI测试、集成测试)
+6. API文档/Schema定义更新为新的响应格式
+
+## Tasks / Subtasks
+
+- [ ] **任务1: 修改管理员广告路由响应格式** (AC: 1, 2, 3)
+  - [ ] 修改 `packages/unified-advertisements-module/src/routes/admin/unified-advertisements.admin.routes.ts`
+  - [ ] 列表响应:移除 `code`, `message`,将 `data.list` 改为 `data`(数组),将分页信息移到 `pagination` 对象,`page` 改为 `current`
+  - [ ] GET单项响应:移除 `code`, `message`,直接返回验证后的资源对象
+  - [ ] CREATE响应:返回201状态码,直接返回资源对象
+  - [ ] UPDATE响应:返回200状态码,直接返回资源对象
+  - [ ] DELETE响应:返回204状态码,空响应(`c.body(null, 204)`)
+
+- [ ] **任务2: 修改管理员广告类型路由响应格式** (AC: 1, 2, 3)
+  - [ ] 修改 `packages/unified-advertisements-module/src/routes/admin/unified-advertisement-types.admin.routes.ts`
+  - [ ] 应用与任务1相同的响应格式修改
+
+- [ ] **任务3: 修改用户端广告路由响应格式** (AC: 1, 2, 3)
+  - [ ] 修改 `packages/unified-advertisements-module/src/routes/unified-advertisements.crud.routes.ts`
+  - [ ] 列表响应:应用标准格式(注意:这是只读路由,只有GET操作)
+  - [ ] GET单项响应:直接返回资源对象
+
+- [ ] **任务4: 修改用户端广告类型路由响应格式** (AC: 1, 2, 3)
+  - [ ] 修改 `packages/unified-advertisements-module/src/routes/unified-advertisement-types.crud.routes.ts`
+  - [ ] 列表响应:应用标准格式
+
+- [ ] **任务5: 更新路由Schema定义** (AC: 6)
+  - [ ] 修改所有路由的 `responses.openapi` schema定义以匹配新格式
+  - [ ] 列表响应schema:`{ data: z.array(schema), pagination: { total, current, pageSize } }`
+  - [ ] 单项响应schema:直接使用资源schema(不包装)
+  - [ ] 删除响应schema:`204 No Content`
+
+- [ ] **任务6: 适配统一广告管理UI** (AC: 4)
+  - [ ] 修改 `packages/unified-advertisement-management-ui/src/hooks/useAdvertisementManagement.ts`
+  - [ ] 更新数据处理逻辑:适配新的响应格式(`response.data` 直接是数组,`response.pagination` 包含分页信息)
+  - [ ] 更新单项数据处理:适配直接返回资源对象的格式
+  - [ ] 修改 `packages/unified-advertisement-management-ui/src/hooks/useAdTypeManagement.ts` 应用相同修改
+
+- [ ] **任务7: 更新UI测试Mock数据** (AC: 5)
+  - [ ] 修改 `packages/unified-advertisement-management-ui/tests/` 中的所有mock响应
+  - [ ] 确保mock数据符合新的响应格式
+  - [ ] 验证所有UI测试通过
+
+- [ ] **任务8: 更新后端集成测试** (AC: 5)
+  - [ ] 修改 `packages/unified-advertisements-module/tests/integration/` 中的测试断言
+  - [ ] 验证列表响应包含 `data` 数组和 `pagination` 对象
+  - [ ] 验证单项响应直接返回资源对象
+  - [ ] 验证删除返回204状态码
+
+- [ ] **任务9: 更新Server包集成测试** (AC: 5)
+  - [ ] 检查 `packages/server/tests/integration/` 中涉及统一广告的测试
+  - [ ] 更新测试断言以匹配新的响应格式
+  - [ ] 验证测试通过
+
+- [ ] **任务10: 类型检查和代码质量** (AC: 5)
+  - [ ] 运行 `pnpm typecheck` 确保无TypeScript类型错误
+  - [ ] 运行 `pnpm lint` 确保代码规范检查通过
+  - [ ] 运行所有相关测试并确保通过
+
+## Dev Notes
+
+### 问题说明
+
+**当前响应格式(不符合规范)** [Source: packages/unified-advertisements-module/src/routes/admin/unified-advertisements.admin.routes.ts]:
+```typescript
+// 列表响应 - 当前格式
+{
+  code: 200,
+  message: 'success',
+  data: {
+    list: [...],      // ← 嵌套在 list 中
+    total: 100,
+    page: 1,          // ← 使用 page 而非 current
+    pageSize: 10
+  }
+}
+
+// 单项响应 - 当前格式
+{
+  code: 200,
+  message: 'success',
+  data: { id: 1, ... }  // ← 嵌套在 data 中
+}
+
+// 删除响应 - 当前格式
+{
+  code: 200,
+  message: 'Advertisement deleted successfully'  // ← 有内容
+}
+```
+
+**标准响应格式(generic-crud.routes.ts)** [Source: packages/shared-crud/src/routes/generic-crud.routes.ts]:
+```typescript
+// 列表响应 - 标准格式
+{
+  data: [...],           // ← 数组直接在根级别
+  pagination: {
+    total: 100,
+    current: 1,          // ← 使用 current
+    pageSize: 10
+  }
+}
+
+// 单项响应 - 标准格式
+{ id: 1, name: "..." }   // ← 直接返回资源对象
+
+// 删除响应 - 标准格式
+204 No Content          // ← 空响应
+```
+
+### 需要修改的文件清单
+
+**后端路由文件**:
+1. `packages/unified-advertisements-module/src/routes/admin/unified-advertisements.admin.routes.ts`
+2. `packages/unified-advertisements-module/src/routes/admin/unified-advertisement-types.admin.routes.ts`
+3. `packages/unified-advertisements-module/src/routes/unified-advertisements.crud.routes.ts`
+4. `packages/unified-advertisements-module/src/routes/unified-advertisement-types.crud.routes.ts`
+
+**前端UI文件**:
+1. `packages/unified-advertisement-management-ui/src/hooks/useAdvertisementManagement.ts`
+2. `packages/unified-advertisement-management-ui/src/hooks/useAdTypeManagement.ts`
+3. `packages/unified-advertisement-management-ui/tests/` 中的所有测试文件
+
+**测试文件**:
+1. `packages/unified-advertisements-module/tests/integration/` 中的所有集成测试
+2. `packages/server/tests/integration/` 中涉及统一广告的测试(如有)
+
+### 相关标准规范
+
+**后端模块开发规范** [Source: docs/architecture/backend-module-package-standards.md]:
+- 使用 `OpenAPIHono` 定义路由
+- 使用 `createRoute` 定义路由schema
+- 响应格式应与 `shared-crud` 保持一致
+
+**编码标准** [Source: docs/architecture/coding-standards.md]:
+- 自定义路由必须使用 `parseWithAwait` 验证响应数据
+- 使用 `z.coerce.date<Date>()` 和 `z.coerce.number<number>()`(Zod 4.0需要泛型参数)
+
+### 前一故事关键要点
+
+**来自故事 010.011(集成统一文件模块)**:
+- 统一广告模块已完成迁移到 `UnifiedFile` 实体
+- 统一广告管理UI已集成统一文件选择器
+- 测试覆盖:57/57 模块测试通过,51/51 UI测试通过
+- 关联查询:`relations: ['imageFile', 'advertisementType']`
+
+**来自故事 010.003(路由路径规范问题)**:
+- 模块内路由使用相对路径(如 `/` 和 `/:id`)
+- Server包注册时添加完整前缀(如 `/api/v1/admin/unified-advertisements`)
+
+### API端点参考
+
+**管理员广告API**:
+- `GET /api/v1/admin/unified-advertisements` - 列表(需修改响应格式)
+- `GET /api/v1/admin/unified-advertisements/:id` - 单项(需修改响应格式)
+- `POST /api/v1/admin/unified-advertisements` - 创建(需修改响应格式)
+- `PUT /api/v1/admin/unified-advertisements/:id` - 更新(需修改响应格式)
+- `DELETE /api/v1/admin/unified-advertisements/:id` - 删除(需修改响应格式)
+
+**管理员广告类型API**:
+- `GET /api/v1/admin/unified-advertisement-types` - 列表(需修改响应格式)
+- `GET /api/v1/admin/unified-advertisement-types/:id` - 单项(需修改响应格式)
+- `POST /api/v1/admin/unified-advertisement-types` - 创建(需修改响应格式)
+- `PUT /api/v1/admin/unified-advertisement-types/:id` - 更新(需修改响应格式)
+- `DELETE /api/v1/admin/unified-advertisement-types/:id` - 删除(需修改响应格式)
+
+**用户展示API**(只读):
+- `GET /api/v1/advertisements` - 列表(需修改响应格式)
+- `GET /api/v1/advertisements/:id` - 单项(需修改响应格式)
+- `GET /api/v1/advertisement-types` - 列表(需修改响应格式)
+
+### Testing
+
+**测试文件位置** [Source: docs/architecture/testing-strategy.md]:
+- 后端模块测试:`packages/{module-name}/tests/`
+- UI包测试:`packages/{ui-name}/tests/`
+- Server集成测试:`packages/server/tests/integration/`
+
+**测试框架**:
+- 后端:Vitest + hono/testing
+- UI:Vitest + Testing Library
+
+**测试要求**:
+- 更新所有涉及响应格式的测试断言
+- 验证新响应格式的正确性
+- 确保测试覆盖率不低于修改前水平
+
+## Change Log
+
+| Date | Version | Description | Author |
+|------|---------|-------------|--------|
+| 2026-01-04 | 1.0 | 初始创建故事 | James (Dev Agent) |
+
+## Dev Agent Record
+
+### Agent Model Used
+_待开发时填写_
+
+### Debug Log References
+_待开发时填写_
+
+### Completion Notes List
+_待开发时填写_
+
+### File List
+_待开发时填写_
+
+## QA Results
+_待QA评审时填写_