# Aslan 礼物挑战活动接口 ## 接入约定 - H5 基础路径:`/activity/gift-challenge/aslan` - WebConsole 基础路径:`/activity/gift-challenge` - H5 请求必须经过网关并携带 `Authorization: Bearer ...`、`Req-Sys-Origin: ATYOU`、 `Req-Client` 和 `Req-App-Intel`。用户 ID 与来源由网关注入,接口不接收客户端 userId。 - 时间均为毫秒时间戳;日榜日期是活动 `timeZone` 下的 `yyyy-MM-dd`。 - 单个活动最多覆盖 366 个活动时区自然日;首次启用会批量幂等预建全部 DAILY 结算门闩, 因此没有任何参与者的日期也会按时冻结为空榜。 - 启用会冻结任务、排名区间所引用资源组的完整奖励配置(发放字段和 H5 展示字段),最多 5000 个奖励项。总榜结算开始前,即使活动已经进入或走完时间窗,WebConsole 仍可修改 时间、时区、任务、榜单和奖励;新配置只影响之后的事件和尚未物化/冻结的数据。 - 已生成用户任务、已冻结日榜、榜奖 parent 和 delivery item 永不回写;这些记录引用的 奖励组快照始终保留。同一已引用资源组不会刷新,修改奖励内容必须选择新的资源组。 - `dailySettlementDelayMinutes` 与 `overallSettlementDelayMinutes` 是有界迟到窗口,不是无限 追溯。结算门闩开始后对应榜单不再接受迟到写入;执行自动或人工结算前必须监控 `ASLAN_GIFT_CHALLENGE_GIFT` consumer group lag,确认落后量已进入可接受范围。 - 积分直接消费原始送礼事件:仅 `ATYOU + GOLD + 非背包 + amount > 0`,强制排除 `LUCKY_GIFT` 与 `MAGIC`,并且事件时间满足 `[startTime, endTime)`。金额固定使用 `GiveAwayGiftBatchEvent.countConsumAmountTotal()`,与礼物主流水口径一致。 ## H5 接口 ### 1. 活动详情 `GET /activity/gift-challenge/aslan/detail?activityId={id}` - `activityId` 可选;缺省时返回当前进行中、最近待开始或最近结束的已启用活动。 - 返回 `activity`、三个任务配置、`DAILY/OVERALL` 排名奖励、活动状态和服务端时间。 - 本接口不修改任务;H5 打开页面后必须调用 `/enter`。 ### 2. 每日进入并读取用户状态 `POST /activity/gift-challenge/aslan/enter` ```json { "activityId": "1234567890123456789" } ``` - 服务端按活动时区创建当天三个任务快照,并幂等完成所有 `ENTER_PAGE` 任务。 - 返回 `activityId`、`statDate`、总积分、今日积分、日榜/总榜名次以及三个任务状态。 - 重复进入不会重复累计,也不会改变 `SEND_GIFT_GOLD` 任务进度。 ### 3. 排行榜 `GET /activity/gift-challenge/aslan/ranking?activityId={id}&period={DAILY|OVERALL}&statDate={yyyy-MM-dd}&limit=100` - `period` 缺省为 `DAILY`。 - `statDate` 只对 `DAILY` 生效;缺省时自动选择活动窗口内的当前、首日或末日。 - `limit` 最终受活动 `displayTopN` 和服务端最大值 500 双重限制。 - 返回 `entries`、`my`、`settled`;排序固定为积分降序、达到当前积分时间升序、userId 升序。 - 神秘人能力用户不出现在其他用户看到的公开榜单中,但本人仍可看到自己的排名。 ### 4. 领取每日任务奖励 `POST /activity/gift-challenge/aslan/tasks/{taskCode}/claim` ```json { "activityId": "1234567890123456789", "requestId": "h5-generated-request-id" } ``` - 任务必须属于当前活动日并且已完成。 - `taskCode` 只允许 `A-Z/a-z/0-9/_/-`,长度 1 到 64,保证它可安全作为 URL 路径段。 - 活动日任务行和逐奖励项 delivery item 是幂等边界;重复请求不会重复发放成功项。 - 首次成功抢占领取状态的 `requestId` 会写入任务日快照作为审计号;它不替代服务端任务行 和 delivery item 的发奖幂等边界。 - 发奖结果不确定时任务进入 `UNKNOWN`,H5 不会自动重发,需运营在后台核账。 - 返回最新的完整用户状态。 ## WebConsole 接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/activity/gift-challenge/list` | 活动列表 | | GET | `/activity/gift-challenge/detail/{id}` | 活动、任务、排名奖励详情 | | POST | `/activity/gift-challenge/save` | 新增或按 version 乐观锁更新活动 | | PUT | `/activity/gift-challenge/enable/{id}?enabled=true` | 启停活动 | | GET/PUT | `/activity/gift-challenge/tasks/{id}` | 查询或保存恰好三个任务槽 | | GET/PUT | `/activity/gift-challenge/rank-rewards/{id}` | 查询或保存日榜/总榜奖励区间 | | GET | `/activity/gift-challenge/ranking/{id}` | 查询实时或冻结榜单 | | GET | `/activity/gift-challenge/settlement-records/{id}` | 查询结算及逐项发奖状态 | | POST | `/activity/gift-challenge/settlement/{id}` | 手动执行到期 DAILY/OVERALL 结算;period 必填,DAILY 还必须传 statDate | | POST | `/activity/gift-challenge/delivery-item/resolve/{itemId}` | 核账确认 UNKNOWN 已到账或未到账 | 任务配置必须恰好三条:一条 `ENTER_PAGE` 和两条 `SEND_GIFT_GOLD`;两档送礼任务可分别 配置金币门槛和奖励,并且金币门槛必须按 `sortOrder` 严格递增。活动启用前必须同时配置 DAILY 和 OVERALL 奖励, 同一周期排名区间不得重叠。启用后的 H5 奖励展示、每日任务发奖和榜单结算发奖均只读取 该活动自己的冻结快照;共享资源组之后改名、改奖励或下架都不会改变本期用户所得。 | 活动状态 | 核心配置 | 启停约束 | | --- | --- | --- | | 未启用 + `NOT_STARTED`(包括旧开始时间已过) | 时间、任务、榜单和奖励全部可编辑 | 启用前必须改为未来开始时间 | | 已启用 + `NOT_STARTED`(开始前、进行中或已过结束时间) | 全部可编辑 | 历史事实保留,新配置向后生效;已有业务事实后禁止停用 | | 任意已进入结算的状态 | 仅活动名称和说明可编辑 | 核心配置始终锁定,不受时间字段影响 | 三个任务的 `taskCode/taskType/sortOrder` 固定为 `daily_enter/ENTER_PAGE/1`、 `daily_gift_1/SEND_GIFT_GOLD/2`、`daily_gift_2/SEND_GIFT_GOLD/3`;活动中仅可修改文案、 门槛和奖励组。修改时区或时间窗后,旧日期已完成但未成功发放的任务仍可通过原 taskCode 继续领取,旧日榜也以实际保留的 period header 为准继续查询和结算。 ## 礼物事件与发奖 活动使用独立 consumer group `ASLAN_GIFT_CHALLENGE_GIFT` 直接订阅原始 `GiveGiftSink.TAG`,与主礼物消费者形成 RocketMQ fan-out,不依赖主消费者完成 Mongo 落库后再派生消息。对于 broker 已接收的消息,本 consumer 依靠 RocketMQ 重投和业务 唯一键实现 at-least-once;原 tag 发送失败沿用既有 `GiftMqRetryTask` 全局补偿,活动内 不再新增第二套 retry tag。活动服务会再次校验完整资格,并通过 `(activity_id, source_event_track_id)` 唯一键保证 RocketMQ 重投不会重复加分。 本活动不新增 IM 消息。奖励复用活动资源组发送器;启用时先形成活动级不可变奖励快照, 实际领取和结算再把快照中的每个资源配置物化为独立 delivery item 并抢占。超时或 进程中断统一转为 `UNKNOWN`,避免在下游到账结果不明时盲目重发。系统不设普通失败 重试分支;运营核账确认未到账后,该单项才会回到 `PENDING` 并补发。排行榜冻结与奖励 物化分属两个提交事务:门闩和获奖 parent 先提交,奖励项物化或发送短暂失败只会让 parent 保持 `PENDING`、周期保持 `PROCESSING`;调度器会从活动快照幂等物化并继续发放, 不会读取已经变化的共享资源组,也不会把已经冻结的榜单重新开放。