## 约束与对齐 - 管理端仅支持“定时到具体时间点”的开奖,不支持设置“定时 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、哈希凭证、定时结算器、退款日志与发券流程、测试与文档。