160 lines
7.0 KiB
Markdown
160 lines
7.0 KiB
Markdown
# 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*
|
||
*本文件为最终输出,所有成员投票结果均已记录。*
|