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