vr-shopxo-plugin/reviews/council-ghost-spec-summary.md

8.2 KiB
Raw Blame History

幽灵 Spec 问题 — 三方调研汇总报告(终版)

版本: v2.0 日期: 2026-04-20 汇总人: SecurityEngineer 来源报告: SecurityEngineer-GHOST_SPEC_SECURITY.md + council-ghost-spec-FrontendDev.md + council-ghost-spec-BackendArchitect.md


一、问题概述

当票务商品关联的场馆模板被硬删除后,编辑商品时出现「规格不允许重复」错误。

注意ticket_detail.htmlC 端购票页面(用于用户选座下单),不是后台商品编辑页面。「规格不允许重复」错误的真正触发点在 ShopXO 后台服务层 GoodsService.php:1859/1889/1925

问题触发路径

1. 商品选择场馆 A → vr_goods_config 存储 template_id=A、template_snapshot
2. 场馆 A 被硬删除 → vr_seat_templates 表中无记录
3. 编辑商品 → GetGoodsViewData() 发现 template_id 无效
   → 将 template_id 置 null、template_snapshot 置 null
   → 写回 DB自愈行为
   → 前端收到 template_id=null选单为空
4. 若 template_id 未被及时清理 → 保存时 BatchGenerate 返回 "座位模板 N 不存在"
5. 若 template_id 已清理 → 保存成功,但原规格数据丢失

二、各 Agent 调研结论

2.1 FrontendDev 调研结论(来源:council-ghost-spec-FrontendDev.md

问题 文件:行号 严重度
loadSoldSeats() 未实现TODO 空函数) ticket_detail.html:375-383 P2
模板不存在时 fallback 行为正确 SeatSkuService.php:383
「规格不允许重复」不在前端触发 GoodsService.php:1859
config 块残留(硬删除后未移除) AdminGoodsSaveHandle.php P2
spec_base_id_map 不影响前端 ticket_detail.html:417 P3

前端关键发现

  • ticket_detail.html 本身不构建 ShopXO 规格表格,其规格项仅为场次选择器
  • 模板不存在时前端展示空白购票页(符合业务预期)
  • loadSoldSeats() 是 TODO 注释,未发送 HTTP 请求,已售座位无法灰显

修复建议

  • P2: 实现 loadSoldSeats() 从后端加载已售座位数据
  • P2: AdminGoodsSaveHandle 硬删除后移除整个 config 块而非仅置 null

2.2 BackendArchitect 调研结论(来源:council-ghost-spec-BackendArchitect.md

优先级 根因描述 文件:行号 影响
P1 无效 config 块未从数组移除,continue 后脏数据写回 DB AdminGoodsSaveHandle.php:88-89 + 148-150 幽灵 config 累积,无效 template_id 持续残留
P2 GetGoodsViewData 单模板模式处理,多模板场景会覆盖有效配置块 SeatSkuService.php:368 + 386-388 多模板商品中一个模板删除后整体数据损坏
P3 BatchGenerate 对无效 template_id 返回 code=-2阻断整个保存 AdminGoodsSaveHandle.php:164-170 用户看到"座位模板不存在"错误
P4 前端过滤后 configs 为空时,用户无声失去所有配置 AdminGoodsSave.php:196-229 体验问题:用户不知道配置被过滤
P5 loadSoldSeats() 未实现 ticket_detail.html:375-383 顾客可选已售座位,可能超卖

后端关键发现

  1. P1 根因CriticalAdminGoodsSaveHandle.php:88-89continue 不删除 config 块,导致含无效 template_id 的脏配置被写回 DB第 148-150 行)。无效模板的 config 块在每次保存后持续累积。

  2. spec_base_id_map 不是幽灵 spec 来源:该字段存储在 vr_seat_templates 表,模板硬删除后自然消失,不会在 goods 表的 vr_goods_config 中残留。

  3. spec_base_id_map 数据流:存储在模板表 → GetGoodsViewData 读取解码SeatSkuService.php:404-409→ 前端 JS 接收。删除后前端 fallback 到 sessionSpecId

  4. 多模板模式 P2 缺陷GetGoodsViewData 第 368 行只取 $vrGoodsConfig[0],多模板模式下第 2、3... 个配置块被完全忽略。第 386-388 行写回 DB 时只写 [$config](单元素),会覆盖其他有效配置块。

