Files
tiku-backend.net/docs/migration/phase-3-tenant-isolation-and-shared-question-bank.md

2.3 KiB
Raw Blame History

第三阶段:租户隔离、共享题库与前端运行时

状态:已完成主线设计和实现。

目标

  • 普通业务代码默认只能读取和写入当前租户数据。
  • 公共题库由平台主体拥有,有效租户可访问。
  • 租户私题只属于本租户。
  • 公共题和私题可混合组卷、答题、收藏、错题和统计。
  • 租户自定义域名安全解析到统一前端运行时配置。

结果

  • ITenantContext 只读化,请求租户由中间件解析。
  • EF Core Query Filter 自动按租户过滤。
  • SaveChanges 拦截器自动写入当前租户并拒绝跨租户写入。
  • DbContext 使用 scoped AddDbContext,避免池化串租户状态。
  • TenantResolutionMiddleware 在认证前按可信 Host 解析租户。
  • JWT tenant claim 与 Host 解析不一致时返回 403。
  • 未知、Pending、禁用域名在业务前返回 404。
  • 唯一 PlatformOwned 租户拥有公共题库、公共题、公共题版本和公共分类主干。
  • TenantQuestionReference 作为公共题/私题消费引用。
  • PracticeSessionQuestion 锁定题目版本,历史答题按原版本回放。
  • TenantFrontendConfig 支持 Draft / Preview / Publish。
  • GET /api/runtime/bootstrap 仅根据当前 Host 返回公开配置。

数据库边界

EF Core 负责实体、索引、外键和普通约束。以下跨表租户不变量由集中 PostgreSQL guard 管理:

  • TenantQuestionReference 只能引用平台公共题或当前租户私题。
  • TaxonomyNode 父节点只能属于平台主体或当前租户。

维护规则见根目录 README 的“数据库与 ORM 分工”。

验收

  • A 租户不能读取、修改、删除或 Attach B 租户数据。
  • A 可访问公共题和 A 私题,不能构造 B 私题引用。
  • 公共题 V1 创建会话后发布 V2旧会话仍使用 V1新会话使用 V2。
  • Host A 携带 Tenant B JWT 返回 403。
  • Pending/未知域名和 Suspended 租户无法获取 runtime bootstrap。
  • 新增租户实体漏写 filter、组合外键或租户索引时模型测试失败。
dotnet build TIKU-BACKEND.slnx --no-restore
dotnet test Tiku.UnitTests/Tiku.UnitTests.csproj --no-build
dotnet test Tiku.IntegrationTests/Tiku.IntegrationTests.csproj --no-build
dotnet ef migrations script --project Tiku.Infrastructure --startup-project Tiku.DbMigrator
git diff --check