# mjava-pro 多客户单部署运行时(A 档公共托管)。一个 jar 通过 `X-Tenant-Id` 路由到不同租户配置,按租户隔离凭据/缓存/日志/数据。 > 客户分档:见 `openspec/changes/define-customer-tiering/specs/customer-tiering/spec.md` R1。当前 mjava-pro = A 档容器。 ## 端口与上下文 - 端口:`9010` - context-path:`/api/pro` ## 调用范式 请求必须带 `X-Tenant-Id` Header(`TenantInterceptor` 识别,未带返 401 `TENANT_REQUIRED`,无对应配置返 403 `TENANT_NOT_FOUND`)。 业务代码示例: ```java @RestController @RequestMapping("/example") public class ExampleController { @Autowired DynamicYDService ydService; @Autowired YDClient_Form ydForm; @GetMapping("/forms") public McR listForms() { // ydService.buildAuth() 自动从当前租户拿凭据 + 钉钉 token Object data = ydForm.searchForm(ydService.buildAuth(), "FORM-XXX", null, null); return McR.success(data); } } ``` 钉钉直调: ```java @Autowired DynamicDDService ddService; ... String token = ddService.getAccessToken(); // {tenantId}:dingtalk:{appKey} namespace cache String corpId = ddService.currentCorpId(); ``` ## 新增租户(A 档入驻 SOP) > 标准入驻清单见 `define-customer-tiering` spec R4。 1. **校验**:确认客户不命中 A→B 任一硬指标(无自定义 Controller / 无私有 schema / 无独立部署要求) 2. **宜搭应用表加一行**(formUuid 配在 `application.yml` 的 `tenant.registry.formUuid`): | 字段 | 必填 | 说明 | |---|---|---| | `tenantId` | ✅ | 业务唯一标识,禁中文/特殊字符 | | `tenantName` | ✅ | 中文展示名(日志/监控可读性) | | `vendor` | ✅ | `dingtalk` / `aliwork` / ... | | `appKey` | ✅ | 产品方 appKey | | `appSecret` | ✅ | 产品方 appSecret(宜搭加密字段) | | `corpId` | 钉钉系必填 | — | | `extraJson` | 可选 | vendor 特定参数 JSON 字符串(如宜搭的 `appType` / `systemToken` / `userId`) | | `enabled` | ✅ | false 拒绝该 tenant 请求 | 3. **热加载**:调 `POST /_admin/reloadTenant`(dev profile)或等下次 `@Scheduled` 刷新(默认 TTL 配在 `application.yml`) 4. **凭据热验证**:`GET /api/pro/_diag/tenant/{tenantId}` 探活(接口归后续 task 实现) 5. **上线通告**:邮件抄送运维 + 客户对接人 ## 隔离边界 | 维度 | 隔离方式 | |---|---| | **DB** | 共享 schema,业务表必须含 `tenant_id` 列;JPA Interceptor 自动注入 WHERE 条件(待 task 实现) | | **缓存** | `UtilToken` key 命名空间扩为 `{tenantId}:{vendor}:{appKey}`(`DynamicDDService` 已实现) | | **日志** | MDC 自动注入 `tenantId`;logback pattern 含 `[%X{tenantId:-}]`(已落) | | **异步线程** | `TaskDecorator` 传播 ThreadLocal(待生产启用时评估) | ## 配置文件 | 文件 | 说明 | |---|---| | `application.yml` | 通用配置(端口、context-path、scheduling 等) | | `application-dev.yml.example` | dev profile 占位 | | `application-prod.yml.example` | prod profile 占位 | | `application-{profile}.yml` | 实际配置(**不入 git**) | `tenant.registry.*` 配置块: ```yaml tenant: registry: appType: ${TENANT_REG_APP_TYPE} systemToken: ${TENANT_REG_SYSTEM_TOKEN} formUuid: ${TENANT_REG_FORM_UUID} userId: ${TENANT_REG_USER_ID} ttlSeconds: 600 failFast: true ``` ## 关联文档 - 客户分档 spec:`openspec/changes/define-customer-tiering/specs/customer-tiering/spec.md` - 多租户 capability:`openspec/changes/add-mjava-pro/specs/multi-tenant-runtime/` + `specs/tenant-registry/` - 基座 Client/Service 分层:`openspec/specs/client-service-layering/spec.md` R1~R7 - 后端开发主规范:`/Users/malk/Desktop/Tech/claude/后端/CLAUDE.md`