spec.md 2.4 KB

multi-tenant-runtime

REQ-MT-001 租户识别

  • Controller 入口通过 TenantInterceptor 读 HTTP Header X-Tenant-Id
  • Header 缺失:返回 401 { code: "TENANT_REQUIRED" }
  • Header 存在但租户不在注册表:返回 403 { code: "TENANT_NOT_FOUND" }
  • 识别成功:写入 TenantContext.set(profile);请求结束时 TenantContext.clear()(务必在 finally)

REQ-MT-002 异步任务传递

  • @Async 线程池必须通过 TaskDecorator 复制 TenantContext 到子线程(参考现有 MdcTaskDecorator
  • CompletableFuture 手动切换线程时需显式 TenantContext.propagate(ctx, () -> ...)

REQ-MT-003 Token 隔离

  • UtilToken key 格式统一为 {tenantId}:{vendor}:{appKey}
  • mjava-pro 不得使用无 tenant 前缀的 UtilToken 接口
  • 无租户上下文(如定时任务)显式传 tenantId,或声明为 SYSTEM 伪租户

REQ-MT-004 审计日志扩展

  • UtilHttp 审计日志在 mjava-baseline §3.5 字段基础上追加 tenantId
  • 日志输出目标 ./log/{日期}/pro-{tenantId}.log(按租户分片,方便定责)

tenant-registry

REQ-TR-001 注册源

  • 租户配置存放于宜搭"应用表"(formUuid 配置在 tenant.registry.formUuid
  • 字段约定见 design.md 表格
  • 访问宜搭本身使用 application-{profile}.yml 配置的 aliwork.appType / aliwork.systemToken(这是 mjava-pro 自身的入口凭据,非租户凭据)

REQ-TR-002 加载与缓存

  • 启动时全量拉取一次,写入 Map<String, TenantProfile>
  • TTL:默认 600 秒(tenant.registry.ttlSeconds 可覆盖)
  • 过期后首次访问触发异步刷新,旧值继续可用直到新值就绪(stale-while-revalidate)
  • 热刷入口:POST /api/pro/_admin/reloadTenant(仅 dev profile)

REQ-TR-003 敏感字段处理

  • appSecret / systemToken 等字段在日志输出时必须脱敏(***
  • 内存中允许保留明文(TenantProfile 字段直接 String,不引入加密存储以保持简单)

REQ-TR-004 失效与禁用

  • 宜搭应用表 radioField_enabled=off → 注册表移除该 tenantId
  • 请求携带已禁用 tenantId → 返回 403 TENANT_DISABLED

非目标明示

  • 不定义 tenantId 命名规范(客户代号 / UUID / 数字 ID 均可,由运营决定)
  • 不定义 tenant-level feature flag(有需要另外提案)
  • 不定义多 tenant 同库的 row-level security(共享库方案下由业务 service 自行按 tenantId 过滤)