Files
webman-buildadmin-mall/docs/积分商城-内部对接与流程说明.md
2026-03-20 18:11:00 +08:00

18 KiB
Raw Permalink Blame History

1. 文档目的与读者

本文件为 内部使用 的完整说明,用于:

  • 梳理积分商城与 PlayX 之间的 全量业务流程(含当前选型与备选方案)。
  • 统一后台实现口径(资产计算、订单状态机、幂等、重试、对账)。
  • 为后续版本扩展(实时 webhook、同步按钮、PlayX 拉取模式)预留空间。

对外给 PlayX 的精简版请参考:PlayX-对接文档(积分商城).md

2. 当前选型概览V1.0

  • 主键标识user_id(贯穿每日推送、资产、订单、发放接口)。
  • 集成方式
    • 前端:商城 H5 以 Iframe 嵌入 PlayXpostMessage 传 token/session。
    • 后端:商城独立服务,通过 REST API 与 PlayX 通讯。
  • 数据来源
    • 资产池:仅使用 每日 Cron 推送T+1 的历史输赢与充值数据。
    • 不引入实时充值/流水 webhook 作为资产来源。
  • 发放模式
    • 商城在红利/提现下单后,直接调用 PlayX 发放接口Bonus Grant / Balance Credit
    • PlayX 侧每 10 分钟 Cron 执行 5.9 adjustment / 最终入账。
  • 幂等责任分工(方案 A与对外文档一致
    • PlayX:对 Bonus Grant / Balance Credit 按 externalTransactionId 严格幂等——同一单号重复请求不得产生第二笔发放;须返回与首次受理一致或可识别的幂等结果(具体 HTTP 体字段由联调约定)。
    • 商城:为每笔红利/提现生成全局唯一 externalTransactionId;收到 HTTP 200 且 status="accepted"不再向发放接口重放;对网络超时等“未知是否受理”场景,可在有限次内重试同一 externalTransactionId,依赖 PlayX 幂等保证不双发(见第 6 章)。

3. 角色、系统与对象

3.1 角色

  • 会员:在 PlayX 内通过 Iframe 使用积分商城。
  • 运营/客服:使用商城后台管理商品、订单、调账。
  • PlayX 平台:数据源与权益发放执行方。

3.2 主要对象与前端看板展示映射

  • 目前可提现(现金)
    • 前端展示专用虚拟字段由可用积分按固定比例折算10 分 = 1 元),用于给玩家呈现直观价值,非底层独立资产。
  • 待领取积分 (LockedPoints)
    • 定义:基于昨日玩家亏损转化来的“保障池”,未领取前不可消费。
    • 数据源PlayX 每日推送的 Yesterday Player Win loss(取绝对值 × 返还比例)。
  • 可用积分 (AvailablePoints)
    • 定义:玩家当前拥有的、可立即抵扣兑换和提现的真实积分资产。
    • 交互消耗:所有兑换、提现操作均扣减该字段。
  • 今日可领取上限 (TodayLimit)
    • 定义:限制玩家当日最多能“挽回”多少积分。
    • 数据源PlayX 每日推送的 Yesterday Total Deposit(昨日总充值 × 解锁比例)。
  • 今日已领取 (TodayClaimed)
    • 定义:记录玩家当日累计已领取的积分规模,辅助校验上限,每日重置。
  • 订单 (Order)
    • 类型BONUS / PHYSICAL / WITHDRAW
    • 状态PENDING / COMPLETED / SHIPPED / REJECTED

4. 端到端流程(内部视角)

4.1 登录与会话建立

  1. 会员在 PlayX 点击“积分商城”入口。
  2. 父页面加载 Iframe商城前端进入“连接中/鉴权中”态。
  3. PlayX 前端通过 postMessage 发送:
    • token 或 session 标识。
  4. 商城前端将 token 传给后端,后端调用 PlayX 的 Token Verification API 验证身份:
    • 请求参数
      • token:接收到的用户会话凭证。
      • request_id:系统发起的鉴权校验流水号。
    • 响应参数
      • user_id:解析出的玩家在平台的唯一标识主键。
      • username:仅用于前端展示的昵称。
      • token_expire_at:用于判断并在濒临过期时触发换取新 Token无感续期
  5. 商城根据 user_id 加载本地资产与订单数据,渲染首页。

安全与会话续期要点

  • 安全拦截:不信任前端传入的 user_id,必须通过 Token Verification API 获取可信 user_id
  • Token 续期:如果用户在商城停留过久导致 Token 过期(接口返回 401 / INVALID_TOKEN),商城前端需通过 postMessage 通知 PlayX 父页面重新派发新 Token 以实现静默续期;若无法自动续期,则需弹窗引导用户重新进入商城。

