Skip to content

Develop#385

Open
Matrix-X wants to merge 10 commits into
release/v1.0.0from
develop
Open

Develop#385
Matrix-X wants to merge 10 commits into
release/v1.0.0from
develop

Conversation

@Matrix-X

@Matrix-X Matrix-X commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • 简述本次改动目标与范围

Changes

  • 列出核心改动点(代码/文档/配置)

Verification

  • 本地验证步骤已执行(请附关键命令/结果)

WS/TaskBus Contract Checklist(必填)

  • 本次是否涉及 WS/TaskBus(topic、publish/register、envelope、鉴权、tenant/trace)?
  • 若涉及,是否同步更新主契约:specs/004-eventbus-message-fabric/spec.md
  • 若涉及 WS 传输,是否同步更新:specs/023-websocket-notify/spec.mdspecs/023-websocket-notify/contracts/http-openapi.yaml
  • 是否运行一致性检查:bash scripts/specs/check_ws_taskbus_contracts.sh

Risks

  • 已评估兼容性/回滚影响

Matrix-X and others added 10 commits May 26, 2026 14:25
  - docs/plan/iam/saas-account-and-plugin-isolation.md
  - specs/026-iam/spec.md
  - specs/026-iam/data-model.md
  - specs/026-iam/research.md
  - specs/026-iam/plan.md
  - specs/026-iam/tasks.md
  - specs/026-iam/quickstart.md
  - specs/026-iam/contracts/http-openapi.yaml
  - specs/026-iam/contracts/iam-rbac-admin.proto

  整理出的核心方案:

  1. 账号模型
      - User 是全局账号。
      - Member 是用户在某个租户里的身份。
      - token/context 必须到 tenant_uuid + member_id/member_uuid 粒度。
      - root 是平台身份,不等于任意业务租户 admin。
  2. Root 边界
      - root 默认进入 Platform Console。
      - root 默认不看租户 AI Settings、租户插件业务页面。
      - root 进入业务租户必须走 Support Session,并记录 reason/audit。
  3. SaaS 注册
      - 新增规格:POST /api/v1/public/saas/signup
      - 创建 tenant、user/member、role_owner/role_admin/role_user、默认配置必须事务化。
      - 已有 user 创建第二租户时必须校验密码。
      - 失败不能留下半成品 tenant/member/role binding。
  4. 历史数据迁移
      - 不手动删除或重建现有组织架构。
      - 保留 root user、root 的 system tenant member、setup 完成记录。
      - 新增 IAM migration report。
      - 缺 owner 但有 admin 的租户可自动补 owner 并审计。
      - 缺 admin 的租户只报告,不自动猜。
  5. 插件 SaaS 隔离
      - 明确三层:
          - Plugin Package:平台级物理包和版本。
          - Plugin RuntimeProcess:平台级共享运行进程。
          - Tenant Plugin Instance:租户级订阅、启用、配置、凭证、权限。
      - 1000 个租户启用同一插件,不是 1000 个进程。
      - 同一插件在一个 PowerX 节点内只有一组 plugin_id / plugin_id_admin 进程。
      - 租户启用/停用只影响本租户菜单、API、Scheduler/Event/Capability,不停止全局进程。
  6. 权限边界
      - Root/Platform:安装、卸载、升级、启动、停止、切版本、管理套餐可见范围。
      - Tenant Owner/Admin:订阅/购买、启用/停用本租户插件实例、配置本租户插件参数。
      - Tenant Member:使用已授权插件业务能力。
  7. 发现的实现风险
      - 当前 Enable(ctx, plugin_id) 会把某个 tenant 的 STS/Gateway env 注入全局插件进程。
      - 这和 SaaS shared runtime 不一致。
      - 后续实现任务里已加 T085:需要移除全局进程启动阶段对单一租户凭证的绑定,改成请求/事件维度解析 tenant/member。
  8. 任务拆分
      - specs/026-iam/tasks.md 已新增 T045-T090
      - 覆盖 SaaS signup、root support、租户插件实例隔离、共享运行时、历史 IAM 巡检迁移、生命周期权限测试。

  另外我把旧规格里的 ctx/ctx_sig/ctx_jwt 清掉了,避免继续延续之前那套错误上下文透传模型。当前文档已经按 STS/member/token/context 的方向整理。
      - drain/blockers 查询到 Event Task / Scheduler Job 都为 0 时,会自动推进 active drain job。
      - 租户插件实例会从 draining_requested 进入 drained。
      - drain job 会进入 ready_to_uninstall,页面可以继续最终卸载。
  - 修复 drain 页面状态不同步:
      - 打开“阻断详情”后刷新插件运行状态,避免弹窗显示 0 阻断但外层仍是“等待 drain 完成”。
  - 修复插件菜单被错误过滤:
      - 菜单聚合层只处理宿主菜单权限:admin:root、admin:tenant、admin:tenant_only。
      - 插件业务权限如 template:read 不再导致整棵插件菜单被隐藏。
      - admin:root 仍然生效,所以 root-only 子菜单仍只给 root。
  - 验证:
      - go test ./internal/service/plugin
      - go test ./internal/transport/http/admin/menu ./internal/transport/http/admin/plugin
      - web-admin npm run build
    现在会同时启用当前请求租户的插件实例,恢复 plugin_instance_configs 到 enabled。

  - 修复 drain 生命周期残留。
    旧的 ready_to_uninstall drain job 在重新安装并启用时会标记为 completed,避免继续阻断新订阅/菜单/usage。

  - Event Fabric seed 改成声明式同步:
      - manifest 当前声明的 topic 走 upsert。
      - manifest 不再声明的旧 topic 会 retired。
      - 旧 binding 会软删。
      - 安装/启用时自动同步,不再依赖手动 resync。

  - Topic 规范对齐到 member 维度。
    支持 tenant_<uuid> segment 和 member_{{member_uuid}} runtime token,旧 tenant-only topic 被 retired。

  - WebSocket topic 权限与前端订阅格式对齐。
    root 也按当前租户 + member 维度订阅,不再用 tenant-only topic。

  - 插件安装/切版本 drain guard 加强。
    force install 不能绕过 active tenant instance。需要 drain 时后端返回结构化 PLUGIN_DRAIN_REQUIRED details。

  - 前端安装弹窗改造:
      - 能识别 drain required。
      - 可在弹窗内发起 drain。
      - 发起后不自动跳详情,只显示已发起,并提供“查看 drain 进度”。

  - 插件详情页状态修复。
    系统 runtime enabled 时,不再把历史 ready_to_uninstall job 当作当前卸载状态,避免“系统启用 + 本租户 drained + 可最终卸载”混在一起。

  - API client 错误对象保留后端 details。
    前端能拿到 requires_drain/plugin_id/version 等结构化信息。
    现在会同时启用当前请求租户的插件实例,恢复 plugin_instance_configs 到 enabled。

  - 修复 drain 生命周期残留。
    旧的 ready_to_uninstall drain job 在重新安装并启用时会标记为 completed,避免继续阻断新订阅/菜单/usage。

  - Event Fabric seed 改成声明式同步:
      - manifest 当前声明的 topic 走 upsert。
      - manifest 不再声明的旧 topic 会 retired。
      - 旧 binding 会软删。
      - 安装/启用时自动同步,不再依赖手动 resync。

  - Topic 规范对齐到 member 维度。
    支持 tenant_<uuid> segment 和 member_{{member_uuid}} runtime token,旧 tenant-only topic 被 retired。

  - WebSocket topic 权限与前端订阅格式对齐。
    root 也按当前租户 + member 维度订阅,不再用 tenant-only topic。

  - 插件安装/切版本 drain guard 加强。
    force install 不能绕过 active tenant instance。需要 drain 时后端返回结构化 PLUGIN_DRAIN_REQUIRED details。

  - 前端安装弹窗改造:
      - 能识别 drain required。
      - 可在弹窗内发起 drain。
      - 发起后不自动跳详情,只显示已发起,并提供“查看 drain 进度”。

  - 插件详情页状态修复。
    系统 runtime enabled 时,不再把历史 ready_to_uninstall job 当作当前卸载状态,避免“系统启用 + 本租户 drained + 可最终卸载”混在一起。

  - API client 错误对象保留后端 details。
    前端能拿到 requires_drain/plugin_id/version 等结构化信息。
      - 显式传 tenantUUID 登录时,如果租户不存在或用户不是该租户成员,现在直接返回错误,不再清空 tenantUUID 后 fallback 到其他租户。
      - Refresh() 现在会重新加载 tenant / user / member / roles,并用最新角色重新签 access token,不再复用 refresh token 里的旧 claims.Roles。
      - 额外校验 refresh token 里的 user_uuid/member_uuid/tenant_uuid 和数据库记录一致,避免 token 绑定漂移。

  - tenant_handler.go
      - 把租户插件启用逻辑抽成 enableTenantPluginInstance(...)。
      - 新旧入口共用已解析的 request,不再在 /admin/plugins/:id/tenant_enable 启用分支里二次绑定 JSON body,避免 EOF。

  验证已跑过:

  go test ./internal/service/auth ./internal/transport/http/admin/plugin ./internal/service/plugin ./internal/infra/plugin/manager

  全部通过。
    把 media / agent / ai 的分散判断统一成 core capability REST 路由表,严格匹配声明路径,避免泛化放开 /media/* 或 /ai/*。

  - Media capability 补齐
    PUT /api/v1/media/assets/{uuid} 已加入 corex.media.assets.manage,用于本地 media driver 的实际上传动作。之前只声明了 create/get/delete/presign,上传动作语义不完整。

  - AI Settings 权限修正
    /settings/ai、成本配置、连接器、上下文优化页面现在允许 root 或当前租户 admin 访问。之前页面内和 middleware 把 root 排除了,导致点击“模型配置”跳 dashboard。

  - Ollama 默认地址修正
    默认从 http://localhost:11434 改为 http://127.0.0.1:11434,避免 Go 后端解析 localhost 到 IPv6 ::1,而本机 Ollama 只监听 IPv4。

  - Ollama 错误 i18n 化
    后端不再返回硬编码中文,改为稳定错误码 OLLAMA_MODEL_NOT_FOUND model=...,前端模型配置页用 i18n 展示中文/英文提示。

  - framework 依赖升级
    PowerXPlugin skeleton / scaffold / CLI template / template registry 已统一到:
      - @artisan-cloud/plugin-framework-admin@0.0.8
      - @artisan-cloud/plugin-framework-client@0.0.8
  - 统一媒体资源模型:一个 media_assets.uuid 是一个逻辑资源,origin、preview、thumbnail 是同一个 asset 的不同版本。
  - 新增/接入 media_asset_variants 表模型,用来保存 preview、thumbnail 等变异体。
  - 修正本地存储路径:
      - 原图:{asset_uuid}/origin
      - 预览:{asset_uuid}/preview
      - 缩略图:{asset_uuid}/thumbnail

  - 明确预览规则:
      - 页面、插件、外部嵌入预览必须走 preview 或 thumbnail
      - 只有下载原图/后端原始处理才走 origin
      - 不允许 preview 缺失时 fallback 到 origin

  - Web Admin 媒体库已改为预览使用 variant,下载才用 origin。
  - 删除语义已梳理:
      - 普通删除 = 软删除,文件保留,进入回收站
      - 永久删除 = /purge,删除数据库记录和物理文件
      - 本地 driver 永久删除后会清理空的 {asset_uuid}/ 目录

  - 文档/OpenAPI/capability catalog 已同步说明外部插件怎么用。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant