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

170 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 约束与对齐
- 管理端仅支持“定时到具体时间点”的开奖,不支持设置“定时 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` 精确到毫秒
- 客户端校验本地按相同算法计算签名并比对凭证包含必要输入
## 数据模型(核心字段)
- `activities``id``name``play_type`(ichiban/infinite/match/tower)、`draw_mode`(scheduled/instant)、`min_participants``scheduled_time``refund_coupon_type``refund_coupon_amount``status`(draft/active/closed)。
- `issues``id``activity_id``seed``seed_version``original_qty``quantity``status`(pending/drawing/done/failed)。
- `rewards``id``issue_id``name``weight``original_qty``quantity``type``meta`
- `draw_logs``id``issue_id``activity_id``user_id``reward_id``signature``timestamp``nonce``receipt_json`
- `lottery_refund_logs``id``issue_id``order_id``user_id``amount``coupon_type``coupon_amount``reason``created_at``status`(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`;拒绝包含“分钟”相对参数。
2) 更新活动
- `PATCH /api/admin/lottery/activities/:activity_id`
- Body同创建可部分字段
- 禁止将 `scheduled_time` 更新为相对分钟;仅允许更新为更晚的绝对时间。
3) 创建活动期(含奖池与种子)
- `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
}
```
4) 活动列表/详情
- `GET /api/admin/lottery/activities?play_type=&draw_mode=&status=&page=&size=`
- `GET /api/admin/lottery/activities/:activity_id`
5) 期列表/详情
- `GET /api/admin/lottery/activities/:activity_id/issues?page=&size=`
- `GET /api/admin/lottery/issues/:issue_id`
6) 手动关闭活动/期
- `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"
}
```
2) 即时抽奖(支付成功后自动触发,若需要主动查询)
- `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...=="
}
}
}
```
3) 定时开奖结果查询(到点统一结算后)
- `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 }
}
```
4) 客户端校验助手(可选)
- `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_id` `order_id` 作为幂等键退款/赠券均防重复
- 定时任务定期扫描 + 重试机制失败写入日志告警通知
- 网络中断客户端可凭 `join_id` 查询结果服务端保证结算原子性
## 错误码(示例)
- `400`活动未开始/已结束/库存不足/限频/参数错误
- `402`未支付
- `409`重复参与/幂等冲突
- `500`系统错误/结算失败可重试
## 测试与验收
- 单元HMAC 随机选择拒绝采样无偏事务一致性幂等与重试
- 集成支付即时报奖收据校验定时人数不足退款+送券
- 文档Swagger 补充所有请求/响应体明确禁止 N 分钟相对定时”,仅允许绝对时间戳
## 交付清单
- 策略模块管理端与 APP API哈希凭证定时结算器退款日志与发券流程测试与文档