108 lines
8.8 KiB
Markdown
108 lines
8.8 KiB
Markdown
# AGENT.md - AI Agent 开发规范
|
||
|
||
## 开发流程
|
||
|
||
### 1. 梳理需求
|
||
|
||
使用 `brainstorming` 进行头脑风暴, 文档存放与命名规则如下:
|
||
|
||
| 需求类型 | 计划目录 | 命名规则 | 示例 |
|
||
| -------- | ----------------- | --------------------- | ----------------------- |
|
||
| 新功能 | `plans/feature/` | `xxx-xxx-feature.md` | `smart-view-feature.md` |
|
||
| 修 Bug | `plans/fix/` | `xxx-xxx-fix.md` | `token-refresh-fix.md` |
|
||
| 重构 | `plans/refactor/` | `xxx-xxx-refactor.md` | `api-split-refactor.md` |
|
||
|
||
使用 writing-plans 技能制定实施计划
|
||
|
||
**开发新功能时必须评估权限需求**:每个新功能/新操作都需要考虑是否需要纳入权限控制。具体评估方式见下方「权限系统」章节。
|
||
|
||
可参考的开发文档位于 `docs/dev/*`
|
||
|
||
### 2. 建立开发分支
|
||
|
||
确定好需求之后,就使用 `enterprise-git-spec` 技能来建立分支。
|
||
|
||
### 3. 按照需求开发
|
||
|
||
按照当前功能的计划文档的任务项及其任务细节来逐步实现功能, 全程严格地遵循技能 test-driven-development 进行 TDD 开发流程, 并遵循 executing-plans 技能来执行开发计划。
|
||
|
||
**重要原则:所有测试必须通过**
|
||
|
||
- 开发过程中,必须确保所有测试用例都通过,包括新功能的测试和现有功能的测试
|
||
- 如果发现现有测试失败,必须立即修复,确保新功能不会破坏旧功能
|
||
- 只有在所有测试都通过的情况下,才能认为开发完成
|
||
|
||
所有任务完成后请遵循 verification-before-completion 技能完成验证
|
||
|
||
### 4. 合并到开发分支
|
||
|
||
所有测试通过后,使用 `enterprise-git-spec` 技能提交分支,然后合并回 `develop` 分支。
|
||
|
||
### 5. 沉淀开发经验
|
||
|
||
在实现功能过程中,将适用于任何项目的编码好想法、好思想、注意点等有助于项目推进的内容,及时追加到 `AGENT.md` 中。这些经验是跨功能、跨项目的通用知识,帮助后续开发少走弯路。
|
||
|
||
### 6. 更新项目结构文档
|
||
|
||
每次功能开发完成后,更新 `docs/references/structs.md` 文件。该文件记录整个项目的目录结构和每个模块的简要功能描述,便于每次迭代功能时快速理解整个项目全貌。
|
||
|
||
### 7. 更新使用文档
|
||
|
||
使用文档分为:
|
||
|
||
1. `README.md` - 面向人类使用者,帮助其快速上手项目。仅在新功能开发完成后更新。内容保持简洁,聚焦于让用户快速跑通基础流程。
|
||
2. `docs/references/*` - 面向人类使用者,提供项目的全面使用指南,支持深度探索模块与命令行细节。每次新功能开发完成或已有功能调整后必须更新。示例要丰富,帮助使用者理解各项功能的具体用法。
|
||
3. `skills/[项目名]/SKILL.md` - 面向 LLM / AI Agent,指导大模型如何使用本项目。
|
||
|
||
**快速开始文档**每次新功能开发完成后才更新,具体更新 `README.md` 文件。确保文档包含新增功能的使用示例、命令说明和注意事项,帮助用户快速上手。
|
||
|
||
**详细使用文档**位于 `docs/references/*`,目录文件为 `docs/references/index.md`,请按照功能划分参考文档,并填充详细的使用说明,帮助用户深度探索模块/命令行的使用。每次新功能或旧功能调整了请更新最新的使用方法,例子应该丰富一些,便于使用者理解功能使用。
|
||
|
||
**AGENT使用技能文档**位于 `skills/[项目名]/*`,入口文件为 `skills/[项目名]/SKILL.md`,更新时机和要求与详细使用文档一致。
|
||
|
||
## 开发规范
|
||
|
||
### 代码优化
|
||
|
||
遵循 improve-codebase-architecture
|
||
|
||
### 类型规范
|
||
|
||
参考技能 typescript-advanced-types
|
||
|
||
### 测试规范
|
||
|
||
参考技能 javascript-testing-patterns
|
||
|
||
### 测试
|
||
|
||
每个任务目录应有对应的测试文件 `test/sync/tasks/<task-name>/handler.test.ts`。
|
||
|
||
## 数据库设计
|
||
|
||
PostgreSQL 最佳设计实践: postgresql-table-design 技能
|
||
PostgreSQL 最佳性能调优实践: supabase-postgres-best-practices 技能
|
||
Prisma Postgres 最佳实践: prisma-postgres 技能
|
||
|
||
### 后端规范
|
||
|
||
参考 nestjs-best-practices 技能
|
||
|
||
> 你可以自己增加规范
|
||
|
||
### 经验沉淀(跨项目通用)
|
||
|
||
- **入口 nginx 的真实挂载源在 v1 仓库**:线上 official.inkreach.cc 的 nginx 容器由 `/opt/inkreach/deploy` 创建,挂载的是那边的 `nginx/admin.conf` 与 `certbot/acme` 证书;v2 仓库 `deploy/nginx/admin.conf` 只是同步副本。改线上路由必须改 v1 的文件,再在该目录 `docker compose up -d --force-recreate admin`。v1/v2 目录同名 → compose 项目名相同 → pgdata/uploads 数据卷共享,重建不丢数据。
|
||
- **文件型 bind mount 的 inode 陷阱**:编辑器保存常替换 inode,容器内仍看到旧内容(`:ro` 挂载连 docker cp 都被拒);`docker compose restart` 也不会重新解析挂载。要让新文件内容生效只能 `--force-recreate`,新服务的挂载尽量挂目录而非单个文件。
|
||
- **数据库漂移处理**:连共享开发库时先跑 `prisma migrate status`;若报"列已存在"类错误,说明有人用 `db push` 带外改过库,用 `prisma migrate resolve --applied <name>` 把已存在的迁移标记为已应用,再 `migrate deploy` 应用真正缺的部分。切勿盲目 reset 共享库。
|
||
- **连真实库的集成测试隔离**:jest 并行套件共用一个数据库时,(a) 夹具的天然键(sdsCategoryId、名称等)必须带运行时间戳唯一化,禁止跨运行共享字面量;(b) 全量型操作(如 auto-group 扫全库)会顺带扫到其他并行套件的夹具,其写入路径必须对"成员中途消失"宽容(跳过而非抛错),否则会随机挂测试。
|
||
- **跑全量 jest 前先停 dev server**:`nest start --watch` 等常驻进程与测试共用数据库时,其重编译窗口/后台钩子会与测试写入竞争,造成"单跑绿、全量偶发红"的假阳性;验证基线前先停掉所有 watch 进程再跑。
|
||
- **中文断言勿手写字面量排序**:JS `Array.sort()` 对中文按 UTF-16 码位排(如 烫 U+70EB < 直 U+76F4),手写期望序列容易按拼音/习惯顺序写反;比较选项集合时用 `expect.arrayContaining` + 长度,或从同一排序函数生成期望。
|
||
- **pnpm 仓库容器化执行要挂仓库根**:pnpm 的 node_modules 是相对符号链接指向根 `.pnpm` store,容器里只挂子包目录(如 `apps/api:/app`)会断链报 "Cannot find module";必须挂整个仓库根并 `-w` 到子包。另外 Prisma 引擎与系统 libssl 版本强绑定:node:20-alpine 缺 libssl1.1 会报 engine 加载失败,直接复用项目自身的运行镜像(如 deploy-v2-api)跑 prisma/jest 最稳。
|
||
- **Prisma 唯一查询用字段名而非列名**:`where: { id }` 而非 `@map("category_id")` 映射后的 `categoryId`;schema `@map` 只影响 SQL 列名,Prisma Client 的唯一输入类型永远用 model 字段名。
|
||
- **跨套件分页断言要圈定夹具**:真实库上测"列表排序"时全库数据可能远超 pageSize,夹具根本进不了第一页;给夹具商品名加唯一前缀 + `keyword` 过滤圈定,断言既稳定又能看到完整顺序。
|
||
- **"绝对排序键 + 子集过滤"模式**:需要"任意筛选组合下顺序都正确"时,给每条数据算好一组绝对排序键(如 国家→二级→款→priority,缺失沉底),筛选只做子集过滤不做特殊排序分支——比每个筛选组合写一套 orderBy 逻辑可靠得多。
|
||
- **"代表行选取收敛为单一方法"**:多端点共享同一实体视图(如族化商品对外的代表行)时,代表行选取规则必须收敛为一个私有方法供所有端点复用,禁止各端点各自 `goods[0]`——否则排序参数不同会导致 goodName/主图等字段在列表与详情间漂移。
|
||
- **"物化数组的顺序必须有确定性来源"**:把聚合结果物化进 JSONB(如 price_matrix 的 printCounts/crafts/logistics)时,"Set 去重保首现序"不是顺序保证——源查询没有 orderBy 时 Postgres 不承诺返回序,同一数据两次重算顺序可能漂移。必须:① 聚合后按业务词表序稳定排序(词表外自由文本沉底);② 源查询显式 `orderBy` 固定遍历序。测试用"打乱输入顺序断言输出全等"覆盖顺序确定性。
|
||
- **"新增维度取值 = 标签行 + 两处词表常量,缺一不可"**:工艺/物流/印花数量这类封闭维度新增可选值时,只往 `tags` 表插行不够——矩阵维度词表 `DIM_VALUES` 和展示序 `OPTION_DISPLAY_ORDER` 是硬编码常量,必须同步追加,否则打了新标签的链接会被词表过滤导致价格格子静默消失(比报错更危险)。同时确认自动派生规则(auto-tag-rules / admin origin-name)是否要认识新值;存量数据零影响的前提是"只放开准入,不主动打标"。
|