6.5 KiB
payjsapi nomadvip 对接规范
问题:支付成功后,页面显示账号,但 PocketBase payments 表和 Memos 账户均无记录,导致会员验证失败。
原因:payjsapi 支付回调未正确写入 PocketBase 及创建 Memos 账号。
一、nomadvip 调用流程
用户点击「立即加入」
→ nomadvip POST /api/pay (user_id, site_id: "vip", ...)
→ nomadvip 调用 payjsapi POST /nomadvip/payh5
→ payjsapi 返回支付参数,用户完成支付
→ 支付渠道回调 payjsapi
→ 【payjsapi 必须】写入 PocketBase payments + site_vip,创建 Memos 账号
→ nomadvip 轮询 GET /api/pay/status?order_id=xxx
→ nomadvip 调用 payjsapi GET /nomadvip/order_status?order_id=xxx
→ payjsapi 返回 { paid: true }
二、payjsapi 支付回调必须完成
2.1 写入 PocketBase payments 表
| 字段 | 说明 | 示例 |
|---|---|---|
| user_id | 订单中的 user_id(匿名格式 user1773315608560 或 PB 用户 ID) |
user1773315608560 |
| type | 产品类型 | vip |
| order_id | 支付订单号 | 渠道返回的 out_trade_no |
| total_fee | 金额(分) | 8800 |
| channel | 支付渠道 | wxpay / alipay |
| created | 创建时间 | 自动 |
nomadvip 依赖:app/page.tsx 的 checkPaymentFromPB 按 user_id 查询 payments 判断是否 VIP。不写入则会员验证失败。
2.2 写入 PocketBase site_vip 表
| 字段 | 说明 | 示例 |
|---|---|---|
| user_id | 同 payments.user_id | user1773315608560 |
| site_id | 固定 vip |
vip |
| order_id | 支付订单号 | 可选 |
| expires_at | 到期时间,null 表示永久 | null |
nomadvip 依赖:/api/vip/check 按 user_id + site_id = "vip" 校验 Cookie 登录用户的 VIP 状态。
2.3 创建 Memos 账号
- Memos 地址:qun.hackrobot.cn
- 账号格式:
user+ 时间戳,如user1773315608560 - 默认密码:
12345678
payjsapi 在支付成功后,需调用 Memos API 或内部服务创建账号,账号名与订单中的 user_id 一致(匿名用户即为 user1773315608560 格式)。
nomadvip 依赖:首页「星球登录信息」展示的账号即为此格式,用户需用该账号登录 qun.hackrobot.cn。
三、payjsapi 接口要求
3.1 订单创建 POST /nomadvip/payh5
请求体(nomadvip 已传递):
{
"user_id": "user1773315608560",
"site_id": "vip",
"total_fee": 8800,
"type": "vip",
"channel": "wxpay",
"return_url": "https://vip.hackrobot.cn/paid",
"client_ip": "可选"
}
要求:订单存储时需保存 user_id、site_id,供支付回调使用。
3.2 订单状态 GET /nomadvip/order_status?order_id=xxx
响应:
{ "paid": true }
或
{ "paid": false }
要求:支付回调完成写入 payments/site_vip 后,此接口应返回 paid: true。nomadvip 据此判断支付成功并刷新页面。
四、order_status 接口(关键)
nomadvip 依赖:支付成功后,nomadvip 轮询 order_status,若返回 paid: true 则调用 /api/pay/confirm 写入 PocketBase 和 Memos。若 order_status 返回 false 或接口不存在,则 confirm 失败,payments/site_vip/Memos 均无记录。
payjsapi 必须实现:
GET /nomadvip/order_status?order_id=xxx
响应: { "paid": true } 或 { "paid": false }
- 参数名必须为
order_id(与 nomadvip 传递一致) - 支付渠道回调完成后,必须返回
paid: true - 若 payh5/redirect 返回 301-308 重定向,建议响应头带上
x-pay-order-id,以便 nomadvip 正确轮询
五、已有账号登录(可选,优先于 PocketBase 查询)
nomadvip 会优先调用 payjsapi 验证 VIP,若接口不存在或失败则回退到 PocketBase。
5.1 按 user_id 查 VIP GET /nomadvip/check_vip?user_id=xxx
响应:
{ "vip": true, "email": "user@example.com" }
或
{ "vip": false }
说明:payjsapi 需查 users/payments/site_vip 关联,返回是否 VIP;若已关联邮箱可返回 email 供前端不再显示绑定表单。
5.2 按邮箱+密码查 VIP POST /nomadvip/check_vip_by_email
请求体:
{ "email": "user@example.com", "password": "xxx" }
响应:
{
"vip": true,
"token": "PB token",
"record": { "id": "xxx", "email": "xxx" },
"effectiveUserId": "user1773315608560"
}
或
{ "vip": false }
说明:payjsapi 需验证邮箱密码(PB users),再查 payments/site_vip 关联,返回 VIP 状态及 PB token/record。
六、检查清单(payjsapi 侧)
- 支付回调写入 PocketBase
payments表 - 支付回调写入 PocketBase
site_vip表(site_id = "vip") - 支付回调创建 Memos 账号(user_id 格式,密码 12345678)
order_status在支付成功后返回paid: true(否则 nomadvip confirm 失败)- 订单创建时正确保存
user_id、site_id - (可选)
GET /nomadvip/check_vip?user_id=xxx按 user_id 查 VIP - (可选)
POST /nomadvip/check_vip_by_email按邮箱密码查 VIP
七、PocketBase 配置
payjsapi 需配置:
POCKETBASE_URL:PocketBase 地址(如 https://pocketbase.hackrobot.cn)POCKETBASE_EMAIL/POCKETBASE_PASSWORD:管理员账号,用于写入 payments、site_vip
八、日志要求(排查 VIP 登录问题)
payjsapi 需在以下接口打印日志,便于排查「已有账号登录」失败:
| 接口 | 建议日志 |
|---|---|
GET /nomadvip/check_vip?user_id=xxx |
请求 user_id、查询结果 vip |
POST /nomadvip/check_vip_by_email |
请求 email、PB 登录结果、vip 查询结果 |
GET /nomadvip/order_status?order_id=xxx |
请求 order_id、返回 paid |
| 支付回调 | 写入 payments/site_vip 的 user_id、order_id |
示例(Node/Express):
// check_vip
console.log("[payjsapi] check_vip user_id=%s vip=%s", user_id, vip);
// check_vip_by_email
console.log("[payjsapi] check_vip_by_email email=%s pbLogin=%s vip=%s", email, !!token, vip);
// order_status
console.log("[payjsapi] order_status order_id=%s paid=%s", order_id, paid);
九、Memos 集成
Memos 账号创建方式取决于现有架构,可选:
- 直接调用 Memos API 创建用户
- 通过内部服务/队列异步创建
- 与 PocketBase users 表联动(若 Memos 与 PB 共享用户)
账号名必须与 user_id 一致,以便 nomadvip 页面展示与登录流程一致。