bindbox-game/.trae/documents/多玩法抽奖系统设计与实现计划.md
邹方成 45815bfb7d chore: 清理无用文件与优化代码结构
refactor(utils): 修复密码哈希比较逻辑错误
feat(user): 新增按状态筛选优惠券接口
docs: 添加虚拟发货与任务中心相关文档
fix(wechat): 修正Code2Session上下文传递问题
test: 补充订单折扣与积分转换测试用例
build: 更新配置文件与构建脚本
style: 清理多余的空行与注释
2025-12-18 17:35:55 +08:00

6.7 KiB
Raw Blame History

约束与对齐

  • 管理端仅支持“定时到具体时间点”的开奖,不支持设置“定时 N 分钟后开奖”。
  • 计划包含:玩法策略、哈希可验证抽奖、退款+赠券流程、数据一致性、完整 API 与参数。

玩法与流程

  • 一番赏
    • 定时开奖:必填 scheduled_time(绝对时间戳) 与 min_participants(最低人数)。到时若人数 < N全额退款+赠券。≥N统一开奖。
    • 即时开奖:用户支付成功后立即抽奖并返回凭证。
  • 无限赏/对对碰/爬塔:标准抽奖流程(即时抽奖),策略差异体现在权重、过滤规则、后置效果。

抽奖与可验证性

  • 种子:服务端使用加密安全 crypto/rand 生成 32 字节 seed,按期(issue)维度保存。
  • 哈希签名:signature = HMAC-SHA256(seed, user_id|issue_id|timestamp|nonce)nonce 为 16 字节随机串,timestamp 精确到毫秒。
  • 客户端校验:本地按相同算法计算签名并比对;凭证包含必要输入。

数据模型(核心字段)

  • activitiesidnameplay_type(ichiban/infinite/match/tower)、draw_mode(scheduled/instant)、min_participantsscheduled_timerefund_coupon_typerefund_coupon_amountstatus(draft/active/closed)。
  • issuesidactivity_idseedseed_versionoriginal_qtyquantitystatus(pending/drawing/done/failed)。
  • rewardsidissue_idnameweightoriginal_qtyquantitytypemeta
  • draw_logsidissue_idactivity_iduser_idreward_idsignaturetimestampnoncereceipt_json
  • lottery_refund_logsidissue_idorder_iduser_idamountcoupon_typecoupon_amountreasoncreated_atstatus(success/failed/retry)。

管理端 API 与参数

  1. 创建活动
  • POST /api/admin/lottery/activities
  • Body
{
  "name": "一番赏·七月",
  "play_type": "ichiban",                 // 枚举: ichiban | infinite | match | tower
  "draw_mode": "scheduled",               // 枚举: scheduled | instant
  "min_participants": 100,                 // 定时玩法必填
  "scheduled_time": "2025-12-05T20:00:00Z", // 绝对时间戳,禁止传相对分钟
  "refund_coupon_type": "cash",           // 枚举: cash | discount | gift
  "refund_coupon_amount": 20.0,            // 金额或面额
  "description": "..."
}
  • Response
{ "activity_id": 123 }
  • 校验:当 draw_mode==scheduled 时必须存在 scheduled_time(>= 当前时间+最小提前量) 与 min_participants;拒绝包含“分钟”相对参数。
  1. 更新活动
  • PATCH /api/admin/lottery/activities/:activity_id
  • Body同创建可部分字段
  • 禁止将 scheduled_time 更新为相对分钟;仅允许更新为更晚的绝对时间。
  1. 创建活动期(含奖池与种子)
  • POST /api/admin/lottery/activities/:activity_id/issues
  • Body
{
  "rewards": [
    { "name": "SSR皮肤", "weight": 1, "original_qty": 1, "type": "virtual", "meta": {"skin_id": 88} },
    { "name": "SR皮肤",  "weight": 10, "original_qty": 50, "type": "virtual", "meta": {"skin_id": 77} }
  ]
}
  • Response
{
  "issue_id": 456,
  "seed_version": 1
}
  1. 活动列表/详情
  • GET /api/admin/lottery/activities?play_type=&draw_mode=&status=&page=&size=
  • GET /api/admin/lottery/activities/:activity_id
  1. 期列表/详情
  • GET /api/admin/lottery/activities/:activity_id/issues?page=&size=
  • GET /api/admin/lottery/issues/:issue_id
  1. 手动关闭活动/期
  • POST /api/admin/lottery/activities/:activity_id/close
  • POST /api/admin/lottery/issues/:issue_id/close

