feat: 迁移 Admin Repository 到 MySQL 8 (#79)

This commit is contained in:
chengma
2026-08-10 02:21:31 +08:00
parent 05793e48b3
commit 13cfced80d
29 changed files with 390 additions and 240 deletions
+2 -2
View File
@@ -29,8 +29,8 @@
| 服务端渲染 | 页面的 HTML 在服务器上拼好再发给浏览器 | 与之相对的是前端框架在浏览器里拼,本项目**不用** |
| htmx | 一个单文件 JS 库,让 HTML 标签直接发请求换局部内容 | 需要局部刷新时可用,**没有构建步骤** |
| upsert | "有就更新、没有就新增",一次操作搞定 | Excel 导入的唯一正确做法,见 §3 |
| cgo | Go 调用 C 代码的机制。**用了就需要装 C 编译器** | 本项目**避开它**,所以 SQLite 驱动选纯 Go 的 |
| `modernc.org/sqlite` | 纯 Go 实现的 SQLite,不需要 cgo | 固定用它,`go build` 直接出 exe |
| cgo | Go 调用 C 代码的机制。**用了就需要装 C 编译器** | 本项目**避开它**;MySQL 和历史 SQLite 迁移驱动都是纯 Go |
| `modernc.org/sqlite` | 纯 Go 实现的 SQLite,不需要 cgo | 只用于读取历史 `admin.db` 和迁移回归,不进入生产运行时 |
| excelize | Go 读写 Excel 的库 | 固定用它读蝦皮报表 |
| CSRF | 攻击者诱导你在已登录状态下发出非本意的请求 | 所有写操作都要防,见 [06](06-quality-security.md) §4 |
| 参数化查询 | SQL 里用 `?` 占位、值单独传,而不是拼字符串 | 防 SQL 注入的唯一正确做法 |
+3 -3
View File
@@ -271,9 +271,9 @@ M 个 SKU,K 行解析失败"),覆盖掉正常的统计文案,并且回
前者是还没采,后者是采集出了问题(商品下架、页面改版、解析器没认出来),
都显示成 `—` 就看不出区别了。
`[建议]` 规格数用 SQLite 的 `json_array_length(skus_json, '$.skus')` 直接算,
不要把整个 JSON 读进 Go 再数。`[必须]` 外面要包一层 `json_valid`——
`skus_json` 万一存进了坏数据,`json_array_length` 会让**整条查询报错**,页面直接打不开。
`[建议]` 规格数用 MySQL 的 `JSON_LENGTH(skus_json, '$.skus')` 直接算,
不要把整个 JSON 读进 Go 再数。`[必须]` 外面要包一层 `JSON_VALID`——
`skus_json` 万一存进了坏数据,`JSON_LENGTH` 会让**整条查询报错**,页面直接打不开。
`[必须]` 空状态分两种文案:从没创建过 → 引导去点「创建」;筛选无结果 → 给"查看全部"的入口。
+3 -3
View File
@@ -412,9 +412,9 @@ Go 侧不用跟着调。
这几条不是抓包结论,是本项目的决定,写在这里避免每次重新讨论:
`[必须]` **会话缓存存 SQLite,不引入 Redis。** Admin 的定位是「双击 exe 就能跑」,
`data/` 在 exe 旁边。示例脚本用 Redis 是因为它是反复启动的一次性脚本,
进程间要传会话;Admin 是常驻进程,没有这个需求,持久化只为重启后免登录。
`[必须]` **会话缓存存 Admin 的 MySQL,不引入 Redis。** 示例脚本用 Redis 是因为
它是反复启动的一次性脚本,进程间要传会话;Admin 是常驻进程,没有这个需求,
持久化只为重启后免登录,继续复用现有数据库即可。
`[决定已变更]` ~~不引入 OCR 服务。~~ 这条判断在工单 #47 里被推翻了,
原文和推翻理由都留在这里,方便后来人知道这个决定变过、为什么变: