#38 归档记录了打回一次的经过(ParseSpec 两个失败分支无测试覆盖, 其中 size=="" 就是真实数据里 2 行走的分支),以及架构角色第一轮 变异打在死分支上、差点误报「测试没牙」的过程。 改正:/usr/local/go 从 2026-07-02 起一直是 1.26.5,而六份归档都写着 「架构角色亲自执行(Go 1.23.0)」——那是照项目固定版本抄的, 没有实际验证过工具链,违反 CLAUDE.md §9「说验证过必须真的跑过」。 措辞改为不宣称具体版本。已用 GOTOOLCHAIN=go1.23.0 补验,结论不变。 admin/AGENTS.md 加两条 [必须]: - 交付前至少跑一次带 GOTOOLCHAIN=go1.23.0 的验证。开发机装的可能更新, Go 会默默用它编译,测过的不是要交付的那个版本。新加依赖时尤其要跑。 - 改数据库时不要只测全新库,先列出现实中存在哪些 schema 状态再一个个验(来自 #20)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7.6 KiB
7.6 KiB
Admin 子项目规则
本文件适用于 admin/ 下的全部代码、模板和测试,并继承仓库根目录 AGENTS.md 的
红线、工作流、Git、安全、文档和初级程序员维护规则。
开始工作前
- 从仓库根目录执行 Admin 任务时,也必须先读取本文件。
- 第一次接手,先看这两份:
- 只读取与当前任务有关的长期基线,不必每次加载全部文档:
- Admin 提供的接口必须满足 Client 侧契约 docs/client/04-admin-api-contract.md, 两边不一致时以 Client 契约为准,要改先走工单。
技术栈
Go 版本固定 1.23.0。 依赖版本受它约束,见下面的表。
- 固定使用 Go + Gin + Go 标准库
html/template。 - 数据库固定 SQLite,驱动固定
modernc.org/sqlite。 不得改用mattn/go-sqlite3—— 那个要 cgo,Windows 上得装 gcc, 交叉编译和打包 exe 都会变得很麻烦。 - Excel 读取固定
github.com/xuri/excelize/v2。
依赖版本已钉死,不要随手升
| 依赖 | 固定版本 | 为什么不能用更新的 |
|---|---|---|
github.com/gin-gonic/gin |
v1.11.0 | v1.12.0 起要求 Go ≥ 1.25.0 |
modernc.org/sqlite |
v1.38.0 | v1.40.0 起要求 Go ≥ 1.24.0,v1.48.0 起要求 ≥ 1.25.0 |
github.com/xuri/excelize/v2 |
v2.9.1 | v2.10.0 要求 Go ≥ 1.24.0,v2.11.0 要求 ≥ 1.25.0 |
excelize 目前还不在
go.mod里——导入功能还没写,没有代码 import 它,go mod tidy会把它去掉,这是 Go 的正常行为。写导入功能时用go get github.com/xuri/excelize/v2@v2.9.1加进来。
这三个版本是在 Go 1.23.0 下实测能编译通过的最高版本。
[必须] 直接跑 go get <包名>(不带版本)会拉到最新版,然后报
requires go >= 1.25.0。拉依赖要带版本号,见
00 上手指南 §2。
[必须] 要升依赖就得先升 Go,这是一个决定不是两个。
升 Go 属于会影响构建的变更,先过工单。
- 实际版本以
admin/go.mod/go.sum为准,这两个文件都要提交 Git。 - 新增或升级依赖前先过工单。
前端约束
- 不得引入 React、Vue、Angular 等前端框架,不得引入 npm 构建流程。 页面一律服务端渲染。
- 搜索、删除、导入这类操作用普通表单提交,零 JavaScript。
- 勾选、弹窗、导入进度确实需要 JS,只允许两种做法:
- 原生 JavaScript,直接写在模板里或放
static/js/下的独立文件; - htmx(单个 js 文件,无构建步骤)。
- 原生 JavaScript,直接写在模板里或放
- 不得引入打包器(webpack/vite/esbuild)。CSS 手写,放
static/css/。
代码分层
handler只负责解析请求、调用 service、渲染模板或返回 JSON,不写业务逻辑,不拼 SQL。service放业务逻辑(导入解析、创建任务、匹配复用),不认识 Gin 的*gin.Context。repository封装 SQLite,只有这一层能写 SQL。model只放数据结构,不导入 Gin 和数据库驱动。- 给 Client 的接口和给浏览器的页面分开放(
handler/api/和handler/web/), 两者的错误格式、认证方式都不一样,混在一起迟早出事。
数据与接口
- 表结构以 03 数据模型 为准。
- 给 Client 的接口以 docs/client/04-admin-api-contract.md 为准。
[必须]金额一律用整数存,人民币用分、台币用分,字段名带单位后缀(_cent)。 禁止用 float 存金额。[必须]时间一律带时区 ISO 8601,库里存 UTC,页面上转本地时区显示。[必须]Excel 导入只做 upsert(更新或新增), 绝不允许先清空再导入 —— 会把人工填的 PDD 链接全洗掉。[必须]蝦皮规格原文(spec_raw)永远保留,解析不出来就留空,不要瞎猜。[必须]Client 提交结果时,不管任务是否已取消、是否已重派,一律接受, 理由见 Client 契约 §6.1。这条最容易被顺手违反。[必须]repository/db.go里的migrations只追加,不得修改已经发布过的条目。 改了的话,已经建过库的机器user_version已经越过它,永远不会重跑, 程序会拿着对不上的库静默启动(见 #20)。需要改结构就加新的一条。
界面规则
- 五个模块统一使用三段式布局:顶部工具条 / 中间带勾选的表格 / 底部状态条。 第一个页面写完,其余四个照抄结构改字段,不要给某个模块搞特殊。
- 表格行的身份用业务主键,不得用行号。
- 批量删除必须二次确认,并显示"将删除 N 条"。
- 破坏性操作(删除、导入覆盖)用 POST,不得用 GET。
- 页面必须能在 1366×768 上正常使用,表格横向滚动而不是压缩列宽。
安全
- 根目录
AGENTS.md的五条红线同样适用。 [必须]所有写操作(新增/编辑/删除/导入/建任务)加 CSRF 防护。[必须]SQL 一律用参数化查询,禁止字符串拼接 SQL。[必须]模板输出走html/template的自动转义, 禁止用template.HTML包裹用户可控内容。[必须]上传的 Excel 限制大小和扩展名,解析失败要有明确报错,不能让整个进程崩掉。[必须]日志、页面、导出里不得出现 token、密码、Cookie。
验证
全部命令从 admin/ 目录执行。
go vet ./...
go build ./...
go test ./...
go run .
[必须] 交付前至少跑一次带 GOTOOLCHAIN=go1.23.0 的验证:
$env:GOTOOLCHAIN="go1.23.0"; go build ./...; go test ./... -count=1
Remove-Item Env:GOTOOLCHAIN
本项目固定 Go 1.23.0(见 00 上手指南),
但开发机上装的可能是更新的版本,Go 会默默用它编译,测过的不是要交付的那个版本。
本项目已经发生过:连续六份归档写着「Go 1.23.0 验证通过」,实际全跑在 1.26.5 上。
新加依赖时尤其要跑——依赖的 go 指令高于 1.23.0 的话,只有这条命令能发现。
go run .启动后访问http://localhost:8080,不会连手机、不会下单,可随时运行。- 修改数据库时测试首次建库和从上一版本迁移。
[必须]不要只测全新库。 先列出现实中存在哪些 schema 状态 (不同版本的程序建过的库都算),一个个迁过来验。见docs/task/20-*.md。 - 修改给 Client 的接口时,跑契约测试,确认仍满足 Client 侧 §6.1 的无条件接受。
- 修改 Excel 导入时用
raw_data/下的样本跑一遍,核对导入条数。 该样本含商业数据、不在仓库里,需向项目负责人索取;自动化测试用testdata/下的脱敏小样本。 - 交付时说明已运行的命令、结果和未验证的部分。