1078 lines
25 KiB
Markdown
1078 lines
25 KiB
Markdown
# 方案 A:订单编排与自动兑换设计
|
||
|
||
## 1. 目标
|
||
|
||
基于现有两个项目:
|
||
|
||
- 后端 [order-site-backend](/Users/yml/codes/order-site-backend)
|
||
- 前端 [order-site-rewrite](/Users/yml/codes/order-site-rewrite)
|
||
|
||
增加一条面向真实订单的自动化交付链路:
|
||
|
||
1. 第三方平台通过订单创建成功或支付成功通知,将订单数据推送到我方后端。
|
||
2. 后端根据订单和商品信息匹配需要发放的 CDK,并创建交付任务。
|
||
3. 后端生成一个面向用户的领取链接,并通过可用渠道发送给用户。
|
||
4. 用户打开链接后,通过 QQ 或 WX 完成角色绑定。
|
||
5. 后端复用现有 Playwright 自动化能力,自动提交 CDK、执行绑定、生成截图。
|
||
6. 前端实时展示绑定状态、兑换状态和最终截图。
|
||
|
||
该方案采用“订单编排层 + 浏览器自动化执行层”两层结构,不直接把现有浏览器会话工具当作订单系统使用。
|
||
|
||
## 2. 当前系统现状
|
||
|
||
### 2.1 后端现状
|
||
|
||
当前后端主线是浏览器会话兑换工具,而不是订单系统。
|
||
|
||
- Express 入口在 [src/index.js](/Users/yml/codes/order-site-backend/src/index.js:1)
|
||
- 现有路由只覆盖腾讯浏览器会话接口,在 [src/routes/tencent.js](/Users/yml/codes/order-site-backend/src/routes/tencent.js:1)
|
||
- 浏览器会话创建、刷新、关闭、兑换都集中在 [src/services/session.js](/Users/yml/codes/order-site-backend/src/services/session.js:80)
|
||
- 验证码识别与兑换提交流程在 [src/services/session-redeem.js](/Users/yml/codes/order-site-backend/src/services/session-redeem.js:3)
|
||
- 截图、结果 JSON、证明产物生成在 [src/services/session-proof.js](/Users/yml/codes/order-site-backend/src/services/session-proof.js:16)
|
||
- OCR 子服务使用 `uv` 启动,在 [src/services/ocr.js](/Users/yml/codes/order-site-backend/src/services/ocr.js:83)
|
||
|
||
当前系统没有以下关键能力:
|
||
|
||
- 没有订单表
|
||
- 没有 CDK 库存表
|
||
- 没有 webhook 接收和签名校验
|
||
- 没有任务状态机
|
||
- 没有用户领取链接管理
|
||
- 没有消息投递模块
|
||
- 没有浏览器会话与订单任务的绑定关系
|
||
|
||
### 2.2 前端现状
|
||
|
||
当前前端是一个单页腾讯兑换工具。
|
||
|
||
- 路由只包含 `/tx/browser`,在 [src/router/index.ts](/Users/yml/codes/order-site-rewrite/src/router/index.ts:1)
|
||
- 主页面在 [src/views/tx/TencentBrowserView.vue](/Users/yml/codes/order-site-rewrite/src/views/tx/TencentBrowserView.vue:1)
|
||
- 页面编排在 [src/composables/useTencentBrowserSessionPage.ts](/Users/yml/codes/order-site-rewrite/src/composables/useTencentBrowserSessionPage.ts:1)
|
||
- 状态轮询在 [src/composables/tencent/useTencentBrowserSessionPolling.ts](/Users/yml/codes/order-site-rewrite/src/composables/tencent/useTencentBrowserSessionPolling.ts:1)
|
||
- 兑换前角色确认、兑换按钮、结果展示已经具备基础 UI,可复用
|
||
|
||
当前前端没有以下能力:
|
||
|
||
- 没有订单领取页
|
||
- 没有 token 校验页
|
||
- 没有订单详情页
|
||
- 没有任务状态驱动的前端展示
|
||
- 没有“订单上下文中的浏览器会话”概念
|
||
|
||
## 3. 总体架构
|
||
|
||
### 3.1 分层设计
|
||
|
||
建议分成 4 层:
|
||
|
||
1. 平台接入层
|
||
负责接收订单创建成功、支付成功、售后等通知,完成签名校验和原始数据落库。
|
||
2. 订单编排层
|
||
负责订单幂等、商品解析、CDK 预占、任务创建、链接生成、状态流转。
|
||
3. 浏览器自动化执行层
|
||
复用现有腾讯浏览器会话、角色识别、验证码识别、兑换提交、截图生成能力。
|
||
4. 用户交互层
|
||
用户通过领取链接进入前端页面,完成 QQ/WX 登录、角色确认、查看结果。
|
||
|
||
### 3.2 核心原则
|
||
|
||
- 订单与浏览器会话解耦
|
||
- CDK 先预占、后核销
|
||
- 所有平台通知必须幂等
|
||
- 用户访问链接使用 token,不直接使用订单号鉴权
|
||
- 浏览器自动化失败必须可重试、可人工接管
|
||
- 所有关键节点都要保留审计数据
|
||
|
||
## 4. 业务流程
|
||
|
||
### 4.1 主流程
|
||
|
||
1. 平台发送订单通知到后端 webhook。
|
||
2. 后端校验签名,按平台订单号幂等写入 `orders`。
|
||
3. 根据订单商品、规格、渠道信息生成一个或多个 `delivery_tasks`。
|
||
4. 系统从 `cdk_inventory` 中为任务预占可用 CDK。
|
||
5. 系统生成 `claim_token`,构造领取链接。
|
||
6. 系统通过站内消息、短信、客服人工转发或支付成功页展示,把链接给用户。
|
||
7. 用户打开链接,前端调用后端校验 token 和任务状态。
|
||
8. 用户选择 QQ 或 WX 登录,后端创建浏览器 session,并绑定到 `delivery_task`。
|
||
9. 用户扫码后,后端识别角色、大区、昵称等信息。
|
||
10. 前端展示识别结果,用户确认角色无误。
|
||
11. 后端自动执行 CDK 提交、验证码识别、截图生成。
|
||
12. 成功后任务进入 `redeemed`,CDK 进入 `delivered`。
|
||
13. 前端展示截图、结果消息、订单号、角色信息。
|
||
|
||
### 4.2 异常流程
|
||
|
||
- webhook 重复推送:只更新状态,不重复创建任务
|
||
- 商品无法匹配 CDK:任务进入 `manual_review`
|
||
- CDK 库存不足:任务进入 `waiting_inventory`
|
||
- token 过期:提示用户重新获取领取链接
|
||
- 浏览器自动化失败:任务进入 `retry_pending` 或 `manual_review`
|
||
- 用户长时间未领取:任务进入 `expired`,释放预占 CDK
|
||
|
||
## 5. 数据模型设计
|
||
|
||
建议先上 SQLite,跑通后如有并发压力再切 PostgreSQL。当前项目还没有数据库依赖,先用 SQLite 可以把复杂度压低。
|
||
|
||
### 5.1 `orders`
|
||
|
||
订单主表。
|
||
|
||
字段建议:
|
||
|
||
- `id`
|
||
- `platform`
|
||
- `platform_order_id`
|
||
- `order_status`
|
||
- `pay_status`
|
||
- `buyer_id`
|
||
- `buyer_name`
|
||
- `raw_payload_json`
|
||
- `created_at`
|
||
- `updated_at`
|
||
- `paid_at`
|
||
|
||
约束建议:
|
||
|
||
- `platform + platform_order_id` 唯一
|
||
|
||
### 5.2 `order_items`
|
||
|
||
订单子项表,用于一单多商品。
|
||
|
||
字段建议:
|
||
|
||
- `id`
|
||
- `order_id`
|
||
- `sku_code`
|
||
- `sku_name`
|
||
- `quantity`
|
||
- `spec_json`
|
||
- `delivery_mode`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
### 5.3 `cdk_inventory`
|
||
|
||
CDK 库存表。
|
||
|
||
字段建议:
|
||
|
||
- `id`
|
||
- `batch_no`
|
||
- `sku_code`
|
||
- `cdk_code`
|
||
- `status`
|
||
- `reserved_by_task_id`
|
||
- `delivered_at`
|
||
- `invalid_reason`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
状态建议:
|
||
|
||
- `available`
|
||
- `reserved`
|
||
- `delivered`
|
||
- `invalid`
|
||
|
||
### 5.4 `delivery_tasks`
|
||
|
||
交付任务表,是整个方案的核心。
|
||
|
||
字段建议:
|
||
|
||
- `id`
|
||
- `order_id`
|
||
- `order_item_id`
|
||
- `platform_order_id`
|
||
- `task_no`
|
||
- `task_status`
|
||
- `login_type`
|
||
- `claim_token_id`
|
||
- `reserved_cdk_id`
|
||
- `browser_session_id`
|
||
- `role_id`
|
||
- `role_name`
|
||
- `area`
|
||
- `partition`
|
||
- `nickname`
|
||
- `result_code`
|
||
- `result_message`
|
||
- `screenshot_path`
|
||
- `artifacts_json`
|
||
- `last_error`
|
||
- `retry_count`
|
||
- `expires_at`
|
||
- `claimed_at`
|
||
- `redeemed_at`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
状态建议:
|
||
|
||
- `pending_payment`
|
||
- `paid`
|
||
- `waiting_inventory`
|
||
- `cdk_reserved`
|
||
- `link_generated`
|
||
- `claimed`
|
||
- `role_confirmed`
|
||
- `redeeming`
|
||
- `redeemed`
|
||
- `retry_pending`
|
||
- `manual_review`
|
||
- `expired`
|
||
- `closed`
|
||
|
||
### 5.5 `claim_tokens`
|
||
|
||
领取链接表。
|
||
|
||
字段建议:
|
||
|
||
- `id`
|
||
- `task_id`
|
||
- `token`
|
||
- `status`
|
||
- `expired_at`
|
||
- `used_at`
|
||
- `max_use_count`
|
||
- `used_count`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
状态建议:
|
||
|
||
- `active`
|
||
- `used`
|
||
- `expired`
|
||
- `revoked`
|
||
|
||
### 5.6 `webhook_events`
|
||
|
||
保留原始通知,便于审计和重放。
|
||
|
||
字段建议:
|
||
|
||
- `id`
|
||
- `platform`
|
||
- `event_type`
|
||
- `event_key`
|
||
- `signature_valid`
|
||
- `headers_json`
|
||
- `query_json`
|
||
- `body_json`
|
||
- `processed`
|
||
- `process_error`
|
||
- `created_at`
|
||
|
||
## 6. 后端模块拆分
|
||
|
||
建议在现有后端上新增以下模块。
|
||
|
||
### 6.1 路由层
|
||
|
||
新增路由目录建议:
|
||
|
||
- `src/routes/webhooks.js`
|
||
- `src/routes/orders.js`
|
||
- `src/routes/claims.js`
|
||
- `src/routes/admin.js`
|
||
|
||
说明:
|
||
|
||
- `webhooks.js` 接平台推送
|
||
- `orders.js` 给内部系统或管理端查订单和任务
|
||
- `claims.js` 给用户领取页调用
|
||
- `admin.js` 做手工补单、重试、失效处理
|
||
|
||
### 6.2 服务层
|
||
|
||
新增服务建议:
|
||
|
||
- `src/services/order-service.js`
|
||
- `src/services/order-item-service.js`
|
||
- `src/services/delivery-task-service.js`
|
||
- `src/services/cdk-service.js`
|
||
- `src/services/claim-service.js`
|
||
- `src/services/webhook-service.js`
|
||
- `src/services/message-service.js`
|
||
- `src/services/redeem-executor-service.js`
|
||
|
||
职责划分建议:
|
||
|
||
- `webhook-service`
|
||
负责签名校验、原始通知记录、事件分发
|
||
- `order-service`
|
||
负责订单幂等写入和状态更新
|
||
- `delivery-task-service`
|
||
负责任务状态机
|
||
- `cdk-service`
|
||
负责 CDK 分配、预占、释放、核销
|
||
- `claim-service`
|
||
负责 token 生成、校验、过期
|
||
- `message-service`
|
||
负责发链接
|
||
- `redeem-executor-service`
|
||
负责把任务桥接到现有腾讯浏览器会话执行器
|
||
|
||
### 6.3 持久化层
|
||
|
||
建议新增:
|
||
|
||
- `src/db/`
|
||
- `src/repositories/`
|
||
|
||
推荐目录:
|
||
|
||
- `src/db/client.js`
|
||
- `src/repositories/order-repo.js`
|
||
- `src/repositories/task-repo.js`
|
||
- `src/repositories/cdk-repo.js`
|
||
- `src/repositories/claim-repo.js`
|
||
- `src/repositories/webhook-repo.js`
|
||
|
||
## 7. 对现有浏览器自动化能力的复用方式
|
||
|
||
现有后端能力不废弃,而是作为执行器继续使用。
|
||
|
||
### 7.1 可直接复用的能力
|
||
|
||
- 创建浏览器会话:`createTencentBrowserSession`
|
||
- 轮询会话状态:`getTencentBrowserSession`、`getTencentBrowserSessionSummary`
|
||
- 扫码登录后识别角色信息:`session.js` 内已有活动页信息抽取逻辑
|
||
- 执行兑换:`redeemTencentBrowserSession`
|
||
- 生成截图和结果 JSON:`saveRedeemArtifacts`
|
||
- OCR worker:继续使用当前 `uv run ocr-worker worker`
|
||
|
||
### 7.2 需要补的一层包装
|
||
|
||
不要让订单系统直接操作裸 `sessionId`,应通过 `redeem-executor-service` 管理:
|
||
|
||
1. 根据 `taskId` 创建浏览器 session
|
||
2. 把 `taskId <-> sessionId` 关系落库
|
||
3. 用户扫码完成后,把识别到的角色信息同步回任务
|
||
4. 用户确认角色后,再触发兑换
|
||
5. 兑换完成后,把截图路径和最终结果回写到任务
|
||
|
||
## 8. API 设计
|
||
|
||
### 8.1 平台 webhook
|
||
|
||
`POST /api/v1/webhooks/agiso/trade`
|
||
|
||
职责:
|
||
|
||
- 接收订单创建成功通知
|
||
- 接收支付成功通知
|
||
- 验签
|
||
- 幂等入库
|
||
- 推进任务状态
|
||
|
||
### 8.2 用户领取页相关
|
||
|
||
`GET /api/v1/claim/:token`
|
||
|
||
返回:
|
||
|
||
- token 是否有效
|
||
- 订单号
|
||
- 商品摘要
|
||
- 当前任务状态
|
||
- 是否已绑定角色
|
||
- 是否已有截图
|
||
|
||
`POST /api/v1/claim/:token/session`
|
||
|
||
入参:
|
||
|
||
- `loginType: qq | wx`
|
||
|
||
职责:
|
||
|
||
- 校验 token
|
||
- 创建腾讯浏览器 session
|
||
- 将 session 绑定到任务
|
||
- 返回二维码和 session 摘要
|
||
|
||
`GET /api/v1/claim/:token/session/summary`
|
||
|
||
职责:
|
||
|
||
- 轮询当前领取任务下的 session 状态
|
||
- 返回角色信息、二维码状态、截图状态
|
||
|
||
`POST /api/v1/claim/:token/confirm-role`
|
||
|
||
职责:
|
||
|
||
- 用户确认当前角色无误
|
||
- 把任务推进到 `role_confirmed`
|
||
|
||
`POST /api/v1/claim/:token/redeem`
|
||
|
||
职责:
|
||
|
||
- 后端读取预占 CDK
|
||
- 调用执行器自动提交
|
||
- 回写结果
|
||
|
||
`GET /api/v1/claim/:token/screenshot`
|
||
|
||
职责:
|
||
|
||
- 返回最终截图
|
||
|
||
### 8.3 管理后台或内部接口
|
||
|
||
`POST /api/v1/admin/tasks/:taskId/retry`
|
||
|
||
`POST /api/v1/admin/tasks/:taskId/release-cdk`
|
||
|
||
`POST /api/v1/admin/tasks/:taskId/close`
|
||
|
||
`GET /api/v1/admin/orders/:orderId`
|
||
|
||
`GET /api/v1/admin/tasks/:taskId`
|
||
|
||
## 9. 运营后台设计
|
||
|
||
### 9.1 是否需要后台
|
||
|
||
需要,而且应作为正式模块纳入方案。
|
||
|
||
原因:
|
||
|
||
- 订单通知会重复、失败或延迟,必须能人工排查
|
||
- CDK 库存需要日常导入、校验、释放、核销
|
||
- 自动化链路不是 100% 成功,必须有失败任务处理入口
|
||
- 用户咨询时,需要快速看到订单、任务、角色、截图和错误原因
|
||
- 后续一定会出现补发、重试、关闭任务、重新生成链接等运营动作
|
||
|
||
如果没有后台,系统上线后所有异常都会退化成查数据库、查日志、手改数据,维护成本会快速失控。
|
||
|
||
### 9.2 更稳的做法
|
||
|
||
更稳的做法不是把管理页面直接混进用户领取页,而是拆成两套入口:
|
||
|
||
1. 用户前台
|
||
继续服务用户领取、扫码登录、角色确认、结果查看。
|
||
2. 运营后台
|
||
专门服务订单排查、CDK 管理、任务重试、异常处理。
|
||
|
||
建议形式:
|
||
|
||
- 用户前台继续使用 [order-site-rewrite](/Users/yml/codes/order-site-rewrite)
|
||
- 运营后台先作为同仓库下独立路由模块实现,例如 `/admin`
|
||
- 后端单独提供 `/api/v1/admin/*` 接口
|
||
|
||
这样做的好处:
|
||
|
||
- 用户链路和运营链路隔离
|
||
- 权限边界更清楚
|
||
- 页面状态不会互相污染
|
||
- 以后即使单独拆管理后台,也不会影响用户前台
|
||
|
||
### 9.3 后台第一版目标
|
||
|
||
第一版后台不追求复杂权限系统和漂亮界面,目标只有一个:
|
||
|
||
让你能稳定运营这条自动交付链路。
|
||
|
||
第一版最少应覆盖:
|
||
|
||
1. 查订单
|
||
2. 查交付任务
|
||
3. 导入和维护 CDK
|
||
4. 查看 webhook 日志
|
||
5. 重试失败任务
|
||
6. 释放预占 CDK
|
||
7. 重新生成领取链接
|
||
|
||
### 9.4 后台页面模块建议
|
||
|
||
#### 1. 概览页
|
||
|
||
展示核心数字:
|
||
|
||
- 今日订单数
|
||
- 已支付待领取数
|
||
- 领取中任务数
|
||
- 兑换成功数
|
||
- 异常任务数
|
||
- 库存不足的 SKU 数
|
||
|
||
这页主要用来让你快速判断系统是否在健康运行。
|
||
|
||
#### 2. 订单列表页
|
||
|
||
展示字段建议:
|
||
|
||
- 订单号
|
||
- 平台
|
||
- 商品摘要
|
||
- 支付状态
|
||
- 订单状态
|
||
- 创建时间
|
||
- 更新时间
|
||
- 对应任务数
|
||
|
||
支持筛选:
|
||
|
||
- 平台订单号
|
||
- 支付状态
|
||
- 时间范围
|
||
- 商品 SKU
|
||
|
||
进入详情后可查看:
|
||
|
||
- 原始订单通知
|
||
- 子项列表
|
||
- 对应交付任务
|
||
|
||
#### 3. 交付任务列表页
|
||
|
||
这是后台最核心的页面。
|
||
|
||
展示字段建议:
|
||
|
||
- `task_no`
|
||
- 平台订单号
|
||
- 商品 SKU
|
||
- 当前任务状态
|
||
- 预占 CDK
|
||
- 登录方式
|
||
- 角色名
|
||
- 角色 ID
|
||
- 浏览器 sessionId
|
||
- 重试次数
|
||
- 最后错误
|
||
- 创建时间
|
||
- 更新时间
|
||
|
||
支持操作:
|
||
|
||
- 查看详情
|
||
- 重新生成链接
|
||
- 重试任务
|
||
- 释放 CDK
|
||
- 关闭任务
|
||
- 标记人工处理
|
||
|
||
#### 4. CDK 管理页
|
||
|
||
这是第二核心页面。
|
||
|
||
应支持:
|
||
|
||
- 单条新增
|
||
- 批量导入
|
||
- 按 SKU 查看库存
|
||
- 查看状态分布
|
||
- 查看预占任务
|
||
- 手动失效
|
||
- 手动释放
|
||
|
||
展示字段建议:
|
||
|
||
- `sku_code`
|
||
- `batch_no`
|
||
- `cdk_code`
|
||
- `status`
|
||
- `reserved_by_task_id`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
导入方式建议至少支持:
|
||
|
||
- 文本框多行粘贴导入
|
||
- CSV 文件导入
|
||
|
||
导入校验建议:
|
||
|
||
- 去重
|
||
- 空值校验
|
||
- SKU 必填
|
||
- 批次号可选但建议保留
|
||
|
||
#### 5. webhook 日志页
|
||
|
||
展示:
|
||
|
||
- 平台
|
||
- 事件类型
|
||
- 平台订单号
|
||
- 验签是否通过
|
||
- 是否处理成功
|
||
- 错误信息
|
||
- 到达时间
|
||
|
||
支持查看:
|
||
|
||
- headers
|
||
- query
|
||
- body
|
||
- 对应生成的订单和任务
|
||
|
||
可选操作:
|
||
|
||
- 手动重放处理
|
||
|
||
#### 6. 任务详情页
|
||
|
||
任务详情页建议整合以下信息:
|
||
|
||
- 订单信息
|
||
- 商品和 SKU
|
||
- claim token 状态
|
||
- 浏览器 session 状态
|
||
- 角色识别结果
|
||
- 兑换结果
|
||
- 截图预览
|
||
- 原始错误日志
|
||
- 操作按钮
|
||
|
||
这个页面会成为你处理异常单的主工作台。
|
||
|
||
### 9.5 后台最小接口集
|
||
|
||
建议新增后台接口:
|
||
|
||
#### 订单
|
||
|
||
- `GET /api/v1/admin/orders`
|
||
- `GET /api/v1/admin/orders/:orderId`
|
||
|
||
#### 任务
|
||
|
||
- `GET /api/v1/admin/tasks`
|
||
- `GET /api/v1/admin/tasks/:taskId`
|
||
- `POST /api/v1/admin/tasks/:taskId/retry`
|
||
- `POST /api/v1/admin/tasks/:taskId/close`
|
||
- `POST /api/v1/admin/tasks/:taskId/release-cdk`
|
||
- `POST /api/v1/admin/tasks/:taskId/regenerate-claim-link`
|
||
- `POST /api/v1/admin/tasks/:taskId/mark-manual-review`
|
||
|
||
#### CDK
|
||
|
||
- `GET /api/v1/admin/cdks`
|
||
- `POST /api/v1/admin/cdks`
|
||
- `POST /api/v1/admin/cdks/import`
|
||
- `POST /api/v1/admin/cdks/:cdkId/invalidate`
|
||
- `POST /api/v1/admin/cdks/:cdkId/release`
|
||
|
||
#### webhook
|
||
|
||
- `GET /api/v1/admin/webhook-events`
|
||
- `GET /api/v1/admin/webhook-events/:eventId`
|
||
- `POST /api/v1/admin/webhook-events/:eventId/replay`
|
||
|
||
#### 概览
|
||
|
||
- `GET /api/v1/admin/dashboard/summary`
|
||
|
||
### 9.6 后台权限建议
|
||
|
||
第一版建议至少分两层:
|
||
|
||
1. `admin`
|
||
可导入 CDK、改任务状态、重试任务、关闭任务、重放 webhook。
|
||
2. `operator`
|
||
可查订单、查任务、看截图、看日志,但不能做高风险修改。
|
||
|
||
如果第一版先不做完整账号体系,也至少要做一个最简单的后台鉴权,例如:
|
||
|
||
- 独立后台口令
|
||
- 基础登录态
|
||
- 后端校验管理接口访问权限
|
||
|
||
不要把后台接口直接裸露给公网无鉴权访问。
|
||
|
||
### 9.7 后台与前台的边界
|
||
|
||
建议明确边界:
|
||
|
||
- 前台只处理用户领取和结果查看
|
||
- 后台只处理运营和异常处置
|
||
|
||
前台不要出现:
|
||
|
||
- 手动改任务状态
|
||
- 手动改 CDK
|
||
- 看其他订单
|
||
|
||
后台不要承担:
|
||
|
||
- 用户扫码登录入口
|
||
- 用户领取页展示逻辑
|
||
|
||
这样职责清晰,后续维护成本最低。
|
||
|
||
### 9.8 后台的落地顺序
|
||
|
||
建议放在整体计划的阶段 4 中作为正式内容,但有两个能力应提前做:
|
||
|
||
1. CDK 导入
|
||
2. 任务列表与详情查看
|
||
|
||
原因:
|
||
|
||
- 没有 CDK 导入能力,阶段 1 根本跑不顺
|
||
- 没有任务查看能力,阶段 2 和阶段 3 出问题时无法排查
|
||
|
||
因此更合适的执行顺序是:
|
||
|
||
- 阶段 1 完成订单骨架后,先补一个极简后台
|
||
- 阶段 2 和 3 继续完善业务闭环
|
||
- 阶段 4 再补全 webhook 重放、统计面板、权限细化
|
||
|
||
### 9.9 后台最小可行版本
|
||
|
||
后台 MVP 建议包含:
|
||
|
||
1. 登录页
|
||
2. 概览页
|
||
3. 订单列表页
|
||
4. 任务列表页
|
||
5. 任务详情页
|
||
6. CDK 导入页
|
||
7. webhook 日志页
|
||
|
||
这已经足够支撑第一版系统上线和日常运营。
|
||
|
||
### 9.10 结论
|
||
|
||
后端侧需要一个管理界面,而且应当作为正式模块设计,不建议临时拼接。
|
||
|
||
更稳的做法是:
|
||
|
||
- 用户前台与运营后台分离
|
||
- 后台先做最小可行版本
|
||
- 优先覆盖查单、查任务、导入 CDK、重试异常
|
||
- 后台接口独立鉴权
|
||
|
||
## 10. 前端设计
|
||
|
||
### 9.1 路由设计
|
||
|
||
现有前端只有 `/tx/browser`,建议新增:
|
||
|
||
- `/claim/:token`
|
||
|
||
这个页面才是正式业务入口。
|
||
|
||
`/tx/browser` 保留为内部调试工具页,不作为正式交付页面。
|
||
|
||
### 9.2 页面结构
|
||
|
||
建议页面拆成 4 个区域:
|
||
|
||
1. 订单摘要区
|
||
展示订单号、商品名、状态说明
|
||
2. 登录绑定区
|
||
复用现有二维码卡片能力
|
||
3. 角色确认区
|
||
复用现有角色展示和确认能力
|
||
4. 结果展示区
|
||
复用现有截图和结果卡片能力
|
||
|
||
### 9.3 可复用的前端模块
|
||
|
||
可以复用:
|
||
|
||
- [TencentAuthCard.vue](/Users/yml/codes/order-site-rewrite/src/components/tencent/TencentAuthCard.vue:1)
|
||
- [TencentRedeemPanel.vue](/Users/yml/codes/order-site-rewrite/src/components/tencent/TencentRedeemPanel.vue:1)
|
||
- [TencentResultPanel.vue](/Users/yml/codes/order-site-rewrite/src/components/tencent/TencentResultPanel.vue:1)
|
||
- [useTencentBrowserSessionPolling.ts](/Users/yml/codes/order-site-rewrite/src/composables/tencent/useTencentBrowserSessionPolling.ts:1)
|
||
- [useTencentBrowserSessionPresentation.ts](/Users/yml/codes/order-site-rewrite/src/composables/tencent/useTencentBrowserSessionPresentation.ts:1)
|
||
|
||
但需要改造:
|
||
|
||
- 不再让前端自己输入兑换码
|
||
- 不再让前端自己决定是否创建裸 session
|
||
- 页面所有操作都基于 `claim token`
|
||
|
||
### 9.4 前端状态设计
|
||
|
||
建议页面状态围绕任务状态展开,而不是围绕裸 session:
|
||
|
||
- `tokenValid`
|
||
- `taskStatus`
|
||
- `orderSummary`
|
||
- `session`
|
||
- `activityInfo`
|
||
- `roleConfirmed`
|
||
- `redeemResult`
|
||
- `screenshotUrl`
|
||
|
||
## 11. 状态机设计
|
||
|
||
### 10.1 任务状态流转
|
||
|
||
主状态机建议如下:
|
||
|
||
1. `pending_payment`
|
||
2. `paid`
|
||
3. `waiting_inventory`
|
||
4. `cdk_reserved`
|
||
5. `link_generated`
|
||
6. `claimed`
|
||
7. `role_confirmed`
|
||
8. `redeeming`
|
||
9. `redeemed`
|
||
|
||
异常分支:
|
||
|
||
- `retry_pending`
|
||
- `manual_review`
|
||
- `expired`
|
||
- `closed`
|
||
|
||
### 10.2 CDK 状态流转
|
||
|
||
1. `available`
|
||
2. `reserved`
|
||
3. `delivered`
|
||
|
||
异常分支:
|
||
|
||
- `invalid`
|
||
|
||
### 10.3 token 状态流转
|
||
|
||
1. `active`
|
||
2. `used`
|
||
|
||
异常分支:
|
||
|
||
- `expired`
|
||
- `revoked`
|
||
|
||
## 12. 安全与风控
|
||
|
||
### 11.1 token 安全
|
||
|
||
- token 必须使用高熵随机串
|
||
- 不要把订单号作为唯一访问凭证
|
||
- token 要支持过期
|
||
- token 要支持撤销
|
||
- token 校验失败不要泄露订单是否存在
|
||
|
||
### 11.2 webhook 安全
|
||
|
||
- 验签必须在业务处理前完成
|
||
- 保存原始 query、body、headers
|
||
- 根据平台订单号和事件类型做幂等
|
||
- 对重复通知返回成功,避免平台无限重试
|
||
|
||
### 11.3 自动化风险
|
||
|
||
- 登录状态和验证码都可能失败
|
||
- 活动页 DOM 变更会导致自动化失效
|
||
- 平台风控弹窗可能导致流程卡死
|
||
- 必须保留重试和人工兜底入口
|
||
|
||
## 13. 失败补偿机制
|
||
|
||
### 12.1 自动重试
|
||
|
||
可自动重试的场景:
|
||
|
||
- OCR 识别失败
|
||
- 页面刷新失败
|
||
- 临时网络超时
|
||
- 可恢复的验证码错误
|
||
|
||
不建议自动无限重试,应限制次数并回写错误。
|
||
|
||
### 12.2 人工接管
|
||
|
||
以下场景建议直接转人工:
|
||
|
||
- 角色识别异常
|
||
- 商品和 CDK 映射无法确认
|
||
- 自动化连续失败
|
||
- CDK 已疑似提交但返回结果不明确
|
||
|
||
### 12.3 过期处理
|
||
|
||
- 领取链接超时未使用,任务转 `expired`
|
||
- 任务过期后释放 `reserved` 状态的 CDK
|
||
- 如已创建浏览器 session,应主动清理
|
||
|
||
## 14. 技术选型建议
|
||
|
||
### 13.1 后端
|
||
|
||
当前后端是 Node.js + Express + Playwright,建议保持不变。
|
||
|
||
新增建议:
|
||
|
||
- 数据库先用 SQLite
|
||
- 数据访问先用简单 repository 封装
|
||
- 后续需要时再引入 ORM
|
||
|
||
原因:
|
||
|
||
- 先把主流程跑通
|
||
- 当前系统规模小,没必要过早引入太重的基础设施
|
||
- 浏览器自动化已经在 Node 侧,订单编排继续留在同一进程更简单
|
||
|
||
### 13.2 前端
|
||
|
||
当前前端是 Vue 3 + Element Plus,建议保持不变。
|
||
|
||
只需要增加:
|
||
|
||
- claim 页面
|
||
- claim 相关 API service
|
||
- task 视图模型
|
||
|
||
### 13.3 Python 相关
|
||
|
||
当前 Python 仅用于 OCR worker,继续使用 `uv` 管理即可。
|
||
|
||
如果后续需要:
|
||
|
||
- 图像增强
|
||
- 模板匹配
|
||
- 截图后处理
|
||
|
||
仍然应放在独立 Python 子服务里,并统一通过 `uv` 维护依赖。
|
||
|
||
## 15. 推荐执行顺序
|
||
|
||
建议分 4 个阶段实施。
|
||
|
||
### 阶段 1:后端订单骨架
|
||
|
||
目标:
|
||
|
||
- 接 webhook
|
||
- 落订单
|
||
- 建任务
|
||
- 预占 CDK
|
||
- 生成领取链接
|
||
|
||
要做的事:
|
||
|
||
1. 增加数据库和表结构
|
||
2. 实现 webhook 验签和幂等
|
||
3. 实现订单、任务、CDK、token 的 repository 和 service
|
||
4. 实现任务状态机基础逻辑
|
||
5. 实现领取链接生成
|
||
|
||
阶段产出:
|
||
|
||
- 支付成功后,系统能自动生成领取任务和领取链接
|
||
|
||
### 阶段 2:极简后台 + 前端领取页
|
||
|
||
目标:
|
||
|
||
- 有基本运营能力
|
||
- 用户通过 token 打开页面
|
||
- 看见订单信息
|
||
- 创建登录 session
|
||
- 扫码并确认角色
|
||
|
||
要做的事:
|
||
|
||
1. 新增 `/admin` 路由和极简后台骨架
|
||
2. 实现订单列表、任务列表、任务详情、CDK 导入
|
||
3. 新增 `/claim/:token` 路由
|
||
4. 新增 claim 页面和 API service
|
||
5. 复用当前二维码、轮询、角色确认组件
|
||
6. 页面状态从 `session 驱动` 改成 `task + session 双驱动`
|
||
|
||
阶段产出:
|
||
|
||
- 运营能查任务和导入 CDK,用户能进入正式领取页面并完成角色绑定
|
||
|
||
### 阶段 3:自动兑换闭环
|
||
|
||
目标:
|
||
|
||
- 用户确认角色后自动提交 CDK
|
||
- 生成截图并前端展示
|
||
|
||
要做的事:
|
||
|
||
1. 封装 `redeem-executor-service`
|
||
2. 将任务与 session 建立绑定关系
|
||
3. 后端从预占 CDK 读取兑换码,不再由前端输入
|
||
4. 回写截图路径、业务返回码、错误信息
|
||
|
||
阶段产出:
|
||
|
||
- 从订单通知到最终截图形成完整闭环
|
||
|
||
### 阶段 4:补偿和完整运营能力
|
||
|
||
目标:
|
||
|
||
- 可重试
|
||
- 可过期释放
|
||
- 可人工处理
|
||
- 有更完整的后台能力
|
||
|
||
要做的事:
|
||
|
||
1. 增加任务重试接口
|
||
2. 增加过期清理任务
|
||
3. 增加 webhook 重放
|
||
4. 增加概览统计和异常筛选
|
||
5. 增加后台权限细化
|
||
6. 增加关键日志和审计落库
|
||
|
||
阶段产出:
|
||
|
||
- 系统具备基本上线可运维性
|
||
|
||
## 16. 最小可行版本定义
|
||
|
||
第一版上线目标不建议追求“完全无人值守”,建议定义为:
|
||
|
||
- 平台支付成功后自动创建领取任务
|
||
- 自动预占 CDK
|
||
- 自动生成领取链接
|
||
- 用户进入页面后自行扫码登录
|
||
- 用户确认角色后系统自动提交 CDK
|
||
- 成功后展示截图
|
||
- 运营可在后台查看订单、任务、库存和 webhook 日志
|
||
- 失败后进入重试或人工处理
|
||
|
||
这是当前代码基础上最稳、最容易落地、售后风险最低的版本。
|
||
|
||
## 17. 关键决策结论
|
||
|
||
- 采用方案 A 是合理的
|
||
- 不建议直接用订单号做访问凭证
|
||
- 不建议前端继续保留“手输 CDK”的正式业务模式
|
||
- 不建议一开始就做全自动零确认绑定
|
||
- 建议先做订单编排层,再复用现有浏览器自动化执行层
|
||
- 建议优先做 SQLite 版本跑通链路
|
||
- 建议把 `/tx/browser` 保留为内部调试页,把 `/claim/:token` 做成正式业务入口
|
||
- 建议把运营后台作为正式模块纳入,而不是后补工具页
|
||
|
||
## 18. 下一步落地建议
|
||
|
||
下一步建议直接进入“阶段 1 实施设计”,输出更细的开发清单:
|
||
|
||
1. 数据库表结构 SQL
|
||
2. 后端目录和文件改造清单
|
||
3. API 请求和响应示例
|
||
4. 前台 `/claim/:token` 页面状态图
|
||
5. 后台 `/admin` 页面结构与接口契约
|
||
6. 任务状态机枚举定义
|
||
|
||
如果继续推进,我建议下一步先把:
|
||
|
||
- 表结构
|
||
- 后端 API 草案
|
||
- 前端 `/claim/:token` 页面接口契约
|
||
- 后台 `/admin` 核心接口契约
|
||
|
||
这三部分先定死,然后再开始编码。
|