APP 端 API 与参数

  1. 参与抽奖(创建订单/入场)
  • POST /api/app/lottery/join
  • Body
{
  "activity_id": 123,
  "issue_id": 456,
  "channel": "wechat",          // 支付渠道
  "client_nonce": "base64..."   // 可选,客户端随机串
}
  • Response即时模式可能包含抽奖结果定时模式仅返回入场信息
{
  "join_id": "J202512030001",
  "order_id": "O202512030009",
  "pay_params": { /* JSAPI 等 */ },
  "queued": true,                 // 定时玩法
  "draw_mode": "scheduled"
}
  1. 即时抽奖(支付成功后自动触发,若需要主动查询)
  • GET /api/app/lottery/result?join_id=J202512030001
  • Response包含可验证凭证
{
  "result": {
    "reward_id": 789,
    "reward_name": "SR皮肤"
  },
  "receipt": {
    "issue_id": 456,
    "seed_version": 1,
    "timestamp": 1733251200123,
    "nonce": "rB1A...==",
    "signature": "hmacSha256Base64...",
    "algorithm": "HMAC-SHA256",
    "inputs": {
      "user_id": 10086,
      "issue_id": 456,
      "timestamp": 1733251200123,
      "nonce": "rB1A...=="
    }
  }
}
  1. 定时开奖结果查询(到点统一结算后)
  • GET /api/app/lottery/scheduled/result?issue_id=456&user_id=10086
  • Response 同上(若未达人数,返回退款与赠券信息)
{
  "refunded": true,
  "refund": { "order_id": "O202512030009", "amount": 29.9 },
  "coupon": { "type": "cash", "amount": 20.0, "coupon_id": 33001 }
}
  1. 客户端校验助手(可选)
  • GET /api/app/lottery/issue/:issue_id/seed_version
  • Response { "seed_version": 1 }

支付/退款/赠券

  • 支付回调:沿用 /api/pay/wechat_notify(落库订单状态,触发即时抽奖或定时入场)。
  • 定时结算器:服务端按 scheduled_time 扫描:
    • 人数 < N批量退款并为每位用户发放预设优惠券system_coupons)。
    • 人数 ≥ N统一抽奖与发放写入 draw_logs 与事务扣减奖励。
  • 退款接口(内部调用):对每个订单创建退款,记录 lottery_refund_logs 并保证幂等。

一致性与异常处理

  • 事务:入场/库存扣减/日志写入使用同一事务;失败回滚。
  • 幂等:join_idorder_id 作为幂等键,退款/赠券均防重复。
  • 定时任务:定期扫描 + 重试机制;失败写入日志,告警通知。
  • 网络中断:客户端可凭 join_id 查询结果;服务端保证结算原子性。

错误码(示例)

  • 400:活动未开始/已结束/库存不足/限频/参数错误
  • 402:未支付
  • 409:重复参与/幂等冲突
  • 500:系统错误/结算失败(可重试)

测试与验收

  • 单元HMAC 随机选择、拒绝采样无偏、事务一致性、幂等与重试。
  • 集成:支付→即时报奖→收据校验;定时人数不足→退款+送券。
  • 文档Swagger 补充所有请求/响应体;明确“禁止 N 分钟相对定时”,仅允许绝对时间戳。

交付清单

  • 策略模块、管理端与 APP 端 API、哈希凭证、定时结算器、退款日志与发券流程、测试与文档。