# 需求:Admin_Template-骨架两处致命缺陷-菜单-ID-用「基准+1」推导撞主键、种子非幂等导致半成品状态启动即-fatal

状态: done(2026-10-20 已上线:模板 48364c9 种子改逐项同步（角色 code/菜单 code 复用真 ID/role_menu 复合键/admin username），半截状态自愈不撞主键；seed_guard 静态闸门禁 GenID()+N；03ee7d2 真库按包隔离，go test ./... 不加 -p 1 全绿连跑两遍)
归属: Admin_Template(模板与脚手架)
来源: 登记缺口(ops/products/#onboard-hub)
日期: 2026-10-16
建议: 做,onboard-hub 首次部署到 NAS 时踩中:半成品种子状态让服务每次启动都 fatal(容器重启循环、健康检查永不就绪);菜单 ID 推导与雪花 ID 撞 menus 主键。凡走 admin-cli create 生成的后端都会继承这两条,属模板级缺陷,不修则每个新项目都要重复踩一次。

## 现状

- 盘点缺口来源产品:onboard-hub
- 触发场景:`admin-cli create` 生成的后端(onboard-hub)首次 docker 部署到 NAS,容器起来后连库/迁移都成功,随即 fatal 重启循环,健康检查永不就绪;`deploy` 脚本正确判失败,耗时两轮定位。
- **缺陷 1(种子非幂等)**:`internal/seed/seed.go` 的角色 / 菜单 / 角色菜单关联 / 管理员账号一律无条件 `Create`。只要上一轮跑到一半失败(例如建完角色与菜单、建管理员前中断),库里就留下**半成品状态**,此后**每次启动都 fatal**:
  `初始化默认数据失败: 创建 admin 角色失败: Error 1062 (23000): Duplicate entry '超级管理员' for key 'roles.uni_roles_name'` —— 服务不可自愈,只能人工清库。
  证据:2026-10-16 onboard-hub 首轮 NAS 部署 `docker logs onboard-hub-api`(完整原文见 onboard-hub worklog 与 `docs/项目计划书-入职中间件.md` §2.6 实测事实 9)。
- **缺陷 2(菜单 ID 推导撞主键)**:`buildDefaultMenus()` 用「基准 ID + 偏移」推第二个菜单的 ID(`ID: dashboardID + 1`),而雪花 ID 相邻调用本就是连续 +1 → 推导值直接与下一次 `GenID()` 撞 `menus` 主键:
  `Error 1062 (23000): Duplicate entry '2111049929093812225' for key 'menus.PRIMARY'`。生产那次没炸只是**凑巧跨了毫秒**,属概率性启动失败。
- 影响面:凡走 `admin-cli create` 生成的后端都继承这两条(模板仓 `backend/starter-app` + `Admin_Template/backend/core` 的 seed 生成物),不是 onboard-hub 独有。

## 方案

1. **模板侧改种子为逐项幂等**(代改范围:`Admin_Template` 骨架/模板内 `internal/seed/seed.go` 与 `admin-cli` 生成器模板):
   - 角色按 `code` 查再建(复用已存在,不重插);
   - 菜单按 `code` 查再建,**并记住已存在记录的真实 ID**(后续关联必须引用真实 ID,不能用新生成的);
   - 角色-菜单关联按 `(role_id, menu_id)` 查再建;
   - 管理员按 `username` 查再建;整条种子可重复执行、可从任意半成品状态续跑。
2. **菜单 ID 一律每次 `GenID()`**,删除「基准 ID + 偏移」写法(偏移推导与雪花序列冲突是必然而非偶然)。
3. **补回归用例**(真 MySQL 引擎、真 `AutoMigrate`,不用 sqlite / 不用 mock),三条负向:
   - 角色+菜单已建、管理员未建 → 重跑必须自愈(不报错,管理员补齐、角色数仍为 1);
   - 只有角色已存在 → 重跑不撞 `roles.uni_roles_name`;
   - 连跑两次 → 用户/角色/菜单数不翻倍。
   可移植参照实现:onboard-hub `backend/internal/seed/seed_test.go`(已先红后绿:旧代码上复现出上述两条 1062,新代码 4/4 绿)。
4. **同批机检**:模板仓/生成的骨架把「seed 里出现 `GenID() + 数字` 形态」与「seed 里出现裸 `db.Create(&models.Role{...})` 无存在性判断」列为探测器条款(可挂 rulecheck 或 CLI 自检)。

## 验收标准

- [ ] 在模板仓生成的骨架里,把库里造出「角色+菜单已建、管理员未建」状态后重启服务,**不再 fatal**,管理员被补齐(启动日志正常、`/health` 就绪)
- [ ] 连跑两次种子,`sys_users` / `roles` / `menus` 行数不翻倍;`menus` 无主键冲突
- [ ] 旧实现上必然失败、新实现上必然通过的三条回归用例进入模板仓测试套件(先红后绿留证)
- [ ] 全仓 grep 无「基准 ID + 数字偏移」派生主键的写法;新增机检条款命中即判红
- [ ] `admin-cli create` 新生成的项目跑通一次「首启 → 半成品中断 → 重启自愈」全链
