# 需求:admin-cli-生成物缺站内信标配模块(铃铛一族接口全-404)+-模板发件聚合在真-MySQL-上-500

状态: done(2026-10-20 已上线:模板 b3d9640 真 MySQL 判据 3 条 PASS 含负向对照（旧写法必须 1064）+ 保留字闸门行级豁免 + docs/UPGRADE.md 老项目升级节；已 push origin bcfa23c)
归属: 公司运营(Admin_Template/admin-cli 交付链)
来源: 登记缺口(ops/products/#onboard-hub)
日期: 2026-10-17
建议: 做,标配模块缺失=每个用 CLI 起的项目都带这一族 404(老板实测撞上);模板发件聚合的 SUM(...) AS read 撞 MySQL 保留字,真库整页 500 而 sqlite 判据永远测不出 —— 交付给外部客户的正是 MySQL 形态,必须从源头修

## 现状

- 盘点缺口来源产品:onboard-hub
- **一、CLI 生成物缺站内信标配模块**(老板 2026-10-16 实测:「发现 cli 生成的接口有部分报错,好像是发站内信部分,这块 cli 好像做掉了」):壳(`@admin-template/admin-core`)自 0.1.1 起就声明并按铃铛轮询 `/api/messages/*` 共 **10 条**接口(`/messages/my`、`/all`、`/unread-count`、`/{id}`、`/{id}/read`、`/read-batch`、`/read-all`、`/delete-batch`、`DELETE /{id}`、`POST /messages`),契约定在 Admin_Template `docs/ADMIN-CORE-CONTRACT.md` §12(站内信两屏是标配);模板 `backend/starter-app/internal/message/` 有完整实现(handler 388 行 / service 365 行 / model 72 行 / 判据 573 行),`cli/src/create.js` 是**整份拷贝 starter-app**。但 onboard-hub 这仓早于该模块生成 → 模块/迁移/菜单/前端两屏全缺:实测探针里 `/api/messages/my`、`/api/messages/unread-count` 清一色 **404**,控制台噪音,菜单树里也没有入口。**这是「生成期版本滞后」型缺口,凡早于模块生成的仓都要补。**
- **二、模板发件聚合查询在真 MySQL 上直接 500**(接回模块后用真 MySQL 跑模板自带判据才暴露):`service.go` 的 `Sent()` 用 `Select("message_id, COUNT(*) AS total, SUM(CASE WHEN is_read THEN 1 ELSE 0 END) AS read")`,`read` 是 **MySQL 保留字** → `Error 1064 (42000): You have an error in your SQL syntax ... near 'read FROM message_receivers'`;而模板判据跑在 **sqlite**(不认保留字)所以从来没红过 → 生成到 MySQL 的项目「站内信 → 发件视图」整页 500。剧本形态与外包交付形态都是 **MySQL**(公司口径:Go 后台测试/生产一律连 MySQL),漏检概率≈100%。
- 证据链:onboard-hub 线上真浏览器整链验收(0.5.1)—— 建收件账号 → admin 发信(扇出 1)→ 发件视图 `收件人数=1 已读=0` → 收款方 `unread-count=1`、「我的消息(1)」列表出现该标题 → 标记已读 → 发件侧 `已读=1/1 人已读` → 回收删账号删消息,全程零 4xx/5xx、零 pageerror。

## 方案

- **模板侧(Admin_Template,待 boss 确认后入库;本会话只改了工作区未 commit)**:①`starter-app/internal/message/service.go` 的聚合别名 `read` → `read_count`(结构体 tag 同步改 `column:read_count`),并留注释说明保留字坑;②模板自带判据从 sqlite 换真 MySQL(或至少加一条 MySQL 冒烟),否则同类保留字/方言问题还会静默通过。companion:全仓 grep 一遍 `AS read`/`AS order`/`AS key` 这类保留字别名。
- **生成器侧(admin-cli)**:`create.js` 已整份拷贝 starter-app,无需改代码;但要在 `docs/` 里写清「**已存在的项目升级标配模块**」的做法(迁移 + 路由 + 标配菜单),或给 `admin-cli upgrade` 之类能力 —— 否则每个老仓都要人工考古一次。
- **业务仓侧(onboard-hub,已完成 0.5.0/0.5.1)**:按模板原样接回 `internal/message/{model,service,handler}.go`;迁移补 `messages`/`message_receivers`;JWT 组下注册 10 条路由;种子补「消息」FOLDER +「我的消息」「站内信」两屏(component 与 menus.code 同模板,后者兼发信权限码);前端补 `composables/useAdminGrid.ts`、`api/system/message.ts`、`views/personal/{messages,system-message}/index.vue` 并挂进 `api/index.ts`。
- **顺带修掉一个更隐蔽的种子缺陷(onboard-hub,已完成)**:种子原先拿「`sys_users` 为空」当整段闸门 → **上线后新增的标配菜单永远补不上**(线上库早有 admin,新菜单既不落库也没入口,表现是「代码补了但看不见」)。改为每次启动逐项幂等同步角色/菜单/关联,闸门只留给管理员本身(用户表非空不动口令、不复活有意删掉的默认账号)。

## 验收标准

- [x] 模板 `Sent()` 在真 MySQL 上返回 code=0(sqlite 判据外再有一条 MySQL 判据承载),且不会有 `read_count` 之类的列名/别名回归。
      → 2026-10-20 实测 `TestSentAggregationOnMySQL` / `TestInboxOnMySQL` PASS，负向对照 `TestReservedWordAliasIsRejectedByMySQL` 要求旧写法在真库必须 1064 且确实 1064（库=`admin_tpl_test@192.168.31.%` / 8.4.9）
- [x] 用 `admin-cli create` 新起的项目开箱即含站内信 10 条接口 + 两屏菜单,铃铛不再 404(生成物级验证,不是单仓验证)。
      → 2026-10-20 生成物级实测：`demo-remote`（远端 `-v main` 生成）内 `internal/message/handler.go` 注册 `/messages` 组、`go test ./internal/message/...` 真库 `ok 11.748s`；`internal/seed/seed.go` 含 `personal:messages` / `personal:system-message` 两屏菜单且前端 `src/views/personal/{messages,system-message}` 就位，`check-menu-views` 生成项目内 PASS 7 条
- [x] 老项目升级路径有文档或工具(把「标配模块/标配菜单增量同步」写进模板 docs)。
      → `docs/UPGRADE.md` 新增整节（种子增量语义表 / 页面就位 / 真库判据跑法 / 升级后 5 条回归），commit `b3d9640`
- [x] 种子类逻辑不再用「整表为空」当闸门:新增标配菜单/权限必须能在已有数据的库上补齐(判据:管理员已存在 + 菜单被删 → 重跑种子补回且不重置口令)。
      → commit `48364c9`；真库判据 `TestSeedDoesNotClashWhenOnlyRoleExistsMySQL` / `TestSeedRecoversFromHalfStateMissingAdminMySQL` / `TestSeedIsIdempotentAcrossTwoRunsMySQL` 三条 PASS，另 `seed_guard.go` 静态闸门禁 `GenID()+N`
- onboard-hub 侧线上整链复验（发信 → 收款方未读 → 发件聚合读数 → 已读回流 → 回收）：**已转出**为独立票，不属模板修复范围（模板侧只能给到生成物级判据，线上整链要 NAS 部署环境与真实账号）。转移见当日 worklog 结注。
