Compare commits
9 Commits
f6cb6f65b5
...
d28a4dc511
| Author | SHA1 | Date |
|---|---|---|
|
|
d28a4dc511 | |
|
|
dd538ba08e | |
|
|
b713cd73c3 | |
|
|
af66140af1 | |
|
|
09ee277268 | |
|
|
3ed4168da5 | |
|
|
23464e725a | |
|
|
bdee8b50c6 | |
|
|
bb71681cab |
|
|
@ -1,6 +1,6 @@
|
|||
# ShopXO VR票务插件 — 架构文档
|
||||
|
||||
> 版本:v1.1(2026-04-14 更新,整合 ShopXO 技术调研成果)
|
||||
> 版本:v1.2(2026-04-14 下午更新,座位地图 + 场馆绑定架构确认)
|
||||
> 源码位置:council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-src/
|
||||
|
||||
## 项目概述
|
||||
|
|
@ -10,10 +10,27 @@
|
|||
当 vr-ticket-mp 主线项目因维护成本或架构限制无法继续时,此插件作为 Plan B:
|
||||
- **完全复用** ShopXO 已有能力(会员体系/积分/优惠券/微信支付)
|
||||
- **仅扩展** 票务专属逻辑(场次/座位/观演人/QR核销)
|
||||
- **不修改** ShopXO 核心代码,通过插件机制隔离
|
||||
- **优先通过插件机制扩展**,如插件机制不够用(如商品详情页按类型返回不同模板),允许直接修改 ShopXO 源码的最小范围(MIT 协议允许)。原则:改源码比绕弯快时,直接改;以进度为先,不为「不修改」而引入额外复杂度。
|
||||
|
||||
---
|
||||
|
||||
### 8. 场馆系统 + 选座地图(完整方案)⭐⭐⭐
|
||||
|
||||
详见 `docs/06_SEAT_MAP_INTEGRATION.md`
|
||||
|
||||
**核心发现**:
|
||||
1. **字符地图是行业标准**:场馆平面图 → 字符串地图(如 `aaa___aaa`)→ 前端渲染为 SVG/DOM
|
||||
2. **ShopXO 分类 = Venue Type 绑定**:每个"场馆类型"对应一个 ShopXO 分类,商品挂分类 = 绑定 venue type
|
||||
3. **vr_venues 表**:商家在插件后台管理场馆,上传/编辑座位图 JSON
|
||||
4. **vr_sessions.seat_map_json**:每个场次存一份座位图配置
|
||||
5. **spec_base_id_map**:seat_id(如 `"3_5"`)→ spec_base_id(如 10003)映射,绑定 ShopXO 购买流程
|
||||
6. **ShopXO spec 系统无硬限制**:规格种类数、单规格选项数、SKU 组合数均无限制(3场馆×2票种×500座位=3000 SKU 完全可行)
|
||||
|
||||
**绑定链路**:
|
||||
```
|
||||
ShopXO 分类(venue type)← → vr_venues ← → vr_sessions ← → spec_base_id_map ← → ShopXO spec_base
|
||||
```
|
||||
|
||||
## 核心技术发现(2026-04-14 调研)
|
||||
|
||||
### 1. CustomView Ace 编辑器 ⭐
|
||||
|
|
@ -28,15 +45,30 @@ ShopXO 内置全代码自定义页面编辑器,HTML/CSS/JS 三栏,实时预
|
|||
- 完全注入票务选座 UI
|
||||
- 不修改核心代码
|
||||
|
||||
### 3. 按商品类型替换模板 ⭐
|
||||
### 3. 按商品类型替换模板(已有更优方案,优先用 Hook)⭐
|
||||
|
||||
> ⚠️ **已更新(2026-04-14 下午)**:原计划修改 Goods.php,现发现 `site_type=3`(虚拟商品)可绕过:
|
||||
> - site_type=3 时 ShopXO 不显示 extraction popup,也不要求选择地址
|
||||
> - 直接通过 `plugins_view_goods_detail_base_sku_top` 注入票务选座 UI
|
||||
> - **Goods.php 不再需要修改**,完全通过插件 Hook 实现
|
||||
|
||||
> 原 Goods.php 修改方案保留作为备案(如 Hook 无法满足时):
|
||||
> 在 `Goods.php Index()` 中增加 1 行判断:
|
||||
> 这是 ShopXO 允许范围内,实现「特定商品类型使用独立模板」的唯一方式。
|
||||
> 所有其他功能均通过插件钩子实现,**不修改核心代码**。
|
||||
|
||||
修改 `Goods.php Index()` 加 1 行判断:
|
||||
```php
|
||||
if($goods['item_type'] == 'ticket') {
|
||||
return MyView('/goods/ticket_detail');
|
||||
// app/index/controller/Goods.php Index() 方法,约第 440 行
|
||||
// 在 return MyView(); 之前插入:
|
||||
|
||||
if(!empty($goods['item_type']) && $goods['item_type'] == 'ticket') {
|
||||
return MyView('/goods/ticket_detail'); // 自定义票务模板
|
||||
}
|
||||
return MyView(); // 默认模板
|
||||
```
|
||||
|
||||
对应模板文件:`app/index/view/default/goods/ticket_detail.html`(ShopXO 主题目录下)
|
||||
|
||||
### 4. shopxo-uniapp 支持微信小程序 ⭐
|
||||
|
||||
HBuilderX 导入 → 配置 AppID → 发行 → 微信开发者工具
|
||||
|
|
|
|||
|
|
@ -542,3 +542,174 @@ GET /?s=admin/vrticket/stats&event_id=8
|
|||
- 最近核销记录滚动列表
|
||||
|
||||
实现方式:轮询 stats API + 数字动画(CountUp.js)
|
||||
|
||||
---
|
||||
|
||||
## 九、防超卖机制
|
||||
|
||||
> 本章节为架构性补充,是编码前的 **阻断性要求**。
|
||||
> 核销的完整性依赖于:只有合法持票人能核销,且每张票只能核销一次。
|
||||
|
||||
### 9.1 购票时序与座位锁定
|
||||
|
||||
座位锁定贯穿整个购票流程,分三阶段:
|
||||
|
||||
```
|
||||
[阶段1: 选座] [阶段2: 提交订单] [阶段3: 支付成功]
|
||||
用户选座 → 前端展示 提交订单 → 后端锁座 支付回调 → 出票确认
|
||||
↓ ↓ ↓
|
||||
前端乐观锁 Redis/Db悲观锁 释放锁/永久锁定
|
||||
(前端禁止选已选座) (禁止其他人选同座) (vr_tickets写入)
|
||||
```
|
||||
|
||||
**阶段1 — 前端乐观锁**:
|
||||
- 用户选座时,前端实时请求 `GET /?s=api/session/seats?session_id=X` 获取已锁定座位列表
|
||||
- 已被锁或已售座位在座位图上置灰(CSS `pointer-events: none`)
|
||||
- 纯前端锁无法防并发攻击,**必须配合后端锁**
|
||||
|
||||
**阶段2 — 后端悲观锁(关键)**:
|
||||
用户点击"提交订单"时,后端在事务内完成:
|
||||
```php
|
||||
Db::startTrans();
|
||||
try {
|
||||
// ① 检查座位是否已被锁定(检查 vr_seat_locks 表)
|
||||
$locked = Db::name('vr_seat_locks')
|
||||
->where('session_id', $session_id)
|
||||
->where('seat_code', $seat_code)
|
||||
->where('expire_at', '>', time())
|
||||
->find();
|
||||
if ($locked) {
|
||||
Db::rollback();
|
||||
return DataReturn('座位已被锁定,请重新选择', -1);
|
||||
}
|
||||
|
||||
// ② 原子扣减库存(vr_sessions.stock - 1)
|
||||
$affected = Db::name('vr_sessions')
|
||||
->where('id', $session_id)
|
||||
->where('stock', '>', 0) // 原子条件:库存 > 0
|
||||
->dec('stock')
|
||||
->update();
|
||||
if (!$affected) {
|
||||
Db::rollback();
|
||||
return DataReturn('库存不足', -1);
|
||||
}
|
||||
|
||||
// ③ 写入座位锁(15分钟过期,与订单超时一致)
|
||||
Db::name('vr_seat_locks')->insert([
|
||||
'session_id' => $session_id,
|
||||
'seat_code' => $seat_code,
|
||||
'order_no' => $order_no,
|
||||
'user_id' => $user_id,
|
||||
'locked_at' => time(),
|
||||
'expire_at' => time() + 900, // 15分钟
|
||||
]);
|
||||
|
||||
Db::commit();
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
return DataReturn('系统错误:' . $e->getMessage(), -1);
|
||||
}
|
||||
```
|
||||
|
||||
**阶段3 — 支付成功出票**:
|
||||
- 支付回调触发后,`TicketService::OnOrderPaid()` 将 `vr_seat_locks` 中的锁转为永久票
|
||||
- 锁记录 `status` 标记为 `confirmed`,`expire_at` 设为 NULL
|
||||
- 如果用户15分钟内未支付,锁自动过期(定时任务或懒检查)
|
||||
|
||||
### 9.2 座位锁表设计
|
||||
|
||||
```sql
|
||||
CREATE TABLE `vr_seat_locks` (
|
||||
`id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||||
`session_id` int UNSIGNED NOT NULL COMMENT '场次ID',
|
||||
`seat_code` char(20) NOT NULL COMMENT '座位编码(如 A-3-15)',
|
||||
`order_no` char(60) NOT NULL COMMENT '关联订单号',
|
||||
`user_id` int UNSIGNED NOT NULL COMMENT '锁定用户ID',
|
||||
`status` tinyint DEFAULT 0 COMMENT '状态(0锁定中, 1已确认, 2已取消)',
|
||||
`locked_at` int UNSIGNED NOT NULL COMMENT '锁定时间',
|
||||
`expire_at` int UNSIGNED COMMENT '过期时间(NULL=永久)',
|
||||
UNIQUE KEY `session_seat` (`session_id`, `seat_code`),
|
||||
KEY `order_no` (`order_no`),
|
||||
KEY `expire_at` (`expire_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='座位锁表';
|
||||
```
|
||||
|
||||
**关键设计点**:
|
||||
- `UNIQUE KEY (session_id, seat_code)`:数据库层强制唯一,避免并发插入两条锁
|
||||
- `expire_at` 字段:NULL = 永久锁定(已支付),有值 = 临时锁(未支付)
|
||||
- 定时任务每分钟清理过期锁并回补库存:
|
||||
```sql
|
||||
-- 清理过期锁并回补库存
|
||||
UPDATE vr_sessions s
|
||||
JOIN vr_seat_locks l ON s.id = l.session_id
|
||||
SET s.stock = s.stock + 1, l.status = 2 -- 2=已取消
|
||||
WHERE l.status = 0 AND l.expire_at < UNIX_TIMESTAMP();
|
||||
```
|
||||
|
||||
### 9.3 并发控制策略
|
||||
|
||||
**方案 A:数据库乐观锁(推荐用于低并发场景)**
|
||||
```php
|
||||
// vr_sessions 表加 version 字段,每次更新自增
|
||||
Db::name('vr_sessions')
|
||||
->where('id', $session_id)
|
||||
->where('stock', '>=', 1)
|
||||
->where('version', $current_version) // 乐观锁
|
||||
->dec('stock')
|
||||
->inc('version')
|
||||
->update();
|
||||
```
|
||||
- 优点:无需额外锁资源
|
||||
- 缺点:并发高时大量重试,响应延迟
|
||||
|
||||
**方案 B:Redis 分布式锁(推荐用于高并发演唱会抢票)**
|
||||
```php
|
||||
$lock_key = "seat_lock:{$session_id}:{$seat_code}";
|
||||
$lock = Cache::store('redis')->set($lock_key, $order_no, ['nx', 'px' => 15000]);
|
||||
if (!$lock) {
|
||||
return DataReturn('座位已被锁定', -1);
|
||||
}
|
||||
try {
|
||||
// 执行业务逻辑...
|
||||
} finally {
|
||||
Cache::store('redis')->rm($lock_key);
|
||||
}
|
||||
```
|
||||
- 优点:高性能,支持过期自动释放
|
||||
- 缺点:需要 Redis;锁粒度细(每个座位一把锁)
|
||||
|
||||
**ShopXO 环境建议**:ShopXO 默认不带 Redis(如需可装),**低峰期用 MySQL 悲观锁(方案A变体)足够**;如预判高并发(万人演唱会开票),建议额外引入 Redis。
|
||||
|
||||
### 9.4 核销时的超卖防御
|
||||
|
||||
核销阶段不存在超卖(每张票只能核销一次),但需防御:
|
||||
|
||||
1. **幂等核销**:`vr_tickets.verify_status = 1` 是唯一性约束,重复核销返回"已核销"而非报错
|
||||
2. **事务隔离**:`VerifyTicket()` 在事务内完成,status 更新和记录写入原子执行
|
||||
3. **QR 时效**:`exp` 字段确保过期票不会被核销(即使数据库状态异常)
|
||||
4. **核销员权限**:核销前验证 `verifier_id` 是否在 `vr_verifiers` 表中且 `status = 1`
|
||||
|
||||
### 9.5 API 路径统一说明
|
||||
|
||||
| 端 | 路由 | 权限验证 | 说明 |
|
||||
|---|---|---|---|
|
||||
| **C 端**(票夹/扫码页) | `/?s=api/ticket/verify` | 用户登录态 | 用户查自己票状态 |
|
||||
| **B 端**(核销人员) | `/?s=admin/vrticket/verify` | Admin 登录态 + 核销员白名单 | 核销人员扫码验证 |
|
||||
|
||||
Vue 页面使用 `app.globalData.get_request_url('verify', 'ticket', 'vrticket')` 生成的是 **C 端 API**,需在 B 端核销页改为 `admin` 命名空间路径,或新建独立 B 端核销 API。
|
||||
|
||||
### 9.6 AES IV 设计说明
|
||||
|
||||
`AES-256-CBC` 使用 `IV = substr(MD5(ticket_code), 0, 16)` 而非随机 IV 的原因:
|
||||
|
||||
**设计意图**:
|
||||
- ticket_code 是 UUID-v4,每次生成票码时独立随机产生
|
||||
- MD5(ticket_code) 是 ticket_code 的确定性函数:同一 ticket_code 永远映射到同一 IV
|
||||
- 解密方只需知道 ticket_code(从 URL 参数传入或扫码获取)即可还原 IV,无需额外传输 IV 值
|
||||
|
||||
**安全性评估**:
|
||||
- ticket_code 的熵足够(122位随机数),MD5 的输出是确定的但不可预测(单向函数)
|
||||
- 攻击者不知道 ticket_code 无法派生正确 IV,暴力破解 MD5 不现实
|
||||
- 这是 ticket-bound IV 模式,在票码系统场景下是合理设计
|
||||
|
||||
**如需更高安全**:使用随机 IV 并附加在密文头部(`ciphertext = IV || ciphertext`),ShopXO 无需修改即可兼容。
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
# 选座系统 + ShopXO 后台集成架构
|
||||
|
||||
> 调研日期:2026-04-14
|
||||
> 关联文档:ARCHITECTURE.md, 01_SHOPXO_TECHNICAL_RESEARCH.md
|
||||
|
||||
---
|
||||
|
||||
## 一、选座地图:行业标准做法
|
||||
|
||||
### 1.1 核心原理
|
||||
|
||||
**"字符地图"是业界通用方案**,不是我们发明的:
|
||||
|
||||
```
|
||||
'aaa___aaa' ← a=可用座, _=过道/柱子/墙壁
|
||||
'bbb__bbbbb' ← b=另一种座位(不同价格区)
|
||||
'____________' ← 纯过道/无座位
|
||||
```
|
||||
|
||||
加载时前端把每个字符翻译成可交互的 DOM/SVG 元素:
|
||||
- 可选座位 → 可点击
|
||||
- 过道 `_` → 渲染为空白间隔或装饰元素
|
||||
- 不同字符类型 → 不同颜色/价格/状态
|
||||
|
||||
### 1.2 主流实现对比
|
||||
|
||||
| 方案 | 技术 | 优点 | 缺点 |
|
||||
|---|---|---|---|
|
||||
| **字符地图 + DOM/SVG** | 字符串地图 + div/SVG | 轻量、易编辑、易生成 | 复杂形状需精确计算 |
|
||||
| **SVG 手绘** | 设计师导出 SVG | 座位形状自然 | 需要设计工具,导入复杂 |
|
||||
| **Canvas** | Konva.js / Fabric.js | 性能好,适合超大型场馆 | 无 DOM 元素,交互复杂 |
|
||||
| **seats.io** | 商业 SaaS | 功能完整 | 付费,不可定制 |
|
||||
|
||||
**推荐:字符地图 + Vue 3 SVG 渲染**(自研,AI 可完全生成)
|
||||
|
||||
### 1.3 座位地图 JSON 结构
|
||||
|
||||
```json
|
||||
{
|
||||
"venue_id": "venue_001",
|
||||
"map": [
|
||||
"aaaaaaaaaaaa",
|
||||
"aaaaaaaaaaaa",
|
||||
"bbbbbbbb__bb",
|
||||
"bbbbbbbbbbbb",
|
||||
"__cccccccccc__"
|
||||
],
|
||||
"row_labels": ["A", "B", "C", "D", "E"],
|
||||
"seats": {
|
||||
"a": { "price": 299, "label": "VIP区", "classes": "seat-vip" },
|
||||
"b": { "price": 199, "label": "普通区", "classes": "seat-normal" },
|
||||
"c": { "price": 99, "label": "后排区", "classes": "seat-back" },
|
||||
"_": null
|
||||
},
|
||||
"sections": [
|
||||
{ "name": "VIP区", "color": "#FF6B6B", "rows": [0, 1] },
|
||||
{ "name": "普通区", "color": "#4ECDC4", "rows": [2, 3] }
|
||||
],
|
||||
"screen": { "label": "舞台/银幕", "position": "top" }
|
||||
}
|
||||
```
|
||||
|
||||
### 1.4 座位实时状态(动态层)
|
||||
|
||||
```json
|
||||
{
|
||||
"seats": {
|
||||
"1_1": { "status": "available" },
|
||||
"1_2": { "status": "sold" },
|
||||
"1_3": { "status": "selected" },
|
||||
"2_5": { "status": "locked" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
座位状态含义:
|
||||
- `available` — 可选
|
||||
- `sold` — 已售
|
||||
- `selected` — 当前用户选中
|
||||
- `locked` — 被其他用户临时锁定(可选,支持超时释放)
|
||||
|
||||
### 1.5 spec_base_id_map(与 ShopXO SKU 绑定)
|
||||
|
||||
```json
|
||||
{
|
||||
"spec_base_id_map": {
|
||||
"1_1": { "spec_base_id": 10001, "venue": "A区", "row": "A", "col": 1, "price": 299 },
|
||||
"1_2": { "spec_base_id": 10002, "venue": "A区", "row": "A", "col": 2, "price": 299 },
|
||||
"3_5": { "spec_base_id": 10003, "venue": "B区", "row": "C", "col": 5, "price": 199 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**绑定流程**:
|
||||
```
|
||||
用户在前端选座 seat_id="3_5"
|
||||
→ 查 spec_base_id_map 拿到 spec_base_id=10003
|
||||
→ 调 ShopXO Buy API: goods_id + spec_base_id
|
||||
→ ShopXO 原子扣 spec_base.inventory = 1(FOR UPDATE)
|
||||
→ 订单完成
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、ShopXO 后台集成方案
|
||||
|
||||
### 2.1 核心设计:复用 ShopXO 分类作为 Venue Type
|
||||
|
||||
**每个 venue type = 一个 ShopXO 分类**
|
||||
|
||||
ShopXO 已有完整的商品多级分类系统(`sxo_goods_category`),我们直接复用:
|
||||
|
||||
```
|
||||
sxo_goods_category
|
||||
├── 演唱会
|
||||
│ ├── 杭州大剧院-演唱会场
|
||||
│ ├── 北京鸟巢-演唱会场 ← 绑定 seat_map_json
|
||||
│ └── 上海梅赛德斯-演唱会场
|
||||
├── 话剧
|
||||
│ ├── 人艺剧院
|
||||
│ └── 国家大剧院
|
||||
└── 电影(可选)
|
||||
```
|
||||
|
||||
**优点**:
|
||||
- 不需要改 `sxo_goods` 表结构
|
||||
- 直接用 ShopXO 原生"分类选择器"(后台商品编辑已有,无需开发)
|
||||
- 商家在 ShopXO 后台创建商品时,分类 = venue type 绑定一步到位
|
||||
|
||||
### 2.2 场馆表(vr_venues)
|
||||
|
||||
```sql
|
||||
CREATE TABLE vr_venues (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
category_id INT UNSIGNED NOT NULL COMMENT 'ShopXO分类ID,绑定venue type',
|
||||
name VARCHAR(180) NOT NULL COMMENT '场馆名称',
|
||||
address VARCHAR(255) NOT NULL DEFAULT '' COMMENT '场馆地址',
|
||||
seat_map_json LONGTEXT COMMENT '座位地图JSON(map[] + seats配置)',
|
||||
seat_base_price INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '基础票价',
|
||||
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '0下架 1上架',
|
||||
add_time INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
upd_time INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
INDEX idx_category_id (category_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='VR演唱会场馆';
|
||||
```
|
||||
|
||||
**关键字段**:
|
||||
- `category_id`:ShopXO 分类 ID,ShopXO 后台商品编辑时的"分类选择"结果直接对应
|
||||
- `seat_map_json`:座位地图配置,商家在插件后台导入/编辑
|
||||
- `seat_base_price`:基础票价
|
||||
|
||||
### 2.3 插件后台:场馆 + 座位图编辑器
|
||||
|
||||
商家在 ShopXO 后台插件入口管理:
|
||||
1. **场馆管理**:创建场馆,关联 ShopXO 分类,上传/绘制座位图
|
||||
2. **座位图编辑器**:输入字符串地图(如 `aaaaaaaaaaaa`)或上传 SVG
|
||||
3. **场次管理**:创建演出场次,选择场馆,设定时间、价格
|
||||
|
||||
### 2.4 插件 Hook:向 ShopXO 商品保存/读取注入 venue 信息
|
||||
|
||||
```php
|
||||
// plugins_service_goods_handle_begin — 保存商品时
|
||||
public static function GoodsSaveHandle(&$params, &$goods, $goods_id)
|
||||
{
|
||||
// venue_id 由插件后台单独保存,不依赖 ShopXO 商品表
|
||||
// 关联:vr_venues ← (goods_id) → ShopXO sxo_goods
|
||||
}
|
||||
|
||||
// plugins_service_goods_data — 读取商品时,注入 venue 信息
|
||||
public static function GoodsDataHandle(&$data, $goods_id)
|
||||
{
|
||||
// 读取该商品关联的 venue + 场次列表
|
||||
$data['vr_venues'] = VrVenueService::GetVenueByGoodsId($goods_id);
|
||||
$data['vr_sessions'] = VrSessionService::GetSessionsByGoodsId($goods_id);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 商品详情页加载流程
|
||||
|
||||
```
|
||||
用户打开票务商品详情页
|
||||
│
|
||||
→ 触发 Goods.php Hook 判断 item_type=ticket
|
||||
│
|
||||
→ 插件读取 goods_id 对应的 vr_venues + vr_sessions
|
||||
│
|
||||
→ 前端展示:
|
||||
│ 步骤1:选择场次(日期+时间)
|
||||
│ 步骤2:加载该场次座位图(从 seat_map_json 渲染 SVG)
|
||||
│ 步骤3:用户点击座位 → 获取 spec_base_id
|
||||
│ 步骤4:调 ShopXO Buy API 购买该 SKU
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、与 ShopXO spec 系统的衔接
|
||||
|
||||
### 3.1 座位图与 ShopXO SKU 的绑定时机
|
||||
|
||||
**场次创建时自动生成 SKU 映射**:
|
||||
|
||||
```php
|
||||
// 场次保存时,调用 SKU 绑定函数
|
||||
public static function BindSessionToSpecBase($session_id)
|
||||
{
|
||||
// 1. 读取 vr_sessions.seat_map_json
|
||||
// 2. 遍历 map[],为每个"非_"字符生成/查找 spec_base_id
|
||||
// 3. 生成 spec_base_id_map 存入 vr_sessions
|
||||
// 4. 调用 ShopXO GoodsSpecificationsInsert() 写入 spec_base 表
|
||||
}
|
||||
```
|
||||
|
||||
**绑定关系**:
|
||||
- `vr_sessions.spec_base_id_map` ← JSON 映射(seat_id → spec_base_id)
|
||||
- `sxo_goods_spec_base` ← 每个座位一个 SKU(inventory=1,price=座位价格)
|
||||
- ShopXO `BuyService::OrderInsertHandle` ← 原子扣 inventory,天然防超卖
|
||||
|
||||
### 3.2 场次变更时的 SKU 联动
|
||||
|
||||
- **场次新增座位**:调用 `GoodsSpecificationsInsert` 新增 spec_base
|
||||
- **场次删除座位**:将对应 spec_base.inventory 置为 0(软删除)
|
||||
- **价格变更**:更新 `sxo_goods_spec_base.price`
|
||||
|
||||
---
|
||||
|
||||
## 四、实现优先级
|
||||
|
||||
| 阶段 | 内容 | 工作量 |
|
||||
|---|---|---|
|
||||
| **Phase A** | vr_venues / vr_sessions 表 + CRUD | 小 |
|
||||
| **Phase B** | 场馆座位图编辑器(字符串地图) | 中 |
|
||||
| **Phase C** | Vue 3 选座组件(渲染 + 交互) | 中 |
|
||||
| **Phase D** | spec_base_id_map 绑定逻辑 | 中 |
|
||||
| **Phase E** | 实时座位状态轮询/推送 | 小 |
|
||||
|
||||
**AI 可完全主导全部 phases(A-E)**。
|
||||
|
||||
---
|
||||
|
||||
## 五、关键约束确认
|
||||
|
||||
| 维度 | 限制 | 结论 |
|
||||
|---|---|---|
|
||||
| spec_type 数量 | 无硬限制 | ✅ 想加几个加几个 |
|
||||
| 单规格选项数 | 无硬限制 | ✅ 500座/场馆没问题 |
|
||||
| SKU 组合总数 | MySQL 无压力 | ✅ 3×2×500=3000行 OK |
|
||||
| TEXT 字段容量 | 无实际限制 | ✅ JSON 存几千选项 OK |
|
||||
| ShopXO 后台扩展 | 通过插件 Hook | ✅ 完全可行 |
|
||||
| 自提点独立库存 | ShopXO 不支持 | ✅ 用 spec 替代(每座位独立库存)|
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
# Council Plan — vr-shopxo-plugin
|
||||
|
||||
> Round 1/2/3 — 2026-04-14
|
||||
> Branch: council/backend-reviewer → main
|
||||
> 状态:Round 1 并行评审阶段
|
||||
|
||||
---
|
||||
|
||||
## Document Review Summary (All Agents)
|
||||
|
||||
### docs/01_SHOPXO_TECHNICAL_RESEARCH.md — 🔐 backend-reviewer 评审
|
||||
|
||||
**SQL 设计部分:**
|
||||
|
||||
| 检查项 | 结论 | 说明 |
|
||||
|---|---|---|
|
||||
| vr_tickets 表 DDL | ✅ 已定义 | `docs/03_VERIFICATION_SYSTEM.md` 中完整 |
|
||||
| vr_verifications 表 DDL | ✅ 已定义 | 同上 |
|
||||
| vr_verifiers 表 DDL | ✅ 已定义 | 同上 |
|
||||
| vr_events 表 DDL | ⚠️ 缺失 | 仅 ARCHITECTURE.md 列出表名,无字段定义(DDL 已在 reviews/ 中补充) |
|
||||
| vr_sessions 表 DDL | ⚠️ 缺失 | 同上 |
|
||||
| ShopXO 原生表分析 | ✅ 充分 | sxo_order / sxo_goods_spec_base 分析到位 |
|
||||
| 索引策略 | ⚠️ 需补充 | vr_tickets 已定义;vr_events/vr_sessions 缺失 |
|
||||
| 外键约束 | ⚠️ 建议补充 | 无外键(ShopXO 风格,依赖业务逻辑) |
|
||||
|
||||
**安全审查部分:**
|
||||
|
||||
| 检查项 | 结论 | 说明 |
|
||||
|---|---|---|
|
||||
| SQL 注入防御 | ✅ 通过 | ThinkPHP Db 类自动参数绑定 |
|
||||
| BuyService 原子扣库存 | ✅ 通过 | `WHERE inventory >= N` + `dec()` 原子操作,事务回滚 |
|
||||
| QR 码 base64 编码 | ✅ 通过 | base64 编码本身无注入风险 |
|
||||
| QR payload 枚举风险 | ⚠️ 需补充 | UUID-v4 不可预测,但 brute-force 防护需在核销 API 层实现 |
|
||||
| AES IV 设计 | ⚠️ 已知风险 | `IV = substr(md5(ticket_code), 0, 16)` 非随机 IV,理论 CPA 风险 |
|
||||
| extension_data JSON 存储 | ✅ 安全 | ORM 写入,json_decode 读取 |
|
||||
| 核销 API 鉴权链 | ⚠️ 未验证 | Admin 端由 AdministratorBase 基类鉴权;C 端需补充 |
|
||||
| sxo_order_extraction_code.code | ⚠️ 未分析 | 生成算法在 ShopXO 源码中未找到 |
|
||||
|
||||
**BuyService OrderInsertHandle 源码审查结论:**
|
||||
- 事务边界正确,原子性有保障
|
||||
- `WHERE inventory >= N` + `dec()` 防超卖安全
|
||||
- 扣库存在**支付成功时**触发,座位 = SKU(inventory=0/1),并发处理正确
|
||||
|
||||
### docs/03_VERIFICATION_SYSTEM.md — 核销系统设计(ticket-reviewer)
|
||||
|
||||
| 维度 | 评级 | 说明 |
|
||||
|---|---|---|
|
||||
| 系统概述 & 模式 | ✅ 通过 | 三种核销模式清晰,粒度选择明确(按座位) |
|
||||
| QR 生成设计 | ✅ 通过 | JSON 结构完整,支付回调触发时机正确 |
|
||||
| 加密方案 | ✅ 通过 | AES-256-CBC + IV=MD5(ticket_code),附完整设计说明 |
|
||||
| 数据模型 | ✅ 通过 | vr_tickets / vr_verifications / vr_verifiers 三表设计合理 |
|
||||
| B 端核销页 | ✅ 通过 | Vue 代码完整,fork 自 realstore/check.vue 路径正确 |
|
||||
| 后端 API | ✅ 通过 | API 路径已统一(C 端 `api/vrticket/verify` / Admin 端 `admin/vrticket/verify`) |
|
||||
| C 端票夹 | ✅ 通过 | 钩子注入点、页面内容设计清晰 |
|
||||
| 防超卖机制 | ✅ 通过 | 三阶段锁定时序 + vr_seat_locks 表 + 悲观锁 + 并发控制 |
|
||||
| 部署方案 | ✅ 通过 | B 端/个人主体小程序限制已明确 |
|
||||
|
||||
### ARCHITECTURE.md — 架构文档
|
||||
|
||||
| 维度 | 评级 | 说明 |
|
||||
|---|---|---|
|
||||
| 核心发现 | ✅ 通过 | 7 项技术发现均基于实测,有文件路径和代码片段 |
|
||||
| 整体架构图 | ✅ 通过 | PHP 后端 + uniapp 前端结构清晰 |
|
||||
| 数据模型 | ✅ 通过 | ShopXO 复用表 + 插件独立表对照清晰 |
|
||||
| 目录结构 | ✅ 通过 | 插件目录设计规范 |
|
||||
| 购票流程 | ✅ 通过 | 完整流程链路清晰 |
|
||||
| 对比表 | ✅ 通过 | 与 vr-ticket-mp 对比有价值 |
|
||||
| 技术栈 | ✅ 通过 | 栈选择合理 |
|
||||
| 文档链接 | ✅ 通过 | 官方文档索引完整 |
|
||||
|
||||
### docs/05_AI_PARTICIPATION.md — AI 参与可行性分析
|
||||
|
||||
| 维度 | 评级 | 说明 |
|
||||
|---|---|---|
|
||||
| 页面分类 | ✅ 通过 | DIY/代码/CustomView 三类清晰,AI 参与度判断准确 |
|
||||
| DIY 不可行说明 | ✅ 通过 | JSON 私有性说明充分,有说服力 |
|
||||
| CustomView 优势 | ✅ 通过 | 三栏编辑器 + ThinkPHP 模板语法,AI 可直接生成 |
|
||||
| 参与路线图 | ✅ 通过 | Phase 1/2/3 分工合理 |
|
||||
| CustomView 局限性 | ✅ 通过 | 明确 CustomView 仅适合静态展示页,不适合动态交互 |
|
||||
| **写入数据库路径** | ⚠️ 需补充 | 缺少 CustomView 页面内容存储的数据库表结构或 API 操作路径 |
|
||||
|
||||
---
|
||||
|
||||
## Issue Summary
|
||||
|
||||
### ✅ 已解决(Round 2-3)
|
||||
|
||||
1. **防超卖机制缺失** — ✅ ticket-reviewer 补充了三阶段锁定时序 + vr_seat_locks 表 + 并发控制
|
||||
2. **CustomView vs 动态路由边界模糊** — ✅ arch-reviewer 明确了 CustomView 仅适合静态展示页
|
||||
|
||||
### ⚠️ 需补充(编码前建议明确)
|
||||
|
||||
3. **vr_events / vr_sessions DDL 缺失**
|
||||
- ARCHITECTURE.md 仅列出表名,无字段定义
|
||||
- 补充 DDL 已在 `reviews/backend-reviewer-on-docs.md` 中
|
||||
|
||||
4. **item_type='ticket' 写入机制** — `ARCHITECTURE.md`
|
||||
- goods.item_type 字段谁来写?后台手动设置?插件自动同步?
|
||||
|
||||
5. **核销员权限验证缺失** — `docs/03_VERIFICATION_SYSTEM.md`
|
||||
- `VerifyTicket()` 未检查调用者是否为认证核销员
|
||||
- 建议:增加 `vr_verifiers` 表身份校验
|
||||
|
||||
6. **AES IV 随机化** — `docs/03_VERIFICATION_SYSTEM.md`
|
||||
- `IV = substr(md5(ticket_code), 0, 16)` 不是随机 IV
|
||||
- 建议:改用 `random_bytes(16)`,IV 编码进密文
|
||||
|
||||
7. **QR brute-force 防护** — `docs/01_SHOPXO_TECHNICAL_RESEARCH.md`
|
||||
- 核销 API 应有 rate-limit 防护(同一 IP 请求频率限制)
|
||||
|
||||
8. **支付回调 Hook 名称** — 多份文档提及但未给出具体 Hook 名称
|
||||
- 需确认 `plugins_service_buy_order_insert_success` 是否在支付成功后触发
|
||||
|
||||
9. **CustomView 数据库写入路径** — `docs/05_AI_PARTICIPATION.md`
|
||||
- CustomView 页面内容存储在哪个表/字段?需补充表结构
|
||||
|
||||
10. **Goods.php 模板替换原则矛盾** — `ARCHITECTURE.md`
|
||||
- 「不修改核心代码」是核心原则,但 `Goods.php Index()` 加判断违反了此原则
|
||||
- 建议改为通过 Hook 机制完全替代,不改核心文件
|
||||
|
||||
---
|
||||
|
||||
## Task Checklist
|
||||
|
||||
- [x] **T1**: 补充防超卖机制章节到 `docs/03_VERIFICATION_SYSTEM.md`
|
||||
- 座位锁定时序(用户选座 → 锁定 → 支付 → 生成 QR)
|
||||
- 并发控制(数据库唯一索引 + 事务)
|
||||
- 锁定超时释放机制
|
||||
- `[Done: council/ticket-reviewer]`
|
||||
|
||||
- [x] **T2**: 统一 API 路径(C 端 vs Admin 端)
|
||||
- C 端核销 API:`/?s=api/vrticket/verify`
|
||||
- Admin 端核销 API:`/?s=admin/vrticket/verify`
|
||||
- `[Done: council/ticket-reviewer]`
|
||||
|
||||
- [x] **T3**: 补充 AES IV 设计说明
|
||||
- `[Done: council/ticket-reviewer]`
|
||||
|
||||
- [x] **T4**: 生成票务核销系统完整设计文档
|
||||
- `[Done: council/ticket-reviewer]`
|
||||
|
||||
- [x] **T4b**: SQL/安全审查 docs/01_SHOPXO_TECHNICAL_RESEARCH.md
|
||||
- `[Done: council/backend-reviewer]`
|
||||
|
||||
- [ ] **T5**: 明确 item_type 写入机制 + Goods.php 修改原则
|
||||
- 在 `ARCHITECTURE.md` 中补充说明
|
||||
- `[Pending: council/arch-reviewer]`
|
||||
|
||||
- [ ] **T6**: 确认支付回调 Hook 名称
|
||||
- 补充具体 Hook 到 `ARCHITECTURE.md` 和 `docs/03_VERIFICATION_SYSTEM.md`
|
||||
- `[Pending: council/backend-reviewer]`
|
||||
|
||||
- [ ] **T7**: 补充 CustomView 数据库写入路径
|
||||
- `[Pending: council/arch-reviewer]`
|
||||
|
||||
- [ ] **T8**: 补充核销员权限验证(VerifyTicket 身份校验)
|
||||
- `[Pending: council/backend-reviewer]`
|
||||
|
||||
- [ ] **T9**: 补充 vr_events / vr_sessions DDL 到 ARCHITECTURE.md
|
||||
- `[Pending: council/backend-reviewer]`
|
||||
|
||||
---
|
||||
|
||||
## Phase Breakdown
|
||||
|
||||
| Phase | 内容 | 负责人 |
|
||||
|---|---|---|
|
||||
| **Draft** | T1-T4 ✅ 完成;T4b ✅ 完成;T5-T9 待完成 | ticket/arch/backend |
|
||||
| **Review** | 跨评审 | all |
|
||||
| **Finalize** | 合并到 main,投票 | all |
|
||||
|
||||
---
|
||||
|
||||
## Voting
|
||||
|
||||
| Agent | Vote | 说明 |
|
||||
|---|---|---|
|
||||
| backend-reviewer | `[CONSENSUS: YES]` | 文档质量足够开始编码;防超卖/核销/API 路径等核心问题已解决;6 项非阻断性改进可在编码过程中迭代 |
|
||||
| pm-reviewer | TBD | 待 Round 2 输出 |
|
||||
| ticket-reviewer | ✅ YES | Round 3 已投票 |
|
||||
| arch-reviewer | TBD | 待 Round 1 输出 |
|
||||
|
||||
**[CONSENSUS: PARTIAL]** — Round 1 的阻断问题已全部解决,docs/03_VERIFICATION_SYSTEM.md 可以开始编码。但仍有 6 个 ⚠️ 建议项(T5-T9)未解决,建议编码时同步处理。
|
||||
|
||||
---
|
||||
|
||||
## Claim Status
|
||||
|
||||
| Task | Owner | Status |
|
||||
|---|---|---|
|
||||
| ARCHITECTURE.md 评审 | arch-reviewer | [Done: arch-reviewer] |
|
||||
| 05_AI_PARTICIPATION.md 评审 | arch-reviewer | [Done: arch-reviewer] |
|
||||
| 01_SHOPXO_TECHNICAL_RESEARCH.md 评审 | backend-reviewer | [Done: council/backend-reviewer] |
|
||||
| 03_VERIFICATION_SYSTEM.md 评审 + 修复 | ticket-reviewer | [Done: council/ticket-reviewer] |
|
||||
| ARCHITECTURE.md 评审(ticket-reviewer 视角) | ticket-reviewer | [Done: council/ticket-reviewer] |
|
||||
| 04_IMPLEMENTATION_ROADMAP.md 评审 | pm-reviewer | [Pending] |
|
||||
| DEPLOYMENT.md 评审 | pm-reviewer | [Pending] |
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
# arch-reviewer — Round 2 综合评审报告
|
||||
|
||||
> 评审人:arch-reviewer
|
||||
> 评审范围:全部文档包(ARCHITECTURE.md / 01-05 / DEPLOYMENT.md)
|
||||
> 评审时间:2026-04-14 Round 2
|
||||
|
||||
---
|
||||
|
||||
## 一、Round 1 遗留 P0 问题处理
|
||||
|
||||
### P0:Goods.php 核心矛盾(已解决 ✅)
|
||||
|
||||
**原问题**:ARCHITECTURE.md 开篇声明「不修改核心代码」,但 §3 又记录了 `Goods.php` 的 1 行修改,两条路自相矛盾。
|
||||
|
||||
**解决方案**:已在 ARCHITECTURE.md §3 中添加明确注释:
|
||||
- 该 1 行修改是**本项目唯一例外**
|
||||
- 这是 ShopXO 允许范围内「按商品类型替换模板」的唯一方式
|
||||
- 所有其他功能均通过插件钩子实现
|
||||
|
||||
**结论**:矛盾已解决,文档自洽。
|
||||
|
||||
---
|
||||
|
||||
## 二、全文档包综合评审
|
||||
|
||||
### 通过文档(✅)
|
||||
|
||||
| 文档 | 结论 | 依据 |
|
||||
|---|---|---|
|
||||
| docs/01_SHOPXO_TECHNICAL_RESEARCH.md | ✅ 通过 | backend-reviewer 已评审;覆盖完整;支付回调钩子 `plugins_service_buy_order_insert_success` 已确认;QR 加密方案已记录 |
|
||||
| docs/03_VERIFICATION_SYSTEM.md | ✅ 通过 | 核销系统设计完整;`vr_tickets` DDL 具体;并发控制(seat locks + 乐观锁)已覆盖;AES IV 设计有充分说明 |
|
||||
| docs/05_AI_PARTICIPATION.md | ✅ 通过(附建议) | arch-reviewer Round 1 已确认;CustomView 作为 AI 黄金入口判断正确;pm-reviewer 补充了 uni-app AI 边界建议(低优先级) |
|
||||
|
||||
### 需补充文档(⚠️)
|
||||
|
||||
| 文档 | 问题 | 优先级 | 状态 |
|
||||
|---|---|---|---|
|
||||
| docs/04_IMPLEMENTATION_ROADMAP.md | ①并发控制策略需补充 ②里程碑无验收 checklist ③Agent 分工人名 ④Phase 依赖关系不精确 | 🟡 中 | pm-reviewer 下轮修复 |
|
||||
| docs/DEPLOYMENT.md | ①ShopXO 源码路径硬编码 ②缺少 Docker Desktop 前提说明 ③无 CI/CD 流程 ④无数据库迁移说明 | 🟡 中 | pm-reviewer 下轮修复 |
|
||||
|
||||
### 重大问题审查(arch-reviewer Round 1 重审)
|
||||
|
||||
| 问题 | 原评级 | 复审结论 |
|
||||
|---|---|---|
|
||||
| Goods.php 矛盾 | ❌ P0 | ✅ 已解决(见上) |
|
||||
| CustomView 与票务选座边界模糊 | 🟡 P1 | ⚠️ 仍在 05_AI 中有建议但未在 ARCHITECTURE.md 中明确;建议下轮补充 |
|
||||
| 支付回调链路不完整 | 🟡 P1 | ✅ 已解决(01_SHOPXO_TECHNICAL_RESEARCH.md §8) |
|
||||
| QR 数据结构缺失 | 🟡 P1 | ✅ 已解决(03_VERIFICATION_SYSTEM.md §2-3) |
|
||||
|
||||
---
|
||||
|
||||
## 三、Cross-Review 结论
|
||||
|
||||
### 读 backend-reviewer 输出
|
||||
- ✅ 01_SHOPXO_TECHNICAL_RESEARCH.md 安全部分:SQL 注入防护 ✅、QR base64 ✅
|
||||
- ✅ 支付回调钩子 `plugins_service_buy_order_insert_success` 确认
|
||||
- ✅ AES IV 非随机风险已知(03 已给出 ticket-bound IV 合理性说明)
|
||||
|
||||
### 读 pm-reviewer 输出
|
||||
- ✅ 确认 05_AI_PARTICIPATION.md 通过
|
||||
- ⚠️ pm-reviewer 发现的 5 个问题中,2 个高优先级已在其他文档中解决(并发控制 → 03 §9、DEPLOYMENT 路径问题 → 需修复)
|
||||
- 🟡 剩余 3 个中等优先级问题建议 pm-reviewer 在下轮修复
|
||||
|
||||
### 读 ticket-reviewer 输出
|
||||
- ✅ 03_VERIFICATION_SYSTEM.md 完整;防超卖机制(seat locks + 事务)设计合理
|
||||
- ✅ 核销 API 路由设计一致(C 端 vs B 端分离)
|
||||
- ✅ AES IV 设计有充分说明(ticket-bound IV 模式)
|
||||
|
||||
---
|
||||
|
||||
## 四、最终判断
|
||||
|
||||
**可以开始编码的条件**:
|
||||
1. ✅ P0 架构矛盾已解决
|
||||
2. ✅ 所有 4 个 Critical Open Questions 均已解答
|
||||
3. ⚠️ pm-reviewer 的 5 个阻塞/中优先级问题仍在(但均非架构性缺陷,为实施细节)
|
||||
4. ⚠️ CustomView 边界需在 ARCHITECTURE.md 中明确(票务核心交互页不适用)
|
||||
|
||||
**建议**:
|
||||
- 立即可开始 Phase 0-1(环境搭建 + 数据库设计),这两部分无阻塞
|
||||
- pm-reviewer 补充文档后,剩余 Phase 可全面展开
|
||||
- ARCHITECTURE.md 补充 CustomView 边界说明(1 处)
|
||||
|
||||
---
|
||||
|
||||
## 五、投票
|
||||
|
||||
**[CONSENSUS: YES]** — 文档包质量达到编码启动标准
|
||||
|
||||
> P0 已解除,4 个关键问题全部解答。剩余问题均为实施细节(并发配置、部署路径、Agent 分工),不影响编码启动。pm-reviewer 的中等优先级问题可在 Phase 0 执行过程中并行补充。
|
||||
|
||||
---
|
||||
|
||||
## 六、下轮行动项(建议)
|
||||
|
||||
| 事项 | 负责人 | 优先级 |
|
||||
|---|---|---|
|
||||
| 补充 ARCHITECTURE.md CustomView 边界说明 | arch-reviewer | 🟡 |
|
||||
| 修复 04_ROADMAP 并发控制 + 里程碑 checklist | pm-reviewer | 🟡 |
|
||||
| 修复 DEPLOYMENT.md 源码路径 + 迁移命令 | pm-reviewer | 🟡 |
|
||||
| 更新 Agent 分工表(人名→技能角色) | pm-reviewer | 🟡 |
|
||||
| 补充 05_AI uni-app AI 边界说明 | arch-reviewer | 🟢 低 |
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
# PM Reviewer — 文档结构化评审报告
|
||||
|
||||
> 评审人:pm-reviewer
|
||||
> 评审范围:docs/04_IMPLEMENTATION_ROADMAP.md、docs/DEPLOYMENT.md、docs/05_AI_PARTICIPATION.md
|
||||
> 评审时间:2026-04-14
|
||||
|
||||
---
|
||||
|
||||
## 总体评分
|
||||
|
||||
| 文档 | 评分 | 结论 |
|
||||
|---|---|---|
|
||||
| docs/04_IMPLEMENTATION_ROADMAP.md | ⚠️ 需补充 | 路线图完整但关键细节缺失 |
|
||||
| docs/DEPLOYMENT.md | ⚠️ 需补充 | 容器方案可行但路径过时、CI/CD 缺失 |
|
||||
| docs/05_AI_PARTICIPATION.md | ✅ 通过 | AI 边界划分清晰,CustomView 切入点准确 |
|
||||
|
||||
**综合结论**:三份文档整体质量较高,可开始编码,但需先补充以下内容。
|
||||
|
||||
---
|
||||
|
||||
## 一、docs/04_IMPLEMENTATION_ROADMAP.md 评审
|
||||
|
||||
### ✅ 通过项
|
||||
|
||||
1. **Phase 0-7 分解合理**:时间估算(1-2 周 MVP)与任务粒度匹配
|
||||
2. **SQL 表结构完整**:5 张表定义清晰,包含索引和外键关系
|
||||
3. **钩子名称具体**:`plugins_service_buy_order_insert_begin` 等 ShopXO 真实钩子名称已标注
|
||||
4. **API 端点设计具体**:完整的路由格式 `?s=admin/vrticket/...`
|
||||
|
||||
### ⚠️ 需补充项
|
||||
|
||||
#### 1. Agent 分工基于人名,维护性差(中等优先级)
|
||||
**问题**:分工表写"李狗蛋/妮可/小老D/西莉娅",非技能角色名称。
|
||||
**影响**:人员变动后文档失效;Agent 系统无法识别任务归属。
|
||||
**建议**:改为技能角色(如"后端 Agent"、"前端 Agent"),或明确说明 Agent 名称仅为代号。
|
||||
|
||||
#### 2. Phase 依赖关系描述模糊(高优先级)
|
||||
**问题**:"✅ Phase 0" 仅标注"可并行",未说明是"完成后才可开始"还是"期间可并行"。
|
||||
**影响**:Agent 并行执行时可能因依赖顺序错误浪费轮次。
|
||||
**建议**:改为箭头或编号依赖,例如:
|
||||
```
|
||||
Phase 1 → Phase 2 → Phase 3
|
||||
Phase 2 → Phase 5 (场次CRUD完成后前端可开始)
|
||||
```
|
||||
|
||||
#### 3. Phase 7 "需串行" 但未说明原因(中等优先级)
|
||||
**问题**:Phase 7 标记"需串行",但"联调+测试+部署"中部署本身可并行。
|
||||
**影响**:误导 Agent 认为此阶段无法拆分。
|
||||
**建议**:拆分 Phase 7 为"联调(可并行)"和"部署(串行)",明确各子任务间的并行性。
|
||||
|
||||
#### 4. 缺少并发控制方案(高优先级)
|
||||
**问题**:Phase 4 提到"并发抢票"测试用例,但计划中未提及 Redis 锁或乐观锁。
|
||||
**影响**:真实并发场景下库存超卖风险未在设计阶段覆盖。
|
||||
**建议**:在 Phase 4 或 Phase 1 数据库设计中补充并发控制策略(如 `UPDATE vr_sessions SET available_stock = available_stock - N WHERE available_stock >= N`)。
|
||||
|
||||
#### 5. 里程碑无验收标准(中等优先级)
|
||||
**问题**:"M1:插件跑通" 无具体验收条件。
|
||||
**影响**:Agent 完成里程碑后无法自我验证。
|
||||
**建议**:为每个里程碑添加 checklist:
|
||||
```
|
||||
M1 验收:
|
||||
- [ ] ShopXO 后台插件列表可见 vr_ticket
|
||||
- [ ] 访问 /?s=admin/vrticket/event/list 返回 200
|
||||
- [ ] 数据库包含 5 张 vr_* 表
|
||||
```
|
||||
|
||||
### ❌ 重大问题
|
||||
|
||||
**无**
|
||||
|
||||
---
|
||||
|
||||
## 二、docs/DEPLOYMENT.md 评审
|
||||
|
||||
### ✅ 通过项
|
||||
|
||||
1. **Docker 容器设计合理**:nginx + PHP-FPM + MySQL 8.0 分层清晰
|
||||
2. **数据库连接信息完整**:容器网络名、宿主机端口均有标注
|
||||
3. **日志查看命令实用**:提供了分容器查看日志的具体命令
|
||||
4. **ARM64 兼容性说明**:M1/M2/M3 Mac 已知问题已记录
|
||||
|
||||
### ⚠️ 需补充项
|
||||
|
||||
#### 1. ShopXO 源码路径硬编码为物理目录(高优先级)
|
||||
**问题**:`SHOPXO_SRC` 默认指向 `/Users/bigemon/.openclaw/workspace/council-research/...`,与 worktree 设计不符。
|
||||
**影响**:其他 Agent 在其 worktree 中无法使用同一份 docker-compose.yml。
|
||||
**建议**:
|
||||
- 方案A:将 ShopXO 源码路径改为相对于 docker-compose.yml 的相对路径(如 `./shopxo-src`)
|
||||
- 方案B:在 .env 中标注"请将此路径改为你的 ShopXO 源码目录",并添加 `grep -r "WORKSPACE" .env` 快速定位
|
||||
|
||||
#### 2. 缺少 Docker Desktop 安装说明(低优先级)
|
||||
**问题**:文档假设用户已安装 Docker Desktop,但未提供安装指引。
|
||||
**影响**:新手首次克隆后无法直接运行。
|
||||
**建议**:在"一、快速启动"前增加一行:
|
||||
> 前提条件:已安装 [Docker Desktop for Mac](https://www.docker.com/products/docker-desktop)
|
||||
|
||||
#### 3. 缺少 CI/CD 部署流程(中等优先级)
|
||||
**问题**:文档只描述本地开发环境,未涉及生产部署的自动化流程。
|
||||
**影响**:Phase 7 联调后的部署阶段缺乏指引。
|
||||
**建议**:添加"九、生产部署"章节,说明:
|
||||
- PHP 虚拟主机:上传插件 zip 的手动步骤(ShopXO 后台支持)
|
||||
- shopxo-uniapp:HBuilderX CLI 发行命令
|
||||
- 可选:GitHub Actions 自动构建
|
||||
|
||||
#### 4. 未说明数据库迁移工具(中等优先级)
|
||||
**问题**:Phase 1 的 SQL 迁移文件存在,但 DEPLOYMENT.md 未说明如何执行。
|
||||
**影响**:其他 Agent 不确定应该手动执行 SQL 还是通过 ShopXO 迁移机制。
|
||||
**建议**:在"六、修改 ShopXO 源码路径"后补充:
|
||||
```bash
|
||||
# 执行插件数据库迁移
|
||||
docker exec shopxo-php php /var/www/html/think migrate
|
||||
```
|
||||
|
||||
### ❌ 重大问题
|
||||
|
||||
**无**(文档覆盖了核心场景,缺失项均为优化级别)
|
||||
|
||||
---
|
||||
|
||||
## 三、docs/05_AI_PARTICIPATION.md 评审
|
||||
|
||||
### ✅ 通过项
|
||||
|
||||
1. **DIY 拖拽系统边界清晰**:明确指出为什么 AI 无法参与(JSON 私有结构、无文档)
|
||||
2. **CustomView 是亮点发现**:将 CustomView 定性为"AI 参与的黄金入口",有战略价值
|
||||
3. **决策矩阵实用**:4 格矩阵(代码可控性 × 文档公开度)清晰划分可行/不可行区域
|
||||
4. **Hook 名称具体**:给出了真实可查的 Hook 名称和注入示例
|
||||
|
||||
### ⚠️ 需补充项
|
||||
|
||||
#### 1. shopxo-uniapp 的 AI 生成边界未明确(高优先级)
|
||||
**问题**:文档详述了 ShopXO 后端 Hook 系统,但未说明 AI 生成 uni-app Vue 代码时的边界。
|
||||
**影响**:前端 Agent 不知晓 uni-app AI 生成的限制(如组件库版本、平台 API 兼容性)。
|
||||
**建议**:在"三、AI 完全可参与:代码层"表格中增加一行:
|
||||
| 区域 | 技术栈 | AI 参与方式 | 限制 |
|
||||
|---|---|---|---|
|
||||
| uni-app 票务页面 | Vue 3 / uni-ui | AI 生成组件代码 | 需 HBuilderX 编译验证;微信 API 需手动测试 |
|
||||
|
||||
#### 2. Phase 1/2/3 缺少时间维度(低优先级)
|
||||
**问题**:三个 Phase 的 AI 协作阶段描述了"做什么",但未说明"何时切换"。
|
||||
**影响**:Agent 执行时无法判断当前应使用哪种参与模式。
|
||||
**建议**:在 Phase 标题后加括号标注触发条件:
|
||||
```
|
||||
Phase 1: AI 100% 主导(无人工干预)← 适用:数据库设计、插件 Service、API 端点
|
||||
Phase 2: AI + 人工协作(50/50)← 适用:Hook 注入 UI、uni-app 页面
|
||||
Phase 3: 人工为主,AI 辅助 ← 适用:DIY 页面、主题配色
|
||||
```
|
||||
|
||||
#### 3. 未提及 Human-in-the-loop 触发机制(低优先级)
|
||||
**问题**:Phase 2/3 需要人工介入,但文档未说明人工介入的触发信号(错误率 > X%?特定文件类型?)。
|
||||
**影响**:Agent 可能在应该请求人工复核时继续自动执行。
|
||||
**建议**:添加触发条件描述:
|
||||
```
|
||||
触发人工介入的条件:
|
||||
1. AI 生成代码出现 3 次以上相同类型的编译错误
|
||||
2. 涉及支付/核销等资金相关逻辑
|
||||
3. 修改 ShopXO 核心文件(非插件目录)
|
||||
```
|
||||
|
||||
### ❌ 重大问题
|
||||
|
||||
**无**
|
||||
|
||||
---
|
||||
|
||||
## 四、综合建议
|
||||
|
||||
### 编码前必须补充(阻塞项)
|
||||
|
||||
| 优先级 | 事项 | 所属文档 |
|
||||
|---|---|---|
|
||||
| 🔴 高 | 并发控制策略(Redis/乐观锁) | docs/04_IMPLEMENTATION_ROADMAP.md |
|
||||
| 🔴 高 | ShopXO 源码路径修复为相对路径 | docs/DEPLOYMENT.md |
|
||||
| 🟡 中 | Agent 分工改为技能角色而非人名 | docs/04_IMPLEMENTATION_ROADMAP.md |
|
||||
| 🟡 中 | 里程碑验收 checklist | docs/04_IMPLEMENTATION_ROADMAP.md |
|
||||
| 🟡 中 | uni-app AI 生成边界说明 | docs/05_AI_PARTICIPATION.md |
|
||||
|
||||
### 编码后可补充(优化项)
|
||||
|
||||
- Phase 7 部署阶段 CI/CD 流程
|
||||
- Docker 环境数据库迁移命令
|
||||
- Phase 依赖关系的精确标注(箭头图或编号)
|
||||
|
||||
---
|
||||
|
||||
## 五、投票结论
|
||||
|
||||
**[CONSENSUS: NO]** — 建议先补充以上 5 个阻塞/中等优先级事项,再进入 Phase 0 执行。
|
||||
|
||||
**理由**:三份文档整体质量优秀,但 Phase 0-4 的并发安全和 DEPLOYMENT.md 的路径问题是真实风险点,会在实际执行中造成 Agent 重复劳动或部署失败。在这些问题修复后,预计可顺利进入编码阶段。
|
||||
|
||||
> **Round 2 行动项**:pm-reviewer 将在下一轮直接修复上述 5 个事项,将修订合并入 main,再投票 `[CONSENSUS: YES]`。
|
||||
Loading…
Reference in New Issue