4.2 每日 T+1 数据推送与资产入池

数据来源PlayX 每日 Cron。

  • 交互字段说明T+1 核心输入)
    • date:归属业务定日(用于限定该批数据的生效周期)。
    • user_id:玩家平台唯一标识主键。
    • yesterday_win_loss_net:昨日净输赢金额(核心数据源:负数绝对值作为计算新增保障积分类的基准)。
    • yesterday_total_deposit:昨日总充值(核心数据源:作为计算今日领取该积分上限的阈值基准)。
    • lifetime_total_deposit / lifetime_total_withdraw / username:非运算强制性字段,用于冗余显示或阶层判断预留。

商城处理逻辑:

  1. user_id + date 幂等入库,避免重复处理。(注:需与 PlayX 明确 date 的时区定义,如 UTC+8 等)。
  2. 根据业务规则计算:
    • 新增保障金 = ABS(yesterday_win_loss_net) * 返还比例(仅当 yesterday_win_loss_net < 0 时产生)。
    • 今日可领取上限 = yesterday_total_deposit * 解锁比例注意:今日上限每日独立计算,不结转至次日。
  3. 将新增保障金累加到 LockedPoints,更新 TodayLimit

数据修正机制

  • T+1 推送不支持覆盖更新(冲正)。如果 PlayX 上游数据算错导致推送有误,商城在二次推送时会触发去重拦截(deduped)。此类异常数据统一由商城后台人工调账处理。

4.3 领取流程(从待挽回转化为可用)

触发:会员在首页核心看板上查看领取进度(基于 昨日充值 计算),如果进度符合预期,点击“立即领取”。

  • 前端交互
    • 判断逻辑:若 昨日充值(即 TodayLimit均不足导致上限不够按钮可能置灰并提示“昨日存款不足无法全额领取”。
    • 操作反馈:点击后从底部呼出二次确认层(“将待领取积分划转为可用积分后,即可兑换或提现。确定领取?”)。
    • 确认层点击“确定”后发出后端请求。
  • 后端校验条件
    • LockedPoints > 0
    • TodayLimit - TodayClaimed > 0
  • 后端计算与执行
    • canClaim = min(LockedPoints, TodayLimit - TodayClaimed)
    • 原子更新数据库
      • LockedPoints -= canClaim
      • AvailablePoints += canClaim
      • TodayClaimed += canClaim
  • 防重与幂等
    • 接口入参包含 claim_request_id,同一 claim_request_id 重复提交不重复扣减。
  • 前端成功响应
    • 后端处理完成后,前端弹出“领取成功,积分已到账”状态框。
    • 即时刷新看板中的 待领取积分可用积分目前可提现现金
  • 积分有效期说明
    • V1.0 版本积分无有效期限制,LockedPointsAvailablePoints 永久有效并持续累加,后续视财务成本压力再引入年底清零/周期过期机制。

4.4 红利兑换BONUS

  1. 会员在前端选择红利商品(配置来自后台商品管理)。
  2. 前端展示二次确认弹层(金额、流水倍数、说明),并需在 UI 上显式提示会员:“发放预计需等待约 10 分钟内到账”
  3. 提交后,前端进入“兑换中”类似状态,不可直接提示“兑换成功”,随后商城后端执行:
    • 校验积分余额是否足够。
    • 校验商品状态(上架、库存)。
    • 校验订单状态(防重复提交)。
  4. 创建订单:
    • type = BONUS
    • status = PENDING
    • user_id
    • 商品信息 & 消耗积分
  5. 原子扣减 AvailablePoints
  6. 生成 externalTransactionId(例如 BONUS_ORD{订单号})。
  7. 调用 PlayX Bonus Grant API核心透传字段详见外部对接文档
    • externalTransactionId:本单派发流水号(防重:用于要求下游强制幂等拦截)。
    • user_id:玩家标示。
    • amount:红利发放切实的现金面值。
    • multiplier:这笔款项后续提款的流水约束倍数。
    • rewardName:展示给玩家此笔红利来源名称。
    • category:便于平台统计对账的红利业务大类。
  8. PlayX 返回:
    • 若 HTTP 200 且 status = "accepted"
      • 记录 playx_transaction_id
      • 订单保持 PENDING等待对方系统最终发放
      • 发起请求动作不再重试。但商城侧需定时调用 PlayX 提供的 交易状态查询 API 轮询确认该订单最终结果,成功则转 COMPLETED,失败则转 REJECTED 并退分。
    • 否则:
      • 记录失败原因。
      • 进入“可重试队列”(自动/人工重试,见第 6 章)。

4.5 实物兑换PHYSICAL

  1. 会员选择实物商品并填写收货信息。
  2. 商城后端:
    • 校验库存/积分。
    • 创建 PENDING 订单,扣减 AvailablePoints
  3. 后台处理:
    • 发货:录入物流公司与单号,状态 → SHIPPED。(可选:调用 PlayX Inbox API 给用户发送发货通知站内信)
    • 驳回:录入驳回原因,状态 → REJECTED并退回积分。(可选:调用 PlayX Inbox API 告知用户驳回原因)

4.6 提现回平台余额WITHDRAW 操作逻辑)

