vr-shopxo-plugin/plan.md

6.5 KiB
Raw Blame History

vr-shopxo-plugin Issue #9 — 架构决策评议计划

版本v1.0 | 日期2026-04-15 | Agentcouncil/FrontendDev主笔

任务背景

Phase 0/1/2 已完成骨架,但暴露了 P0 架构问题:当前商品 112 的 spec_base 表为空broken statespec_base_id_map 中的 ID 在 DB 不存在ShopXO 原生防超卖机制完全未启用。需要评议方案 A vs B 并给出明确推荐。


核心问题4问

Q1: 方案 A 的后台批量生成 SKU 路径是否可行?

  • 具体实现方式ShopXO 是否有批量创建 SKU 的 API/代码路径?
  • 前端uni-app如何配合

Q2: 当前商品 112 的 broken 状态需要立即修复吗?最小修复集是什么?

  • is_exist_many_spec=0 + spec_base 空的根因是什么?
  • 最小修复:不改 spec_base 表,仅改 is_exist_many_spec flag还是重建 SKU

Q3: $vr- 前缀方案是否有隐患?

  • ShopXO 内部逻辑是否对带 $ 的 spec name 做特殊处理?
  • spec_value 的 name/label 字段是否允许 $ 字符?

Q4: 方案 A vs 方案 B 的最终推荐

  • 考虑:实现成本、安全性(防超卖)、可维护性、多 Zone 混买体验

阶段划分

阶段 内容 负责
Round 1(本轮) 分析 4 个问题,建立共识框架,输出推荐 FrontendDev + BackendArchitect + SecurityEngineer 独立输出
Round 2 交叉评审其他成员的分析,补充或反驳 所有成员
Round 3 最终报告合并,输出 council-output/ARCHITECTURE_DECISION.md FrontendDev 主笔

任务清单

  • Task FD-1: FrontendDev — 分析 Q1-Q4输出推荐plan.md 本文件)
  • Task FD-2: FrontendDev — 评审 BackendArchitect / SecurityEngineer 的分析
  • Task FD-3: FrontendDev — 撰写最终报告 council-output/ARCHITECTURE_DECISION.md
  • Task FD-4: FrontendDev — 更新 plan.md 和 ARCHITECTURE.md合并到 main

依赖关系

  • BackendArchitect 输出后端视角ShopXO spec_base 机制、批量生成可能性)
  • SecurityEngineer 输出安全视角($vr- 前缀风险、防超卖方案安全性)
  • FrontendDev 输出前端视角(多 Zone 混买 UX、$vr- 前端处理)
  • 三方分析完成后,合并为最终报告

行动项FrontendDev Round 1 输出)

Q1 分析:方案 A 批量生成 SKU 路径

结论:可行,但实现路径复杂。

ShopXO spec_base 生成机制:

  • 商品保存时,GoodsService::Save() 调用 SpecService::Save() 逐条写入 sxo_goods_spec_base
  • 没有现成的批量 API — 需要在插件初始化/商品绑定时,批量调用 SpecService 或直接 SQL INSERT
  • 方案 A 的 SKU 数量 = 座位数(一场演唱会可能 10000+ 个座位)
  • 前端配合uni-app 需要维护 seat_id → spec_base_id 映射(已在 spec_base_id_map 中)
  • 关键风险:商品规格管理页面会显示 10000+ 行 SKU可能导致 ShopXO 后台崩溃
  • 解决方向:插件专用规格不出现在 ShopXO 原生规格管理页,通过 Hook 隐藏;建立独立的"座位 SKU 管理"页面

Q2 分析:商品 112 broken state 最小修复集

结论:需要立即修复,推荐最小方案。

根因:is_exist_many_spec=0 意味着 ShopXO 认为此商品无多规格spec_base 表自然为空(从未生成过 SKU

最小修复路径(不破坏现有数据):

  1. 方案甲(最小侵入):在 plugins_service_goods_save_end Hook 中,检测商品有 venue_data$vr- spec 存在时,强制将 is_exist_many_spec 设为 1但不写 spec_base 表(绕过 ShopXO spec 机制,完全走插件自定义逻辑)
  2. 方案乙(规范做法):调用 SpecService::Save() 为每个座位生成一条 spec_base 记录inventory=1, price 从 seat_type 读取)

推荐方案甲(最小修复):

  • 优势:无需重建 SKU不影响现有订单数据
  • 代价:is_exist_many_spec 变成"脏 flag",但这是 ShopXO 的内部状态,插件不依赖它做业务
  • 操作:一条 UPDATE + 一条 Hook 注入

Q3 分析:$vr- 前缀隐患

结论:低风险,但需实测确认。

ShopXO spec name 字段无字符过滤,数据库 varchar 类型允许 $ 字符。潜在风险点:

  • ThinkPHP 的 __isset() / 动态属性访问可能对 $ 敏感(但 spec name 存 DB 而非 PHP 属性,低风险)
  • 前端模板渲染时,$vr- 字符串可能触发 Vue/JS 的变量插值解析({{ $vr-场馆 }})—— 这是真实风险
  • ShopXO 原生规格管理页面可能将 $ 视为特殊字符处理

需要验证uni-app 端 spec value 的渲染方式(是纯文本还是模板字符串?)

Q4 最终推荐:方案 A vs 方案 B

推荐:方案 A每个座位一个 SPEC/SKU

理由:

  1. 安全性ShopXO 原生原子扣库存防超卖,经过大量生产验证;方案 B 的自建 FOR UPDATE 锁在高并发下有死锁风险
  2. 数据一致性:方案 A 的 stock = 1ShopXO 购买流程自带事务保护;方案 B 的 Zone stock 需要插件自己维护一致性和并发安全
  3. 多 Zone 混买:方案 A 前端每 Zone 一个 goods_params 行,后端按 seat_id 原子购买,体验流畅;方案 B 前端分组但后端共享 Zone stock反而增加了前端分组逻辑的复杂度与我们"多 Zone 混买前端分组"的初衷不符)
  4. 维护性:方案 A 依赖 ShopXO 原生机制,故障排查有据可查;方案 B 是"黑盒",出问题只能靠插件自己
  5. $vr- 前缀spec_base_id_map 的 key 可以是 seat_id无需改 ShopXO spec name 存储

方案 B 的唯一优势SKU 数量少Zone 数量 vs 座位数量),后台管理简单。但这个优势在演唱会 10000 座场景下不如安全和一致性重要。


行动项(优先级排序)

  1. 【P0】紧急修复商品 112 broken stateHook 注入 is_exist_many_spec=1,使插件能正常识别票务商品(推荐方案甲,最小侵入)
  2. 【P1】实现方案 A 批量 SKU 生成:在 SeatTemplateService::BindToGoods() 中,座位模板绑定商品时,批量 INSERT spec_base 记录inventory=1, price 从 seat_type 读取)
  3. 【P2】隔离 ShopXO 规格管理页面Hook 隐藏票务商品的原生规格列表,建立独立座位 SKU 管理视图

共识投票

[CONSENSUS: NO] — 本轮仅完成分析,执行待后续阶段


Round 1 完成,输出存档。等待 BackendArchitect 和 SecurityEngineer 的分析结果。