vr-shopxo-plugin/plan.md

9.0 KiB
Raw Blame History

vr-shopxo-plugin 架构决策评议 — plan.md

版本v1.1(合并版)| 日期2026-04-15 | Agentcouncil/FrontendDev + BackendArchitect + SecurityEngineer 关联Issue #9


任务背景

Phase 0/1/2 已完成基础骨架,暴露了一个 P0 架构问题VR 演唱会票务商品中 ShopXO SPEC 与 SKU 的绑定方案。

已知事实:

  • ShopXO goods_spec_baseSKU表当前为空商品 112 的 is_exist_many_spec=0
  • spec_base_id_map 中的 ID如 1001/1002/1003在 DB 中不存在
  • ShopXO 防超卖机制(原子扣 inventory完全未启用

两种架构方向:

  • 方案 A:每个座位 = 一个 SKUstock=1ShopXO 原生防超卖
  • 方案 B:每个 Zone = 一个 SKUstock=Zone座位数自建 FOR UPDATE 防超卖

核心问题4问

# 问题 负责
Q1 方案 A 后台批量生成 SKU 路径是否可行ShopXO 是否有批量 API BackendArchitect
Q2 当前商品 112 的 broken 状态is_exist_many_spec=0 + spec_base 空)是否需要紧急修复?最小修复集? BackendArchitect + SecurityEngineer
Q3 vr- 前缀方案是否有隐患ShopXO 内部是否对 有特殊处理? SecurityEngineer
Q4 方案 A vs 方案 B 最终推荐(实现成本 / 安全性 / 可维护性) 所有成员

阶段划分

阶段 内容 负责
Round 1本轮 独立评议 + plan.md 合并 所有成员
Round 2 各成员深入分析(后台实现路径、安全评估、前端方案) 所有成员
Round 3 综合推荐 + 输出最终决策报告 + council-output/ARCHITECTURE_DECISION.md FrontendDev 主笔

任务清单

  • Q1: 方案 A 批量生成 SKU 路径 [Pending: BackendArchitect]
  • Q2: 商品 112 broken 状态紧急修复 [Pending: BackendArchitect + SecurityEngineer]
  • Q3: $vr- 前缀安全评估 [Pending: SecurityEngineer]
  • Q4: 方案 A vs 方案 B 最终推荐 [Pending: all]
  • Final: council-output/ARCHITECTURE_DECISION.md — 汇总三方推荐 + 最终结论

Claim 状态

任务 Claim 状态
Q1 [Pending: BackendArchitect]
Q2 [Pending: BackendArchitect + SecurityEngineer]
Q3 [Pending: SecurityEngineer]
Q4 [Pending: all]
最终输出 [Pending: all]

依赖关系

  • Q1BackendArchitect先完成后 Q4 才能给出完整推荐
  • Q3SecurityEngineer可与 Q1 并行
  • Q2 可独立完成,紧急程度由 BackendArchitect 判定
  • 三方分析完成后FrontendDev 主笔 Round 3 最终报告

各成员 Round 1 初判

BackendArchitect 初判

Q1 初步判断Plan A 后台批量生成 SKU 可行。ShopXO 的 goods_spec_base 是标准 MySQL 表,插件可直接 INSERT。但需要确认

  • ShopXO 商品保存时是否校验 spec_base 的 referential integrity
  • 上万座位时批量 INSERT 的性能
  • spec_base_id_map 中的 ID 是否需要与 ShopXO 内部 ID 对齐

Q2 初步判断:当前 broken 状态暂不需要立即修复。购买流程走的是裸商品逻辑is_exist_many_spec=0对 Phase 3 的购买流程设计反而是参考点——需要明确购买流程最终走哪条路后再修。

Q4 初步判断:倾向 方案 A。ShopXO 原生防超卖机制比自建锁更可靠DB 层面原子操作),且不破坏 ShopXO 生态完整性。

FrontendDev 初判Q1-Q4 分析)

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反而增加了前端分组逻辑的复杂度
  4. 维护性:方案 A 依赖 ShopXO 原生机制,故障排查有据可查;方案 B 是"黑盒",出问题只能靠插件自己
  5. $vr- 前缀spec_base_id_map 的 key 可以是 seat_id无需改 ShopXO spec name 存储

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

SecurityEngineer 初判Q2/Q3/Q4

Q2紧急修复优先级

当前状态:商品 112 的 broken 状态is_exist_many_spec=0 + spec_base 空)

  • ShopXO 防超卖机制完全未启用
  • spec_base_id_map 指向不存在的 DB 记录

最小修复集:必须立即修复,但需确认走方案 A 还是 B

  • Pending — 方案确定后,填充 spec_base 表(每个 SKU 一行)
  • Pending — 设置 is_exist_many_spec = 1
  • Pending — 关联 spec_base_id_map 与实际 seat 数据

结论Q2 依赖 Q1/Q4 的输出,暂标记为 blocked。

Q3$vr- 前缀安全隐患

已知事实:

  • ShopXO spec name 允许特殊字符($、-、中文均无过滤)
  • ThinkPHP 模板引擎View可能对 $ 有变量插值行为

风险点:

  • View 层Tpl 模板中 {:$spec_name} 是否会解析 $vr- 作为 PHP 变量?
  • DB 层spec name 入库是否经过转义?
  • API 层spec name 作为 JSON key 时是否安全?

结论需要代码验证Round 2 执行)。

Q4方案 A vs B 最终推荐

初步倾向:方案 A每个座位一个 SKU

理由:

  1. 安全性ShopXO 原生原子扣库存,无需自建锁,超卖风险最低
  2. 正确性:与 ShopXO SPEC 机制对齐is_exist_many_spec=1 时原生防超卖生效
  3. 可追溯性:每个 SKU 独立订单项,核销链路清晰

行动项(优先级排序)

优先级 行动项 负责
P0 紧急修复商品 112 broken state BackendArchitect
P1 实现方案 A 批量 SKU 生成 BackendArchitect
P2 隔离 ShopXO 规格管理页面Hook 隐藏插件 SKU FrontendDev

共识投票

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


Round 3 安全审计结果(保留,仅供参考)

Task S1 — Admin 鉴权覆盖完整性审查 验证通过

Task S2 — SQL 注入风险审计 无注入风险

Task S3 — XSS / CSRF 防护检查 通过

Task S5 — IDOR 水平越权检查 通过

Task S4 — 敏感操作审计日志设计 设计完成