本流程旨在将兑换所得的虚拟积分,按照规定“提现”为充入 PlayX 平台账户的真实金额。

  1. 前端选择与展示
    • 会员在首页或“提现到平台”类别列表中选择特定提现档位(如:提现 100 元,需要 1000 积分1倍流水要求
    • 点击“提现”按钮后,前端唤出底部二次确认弹层。
    • 弹层内容展示所选档位所需消耗的积分值以及对应的流水要求倍数,等待二次确认提交。
    • 前端同时需在弹层或说明中向用户提示:提现申请预计约 10 分钟在平台入账)。
  2. 后端可用性校验
    • 用户确认后,前端请求后端。商城后端比较当前用户的 AvailablePoints 是否 >= item.points。如果不足,阻断流程并返回前端 积分不足 的报错浮层。
  3. 资产扣减与订单落库
    • 原子扣减数据库内该会员的 AvailablePoints
    • 创建 WITHDRAW 暂挂订单(状态 PENDING),记录该单提现对应的 amountmultiplier
    • 生成外部交易单号 externalTransactionId(如 WITHDRAW_ORD{订单号})。
  4. 调用 PlayX API 发放(核心参数解析)
    • 商城发包调用 PlayX 的 Balance Credit API
      • externalTransactionId:本提现申请的订单号(提现防重唯一拦截键)。
      • user_id:发起提现的玩家 ID。
      • amount:要充入平台余额池的真金面值。
      • multiplier/turnover_rule:该笔提现资金入账后锁定的打码流水倍数条件。
  5. 异步等待终态与 UI 回显
    • 收到 API accepted 响应后,商城将不间断返回前端“提交成功,预计 10 分钟内处理”。
    • 商城内部保持该订单为 PENDING并进入定时轮询状态监控 PlayX 10 分钟 Cron 执行后的“最终业务发货结果”,闭环完成后才转入 COMPLETED 或对失败按规则退分。

5. 扩展与备选方案(暂不对外)

本章为 扩展设计/备选方案,当前版本不对 PlayX 提出实现要求,只在内部保留。

5.1 实时充值 webhook备选

用途:让“今日可领取上限”不仅依赖 T+1 数据,还能实时响应充值行为。

示例设计:

  • PlayX 在充值成功后,调用商城的充值 webhook
    • 字段:user_idamounttransaction_idoccurred_at
  • 商城:
    • transaction_id 幂等入库。
    • 更新“当日实时充值统计”,供风控或前端展示使用。

当前状态:

  • V1.0 不启用此对接所有领取逻辑仅基于每日推送T+1

5.2 外部积分来源 webhook任务/轮盘)

用途:把 PlayX 任务、幸运轮盘等活动产出的积分汇总到商城。

示例设计:

  • PlayX 调用 webhook
    • 字段:user_idpointssourcetransaction_id
  • 商城:
    • transaction_id 幂等增加 AvailablePoints 或某个“活动积分池”。

当前状态:

  • V1.0 不做接入;防止资产口径复杂化。

5.3 “同步额度”交互逻辑(手动拉取实时充值)

功能目的:由于积分商城的基础计算依赖的是 T+1 每日推送如果不做任何补充今日充值的玩家将无法即刻提升“今日可领取上限TodayLimit”。因此原型中设置了“同步额度”按钮作为手动拉取实施更新的一种补救路径。

前端交互逻辑

  • 用户在首页面板点击“同步额度”次要操作按钮。
  • 前端短暂 loading调用后端接口拉取后弹出轻量级反馈“已同步最新额度”。
  • 页面数据看板数字重新渲染刷新。

