M1 自拆解简报 · control-plane(租户开通主线)
粗粒度里程碑简报。只读本简报 + 本仓代码即可自拆子任务并自验收,无需问人。
上位总纲:主仓 docs/milestones/M1-单命名空间端到端贯通.md。
0. 一句话目标
让"开通一个租户 = 真实在 Keycloak 建 org + 租户管理员"跑通,并给高危 API 接上鉴权;身份打通是整个 demo 的主线。
1. 起点 · 代码现状
- 栈:Java17 / Spring Boot 3.3.5(继承 libs-java BOM 0.2.0)/ JPA + PostgreSQL + Flyway。
- 已有(真实):
Tenant 聚合根 + TenantStatus 状态机 + TenantQuota;Flyway tenant 表含 keycloak_org_id/namespace/db_schema/quota_*;TenantController 暴露 POST /api/v1/tenants + /approve /reject /suspend /resume + DELETE;ProvisioningOrchestrator 按「身份→计算→数据→secrets」时序驱动 4 个 SPI 端口。
- 是 stub/缺失:4 个 Provisioner 全是 stub 适配器(
provisioning.mode=stub),IdentityProvisioner 注释自陈未实现真实逻辑;API 完全未接认证/鉴权(见 README.md:113「上线前接入 Keycloak Bearer + 角色门控」);application.yml 无 server.port(默认 8080)。本地:docker-compose.local.yml(PG + Keycloak 映射 8081)。
2. 范围边界
- ✅ M1:真实 IdentityProvisioner(建 org + 租户管理员);API 接 Keycloak Bearer + superadmin 门控;
GET /me/tenants(返回 membership,先 1 个、模型预留多个);端口规整;契约块/镜像。
- ⛔ 不做:真实 Compute/Data/Secrets Provisioner(留 stub);开通异步化/任务轮询;OIDC 企业联邦。
3. 工作项 & 拆分指引
WP1 真实 IdentityProvisioner(替换 stub)
- 要达成:开通时经 Keycloak Admin API 建 Organization + 一个「租户管理员」角色的首个 user(用
Tenant 已有的 adminEmail),成功后回写 keycloak_org_id。
- 入手点:找
IdentityProvisioner 接口的 stub 实现类,新增真实实现(keycloak-admin-client);Compute/Data/Secrets 保持 stub。
- 参考:身份模型见主仓
docs/architecture/05;开通设计见 prototype/docs/01-管理中心/02-工作空间与租户开通(自研).md。
- 可拆:- [ ] 引入 keycloak-admin-client + 连接配置 - [ ] 建 org - [ ] 建租户管理员 user+角色 - [ ] 回写 keycloak_org_id - [ ] 失败补偿(删 org)。
- 验收:对真实/本地 Keycloak 开通一个租户,Keycloak 后台可见 org + admin user,
tenant.keycloak_org_id 落库。
WP2 API 接鉴权(消除裸奔)
- 要达成:
/approve /reject DELETE 等高危端点限 superadmin(平台管理员角色)。
- 入手点:用
starter-security 的网关前置鉴权 + @PreAuthorize("hasRole('SUPERADMIN')");本地可配 Keycloak Bearer。
- 验收:无 token/非 superadmin → 401/403;superadmin → 200。
WP3 GET /me/tenants(为 D1/D2 预留多租户)
- 要达成:返回当前 user 的 membership 列表(先返回 1 个,DTO/契约按数组、可属多租户)。
- 约束:对齐 D1(单 User + 多 Membership)、D2(切换=重新换 token)。
WP4 端口/契约块/镜像
- 端口
${SERVER_PORT:8081} / ${MANAGEMENT_SERVER_PORT:9081};修 CLAUDE.md 契约块(producer 实为 openapi/control-plane-v1 + icd/control-plane-provisioning,现写「暂无」);CI 推 ghcr.io/hashmatrixdata/control-plane:<semver>。
4. 关键参考
- 契约:主仓
contracts/openapi/control-plane-v1.yaml(/v1/tenants 全套 operationId)、contracts/icd/control-plane-provisioning-icd.md。
- 身份:主仓
docs/architecture/05-多租户与控制平面.md;libs starter-security。
5. 依赖 & 约束
- 依赖:Keycloak(本地 compose 已带);libs-java
starter-security。
- 被依赖:webui
GET /me/tenants + 开通;gateway OIDC。
- 端口 8081/9081;受 D1/D2/D6 约束。
6. 完成判据
M1 自拆解简报 · control-plane(租户开通主线)
0. 一句话目标
让"开通一个租户 = 真实在 Keycloak 建 org + 租户管理员"跑通,并给高危 API 接上鉴权;身份打通是整个 demo 的主线。
1. 起点 · 代码现状
Tenant聚合根 +TenantStatus状态机 +TenantQuota;Flywaytenant表含keycloak_org_id/namespace/db_schema/quota_*;TenantController暴露POST /api/v1/tenants+/approve/reject/suspend/resume+DELETE;ProvisioningOrchestrator按「身份→计算→数据→secrets」时序驱动 4 个 SPI 端口。provisioning.mode=stub),IdentityProvisioner注释自陈未实现真实逻辑;API 完全未接认证/鉴权(见README.md:113「上线前接入 Keycloak Bearer + 角色门控」);application.yml无server.port(默认 8080)。本地:docker-compose.local.yml(PG + Keycloak 映射 8081)。2. 范围边界
GET /me/tenants(返回 membership,先 1 个、模型预留多个);端口规整;契约块/镜像。3. 工作项 & 拆分指引
WP1 真实 IdentityProvisioner(替换 stub)
Tenant已有的adminEmail),成功后回写keycloak_org_id。IdentityProvisioner接口的 stub 实现类,新增真实实现(keycloak-admin-client);Compute/Data/Secrets 保持 stub。docs/architecture/05;开通设计见prototype/docs/01-管理中心/02-工作空间与租户开通(自研).md。tenant.keycloak_org_id落库。WP2 API 接鉴权(消除裸奔)
/approve/rejectDELETE等高危端点限 superadmin(平台管理员角色)。starter-security的网关前置鉴权 +@PreAuthorize("hasRole('SUPERADMIN')");本地可配 Keycloak Bearer。WP3 GET /me/tenants(为 D1/D2 预留多租户)
WP4 端口/契约块/镜像
${SERVER_PORT:8081}/${MANAGEMENT_SERVER_PORT:9081};修CLAUDE.md契约块(producer 实为openapi/control-plane-v1+icd/control-plane-provisioning,现写「暂无」);CI 推ghcr.io/hashmatrixdata/control-plane:<semver>。4. 关键参考
contracts/openapi/control-plane-v1.yaml(/v1/tenants全套 operationId)、contracts/icd/control-plane-provisioning-icd.md。docs/architecture/05-多租户与控制平面.md;libsstarter-security。5. 依赖 & 约束
starter-security。GET /me/tenants+ 开通;gateway OIDC。6. 完成判据
GET /me/tenants返回数组(先 1 个)