# VR 票务插件项目 Council 评估 — 最终综合报告 > 评估时间:2026-05-26 17:12 GMT+8 > 协调者:西莉雅(Sileya) > 评估成员:BackendArchitect · FrontendDeveloper · SecurityEngineer · PerformanceBenchmarker --- ## 一、投票结果 | 成员 | 投票 | 状态 | |------|------|------| | BackendArchitect(后端架构师) | **C — 双线并行** | ✅ 已投票 | | FrontendDeveloper(前端开发专家) | **C — 双线并行** | ✅ 已投票 | | SecurityEngineer(安全工程师) | **C — 双线并行** | ✅ 已投票 | | PerformanceBenchmarker(性能压测专家) | ⏳ 进行中 | — | **结论:3:0,压倒性共识选择 C(双线并行)** --- ## 二、各维度现状评估 ### 2.1 后端现状(BackendArchitect) | 组件 | 状态 | 说明 | |------|------|------| | Phase 0/1(插件骨架+票务详情页) | ✅ 完成 | — | | Phase B(B端核销) | ✅ 完成 | Admin 核销页 + TicketVerify API | | Phase 2(SeatMapService + seatmap API) | ⚠️ **半完成** | `SeatSkuService::getSoldSeats()` 方法缺失 | | Phase 3(前端模板+购物车) | ✅ 完成 | `submit()` 修复,购物车集成 | | Phase 4(Tree API) | 📋 仅设计文档 | 无实现代码 | | Issue #6 安全问题 | ⚠️ 部分待修复 | 5个严重 → SecurityEngineer 定级 P1-P3 | **关键断裂点(BackendArchitect 发现):** - **P0-1**:`SeatSkuService::getSoldSeats()` 方法被引用但未实现 - **P0-2**:商品详情 API 无 `seatSpecMap` 注入(`plugins_service_goods_data` Hook 未注册) - **P0-3**:购物车 CartSave 无法传递座位信息(`sxo_cart` 表无 extension_data 字段) ### 2.2 前端现状(FrontendDeveloper) | 组件 | 状态 | 说明 | |------|------|------| | vr-shopxo-uniapp fork | ✅ 完成 | 基础框架已搭建 | | goods-vr-ticket 组件 | ⚠️ **未建立** | 票务组件目录不存在 | | ticket_detail.html(H5) | ⚠️ 部分完成 | `loadSoldSeats()` 未实现(TODO 遗留) | | 票务核心页面 | ⚠️ **空白** | 选座/票夹/核销页均无实现 | **API Gap 对前端的影响:** - Gap 1(seatSpecMap 未返回):🔴 致命阻塞,选座组件完全无法开发 - Gap 2(extension_data 链路未确认):🟠 重度阻塞,多座位流程无法开发 - Gap 3(QR payload 缺少 code):🟡 中度影响,可变通处理 ### 2.3 安全现状(SecurityEngineer) **重要结论:支付链路本身安全水位中高,无发现 P0 级别漏洞。** | 威胁 | 保护机制 | 状态 | |------|---------|------| | 超卖(并发下单扣库存) | ShopXO `dec()` 原子条件 UPDATE | ✅ 有效 | | 伪造 QR 票 | HMAC-SHA256 签名 | ✅ 有效 | | 伪造短码 | Feistel 混淆 + goods_id 派生 | ✅ 有效 | | 重复核销 | verifyTicket FOR UPDATE | ✅ 有效 | | 并发发票 | issueTicket 幂等检查(无行锁) | ⚠️ 建议加唯一索引 | | 环境密钥泄露 | VR_TICKET_QR_SECRET 硬编码 fallback | ⚠️ 需确认 .env 配置 | | 前端 XSS | 观演人信息渲染方式未确认 | ⚠️ 需确认 | **Issue #6 定级结论:** 所有问题均属 P1-P3,不应阻塞主攻方向。 ### 2.4 性能现状(PerformanceBenchmarker) ⏳ 评估进行中(未完成) --- ## 三、投票分析 ### 为什么全票投 C(双线并行)? **BackendArchitect 理由:** > 后端 P0 Gap(`getSoldSeats` 缺失、Hook 未注册)属于"修完就能用"的阻断性问题,工作量小但价值高(2-3 小时)。前端当前有 H5 票务页作为保底,可以独立推进 uniapp 选座组件开发,无需等待全部 API。 **FrontendDeveloper 理由:** > H5 ticket_detail.html 完全独立于 API Gap,可立即推进(实现 loadSoldSeats + 表单优化);UniApp 的 Gap 1/2 需要后端配合,但可并行确认。 **SecurityEngineer 理由:** > 安全维度所有问题均为 P1-P3,无 P0。双线并行可以最大化团队效率,同时保证安全改进不遗漏。 ### C vs 其他选项 | 选项 | 为什么被否决 | |------|------------| | A(后端优先) | 完全阻塞前端,浪费 H5 保底能力和前端团队资源 | | B(前端优先) | uniapp 开发被 Gap 1/2 阻断,忽视长期目标 | | D(Phase 4 优先) | Tree API 是锦上添花,Phase 3 核心流程尚未完成 | --- ## 四、具体行动计划(C 双线并行) ### 后端行动项 | 优先级 | 任务 | 预计工时 | 说明 | |--------|------|---------|------| | 🔴 P0 | **实现 `SeatSkuService::getSoldSeats()`** | 1h | 修复 soldSeats API | | 🔴 P0 | **注册 `plugins_service_goods_data` Hook**,注入 seatSpecMap | 1h | 解锁前端 seatSpecMap 获取 | | 🔴 P0 | **决策 CartSave 路径**:票务走绕过购物车的直购模式 | 0.5h | 参股大麦/猫眼,选座→立即下单 | | 🟡 P1 | **实现完整 `/seatmap` API**(统一座位数据接口) | 2h | seat_map + sold_seats + sessions + spec_base_id_map | | 🟡 P1 | **确认 extension_data 写入 order_detail 链路** | 1h | 多座位每座独立 attendee 信息 | | 🟢 P2 | 完善 Phase 4 Tree API 设计文档 | — | API 契约 + 路由设计 | ### 前端行动项 | 优先级 | 任务 | 说明 | |--------|------|------| | 🟡 P1 | **ticket_detail.html** 实现 `loadSoldSeats()` | 调用 seatmap API 填充已售座位 | | 🟡 P1 | **ticket_detail.html** 观演人表单 UX 优化 | 过渡方案,立即可用 | | 🟡 P1 | **ticket_detail.html** 核销码展示(QR + 短码) | 完成票务闭环 | | 🟡 P1 | **vr-shopxo-uniapp** goods-vr-ticket 组件框架 | Gap 1 解决后立即启动 | | 🟢 P2 | UniApp 商品详情页集成 seatSpecMap | 等后端 Hook 注册完成 | | 🟢 P2 | UniApp 选座页 + 购票确认 + 支付 | 依赖 Gap 1/2 全部解决 | ### 安全行动项(与主攻方向并行) | 优先级 | 任务 | 说明 | |--------|------|------| | 🟡 P1 | 确认生产环境 `.env` 配置了 `VR_TICKET_SECRET` 和 `VR_TICKET_QR_SECRET` | 防密钥硬编码泄露 | | 🟡 P1 | 在 `vrt_vr_tickets` 表添加唯一索引 `(order_id, seat_info)` | 从根本上防止并发发票超卖 | | 🟡 P2 | 确认 ticket_detail.html 观演人信息渲染有 XSS 过滤 | 防持久型 XSS | --- ## 五、Gitea Issue 行动建议 建议将以下 P0 任务创建为独立 Issue: | Issue | 标题 | 负责 | |-------|------|------| | 新建 | 实现 `SeatSkuService::getSoldSeats()` 方法 | 后端 | | 新建 | 注册 `plugins_service_goods_data` Hook,注入 seatSpecMap | 后端 | | 新建 | 票务购票路径决策:绕过购物车直购模式 | 后端 + 大头确认 | | 新建 | ticket_detail.html 实现 `loadSoldSeats()` | 前端 | --- ## 六、原始投票文件索引 | 文件 | 成员 | |------|------| | `docs/council-eval-backendarchitect.md` | BackendArchitect | | `docs/council-eval-frontenddeveloper.md` | FrontendDeveloper | | `docs/council-eval-securityengineer.md` | SecurityEngineer | | `docs/council-eval-performancebenchmarker.md` | PerformanceBenchmarker(⏳ 未完成) | --- *综合报告:西莉雅 | 2026-05-26* *本文件为最终输出,所有成员投票结果均已记录。*