diff --git a/backend-review-report.md b/backend-review-report.md new file mode 100644 index 00000000..cbaf1a9d --- /dev/null +++ b/backend-review-report.md @@ -0,0 +1,297 @@ +# BackendReviewer — VR票务补充文档审查报告 + +> 审查时间:2026-05-14 +> 审查人:BackendReviewer(后端架构师视角) +> 文档:`vr-ticket-uniapp-supplement.md` + +--- + +## 文档评分:7/10 + +文档结构完整,覆盖了核心数据结构、API 接口、交互规范。但存在若干后端实现与文档描述不一致的问题,以及缺少关键实现细节。 + +--- + +## 一、发现的问题 + +### 问题 1:QR payload 结构错误(P0 高优先级) + +**文档描述**(第 6.1 节): +```json +{ "id": 482815, "g": 118, "iat": 1745286000, "exp": 1745287800 } +``` + +**实际后端**(`TicketService.php:191-197`): +```php +$qr_payload = BaseService::signQrPayload([ + 'id' => $ticket_id, + 'g' => $og['goods_id'], + 'code' => $ticket_code, // ← 文档漏掉了这个字段! + 'iat' => $now, + 'exp' => $now + 1800, +]); +``` + +**影响**:前端按文档解析 QR payload 会缺少 `code` 字段,导致: +- 无法通过 QR 拿到 ticket_code(核销时可能需要) +- QR 验签逻辑可能失败(后端用 `code` 生成签名) + +**修复建议**:文档第 6.1 节 QR payload 应补充 `code` 字段: +```json +{ + "id": 482815, + "g": 118, + "code": "uuid格式-xxx-xxx", + "iat": 1745286000, + "exp": 1745287800 +} +``` + +--- + +### 问题 2:Auth 鉴权机制描述不准确(P1) + +**文档描述**(第 2.3 节): +> 无参数(依赖 C 端 session) + +**实际后端**(`api/Ticket.php:24-57`): +```php +// 支持三种方式: +// 1. X-Token header +// 2. Authorization: Bearer xxx header +// 3. cookie user_info +// 4. ShopXO 标准 session +``` + +**影响**:前端需要明确使用哪个 Auth 方式。UniApp 中推荐使用 `X-Token` header。 + +**修复建议**:文档第 2.3 节补充鉴权说明: +``` +请求 Header: X-Token: {user_token} +响应 401: 未登录,跳转登录页 +``` + +--- + +### 问题 3:CartSave extension_data 存储链路不清晰(P1) + +**文档描述**(第 2.2 节): +```json +"extension_data": "{\"attendee\":{...},\"seat\":{...}}" +``` + +**实际后端**: +1. `CartSave` 将 `extension_data` 存入订单主表 `order.extension_data` +2. `onOrderPaid` Hook 从 `order.extension_data` 读取 `attendee` 信息 +3. **但**观演人信息实际上是多座位时每座一个,而不是整个订单共用一个 + +**问题**:当用户选多个座位时,每个座位的 `extension_data` 独立存储在各自的 `order_detail` 中,而不是订单主表。后端需要知道每个座位对应哪个观演人。 + +**实际实现**(待确认):ShopXO BuyService 是否支持将 `extension_data` 写入 `order_detail` 表? + +**修复建议**:文档需要明确: +- `extension_data` 写入位置(order 主表 vs order_detail 行) +- 多座位场景下,每个 `goods_data` 条目携带各自的 `extension_data` +- 后端 TicketService 如何从 `order_detail` 获取每座的 attendee 信息 + +--- + +### 问题 4:seatSpecMap 获取方式未确定(P1) + +**文档**(第 4.5 节): +> 待确认:seatSpecMap 获取方式 +> - 方案 A(推荐):后端在商品详情 API 中直接返回 +> - 方案 B:前端 JS 重建(不推荐) +> - 方案 C:新增独立接口 + +**实际情况**: +- `SeatSkuService::GetGoodsViewData()` 是 PHP 方法,UniApp 无法直接调用 +- 商品详情 API `/api/goods/detail` 默认不返回 `seatSpecMap` +- 后端需要改造:在商品详情响应中嵌入 `seatSpecMap` + +**修复建议**:文档应明确推荐方案 A,并列出后端改造任务: +``` +后端任务:在 GoodsService 或插件 hook 中, +当 goods.is_vr_ticket=1 时,在商品详情响应中注入 seatSpecMap +``` + +--- + +### 问题 5:票夹列表响应字段不完整(P2) + +**文档描述**(第 2.3 节): +```json +{ + "id": 482815, + "goods_id": 118, + "goods_title": "VR演唱会", + "seat_info": "主要展厅 A区 1排1座", + "session_time": "15:00-16:59", + "venue_name": "测试场馆", + "real_name": "张三", + "verify_status": 0, + "issued_at": "2026-05-01 12:00:00", + "short_code": "003a2hgmgety" +} +``` + +**实际后端**(`WalletService::getUserTickets`): +- `seat_info` 格式:`场次|场馆|演播室|分区|座位号`(5段,用竖线分隔) +- 需要确认返回字段是否与文档一致 + +**修复建议**:补充 `qr_data` 字段说明(可选,用于直接展示 QR 图) + +--- + +## 二、关键 Gap(前端开发前必须确认) + +### Gap 1:seatSpecMap 返回方式(P0) + +**问题**:前端无法获取座位规格映射表,导致选座功能无法实现。 + +**必须解决**:后端需要在商品详情 API 响应中返回 `seatSpecMap`,或在插件中新增专用接口。 + +**截止时间**:Phase 2 开发前必须完成 + +--- + +### Gap 2:CartSave extension_data 传递链路(P0) + +**问题**:多座位下单时,每个座位的观演人信息如何传递到后端? + +**必须解决**:确认 ShopXO BuyService 如何处理 `extension_data`: +- 写入 `order.extension_data` 还是 `order_detail`? +- 多座位场景下每座独立的 extension_data 如何存储? + +**截止时间**:Phase 3 开发前必须完成 + +--- + +### Gap 3:QR payload 验签逻辑(P1) + +**问题**:前端需要验证 QR payload 的有效性(含 `code` 字段的签名验证) + +**必须解决**: +1. 文档更新 QR payload 结构(补充 `code` 字段) +2. 后端提供签名字段 `sig` 的生成方式(HMAC-SHA256) +3. 前端需要知道 secret 从哪里获取(后端提供接口?) + +**截止时间**:票详情页开发前必须完成 + +--- + +## 三、改进建议(具体的、可操作的) + +### 建议 1:更新 QR payload 文档(第 6.1 节) + +```markdown +### 6.1 QR 票数据结构 + +```json +// QR payload(Base64 编码) +{ + "id": 482815, + "g": 118, + "code": "uuid格式-xxx-xxx", + "iat": 1745286000, + "exp": 1745287800 +} + +// 签名:sig = HMAC-SHA256("code.id.g.iat.exp", secret) 取前8位 +``` +``` + +### 建议 2:补充 Auth 鉴权说明(第 2.3 节) + +```markdown +### 票夹 API + +**请求 Header**: +``` +X-Token: {user_token} +``` +(也支持 Authorization: Bearer xxx,ShopXO session cookie) + +**响应 401**:未登录,跳转登录页 +``` + +### 建议 3:明确后端待配合事项(第 9 节) + +```markdown +## 九、后端待配合事项 + +1. **seatSpecMap 返回**:在商品详情 API 响应中嵌入 `seatSpecMap` + - 触发条件:`goods.is_vr_ticket = 1` + - 数据来源:`SeatSkuService::buildSeatSpecMap()` + - 预计工作量:2h + +2. **CartSave 链路确认**: + - 确认 extension_data 是否写入 order_detail + - 多座位场景下每座独立的 attendee 信息如何存储 + +3. **QR 签名字段说明**: + - 提供前端验签所需的 secret 获取方式 + - 或提供后端验签接口 +``` + +--- + +## 四、对前端开发者的建议(3条) + +### 1. 优先确认 seatSpecMap 接口 + +在开始选座功能开发前,必须与后端确认: +- seatSpecMap 通过哪个 API 获取? +- 返回的数据结构是否与文档一致? + +**建议**:先让后端在商品详情 API 中返回 seatSpecMap,再开始前端开发。 + +--- + +### 2. Auth 统一使用 X-Token + +UniApp 中统一使用 `X-Token` header 进行用户鉴权: +```javascript +uni.request({ + url: '...', + header: { + 'X-Token': uni.getStorageSync('token') + } +}) +``` + +避免混用 Authorization 或 cookie。 + +--- + +### 3. QR 验签先做本地过期检查 + +前端先做本地过期检查,再考虑签名验证: +```javascript +const payload = JSON.parse(atob(qr_data.split('|')[1])); +if (payload.exp < Date.now() / 1000) { + // 已过期,调用 refreshQr 接口获取新 QR +} +``` + +签名验证(sig 字段)可延后实现,先确保核心功能可用。 + +--- + +## 五、审查总结 + +| 维度 | 评分 | 说明 | +|------|------|------| +| 数据结构 | 9/10 | 描述清晰,与后端一致 | +| API 接口 | 6/10 | 存在不一致和缺失(QR payload、Auth) | +| 交互规范 | 8/10 | 详细,可直接参考 | +| 实现细节 | 5/10 | 缺少关键链路说明(extension_data) | + +**综合评分:7/10** + +文档整体质量良好,但 API 部分需要后端确认和修正,特别是: +1. QR payload 结构(缺少 code 字段) +2. Auth 鉴权机制(需明确 X-Token 方式) +3. extension_data 存储链路(多座位场景) + +这三个问题必须在 Phase 2 开发前解决,否则前端无法正确实现购票和票夹功能。 \ No newline at end of file diff --git a/plan.md b/plan.md new file mode 100644 index 00000000..384d0138 --- /dev/null +++ b/plan.md @@ -0,0 +1,63 @@ +# Council Plan — BackendReviewer + +## Task +Review `vr-ticket-uniapp-supplement.md` from backend perspective: check API specs consistency with actual vr-shopxo-plugin implementation, identify missing details, and propose fixes. + +## Files to Review +- `/Users/bigemon/WorkSpace/vr-shopxo-uniapp/docs/vr-ticket-uniapp-supplement.md` +- Backend code: `/Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/` + +## Backend Review Checklist + +- [ ] 1. Compare API spec (Section 2) with actual backend implementations + - [ ] 2.1 商品详情 API — seatSpecMap 返回方式 + - [ ] 2.2 购物车提交 API — extension_data 传递链路 + - [ ] 2.3 票夹 API — 响应字段对照 +- [ ] 2. Check QR payload structure (Section 6.1) +- [ ] 3. Verify short_code format documentation +- [ ] 4. Document missing backend details: + - [ ] extension_data 在 order_detail 中的存储格式 + - [ ] Auth 机制(X-Token vs cookie) + - [ ] 核销 API 完整响应码 +- [ ] 5. Identify top 3 API gaps (must resolve before frontend dev) + +## Phase Breakdown + +### Phase 1: Analysis (current) +Read supplement doc + backend code, compare, identify gaps + +### Phase 2: Report +Output detailed review report with: +- Document score (1-10) +- Found issues (specific) +- Key gaps (must-fix before dev) +- Improvement suggestions (actionable) +- 3 recommendations for frontend devs + +### Phase 3: Finalize +Merge findings into main, coordinate with FrontendReviewer + +## Status + +| Task | Status | +|------|--------| +| Read supplement doc | Done | +| Analyze backend code | Done | +| Identify API gaps | Done | +| Write review report | Done | +| Merge to main | In Progress | + +## Coordination +- FrontendReviewer: reviewing frontend implementation (goods-vr-ticket.vue, components) +- Need to sync on: seatSpecMap acquisition, extension_data format + +## Key Findings (Top 3 API Gaps) + +1. **Gap 1: seatSpecMap 返回方式(P0)** — 前端无法获取座位规格映射表 +2. **Gap 2: CartSave extension_data 传递链路(P0)** — 多座位场景下 attendee 信息存储 +3. **Gap 3: QR payload 结构错误(P1)** — 缺少 `code` 字段 + +## Review Report +- Document score: 7/10 +- Critical issues: 5 +- Must-fix before Phase 2: 2 (seatSpecMap, extension_data) \ No newline at end of file