diff --git a/RuoYi-Vue/docs/superpowers/specs/2026-07-12-one-click-reference-closure-repair-design.md b/RuoYi-Vue/docs/superpowers/specs/2026-07-12-one-click-reference-closure-repair-design.md new file mode 100644 index 0000000..901235d --- /dev/null +++ b/RuoYi-Vue/docs/superpowers/specs/2026-07-12-one-click-reference-closure-repair-design.md @@ -0,0 +1,125 @@ +# 一键生成引用闭环修复设计 + +## 背景 + +项目 104 在一键生成源码阶段创建 ProjectSpec 版本失败:后台菜单 +`librarian_profile` 引用了不存在的后台页面 `librarian_profile_page`。 +实际蓝图只保留 `admin`、`reader` 两个角色,但数据库和后台菜单仍包含独立的 +`librarian` 账户模型。后台页面初始化先把 `librarian` 表分配给管理列表页,随后个人中心 +无法再从“未匹配表”集合中取得该表并被静默跳过,最终形成悬空页面引用。 + +## 目标 + +- 只有角色编码严格等于 `admin` 时才视为系统管理员。 +- 保留 `librarian` 等业务后台角色,并为其生成独立账户表、权限和个人中心。 +- 后台个人中心可以与后台管理列表复用同一账户表。 +- 一键生成在页面初始化结束后、ProjectSpec 快照之前完成引用闭包校验。 +- 唯一可确定的历史数据问题自动修复;存在歧义时在页面初始化阶段给出精确错误。 +- 保持旧蓝图兼容,不要求已有项目立即补齐新字段。 + +## 非目标 + +- 不引入新的 `adminPages` 顶层蓝图集合。 +- 不重构整个 AI 生成服务或模板系统。 +- 不把任意名称包含“管理员”的角色自动提升为系统管理员。 +- 不通过清空 `pageRef`、`visibleRoles` 等方式掩盖引用错误。 + +## 方案选择 + +采用兼容式闭环修复。相比删除悬空菜单,它保留业务后台角色;相比引入完整 +`adminPages` 模型,它能以较小改动修复现有项目并维持模板兼容。 + +## 数据模型 + +`AppMenuDesign` 增加两个可选字段: + +- `tableName`:菜单页面明确绑定的数据表。 +- `pageType`:页面类型,后台个人中心使用 `form`,普通后台管理使用 `list`。 + +AI 应为后台菜单输出这两个字段。历史蓝图字段为空时继续使用名称、编码和路径的语义 +匹配;个人中心还允许从 `_profile` 或 `_profile_page` 推导角色及账户表。 + +## 角色规范化 + +角色编码先规范化为小写蛇形命名。只有规范化编码恰好为 `admin` 的角色才是系统管理员。 +名称不参与系统管理员判定,因此 `librarian/图书管理员`、 +`content_admin/内容管理员` 都保留为独立角色。 + +如果蓝图缺少 `admin`,仍自动补充系统管理员。角色编码重复时保留第一项并报告规范化 +结果,不把其他业务角色合并到 `admin`。 + +菜单中的 `visibleRoles` 不再静默删除未知角色: + +- 对个人中心菜单,若编码前缀能唯一匹配账户表,则恢复对应角色并把该角色写回 + `visibleRoles`。 +- 其他未知角色无法唯一恢复时,一致性校验失败并指出菜单编码和角色编码。 + +## 后台页面初始化 + +后台菜单按以下优先级解析数据表: + +1. `menu.tableName` 精确匹配。 +2. 个人中心菜单从角色编码推导同名账户表,并允许复用已分配表。 +3. 旧蓝图继续使用 `adminMenuName`、菜单名称、编码和路径进行唯一语义匹配。 + +普通管理菜单仍只消费一次未匹配表。个人中心不从未匹配集合中移除账户表,因此 +`librarian_admin_page` 和 `librarian_profile_page` 可以同时绑定 `librarian`。 + +页面类型优先使用 `menu.pageType`;字段为空时,个人中心默认为 `form`,其他后台页面 +默认为 `list`。无法解析表的页面型后台菜单不再 `continue` 静默跳过,而是抛出包含菜单、 +页面编码和候选表信息的 `ServiceException`。 + +## 历史项目自动修复 + +页面初始化读取历史蓝图时,若发现满足以下全部条件的菜单,则恢复业务后台角色: + +- `dataScope=CURRENT_USER`; +- 菜单或页面编码以 `_profile` / `_profile_page` 结尾; +- 编码前缀能唯一匹配项目账户表; +- 该前缀不是 `admin`。 + +修复会补充角色、将菜单 `visibleRoles` 设置为该角色、补齐 `tableName` 和 `pageType=form`, +并持久化蓝图。项目 104 因此恢复 `librarian`,同时生成 +`librarian_profile_page`。无法唯一推导时不猜测,转为明确错误。 + +## 引用闭包预检 + +扩展 `FrontProjectConsistencyValidator`,在页面初始化之后验证: + +- 每个前台菜单的 `pageCode` 存在于前台蓝图页面或前台页面设计。 +- 每个后台菜单的 `pageCode` 存在于后台页面设计。 +- 每个前台页面的 `parentPageCode` 存在于前台页面集合。 +- 每个菜单的 `visibleRoles` 都存在于角色集合。 +- 每个页面绑定的数据表都存在。 + +校验在 `SourcePreviewStageHandler` 创建 ProjectSpec 版本之前执行。ProjectSpecValidator 保留为 +最终防线,但同类问题应在“初始化页面”阶段失败,而不是进入“生成源码”后才失败。 + +## 错误处理 + +- 自动修复必须要求唯一匹配;多候选或无候选均不自动选择。 +- 错误消息包含蓝图路径、菜单或页面编码、缺失引用及可用候选。 +- 不通过删除菜单、清空角色或清空页面引用来让校验通过。 +- 历史页面设计迁移继续保留原 `designId`,避免重复页面记录。 + +## 测试设计 + +按 TDD 增加以下回归场景: + +1. `librarian/图书管理员` 不再被合并为 `admin`。 +2. 个人中心未知角色可从唯一账户表恢复,普通未知角色被拒绝。 +3. 普通管理页和个人中心页可复用 `librarian` 表,分别生成 `list`、`form` 页面。 +4. 显式 `tableName/pageType` 优先于语义匹配,旧蓝图仍能生成。 +5. 无法匹配表的后台菜单在页面初始化阶段失败。 +6. 前台菜单未知页面、后台菜单未知页面、未知父页面和未知角色均被预检拦截。 +7. 项目 104 形态的失败任务重试后不再产生 `UNKNOWN_PAGE_REF`。 +8. 更新 AI 数据库生成测试,使管理员账户表自动补充后的表和字段断言与当前契约一致。 + +验证范围包括角色/蓝图生成、页面初始化、一致性修复、ProjectSpec 装配与校验、一键生成 +编排,以及 `ruoyi-generator` 模块的相关回归测试。 + +## 兼容性与迁移 + +新增菜单字段均为可选字段,旧 JSON 可直接反序列化。新逻辑只改变错误的角色合并、静默 +丢弃权限和静默跳过页面行为。现有 `admin`、普通后台列表页和已保存页面设计继续沿用原有 +编码;历史失败项目在重试页面初始化时自动完成可确定的修复。