From 76eb849b492eb7d74678f46d4585c322e39f5c79 Mon Sep 17 00:00:00 2001 From: yeuimu <2197651308@qq.com> Date: Wed, 2 Sep 2026 10:33:54 +0800 Subject: [PATCH] docs: record style-order semantics, container-run pitfalls and lessons --- AGENTS.md | 6 +++++- docs/references/structs.md | 2 +- plans/feature/category-sort-feature.md | 12 +++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 86cbe70..17417f0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -95,4 +95,8 @@ Prisma Postgres 最佳实践: prisma-postgres 技能 - **数据库漂移处理**:连共享开发库时先跑 `prisma migrate status`;若报"列已存在"类错误,说明有人用 `db push` 带外改过库,用 `prisma migrate resolve --applied ` 把已存在的迁移标记为已应用,再 `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` + 长度,或从同一排序函数生成期望。 +- **中文断言勿手写字面量排序**: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 逻辑可靠得多。 diff --git a/docs/references/structs.md b/docs/references/structs.md index a490f82..d58744c 100644 --- a/docs/references/structs.md +++ b/docs/references/structs.md @@ -113,7 +113,7 @@ apps/api/ | `/public/countries` `GET` | 公开国家列表(仅含已挂商品的国家) | 公开 | | `/public/tags` `GET` | 公开标签列表(带 `group` 字段,按 group 排序) | 公开 | | `/public/tag-groups` `GET` | 公开标签分组列表 | 公开 | -| `/public/goods` `GET` | 分页商品(**族化契约:一族一条**,`goodId`=族ID,`price`=族起价;无族商品不返回;支持 `countryId/categoryId/tags(JSON)/keyword/minPrice/maxPrice/sort/page/pageSize`) | 公开 | +| `/public/goods` `GET` | 分页商品(**族化契约:一族一条**,`goodId`=族ID,`price`=族起价;无族商品不返回;支持 `countryId/categoryId/tags(JSON)/keyword/minPrice/maxPrice/sort/page/pageSize`)。**默认排序 = 款序树**:国家(`countries.sort_order`) → 款所属二级(`categories.sort_order`) → 款(`categories.sort_order`) → `good_priority`;商品经 `origin_goods.sds_category_id` 定位到款(新树三级节点=合并后的款,顺序值由 `排序表.md` 经回填脚本写入),同一款下多条 Good 聚在一起、款内按优先级分先后;`sort=PRICE_ASC/PRICE_DESC/NEWEST` 不受影响 | 公开 | | `/public/goods/:id` `GET` | 款级详情,`:id` = **族 ID**(唯一公开键,SDS 链接 ID 404);公共字段取代表 Good,`variants` = 全体族成员 ∪ 旧副源(去重),`sizeChart/packageSpecs` = 族并集;默认输出 `family` 块(并集尺码表/包装 + 严格五维价格矩阵 尺码×颜色×印花数量×工艺×物流 + 族起价);`PUBLIC_DETAIL_FROM_FAMILY=false` 应急回退 | 公开 | | `/categories` `/tags` `/tag-groups` `/countries` `/positions` | 后台 CRUD | JWT | | `/countries/sort` `PATCH` | 批量保存国家拖拽排序(`items=[{id,sortOrder}]` 全量提交;公开/后台国家列表均按 sortOrder 排序) | JWT | diff --git a/plans/feature/category-sort-feature.md b/plans/feature/category-sort-feature.md index 6a13d2d..26f7ca0 100644 --- a/plans/feature/category-sort-feature.md +++ b/plans/feature/category-sort-feature.md @@ -28,13 +28,19 @@ - 运行容器快照:镜像 `inkreach-api-snapshot:20260901`(docker commit 自 deploy-v2-api-1,含当前代码与依赖) - 代码回滚 = 删 feature 分支 -**执行环境(宿主机无 node,统一用容器跑):** +**执行环境(宿主机无 node;已验证的正确方式——挂仓库根 + 复用运行镜像):** ```bash -# 测试 / prisma 命令统一模板(挂载源码 + 加入 postgres 网络) +# ⚠️ 两个坑(实测踩过): +# 1) pnpm 的 node_modules 是相对符号链接指向根 .pnpm store, +# 只挂 apps/api:/app 会断链(Cannot find module)——必须挂整个仓库根 +# 2) node:20-alpine 缺 libssl1.1,Prisma engine 加载失败—— +# 直接用项目运行镜像 deploy-v2-api(libssl 已匹配) docker run --rm --network deploy-v2_default \ -e DATABASE_URL='postgresql://inkreach:2628adbdf875727ae1b5556b08cb00452bb4e1f80490f6b6@postgres:5432/inkreach' \ - -v /opt/inkreach-v2/apps/api:/app -w /app node:20-alpine npx <命令> + -v /opt/inkreach-v2:/repo -w /repo/apps/api deploy-v2-api npx +# 只读 prisma 元数据(migrate status 等)也可轻量挂载: +# -v /opt/inkreach-v2/apps/api/prisma:/app/prisma deploy-v2-api npx prisma migrate status ``` **排序键定义(getGoods DEFAULT,商品经 origin_goods.sds_category_id 定位到款):**