AGENTS.md
5d85625
syb_product.shopee_product_id
models/schema.go:513
shopee_product
shopee_product.pdd_product_id
models/schema.go:416
pdd_product
models/schema.go:413-415
product/service.go:95-99
ListProductView
ProductView
collectionSelectable
collectionDisabledReason
activeCollectionTaskId
web/src/views/goauto/pdd-products/index.vue
product/service.go:222
Detail
purchase/batch.go:314-324
SYBProduct
OrderCode
:501
TargetColor
TargetSize
:519
采集是以 PDD 商品为中心的操作。采集完成后采购员站在 PDD 商品这一侧,需要回答「这个货源对应哪些虾皮/SYB 商品、接下来去哪继续采购」——这需要反向查询,而反向链路从未实现。
当前只能凭记忆回到 SYB 商品列表逐个查找,商品数量增加后不可行。
领域划分本身是合理的(PDD 商品作为货源档案不感知使用方,ShopeeProduct 注释亦强调商品域不存采购与订单字段),本工单不改变该划分,只补齐只读的反向查询与展示。
ShopeeProduct
PDDProduct
详情接口只增加有界摘要:GET /api/admin/v1/pdd-products/:productId(实现在 product/service.go:222 的 Detail)增加关联虾皮商品列表——商品标题、shopee_item_id、规格映射状态摘要、该虾皮商品下的待处理订单行数量。不在详情响应中嵌入任何订单行明细。
GET /api/admin/v1/pdd-products/:productId
shopee_item_id
订单行走独立分页接口:新增 GET /api/admin/v1/pdd-products/:productId/related-syb-products。
GET /api/admin/v1/pdd-products/:productId/related-syb-products
page
pageSize
scope=actionable|all
actionable
shopeeProductId
pendingOnly
scope
total
order_code
默认展示的处理阶段集合必须明确,不使用「待采购」统称:
purchase_ready
pdd_pending
pdd_collecting
pdd_collection_failed
color_mapping
task_created
purchase_succeeded
order_review
manual_action
pdd_unlinked
scope=all
scope=actionable
阶段计算必须在 purchase 包统一重构,并对缺少当前采购规则容错(阻塞级约束):ProcessStages 在 purchase/process_stage.go:66 调用 purchaserule.CurrentRule,后者在未配置当前采购规则时返回错误(purchaserule/service.go:79),当前实现直接 return nil, err。若原样复用,未配置规则将导致 PDD 商品详情或关联列表整体失败。
ProcessStages
purchase/process_stage.go:66
purchaserule.CurrentRule
purchaserule/service.go:79
return nil, err
processStageFromDataset
purchase
processStage
BatchPreview
purchase/batch.go:88
index.vue:222
规格映射摘要由服务端返回明确结果。详情摘要返回:
{ "specMappingStatus": "complete|incomplete|not_required", "specMappingConfirmedCount": 8, "specMappingTotalCount": 12, "specMappingReason": "已确认 8/12 个规格值" }
mappingStatus
models/replacement.go:52
matching|completed|completed_partial
:109
matching|matched|manual_required
purchase/agent_history.go:62
replacementMappingStatus
specMapping*
complete
confirmed
shopeeproduct/specs.go:30
MappingStatusConfirmed
incomplete
pending
not_required
RoleColor
RoleSize
specsJSON
列表接口不做逐行反查:ListProductView(product/service.go:95-99)每行反查会产生 N+1。如需在列表展示,只允许通过一次聚合查询附加「关联虾皮商品数」,不返回订单行明细。
查询必须有界且批量化:详情的基础查询与关联订单页查询的次数不得随订单行数量线性增长,不得逐行调用阶段计算。关联查询为只读,不得触发 AI 规格匹配(参照 retryQueryEligibility 的既有约束:查询路径永不调用外部 provider)。验收需记录实际查询次数或执行计划。
retryQueryEligibility
batch-preview
batch
shopeeItemId
GET /pdd-products/:productId/related-syb-products
specMappingStatus
go test ./app/goauto/product/... ./app/goauto/purchase/...
Architecture-and-Code-Map
Business-Rules-and-Glossary
Android-Agent-API-Contract
sync
sync --check
待实施(界面需先取得设计证据)。
models/replacement.go
结论:现有目标、领域边界和复用既有采购接口的方向合理;进入生产代码前需补齐以下契约与设计细节。
关联订单行使用独立分页接口,不把全部历史订单嵌入现有详情响应。 建议:
GET /pdd-products/:productId
pageSize=20
明确默认展示的处理阶段集合,不使用模糊的“待采购”统称。 界面建议分为:
缺少当前采购规则时,关联关系和历史订单仍必须可查看。 当前 ProcessStages 会读取当前采购规则;实施时不得让“未配置当前采购规则”导致整个 PDD 详情或关联列表失败。缺少规则应表现为订单行不可创建及明确原因。必要时拆分“基础关联/阶段事实”和“采购资格、价格护栏”计算。
权限落实到独立 API 和自动化测试。 关联接口应显式加入 GoAuto 权限矩阵:管理员、采购员可读;其他角色不可读。不能只依赖前端隐藏区块。采购创建继续使用既有采购权限。
规格映射状态由服务端返回明确结果。 如展示映射摘要,应返回例如 mappingStatus: complete|incomplete|not_required 与原因;前端不得解析 specsJSON 自行推断,避免与采购预检分叉。
mappingStatus: complete|incomplete|not_required
查询必须有界且批量化。 详情基础查询和关联订单页查询次数不得随订单行数量线性增长;不得逐行调用阶段计算或 AI Provider。验收记录实际查询次数或执行计划。
建议先确认统一的多动作选择规范并完成 #162,再实施本工单;#161 涉及新接口、订单数据可见性和详情页两个采购入口,风险更高。
现有修订方向合理。为消除 API 与共享阶段实现的剩余歧义,补充以下阻塞级约束:
独立订单行接口不使用 pendingOnly。推荐契约:
GET /api/admin/v1/pdd-products/:productId/related-syb-products?scope=actionable|all
原因:默认集合同时包含可创建、进行中、失败和待匹配状态,命名为 pendingOnly 不准确,未来也容易产生兼容歧义。前端不得自行维护该阶段集合。
详情摘要建议返回:
{ "mappingStatus": "complete|incomplete|not_required", "mappingConfirmedCount": 8, "mappingTotalCount": 12, "mappingReason": "已确认 8/12 个规格值" }
判定口径:
不得在 product 包复制 processStageFromDataset、捕获缺少规则错误后另建简化判定,或维护第二套阶段原因。应在 purchase 包提供统一的只读阶段计算入口:
total/page/pageSize
设计与可见性:用户于 2026-08-31 确认低保真设计,以及 SYB 订单号、目标颜色/尺码、数量和采购任务状态仅对 admin/purchaser 开放。
实现:
验证:
go test ./app/goauto/product ./app/goauto/purchase ./app/goauto/access
pnpm exec eslint src/views/goauto/pdd-products/index.vue src/api/goauto/pdd-products.js
pnpm build:prod
PLAYWRIGHT_TEST_BASE_URL=http://localhost:9530 PLAYWRIGHT_DISABLE_VIDEO=1 pnpm exec playwright test tests/e2e/pdd-related-products.spec.ts
长期文档:
de7e400503d6
4ba1787539a8
提交:09d9d22,已推送 origin/main。
09d9d22
origin/main
说明:工作区中与 #161 无关的 Android、SYB 文档及未跟踪文件均保留,未纳入提交。状态:待用户验收。
现象:使用 purchaser 打开 PDD 商品详情时,新关联接口返回“没有该接口访问权限”。
根因:启动时 Casbin Enforcer 先从数据库加载旧策略,随后 ReconcilePurchaserPermissions 才写入新策略;对账完成后未刷新内存 Enforcer,因此首次升级重启仍使用旧权限,通常第二次重启才会生效。权限矩阵条目本身正确。
ReconcilePurchaserPermissions
修复:
cmd/api.run
sdk.Runtime.GetCasbin()
LoadPolicy()
验证:go test ./cmd/api ./app/goauto/access ./app/goauto/product ./app/goauto/purchase 全部通过。
go test ./cmd/api ./app/goauto/access ./app/goauto/product ./app/goauto/purchase
提交:d90bf66,已推送 origin/main。部署该提交后只需正常重启一次即可同步数据库与内存 Casbin 策略。
d90bf66
No dependencies set.
The note is not visible to the blocked user.
所属与来源
AGENTS.md「Gitea 交互与工单最小读取」记录回退原因。当前事实(行号按提交
5d85625复核,2026-08-31 修正)syb_product.shopee_product_id(models/schema.go:513)→shopee_productshopee_product.pdd_product_id(models/schema.go:416)→pdd_productmodels/schema.go:413-415)。product/service.go:95-99的ListProductView仅包含ProductView与采集相关字段(collectionSelectable、collectionDisabledReason、activeCollectionTaskId),无虾皮或 SYB 字段。web/src/views/goauto/pdd-products/index.vue中不存在 shopee / syb 相关内容。详情接口的扩展点为product/service.go:222的Detail。purchase/batch.go:314-324);规格映射配置在虾皮商品上并指向 PDD 规格值。SYBProduct携带订单维度信息:OrderCode(虾皮订单号,:501)、TargetColor/TargetSize(:519)、数量等。问题
采集是以 PDD 商品为中心的操作。采集完成后采购员站在 PDD 商品这一侧,需要回答「这个货源对应哪些虾皮/SYB 商品、接下来去哪继续采购」——这需要反向查询,而反向链路从未实现。
当前只能凭记忆回到 SYB 商品列表逐个查找,商品数量增加后不可行。
领域划分本身是合理的(PDD 商品作为货源档案不感知使用方,
ShopeeProduct注释亦强调商品域不存采购与订单字段),本工单不改变该划分,只补齐只读的反向查询与展示。目标
非目标
ShopeeProduct/PDDProduct的领域边界,不在商品域写入采购或订单字段。实施方案
一、服务端:反向关联查询
详情接口只增加有界摘要:
GET /api/admin/v1/pdd-products/:productId(实现在product/service.go:222的Detail)增加关联虾皮商品列表——商品标题、shopee_item_id、规格映射状态摘要、该虾皮商品下的待处理订单行数量。不在详情响应中嵌入任何订单行明细。订单行走独立分页接口:新增
GET /api/admin/v1/pdd-products/:productId/related-syb-products。page、pageSize(默认 20,最大 100)、scope=actionable|all(默认actionable)、可选shopeeProductId;pendingOnly:默认集合同时包含可创建、进行中、失败与待匹配四类状态,pendingOnly名不副实,后续扩档也会产生兼容歧义;非法scope返回参数错误;total/page/pageSize;order_code、目标颜色/尺码、数量、处理阶段与原因、当前采购任务及状态。默认展示的处理阶段集合必须明确,不使用「待采购」统称:
purchase_ready;pdd_pending、pdd_collecting、pdd_collection_failed、color_mapping;task_created、purchase_succeeded、order_review、manual_action、pdd_unlinked)默认隐藏,经「查看全部」(scope=all)进入。scope=actionable固定对应purchase_ready、pdd_pending、pdd_collecting、pdd_collection_failed、color_mapping这五个阶段,该集合由服务端定义,前端不得自行维护。阶段、标签、原因与下一步复用 purchase 包的统一入口(见第 4 项),不在 product 域复制一套判定。
阶段计算必须在 purchase 包统一重构,并对缺少当前采购规则容错(阻塞级约束):
ProcessStages在purchase/process_stage.go:66调用purchaserule.CurrentRule,后者在未配置当前采购规则时返回错误(purchaserule/service.go:79),当前实现直接return nil, err。若原样复用,未配置规则将导致 PDD 商品详情或关联列表整体失败。processStageFromDataset、捕获缺少规则的错误后另建简化判定,或维护第二套阶段原因;purchase包提供统一的只读阶段计算入口:无 AI 调用;未配置或当前采购规则无效时仍返回基础关联、采集、已有任务等阶段事实;只有依赖规则与价格护栏才能决定的订单行标记为不可采购并给出明确原因;processStage、label、reason、nextAction 必须一致。BatchPreview(purchase/batch.go:88)整体返回错误,SYB 商品页前端 catch 后把所有行标成「采购准备检查失败」(index.vue:222附近)。重构后 SYB 页将变为「阶段正常显示、仅不可创建采购」。该变化是改进,但属于既有接口的行为变更,不是纯新增,必须纳入 SYB 页回归验证。规格映射摘要由服务端返回明确结果。详情摘要返回:
mappingStatus:该名称在本仓库已被占用两次且值域不同(models/replacement.go:52为matching|completed|completed_partial,:109为matching|matched|manual_required,另有purchase/agent_history.go:62的replacementMappingStatus)。本工单讲的是规格值映射,统一用specMapping*前缀,避免同名字段第三种值域。complete:所有需要映射的虾皮颜色/尺码规格值均有confirmed映射(shopeeproduct/specs.go:30的MappingStatusConfirmed),且映射目标仍属于当前 PDD 对应维度的可选规格;incomplete:至少一个需要映射的规格值未映射、仍为pending,或映射目标已不属于当前 PDD 可选规格;not_required:虾皮商品不存在需要映射的颜色/尺码维度(RoleColor/RoleSize);不得用「某一订单行目标值为空」判定商品整体为not_required;specsJSON自行推断,避免与采购预检的判定分叉。列表接口不做逐行反查:
ListProductView(product/service.go:95-99)每行反查会产生 N+1。如需在列表展示,只允许通过一次聚合查询附加「关联虾皮商品数」,不返回订单行明细。查询必须有界且批量化:详情的基础查询与关联订单页查询的次数不得随订单行数量线性增长,不得逐行调用阶段计算。关联查询为只读,不得触发 AI 规格匹配(参照
retryQueryEligibility的既有约束:查询路径永不调用外部 provider)。验收需记录实际查询次数或执行计划。二、发起采购
batch-preview/batch),不新写创建逻辑。三、Admin 界面
scope=actionable的阶段,另提供「查看全部」入口。界面模型必须与扁平分页一致:
shopeeProductId、shopeeItemId与虾皮商品标题;shopeeProductId收窄;total/page/pageSize始终针对当前统一过滤条件。四、权限
安全边界
验收标准
GET /pdd-products/:productId/related-syb-products返回,total/page/pageSize准确,不是按每个虾皮商品各自伪分页;pageSize默认 20、上限 100 生效。scope时等价于scope=actionable;非法scope被拒绝;前端未自行维护阶段集合(代码检查佐证)。shopeeProductId」两种过滤分别验证分页与total;同一虾皮商品的订单行跨页出现时展示正确,无伪嵌套子表。specMappingStatus三态与计数按第 5 项定义验证;字段名未与既有mappingStatus混用。incomplete不会阻止其中已满足条件的订单行进入purchase_ready。batch-preview/batch路径(代码检查佐证未新增创建实现)。验证方式
go test ./app/goauto/product/... ./app/goauto/purchase/...依赖、并行与风险
ProcessStages会引入对当前采购规则的硬依赖,未配置规则时整页失败。缓解:第 4 项在 purchase 包统一重构并容错,并在验收中专项检查。文档影响
Architecture-and-Code-Map:PDD 商品的反向关联查询路径与新增的关联订单查询接口。GET /api/admin/v1/pdd-products/:productId/related-syb-products及其权限矩阵条目必须同步记录(接口路径、参数、默认值与上限、可读角色)。Business-Rules-and-Glossary:从 PDD 商品发起采购与备货采购的区别、scope=actionable的阶段集合定义、specMappingStatus三态判定口径。Android-Agent-API-Contract:不涉及 Agent 接口,实施时确认无需改动并在工单说明。sync与一轮sync --check,把页面与 revision 写回本工单。状态
待实施(界面需先取得设计证据)。
修订记录
scope=actionable|all(弃用pendingOnly)、阶段计算在 purchase 包统一重构并对缺少采购规则容错、明确扁平分页的界面模型、定义规格映射摘要三态与计数。另按复核结论做两处调整:映射字段改名为specMapping*(避免与models/replacement.go两处既有mappingStatus值域冲突),并把「SYB 商品页在规则缺失时的既有表现变更」显式声明为有意行为变更并纳入回归。mappingStatus由服务端返回、查询有界;相应更新非目标、验收、验证方式、风险与文档影响。评审结论已并入正文,正文为唯一实施依据。5d85625复核,修正 schema.go 行号引用(pdd_product_id 为 :416,注释为 :413-415),补充详情扩展点 product/service.go:222;将「待采购」判定改为复用采购预检既有处理阶段口径;在安全边界补充跨域数据可见性确认;相应增加两条验收与与 #162 的交互规范前置说明。2026-08-31 实施前评审补充
结论:现有目标、领域边界和复用既有采购接口的方向合理;进入生产代码前需补齐以下契约与设计细节。
必须纳入实施方案
关联订单行使用独立分页接口,不把全部历史订单嵌入现有详情响应。 建议:
GET /pdd-products/:productId继续返回商品详情,并增加关联虾皮商品摘要、待处理数量等有界信息;GET /pdd-products/:productId/related-syb-products,支持page、pageSize、pendingOnly,可选shopeeProductId;pageSize=20,最大 100。原因:一个 PDD 可关联多个虾皮商品,每个虾皮商品可能存在大量历史 SYB 明细;嵌套的逐虾皮分页难以定义统一 total,也会拖慢详情打开。
明确默认展示的处理阶段集合,不使用模糊的“待采购”统称。 界面建议分为:
purchase_ready;pdd_pending、pdd_collecting、pdd_collection_failed、color_mapping;阶段、标签、原因和下一步仍须复用
processStageFromDataset/ProcessStages口径,不在 product 域复制判定。缺少当前采购规则时,关联关系和历史订单仍必须可查看。 当前
ProcessStages会读取当前采购规则;实施时不得让“未配置当前采购规则”导致整个 PDD 详情或关联列表失败。缺少规则应表现为订单行不可创建及明确原因。必要时拆分“基础关联/阶段事实”和“采购资格、价格护栏”计算。权限落实到独立 API 和自动化测试。 关联接口应显式加入 GoAuto 权限矩阵:管理员、采购员可读;其他角色不可读。不能只依赖前端隐藏区块。采购创建继续使用既有采购权限。
规格映射状态由服务端返回明确结果。 如展示映射摘要,应返回例如
mappingStatus: complete|incomplete|not_required与原因;前端不得解析specsJSON自行推断,避免与采购预检分叉。查询必须有界且批量化。 详情基础查询和关联订单页查询次数不得随订单行数量线性增长;不得逐行调用阶段计算或 AI Provider。验收记录实际查询次数或执行计划。
设计证据需覆盖
建议补充验收
建议先确认统一的多动作选择规范并完成 #162,再实施本工单;#161 涉及新接口、订单数据可见性和详情页两个采购入口,风险更高。
2026-08-31 二次评审补充(实施前需并入正文)
现有修订方向合理。为消除 API 与共享阶段实现的剩余歧义,补充以下阻塞级约束:
1. 查询参数改为准确的范围语义
独立订单行接口不使用
pendingOnly。推荐契约:scope=actionable;actionable固定对应purchase_ready、pdd_pending、pdd_collecting、pdd_collection_failed、color_mapping;scope=all返回全部处理阶段;原因:默认集合同时包含可创建、进行中、失败和待匹配状态,命名为
pendingOnly不准确,未来也容易产生兼容歧义。前端不得自行维护该阶段集合。2. 明确定义虾皮商品映射摘要
详情摘要建议返回:
判定口径:
complete:所有需要映射的虾皮颜色/尺码规格值均有confirmed映射,且映射目标仍属于当前 PDD 对应维度的可选规格;incomplete:至少一个需要映射的规格值未映射、仍为pending,或映射目标已不属于当前 PDD 可选规格;not_required:虾皮商品不存在需要映射的颜色/尺码维度;不得用“某一订单行目标值为空”判定商品整体为not_required;3. 共享阶段计算必须在 purchase 包统一重构
不得在 product 包复制
processStageFromDataset、捕获缺少规则错误后另建简化判定,或维护第二套阶段原因。应在purchase包提供统一的只读阶段计算入口:processStage、label、reason、nextAction 必须一致。4. 明确扁平分页的界面模型
shopeeProductId、shopeeItemId、虾皮商品标题;shopeeProductId;total/page/pageSize始终针对当前统一过滤条件。补充验收
scope=actionable;非法 scope 被拒绝;前端未自行维护阶段集合;purchase_ready;shopeeProductId两种过滤验证分页与 total。实施完成,待验收
设计与可见性:用户于 2026-08-31 确认低保真设计,以及 SYB 订单号、目标颜色/尺码、数量和采购任务状态仅对 admin/purchaser 开放。
实现:
specMappingStatus三态、确认/总数及待处理订单数;详情不嵌订单明细。GET /api/admin/v1/pdd-products/:productId/related-syb-products,支持统一扁平分页、scope=actionable|all、可选shopeeProductId,默认 20、最大 100。验证:
go test ./app/goauto/product ./app/goauto/purchase ./app/goauto/access:通过。pnpm exec eslint src/views/goauto/pdd-products/index.vue src/api/goauto/pdd-products.js:通过。pnpm build:prod:通过;仅有仓库既有 CSS 伪类和 chunk-size 警告。PLAYWRIGHT_TEST_BASE_URL=http://localhost:9530 PLAYWRIGHT_DISABLE_VIDEO=1 pnpm exec playwright test tests/e2e/pdd-related-products.spec.ts:1/1 通过,覆盖扁平关联订单展示、不可采购行禁选、仅向预检提交 purchase_ready 子集及入口安全文案。长期文档:
Architecture-and-Code-Maprevisionde7e400503d6。Business-Rules-and-Glossaryrevision4ba1787539a8。提交:
09d9d22,已推送origin/main。说明:工作区中与 #161 无关的 Android、SYB 文档及未跟踪文件均保留,未纳入提交。状态:待用户验收。
重启后采购员新接口 403 修复
现象:使用 purchaser 打开 PDD 商品详情时,新关联接口返回“没有该接口访问权限”。
根因:启动时 Casbin Enforcer 先从数据库加载旧策略,随后
ReconcilePurchaserPermissions才写入新策略;对账完成后未刷新内存 Enforcer,因此首次升级重启仍使用旧权限,通常第二次重启才会生效。权限矩阵条目本身正确。修复:
cmd/api.run在所有数据库采购员权限对账成功后、注册路由和监听端口前,对sdk.Runtime.GetCasbin()中每个 Enforcer 调用LoadPolicy()。验证:
go test ./cmd/api ./app/goauto/access ./app/goauto/product ./app/goauto/purchase全部通过。提交:
d90bf66,已推送origin/main。部署该提交后只需正常重启一次即可同步数据库与内存 Casbin 策略。