后端业务逻辑选型推荐

  • 方案 A建议商城做拉取请求
    • 会员点击同步按钮,商城后端拦截并向 PlayX 系统调用一个**“查询今日实时余额/重算存款 API”**。
    • 获取到最新存款后,累加或覆盖当前的 TodayLimit
  • 方案 BPlayX 控制权)
    • 点击后,通过 iframe 的 postMessage 向父级 PlayX 窗口发送同步指令。
    • PlayX 在自身域内统计今日所有游戏存款流水进行汇总归集(甚至一键转账入主钱包的操作)。
    • 处理完成后 PlayX 主动请求积分商城的更新 webhook来给 TodayLimit 加额,最后前端获取成功事件刷新。
  • 当前定案落地方向
    • 根据原型要求,本功能必须落地。推荐使用方案 A。商城侧需准备一个接受通知的 API或 PlayX 需要支持实时提供玩家当日总存款的只读 API以供点击拉取。对于 V1.0 对外文档里若不打算实现,需与 PlayX 进一步交涉决定是否阉割掉此按钮。

5.4 发放模式备选PlayX 定时拉取

备选方案:

  • 由 PlayX 每 10 分钟调用商城查询接口,拉取待发放订单列表,然后自行发放。

需要新增:

  • 商城提供“待发放订单列表”接口(分页、过滤、幂等标记)。
  • 双方需要就“已拉取但未发放”、“重复拉取”等边界做严格定义。

当前选型:

  • 考虑到复杂度与 PlayX 当前发放系统形态,最终选择 商城主动调用 PlayX 发放 API 的模式,拉取模式仅保留在内部文档中作为备选。

6. 幂等、重试与状态机(内部实现口径)

6.1 幂等键

  • 每日推送:user_id + date
  • 充值/外部积分 webhook如启用transaction_id
  • 领取:claim_request_id
  • 红利/提现发放:externalTransactionId

6.2 发放请求状态机(商城内部)

针对每个订单BONUS/WITHDRAW在商城内部维护发放子状态例如

  • NOT_SENT:未发送给 PlayX。
  • SENT_PENDING:已发送,等待 PlayX 响应。
  • ACCEPTED:收到 HTTP 200 且 status = "accepted"
  • FAILED_RETRYABLE:失败且可重试(如超时、上游错误)。
  • FAILED_FINAL:最终失败(达到重试上限或 PlayX 返回不可恢复错误)。

关键规则:

  • 只有在 NOT_SENTFAILED_RETRYABLE 状态下才允许“再次发送”。
  • 一旦进入 ACCEPTED,不得再发请求(自动或人工)。
  • 订单业务状态PENDING/COMPLETED/REJECTED与发放子状态之间要有清晰映射
    • ACCEPTED + 对账确认成功 → COMPLETED
    • FAILED_FINALREJECTED(并退积分)。

6.3 重试策略(内部)与防重底线

  • 前提PlayX 已承诺按 externalTransactionId 严格幂等(方案 A。在此前提下读超时后使用同一 externalTransactionId 的有限次自动重试是安全的。
  • 自动重试:
    • 仅针对网络错误、Read Timeout读超时PLAYX_UPSTREAM_ERROR 等,且尚未收到 HTTP 200 + status="accepted"
    • 建议间隔1min / 5min / 15min最多 3 次;每次重试必须使用原订单的同一 externalTransactionId,不得生成新单号冒充新单。
  • 人工重试:
    • 仅允许在 FAILED_RETRYABLE 状态下触发。
    • 每次需记录 retry_request_id、操作者、原因。若自动重试耗尽仍失败,可先通过 交易终态查询 API 核对再决定是否人工干预。
  • 绝不重试场景:
    • 发放请求已明确收到 status = "accepted"(后续只走 5.5 轮询与客诉流程,不向发放接口重放)。
    • 明确业务拒绝类错误(如参数非法、规则不满足)。

7. 对账与问题排查

  • 对账来源:
    • 商城订单表(含 externalTransactionId、playx_transaction_id
    • PlayX 提供的对账/流水查询(如有)。
  • 常见问题场景:
    • 商城显示 REJECTED 但会员反馈已收到红利:需检查是否在“发放后回滚积分”链路出错。
    • 商城显示 PENDING 时间过长:需排查 PlayX 侧 10 分钟 Cron 是否正常。

8. 与对外文档的关系

  • 本文档:覆盖“能想到的所有对接与流程设计”,供产品、后端、运营、商务内部统一认识。
  • PlayX-对接文档(积分商城).md
    • 仅暴露 PlayX V1.0 必须提供/实现的部分。
    • 承诺最小闭环,不在主文中提及实时 webhook、同步按钮、拉取模式。
    • 同步额度等能力若产品仍要落地,以本文 5.3 与商务/PlayX 结论为准;对外文档不写不代表产品一定不做。