Files
cmautobuy/admin/AGENTS.md
T

9.2 KiB
Raw Blame History

Admin 子项目规则

本文件适用于 admin/ 下的全部代码、模板和测试,并继承仓库根目录 AGENTS.md 的 红线、工作流、Git、安全、文档和初级程序员维护规则。

开始工作前

技术栈

Go 版本固定 1.23.0。 依赖版本受它约束,见下面的表。

  • 固定使用 Go + Gin + Go 标准库 html/template。
  • 生产数据库固定 MySQL 8.4,驱动固定 github.com/go-sql-driver/mysql v1.9.2(纯 Go,兼容 Go 1.23)。
  • Admin 默认与 MySQL 同机或走私有网络;生产默认连接 127.0.0.1:3307, 不得把 MySQL 端口向全网开放。项目负责人明确批准公网直连时,只允许固定 /32 来源白名单,并同时满足:公网接口其余来源 DROP、账号按来源 IP 创建、最小库权限、 REQUIRE SSL、root 仍仅限本机。公网 IP 变化时先更新白名单,不得临时改成 %。
  • Admin 公网连接必须使用 database.tls_mode: verify_ca 和服务器公开 CA:要求 TLS 1.2+、验证证书链、禁止回退明文。disabled 只允许同机或 SSH 隧道连接; 不得使用驱动的 preferred 或单纯 skip-verify。
  • Windows 本地运行允许把 MySQL 账号密码写入已被 Git 忽略的 admin/config.yaml; 线上部署仍优先使用权限为 600 的环境文件。CMAUTOBUY_DB_* 环境变量按字段 覆盖 YAML,真实 config.yaml 不得提交、打包、截图或复制到工单和日志。
  • modernc.org/sqlite 只保留给 SQLite → MySQL 单向迁移工具和历史库回归, 不得用于生产运行时,也不得做 SQLite/MySQL 双写或自动同步。
  • 仍然不得改用 mattn/go-sqlite3,避免引入 cgo 和 gcc。
  • 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
github.com/go-sql-driver/mysql v1.9.2 v1.9.3 起要求 Go ≥ 1.24.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 文件,无构建步骤)。
  • 不得引入打包器(webpack/vite/esbuild)。CSS 手写,放 static/css/。

代码分层

  • handler 只负责解析请求、调用 service、渲染模板或返回 JSON,不写业务逻辑,不拼 SQL。
  • service 放业务逻辑(导入解析、创建任务、匹配复用),不认识 Gin 的 *gin.Context。
  • repository 封装 MySQL 读写,迁移命令中的 SQLite 读取也只能放在 repository/cmd 边界内;只有这一层能写业务 SQL。
  • model 只放数据结构,不导入 Gin 和数据库驱动。
  • 给 Client 的接口和给浏览器的页面分开放(handler/api/ 和 handler/web/), 两者的错误格式、认证方式都不一样,混在一起迟早出事。

数据与接口

  • Admin 新建采购任务固定为真实下单(不支付),当前账号可见的全部 Client 都允许被指派;创建时不得按 Client 的 purchase_mode 禁用候选或拒绝任务。purchase_mode 只用于领取期判断 Client 的自动运行就绪能力。

  • 表结构以 03 数据模型 为准。

  • 给 Client 的接口以 docs/client/04-admin-api-contract.md 为准。

  • [必须] 金额一律用整数存,人民币用分、台币用分,字段名带单位后缀(_cent)。 禁止用 float 存金额。

  • [必须] 时间一律带时区 ISO 8601,库里存 UTC,页面上转本地时区显示。

  • [必须] Excel 导入只做 upsert(更新或新增), 绝不允许先清空再导入 —— 会把人工填的 PDD 链接全洗掉。

  • [必须] 蝦皮规格原文(spec_raw)永远保留,解析不出来就留空,不要瞎猜。

  • [必须] Client 提交结果时,不管任务是否已取消、是否已重派,一律接受, 理由见 Client 契约 §6.1。这条最容易被顺手违反。

  • [必须] MySQL 的 schema_migrations 只追加,已经发布的版本不得改写。 MySQL DDL 会隐式提交:每条 DDL 必须可重放,整版完成并通过 schema 自检后 才记录版本。历史 SQLite migrations 已冻结,只供迁移工具读取旧库。

界面规则

  • 五个模块统一使用三段式布局:顶部工具条 / 中间带勾选的表格 / 底部状态条。 第一个页面写完,其余四个照抄结构改字段,不要给某个模块搞特殊。
  • 表格行的身份用业务主键,不得用行号。
  • 批量删除必须二次确认,并显示"将删除 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,不会连手机、不会下单,可随时运行。
  • 修改数据库时必须使用独立 MySQL 8.4 测试库验证首次建库、重复迁移和上一版本升级。 测试库名必须以 _test 结尾,禁止测试清理连接生产库。
  • 修改 SQLite 单向迁移时,同时用各历史 SQLite schema 状态演练;源库只读, 目标库必须为空,逐表计数和关键业务关系必须核对。
  • 修改给 Client 的接口时,跑契约测试,确认仍满足 Client 侧 §6.1 的无条件接受。
  • 修改 Excel 导入时用 raw_data/ 下的样本跑一遍,核对导入条数。 该样本含商业数据、不在仓库里,需向项目负责人索取;自动化测试用 testdata/ 下的脱敏小样本。
  • 交付时说明已运行的命令、结果和未验证的部分。