# 一键生成引用闭环修复设计 ## 背景 项目 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`、普通后台列表页和已保存页面设计继续沿用原有 编码;历史失败项目在重试页面初始化时自动完成可确定的修复。