007.007.merchant-module-multi-tenant-replication.md 11 KB

故事007.007: 商户模块多租户复制

状态

已完成

故事

作为 系统管理员, 我想要 复制商户模块并添加多租户支持, 以便 商户可以在租户隔离的环境中管理,同时保持与现有单租户系统的完全兼容性。

验收标准

  1. AC 1: ✅ 成功复制 @d8d/merchant-module@d8d/merchant-module-mt,包含正确的包配置
  2. AC 2: ✅ 创建多租户商户实体 MerchantMt,包含租户ID字段和表名 merchants_mt
  3. AC 3: ✅ 更新所有商户CRUD操作,自动包含租户过滤并在创建时设置租户ID
  4. AC 4: ✅ 验证商户数据隔离在不同租户间正常工作
  5. AC 5: ✅ 保持与现有单租户商户模块功能的完全兼容性
  6. AC 6: ✅ 所有现有单租户API接口保持不变且功能正常
  7. AC 7: ✅ 完整的集成测试证明租户隔离和功能正常
  8. AC 8: ✅ 性能影响相比单租户版本小于5%
  9. AC 9: ✅ 完成所有多租户模块的回归测试验证,确保系统稳定性

任务 / 子任务

  • [x] 复制商户模块为多租户版本 (AC: 1)

    • 复制 packages/merchant-modulepackages/merchant-module-mt
    • 更新包配置为 @d8d/merchant-module-mt
    • 清理单租户文件: 删除多租户包中所有单租户相关文件,避免命名冲突
    • 更新依赖:
    • @d8d/user-module 替换为 @d8d/user-module-mt
    • @d8d/auth-module 替换为 @d8d/auth-module-mt
    • @d8d/file-module 替换为 @d8d/file-module-mt
  • [x] 更新多租户商户实体 (AC: 2)

    • 创建 MerchantMt 实体,表名为 merchants_mt
    • 添加 tenantId 字段和正确的TypeORM配置
    • 保持其他字段与单租户版本一致
  • [x] 更新多租户商户服务 (AC: 3, 4)

    • 创建 MerchantServiceMt 服务,继承GenericCrudService
    • 所有查询操作自动添加租户过滤
    • 创建操作自动设置租户ID
    • 更新登录统计方法支持租户隔离
    • 更新用户名查找方法支持租户过滤
  • [x] 更新多租户路由配置 (AC: 3)

    • 更新用户路由使用多租户实体和服务
    • 更新管理员路由使用多租户实体和服务
    • 保持API接口与单租户版本一致
    • 更新认证中间件支持租户ID提取
  • [x] 更新Schema定义 (AC: 3)

    • 创建多租户商户Schema MerchantSchemaMt
    • 创建多租户用户商户Schema UserMerchantSchemaMt
    • 创建多租户管理员商户Schema AdminMerchantSchemaMt
    • 添加租户ID字段定义
  • [x] 实现租户数据隔离API测试 (AC: 7)

    • packages/merchant-module-mt/tests/integration/user-routes.integration.test.ts 中添加租户隔离测试用例
    • packages/merchant-module-mt/tests/integration/admin-routes.integration.test.ts 中添加跨租户商户访问安全验证
    • 在现有功能测试中验证租户过滤功能正确性
  • [x] 验证单租户系统完整性 (AC: 5, 6)

    • 运行单租户商户模块回归测试
    • 验证单租户API接口不受影响
    • 确认单租户数据库表结构不变
  • [x] 在创建复制的代码修改完后先运行安装

    • 在复制模块后运行 pnpm install 安装依赖
    • 验证新包已正确添加到工作区
    • 确认所有依赖解析正确
  • [x] 执行性能基准测试 (AC: 8)

    • 运行多租户商户模块性能测试
    • 比较单租户与多租户性能差异
    • 确保性能影响小于5%
  • [x] 执行回归测试验证 (AC: 9)

    • 运行所有多租户模块的回归测试
    • 验证权限模块多租户测试 (38个测试)
    • 验证文件模块多租户测试 (40个测试)
    • 验证区域模块多租户测试 (29个测试)
    • 验证用户模块多租户测试 (41个测试)
    • 验证配送地址模块多租户测试 (36个测试)
    • 验证租户模块多租户测试 (16个测试)
    • 确认所有200个测试全部通过

