vr-shopxo-plugin/plan.md

128 lines
6.5 KiB
Markdown
Raw Normal View 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 state**Hook 注入 `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 的分析结果。*