Approved
As a 超级管理员, I want 一个统一的后端广告模块(无租户隔离), so that 可以在租户管理后台统一管理所有广告,所有租户用户端看到相同的广告数据。
packages/unified-advertisements-module 包,包含完整的Entity、Service、Schema、Routes结构tenant_id 字段,与原 advertisements-module-mt 的Entity结构相同但移除租户隔离tenantAuthMiddleware),只有超级管理员(ID=1)可访问authMiddleware),返回统一的广告数据给所有租户@d8d/core-module-mt/file-module-mt),使用 FileMt 实体[x] 任务1: 创建包结构和配置文件 (AC: 1)
packages/unified-advertisements-module 目录package.json,配置包名为 @d8d/unified-advertisements-moduletsconfig.jsonvitest.config.ts(设置 fileParallelism: false)src/ 子目录:entities/, services/, routes/, schemas/tests/ 子目录:integration/, utils/[x] 任务2: 定义Entity(无tenant_id字段) (AC: 2)
src/entities/unified-advertisement.entity.ts,参考 advertisements-module-mt 但移除 tenant_id 字段src/entities/unified-advertisement-type.entity.ts@ManyToOne 关联 FileMt(使用核心包路径)和 AdvertisementTypesrc/entities/index.ts 导出所有Entity[x] 任务3: 实现Service层 (AC: 2, 7)
src/services/unified-advertisement.service.ts,继承 GenericCrudServicesrc/services/unified-advertisement-type.service.tscreate、update、delete 方法(使用 override 关键字)status=0)src/services/index.ts 导出所有Service[x] 任务4: 定义Schema (AC: 5)
src/schemas/unified-advertisement.schema.ts,使用 Zod + OpenAPI装饰器src/schemas/unified-advertisement-type.schema.tsz.coerce.date<Date>() 和 z.coerce.number<number>() 泛型语法Create*Dto、Update*Dto、*ListResponseSchemaz.infer),类型由RPC自动推断src/schemas/index.ts 导出所有Schema[x] 任务5: 实现管理员路由(超级管理员专用) (AC: 3)
src/routes/admin/unified-advertisements.admin.routes.tsOpenAPIHono 和 AuthContext 泛型createRoute 定义路由,包含请求/响应SchematenantAuthMiddleware 中间件(来自 @d8d/tenant-module-mt,独立包)parseWithAwait 验证响应数据createZodErrorResponse 处理Zod错误ZodErrorSchema,其他错误使用 ErrorSchema[x] 任务6: 实现用户展示路由(与原模块保持一致) (AC: 4, 5)
src/routes/unified-advertisements.routes.tsauthMiddleware 中间件(来自 @d8d/core-module-mt/auth-module-mt)GET /api/v1/advertisements、GET /api/v1/advertisements/:idadvertisements-module-mt 一致tenantOptions,返回统一数据给所有租户[x] 任务7: 创建包导出入口 (AC: 1)
src/index.ts,导出Entities、Services、Routes、Schemaspackage.json 的 exports 字段,支持子路径导出[x] 任务8: 编写单元测试 (AC: 7)
tests/utils/test-data-factory.ts[x] 任务9: 编写集成测试 (AC: 7)
tests/integration/unified-advertisements.integration.test.tstenantAuthMiddleware 权限)[x] 任务10: 代码质量检查 (AC: 1, 7)
pnpm typecheck 确保无TypeScript错误pnpm lint 确保代码符合规范pnpm test 确保所有测试通过pnpm test:coverage 确保覆盖率达标[x] 任务11: 添加广告类型管理路由测试 (测试覆盖率提升)
新包位置:
packages/unified-advertisements-module/
├── package.json
├── tsconfig.json
├── vitest.config.ts
├── src/
│ ├── entities/
│ │ ├── unified-advertisement.entity.ts
│ │ ├── unified-advertisement-type.entity.ts
│ │ └── index.ts
│ ├── services/
│ │ ├── unified-advertisement.service.ts
│ │ ├── unified-advertisement-type.service.ts
│ │ └── index.ts
│ ├── routes/
│ │ ├── admin/
│ │ │ └── unified-advertisements.admin.routes.ts
│ │ ├── unified-advertisements.routes.ts
│ │ ├── unified-advertisement-types.routes.ts
│ │ └── index.ts
│ ├── schemas/
│ │ ├── unified-advertisement.schema.ts
│ │ ├── unified-advertisement-type.schema.ts
│ │ └── index.ts
│ └── index.ts
└── tests/
├── integration/
│ └── unified-advertisements.integration.test.ts
└── utils/
└── test-data-factory.ts
参考模块:
packages/advertisements-module-mt@d8d/core-module-mt/auth-module-mt@d8d/core-module-mt/tenant-module-mt@d8d/core-module-mt/file-module-mt统一广告Entity (unified-advertisement.entity.ts):
advertisements-module-mt 的Entity结构tenant_id 字段@ManyToOne 关联 FileMt(从核心包路径引用)@ManyToOne 关联 UnifiedAdvertisementTypeid, title, typeId, code, url, imageFileId, sort, status, actionType, createdAt, updatedAt, createdBy, updatedBy核心包引用规范 [Source: docs/architecture/backend-module-package-standards.md#核心包引用规范]:
// ✅ 正确:从核心包路径引用
import { FileMt } from '@d8d/core-module-mt/file-module-mt';
// ❌ 错误:直接从桥接包引用
import { FileMt } from '@d8d/file-module-mt';
管理员接口 (新增):
GET /api/v1/admin/unified-advertisements # 广告列表
POST /api/v1/admin/unified-advertisements # 创建广告
PUT /api/v1/admin/unified-advertisements/:id # 更新广告
DELETE /api/v1/admin/unified-advertisements/:id # 删除广告
GET /api/v1/admin/unified-advertisement-types # 广告类型列表
POST /api/v1/admin/unified-advertisement-types # 创建广告类型
PUT /api/v1/admin/unified-advertisement-types/:id # 更新广告类型
DELETE /api/v1/admin/unified-advertisement-types/:id # 删除广告类型
用户展示接口 (保持不变 - 小程序端使用):
GET /api/v1/advertisements # 获取有效广告列表(不变)
GET /api/v1/advertisements/:id # 获取单个广告详情(不变)
GET /api/v1/advertisement-types # 获取广告类型列表(不变)
关键设计: 小程序端无需任何改动,API契约100%兼容。只是后端数据源从多租户切换到统一模块。
管理员路由:
tenantAuthMiddleware(来自 @d8d/tenant-module-mt,独立包)import { tenantAuthMiddleware } from '@d8d/tenant-module-mt';packages/tenant-module-mt/src/middleware/用户展示路由:
authMiddleware(来自 @d8d/core-module-mt/auth-module-mt)import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt';Zod 4.0 coerce使用 [Source: docs/architecture/backend-module-package-standards.md#Schema规范]:
// ✅ 正确:Zod 4.0 - 使用泛型指定类型
z.coerce.date<Date>() // 转换为Date类型
z.coerce.number<number>() // 转换为number类型
// ❌ 错误:不指定泛型(Zod 4.0中类型推断可能不准确)
z.coerce.date()
z.coerce.number()
不导出推断类型 [Source: docs/architecture/backend-module-package-standards.md#类型使用说明]:
z.infer<typeof Schema>)测试配置 [Source: docs/architecture/backend-module-package-standards.md#测试配置]:
// vitest.config.ts
export default defineConfig({
test: {
globals: true,
environment: 'node',
include: ['tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
fileParallelism: false // 避免数据库连接冲突
}
});
测试数据工厂 [Source: docs/architecture/backend-module-package-standards.md#测试数据工厂]:
createTestData(overrides) 静态方法createTestRecord(dataSource, overrides) 异步方法关键: 与原 advertisements-module-mt 保持100%API兼容
[Source: docs/architecture/backend-module-package-standards.md#数据库类型规范]
| 数据库类型 | TypeORM类型 | 备注 |
|---|---|---|
int unsigned |
int + unsigned: true |
主键常用 |
varchar(n) |
varchar + length: n |
字符串 |
timestamp |
timestamp |
时间戳 |
int (状态) |
int |
状态枚举 |
[Source: docs/architecture/backend-module-package-standards.md#包配置规范]
{
"name": "@d8d/unified-advertisements-module",
"version": "1.0.0",
"type": "module",
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@d8d/shared-crud": "workspace:*",
"@d8d/shared-types": "workspace:*",
"@d8d/shared-utils": "workspace:*",
"@d8d/core-module-mt": "workspace:*",
"@d8d/tenant-module-mt": "workspace:*",
"@hono/zod-openapi": "^1.0.2",
"typeorm": "^0.3.20",
"zod": "^4.1.12"
}
}
重要说明:
@d8d/core-module-mt: 核心包聚合了 auth-module-mt、file-module-mt、user-module-mt 等基础模块
import { FileMt } from '@d8d/core-module-mt/file-module-mt';import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt';@d8d/tenant-module-mt: 独立的租户管理模块包(不在core-module-mt中)
import { tenantAuthMiddleware } from '@d8d/tenant-module-mt';tests/unit/(与源码文件对应)tests/integration/tests/utils/[Source: docs/architecture/testing-strategy.md]
| 测试类型 | 最低要求 | 目标要求 |
|---|---|---|
| 单元测试 | 70% | 80% |
| 集成测试 | 50% | 60% |
status=0 而非物理删除FileMt 和 AdvertisementType 关联正确# 进入模块目录
cd packages/unified-advertisements-module
# 运行所有测试
pnpm test
# 运行集成测试
pnpm test:integration
# 生成覆盖率报告
pnpm test:coverage
# 类型检查
pnpm typecheck
| Date | Version | Description | Author |
|---|---|---|---|
| 2026-01-02 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
| 2026-01-03 | 1.1 | 完成任务11:添加广告类型管理路由测试 | James (Claude Code) |
claude-opus-4-5-20251101 (d8d-model)
无需调试日志(测试问题直接定位并修复)
测试修复 (2026-01-02): 修复了Service层关键词搜索功能
GenericCrudService.getList 需要显式传入 searchFields 参数才能进行关键词搜索getList 方法,指定默认搜索字段UnifiedAdvertisementTypeService: 搜索 ['name', 'code']UnifiedAdvertisementService: 搜索 ['title', 'code']所有测试通过 (2026-01-02): 36/36 测试通过
任务11完成 (2026-01-03): 添加广告类型管理路由测试
UnifiedAdvertisementType.code添加唯一索引,添加与UnifiedAdvertisement的反向关系包配置文件:
package.json - 包配置tsconfig.json - TypeScript配置vitest.config.ts - Vitest测试配置Entity层:
src/entities/unified-advertisement.entity.ts - 统一广告Entity(无tenant_id字段)src/entities/unified-advertisement-type.entity.ts - 统一广告类型Entitysrc/entities/index.ts - Entity导出Service层:
src/services/unified-advertisement.service.ts - 广告Service(覆盖getList, create, update, delete)src/services/unified-advertisement-type.service.ts - 广告类型Service(覆盖getList, create, update, delete)src/services/index.ts - Service导出Schema层:
src/schemas/unified-advertisement.schema.ts - 广告Schema(使用Zod 4.0语法)src/schemas/unified-advertisement-type.schema.ts - 广告类型Schemasrc/schemas/index.ts - Schema导出路由层:
src/routes/admin/unified-advertisements.admin.routes.ts - 管理员广告路由(使用tenantAuthMiddleware)src/routes/admin/unified-advertisement-types.admin.routes.ts - 管理员广告类型路由src/routes/unified-advertisements.routes.ts - 用户展示路由(使用authMiddleware)src/routes/unified-advertisements.crud.routes.ts - 广告CRUD路由src/routes/unified-advertisement-types.routes.ts - 广告类型展示路由src/routes/unified-advertisement-types.crud.routes.ts - 广告类型CRUD路由src/routes/index.ts - 路由导出包入口:
src/index.ts - 包主入口测试文件:
tests/utils/test-data-factory.ts - 测试数据工厂tests/unit/unified-advertisement.service.test.ts - 广告Service单元测试(12个测试)tests/unit/unified-advertisement-type.service.test.ts - 广告类型Service单元测试(11个测试)tests/integration/unified-advertisements.integration.test.ts - 集成测试(34个测试)
待QA代理填写