开发说明

前面故事的经验教训

从故事007.006(地址模块)学到的关键经验:

  • 共享CRUD库执行顺序: 必须确保在GenericCrudService.getById方法中租户验证先于数据权限验证 [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
  • 测试数据租户ID管理: 测试数据工厂必须显式设置tenantId字段以避免约束错误 [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
  • 跨租户访问状态码: 跨租户访问应该返回404(未找到)而不是403(禁止访问) [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]
  • 文件命名约定: 严格使用 .mt.ts 后缀区分多租户文件 [Source: epic-007-multi-tenant-package-replication.md#最佳实践]
  • 数据库同步: 在vitest配置中使用 fileParallelism: false 避免数据库冲突 [Source: epic-007-multi-tenant-package-replication.md#技术挑战和解决方案]

数据模型

商户实体结构:

  • 表名: merchants_mt (多租户版本)
  • 租户ID字段: tenantId (必需,已索引)
  • 核心字段: name, username, password, phone, realname, loginNum, loginTime, loginIp, lastLoginTime, lastLoginIp, state, rsaPublicKey, aesKey [Source: source-tree.md#商户管理模块]
  • 用户跟踪字段: createdBy, updatedBy [Source: source-tree.md#商户管理模块]
  • 时间戳字段: createdAt, updatedAt [Source: source-tree.md#商户管理模块]

API规范

用户路由:

  • 路径: /api/merchants (用户专用)
  • 认证: authMiddleware 来自 @d8d/auth-module-mt [Source: source-tree.md#商户管理模块]
  • 数据权限: 启用,使用 userIdField: 'createdBy' [Source: source-tree.md#商户管理模块]
  • 搜索字段: ['name', 'username', 'realname', 'phone'] [Source: source-tree.md#商户管理模块]

管理员路由:

  • 路径: /api/admin/merchants (完整权限)
  • 认证: authMiddleware 来自 @d8d/auth-module-mt [Source: source-tree.md#商户管理模块]
  • 数据权限: 管理员路由禁用数据权限控制 [Source: source-tree.md#商户管理模块]

组件规范

商户服务方法:

  • updateLoginStats(merchantId, loginTime, loginIp): 更新商户登录统计信息 [Source: source-tree.md#商户管理模块]
  • findByUsername(username): 根据用户名查找商户,包含租户过滤 [Source: source-tree.md#商户管理模块]
  • getByState(state): 根据状态获取商户列表,包含租户过滤 [Source: source-tree.md#商户管理模块]

文件位置

要创建的源文件:

  • packages/merchant-module-mt/src/entities/merchant.mt.entity.ts (多租户实体)
  • packages/merchant-module-mt/src/services/merchant.mt.service.ts (多租户服务)
  • packages/merchant-module-mt/src/routes/user-routes.mt.ts (多租户用户路由)
  • packages/merchant-module-mt/src/routes/admin-routes.mt.ts (多租户管理员路由)
  • packages/merchant-module-mt/src/schemas/merchant.mt.schema.ts (多租户schemas)
  • packages/merchant-module-mt/tests/integration/tenant-isolation.integration.test.ts (租户隔离测试)

要删除的文件(单租户清理):

  • 多租户包中所有没有 .mt.ts 后缀的文件
  • 任何单租户特定的配置

技术约束

数据库索引:

  • 必须在 tenantId 字段上创建索引以提高性能 [Source: epic-007-multi-tenant-package-replication.md#数据库迁移策略]
  • 为常见查询模式创建复合索引 (tenantId + state, tenantId + username)

认证集成:

  • 使用来自 @d8d/auth-module-mt 的更新版 authMiddleware,从用户上下文中提取租户ID [Source: epic-007-multi-tenant-package-replication.md#租户上下文管理]
  • 租户ID应该从认证用户上下文中自动设置

测试

测试标准:

  • 测试文件位置: packages/merchant-module-mt/tests/integration/ [Source: testing-strategy.md#集成测试]
  • 测试框架: Vitest + hono/testing + shared-test-util [Source: testing-strategy.md#集成测试]
  • 测试模式: 使用测试数据工厂并显式设置tenantId [Source: testing-strategy.md#测试数据管理]
  • 覆盖率目标: ≥ 60% 集成测试覆盖率 [Source: testing-strategy.md#各层覆盖率要求]
  • 数据库策略: 使用测试数据库和事务回滚 [Source: testing-strategy.md#数据库测试策略]

特定测试要求:

  • 租户隔离验证: 验证不同租户的商户无法访问彼此的数据
  • 跨租户访问: 跨租户访问尝试应该返回404状态码
  • 登录统计: 验证登录统计在租户上下文中正确更新
  • 用户名唯一性: 确保用户名唯一性在租户级别强制执行,而不是全局

变更日志

日期 版本 描述 作者
2025-11-14 1.0 初始故事创建,包含从前面的故事中学到的全面经验教训 Bob (Scrum Master)

开发代理记录

实施进展 (2025-11-14):

已完成任务:

  • 成功复制商户模块为多租户版本 @d8d/merchant-module-mt
  • 创建多租户商户实体 MerchantMt 和表结构
  • 更新多租户商户服务 MerchantServiceMt 支持租户过滤
  • 更新多租户路由配置(用户路由和管理员路由)
  • 更新Schema定义支持租户ID字段
  • 在现有测试中添加租户隔离测试用例
  • 解决实体循环依赖问题(UserEntityMt和FileMt使用字符串形式的关系定义)
  • 修复跨租户访问状态码(返回404而不是403)
  • 解决测试数据字段长度问题
  • 修复租户选项配置问题
  • 最终修复: 恢复共享CRUD服务中的正确错误处理逻辑,确保路由层能正确捕获权限错误
  • 回归测试: 完成所有多租户模块的回归测试验证

所有测试通过:

  • 37个集成测试全部通过
  • GET访问其他用户的商户返回404状态码
  • PUT/DELETE操作其他用户的商户返回403状态码
  • Zod验证问题完全解决,数据库数据都能通过Schema验证
  • 租户数据隔离验证成功

回归测试结果 (200个测试全部通过):

  • 权限模块 (auth-module-mt): 38个测试 ✅
  • 文件模块 (file-module-mt): 40个测试 ✅
  • 区域模块 (geo-areas-mt): 29个测试 ✅
  • 用户模块 (user-module-mt): 41个测试 ✅
  • 配送地址模块 (delivery-address-module-mt): 36个测试 ✅
  • 租户模块 (tenant-module-mt): 16个测试 ✅

技术挑战解决:

  • 实体循环依赖:UserEntityMt和FileMt必须使用字符串形式的关系定义
  • 实体注册:确保所有相关实体(RoleMt、FileMt)正确注册
  • 租户验证执行顺序:确保在GenericCrudService中租户验证先于数据权限验证
  • 跨租户访问状态码:返回404(未找到)而不是403(禁止访问)
  • 共享CRUD错误处理: 恢复updatedelete方法中的权限验证抛出错误逻辑,确保路由层能正确捕获并返回相应状态码
  • Zod验证问题: 完全解决所有数据库返回数据的Schema验证问题

代码质量:

  • 创建了商户模块专用的测试工具类 MerchantTestUtils
  • 使用测试数据工厂模式简化测试代码
  • 所有多租户文件使用 .mt.ts 后缀
  • 保持API接口与单租户版本完全兼容
  • 共享CRUD服务中的错误处理逻辑完全符合设计原则
  • 所有多租户模块回归测试通过,确保系统稳定性

QA结果

此部分将在质量保证审查过程中由QA代理填充