修复方案

  • P1 Fix: AdminGoodsSaveHandle.php:88-89continue 改为 unset($configs[$i]),第 145 行后加 $configs = array_values($configs) 重排索引,第 148-150 行前加判空。
  • P2 Fix: SeatSkuService.php:368-393 改为遍历所有有效配置块,写回时使用 $validConfigs 而非单元素数组。

2.3 SecurityEngineer 安全审计结论(来源:SecurityEngineer-GHOST_SPEC_SECURITY.md

ID 问题 严重性
S-1 场馆硬删除后保存失败,错误信息不友好 P2
S-2 GetGoodsViewData 静默修改 DB P2
S-3 loadSoldSeats() 空实现,前端无法标记已售座位 P2
S-4 template_snapshot 无大小限制 P3

P1 安全漏洞发现0 个

维度 评估
脏数据注入 安全 — 无注入路径
规格覆盖 安全 — 先删后建BatchGenerate 是唯一来源
XSS 风险 安全 — 无渲染点
权限绕过 安全 — 依赖 ShopXO 内核
DoS 风险 — 建议 DB 层加字段大小限制

安全评估:幽灵 spec 问题经审计后确认不是安全漏洞(无 P1

  1. spec_base_id_map 不可控:不在表单提交范围内,不在 vr_goods_config
  2. template_snapshot 保存时由后端重建,前端传入值被覆盖
  3. BatchGenerate 有保护:模板不存在时返回错误阻断保存

三、综合结论

问题定性

维度 结论
安全评级 无漏洞0 P1 安全漏洞)
功能评级 P1 — 无效 config 块未被移除,脏数据写回 DB
其他功能缺陷 P2 — 错误信息不友好、自愈行为副作用、超卖风险

重要区分SecurityEngineer 的 P1 定义是「安全漏洞」BackendArchitect 的 P1 定义是「功能性高优先级缺陷」。两者都正确:

  • 从安全角度:无 P1 安全漏洞0 个)
  • 从功能角度:无效 config 块残留是 P1 优先级缺陷(需立即修复)

根因链

1. 场馆硬删除 → vr_seat_templates 表记录消失
2. 商品 vr_goods_config.template_id 仍为已删除场馆的 ID
3. AdminGoodsSaveHandle.php:88-89 执行 continue不删除 config 块)
4. 第 148-150 行将含无效 template_id 的脏 config 写回 DB
5. 幽灵 config 块在 DB 中持续累积
6. 下次保存时 BatchGenerate 检测到无效模板 → 返回 code=-2 → 保存阻断
7. 用户看到不友好的错误信息「座位模板 N 不存在」

关键保护机制

  • BatchGenerate 模板存在性检查SeatSkuService.php:52-57是最后防线模板不存在时保存被阻断无脏数据写入规格表
  • 前端 AdminGoodsSave.php:202 过滤硬删除模板的 config 块(有效)

四、修复建议(优先级排序)

优先级 修复项 涉及文件 Agent 归属
P1 无效 config 块移除(unset + array_values + 判空) AdminGoodsSaveHandle.php:88-145 + 148-150 BackendArchitect
P2-高 GetGoodsViewData 多模板模式修复 SeatSkuService.php:368-393 BackendArchitect
P2-中 改善 BatchGenerate 错误信息,引导用户重新选择场馆 SeatSkuService.php:55-57 BackendArchitect
P2-中 改善前端过滤无效配置后的用户体验提示 AdminGoodsSave.php:196-229 FrontendDev
P2-中 实现 loadSoldSeats() 标记已售座位 ticket_detail.html:375-383 FrontendDev
P3-低 vr_goods_config 字段加 TEXT 限制 DB migration BackendArchitect

五、各 Agent 报告位置

Agent 报告文件
SecurityEngineer reviews/SecurityEngineer-GHOST_SPEC_SECURITY.md
FrontendDev .worktrees/FrontendDev/reviews/council-ghost-spec-FrontendDev.md
BackendArchitect .worktrees/BackendArchitect/reviews/council-ghost-spec-BackendArchitect.md

六、后续行动

  1. BackendArchitect 实施 P1 FixAdminGoodsSaveHandle 无效 config 块移除)
  2. FrontendDev 实施 P2-中修复loadSoldSeats 实现 + 前端提示)
  3. 优先处理 P1无效 config 块移除)和 P2-高(多模板模式)修复