父 Issue:#3(M1 自拆解简报 · 入口级交付)· WP1
目标
把 stub 的 IdentityProvisioner 替换为真实 Keycloak Admin API 适配器:开通时建 Organization + 一个「租户管理员」角色的首个 user(用 Tenant.adminEmail),成功后回写 keycloak_org_id;失败补偿(删 org)。Compute/Data/Secrets 保持 stub。
范围(文件清单)
pom.xml:+ keycloak-admin-client(版本优先经 BOM;BOM 未管理时按 Keycloak 25.x 对齐显式钉一行)。
- 新增
src/main/java/io/hashmatrix/controlplane/provisioning/keycloak/KeycloakIdentityProvisioner.java(真实实现)+ 连接配置类。
application.yml:Keycloak 连接项 + 激活开关(见下「架构决策」)。
- 新增适配器单测(mock keycloak-admin-client,或 Testcontainers Keycloak)。
起点(精确路径 + 真/stub/缺失)
- stub:
provisioning/stub/StubProvisioningConfiguration.java:35 stubIdentityProvisioner()(真·stub,注释自陈未实现真实逻辑,需被真实 Bean 抢占)。
- 缺失:真实适配器、keycloak-admin-client 依赖、连接配置。
- 复用入参:
provisioning/spi/ProvisioningRequest.java(已带 tenantKey/displayName/adminEmail)。
⚠️ 架构决策(不可返工,主仓已拍板)
现 StubProvisioningConfiguration 把四个端口 Bean 统一 gate 在全局 hashmatrix.control-plane.provisioning.mode=stub(matchIfMissing)。直接切全局 mode 会连带丢掉 compute/data/secrets 三个 stub → 启动缺 Bean。
约束:真实 identity 适配器须用与全局 mode 解耦的独立激活条件(如 hashmatrix.control-plane.provisioning.identity=keycloak)+ @ConditionalOnMissingBean,使「真 identity + stub compute/data/secrets」可共存;默认仍 stub,现有路径零改动。子仓不得自行改成「整包切 mode」。
预估 LOC
~180–220(最大刀;原子适配器不中途拆,否则半装配 Bean = 过渡债 → 必要打包)。
测试
- 适配器单测:provision → 调 admin API 建 org + admin user + 角色 + 回写 orgId;provision 失败 → 触发补偿删 org;deprovision 幂等。
- 默认 stub 全量回归仍绿。
依赖
- Blocked by:无(可与 WP2/WP4 并行起步)。
- Blocks:无(WP5 受益但不强依赖)。
可独立 ship
✅ 真实适配器 opt-in、默认行为不变;现有集成测试(stub)不受影响。
验收
目标
把 stub 的
IdentityProvisioner替换为真实 Keycloak Admin API 适配器:开通时建 Organization + 一个「租户管理员」角色的首个 user(用Tenant.adminEmail),成功后回写keycloak_org_id;失败补偿(删 org)。Compute/Data/Secrets 保持 stub。范围(文件清单)
pom.xml:+keycloak-admin-client(版本优先经 BOM;BOM 未管理时按 Keycloak 25.x 对齐显式钉一行)。src/main/java/io/hashmatrix/controlplane/provisioning/keycloak/KeycloakIdentityProvisioner.java(真实实现)+ 连接配置类。application.yml:Keycloak 连接项 + 激活开关(见下「架构决策」)。起点(精确路径 + 真/stub/缺失)
provisioning/stub/StubProvisioningConfiguration.java:35stubIdentityProvisioner()(真·stub,注释自陈未实现真实逻辑,需被真实 Bean 抢占)。provisioning/spi/ProvisioningRequest.java(已带tenantKey/displayName/adminEmail)。现
StubProvisioningConfiguration把四个端口 Bean 统一 gate 在全局hashmatrix.control-plane.provisioning.mode=stub(matchIfMissing)。直接切全局mode会连带丢掉 compute/data/secrets 三个 stub → 启动缺 Bean。约束:真实 identity 适配器须用与全局
mode解耦的独立激活条件(如hashmatrix.control-plane.provisioning.identity=keycloak)+@ConditionalOnMissingBean,使「真 identity + stub compute/data/secrets」可共存;默认仍 stub,现有路径零改动。子仓不得自行改成「整包切 mode」。预估 LOC
~180–220(最大刀;原子适配器不中途拆,否则半装配 Bean = 过渡债 → 必要打包)。
测试
依赖
可独立 ship
✅ 真实适配器 opt-in、默认行为不变;现有集成测试(stub)不受影响。
验收
identity=keycloak开通一租户 → 后台可见 org + 「租户管理员」user。tenant.keycloak_org_id落库。mode=stub全测绿。tenant-demo/@example.com)。