server/laf-cloud/functions/goldMiner/README.md

328 lines
28 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.

# 黄金矿工后端接口 V1.5
## 2026-10-01 商品 ID 一次性修复
六档商品 ID 应为 `gold_miner_0`~`gold_miner_5`。两份 VIP 发布示例已修正;历史订单的 `itemid`、`goldMiner.productSnapshot` 和 `goldMiner.configHash` 不要改名,`iosOrder` 也保留原值,否则可能导致支付回调商品不匹配或转单副本冲突。
新玩家在第一次建立本期任务时读取公共配置;必须修正本期实际选中的 `activityConfigs` 版本,不能顺便将 `publishedAt` 改成开期后的时间。若存在 `control.frozenConfig`,它优先于版本配置,需要先核对;测试临时期读取 `testSchedule.periods[].configSnapshot`。已有顺延权益快照的玩家也需修复,不算完全没有活动数据的新玩家。
已有玩家不会自动重新读取公共 VIP 配置。离线脚本 [repair-product-ids.cjs](repair-product-ids.cjs) 仅修改 `goldMinerPlayerPeriods` 中的 `configSnapshot.productId`、`vipConfigSnapshot.vipTiers[].productId`、`entitlement.configSnapshot.productId`,并重算当前快照的 `configHash`、递增 `revision`、更新 `updatedAt`。只匹配六个错误 ID;不重置任务、进度、领取状态、价格或支付权益。指定期次及源于这些期次的顺延玩家记录都在范围内。
在连接正确生产数据库的 **mongosh** 中运行(不是云函数,不自动联网):
```javascript
const { repair } = require('C:/Users/NK/Desktop/workspace/server/laf-cloud/functions/goldMiner/repair-product-ids.cjs');
// 先确认 db.getName() 是实际生产库;按实际受影响期次填写。
const scope = { periodIds: ['goldMiner:2026-10-01'] };
await repair(db, scope); // 默认只读:查看 planned、fields、samples。
```
预检结果符合预期后,短暂暂停黄金矿工相关写入(进度、下单/支付履约、领奖、jobs),等待在途请求结束,再执行:
```javascript
await repair(db, { ...scope, apply: true });
await repair(db, scope); // 应 planned=0;执行报告 remaining=0、conflicts=[]。
```
每笔写入前保存完整原玩家记录到 `goldMinerProductIdRepairBackups`(一次性运维备份集合,非业务必需集合)。备份失败立即停止;并发修改通过 revision 和快照条件检查跳过并记入 conflicts,不覆盖玩家新数据。脚本可重复执行,已修正记录不再更新;中途失败可能已有部分成功,以再次预检为准。短暂停写用于避免在途支付持有旧权益对象后重新写回;恢复服务后再预检一次。备份仅用于人工核对,不要在恢复游戏写入后整体覆盖回旧玩家文档。
脚本不修改公共配置或订单,不直接授予付费资格。旧商品 ID 订单若已真实支付、支付确认校验通过,后端仍识别为黄金矿工并履约;只创建订单、支付失败或原生回调商品 ID 与原订单不一致不会解锁。核对 `order.goldMiner.confirmedAt`、`fulfillmentStatus`、`fulfillmentRoute`、`targetPeriodId` 和目标玩家期的 `entitlementStatus`;到期延迟支付仍可能补发原期或顺延下一期。
前端接入请阅读 [前端接口文档 V1.5](FRONTEND-API.md),其中按接口说明请求参数、返回字段、支付与领奖恢复流程。
更新时间:2026-09-18。本文件描述本分支实际实现;需求基线见 [PRD](../../../docs/goldMiner-PRD.md) 和 [后端设计](../../../docs/goldMiner-backend-design.md)。尚未部署云函数、配置真实商品或进行真实支付联调。
当前版本的 [Postman Collection、环境模板和使用说明](postman/gold-miner.README.md) 已使用 `/goldMiner/index` 和 `/goldMiner/admin`,可直接导入后填写测试环境变量。旧文件的 `/goldMiner` 和 `/goldMinerAdmin` 需更新;`userLevel`、`userCoin` 和 `wx/*` 地址不变。
## 目录与函数名称
黄金矿工专属云函数、配置、触发器、说明和测试统一位于 `laf-cloud/functions/goldMiner/`:
```text
goldMiner/
index.ts / .yaml 玩家接口:goldMiner/index
admin.ts / .yaml 管理接口:goldMiner/admin
config.ts / .yaml 内部配置规则:goldMiner/config
service.ts / .yaml 内部活动业务:goldMiner/service
payment.ts / .yaml 内部支付业务:goldMiner/payment
merchant.ts / .yaml 内部微信商户请求签名、查单
legacyPayment.ts / .yaml 内部旧客服渠道订单业务
merchantNotify.ts / .yaml 商户支付通知:goldMiner/merchantNotify
jobs.ts / .yaml 内部定时任务:goldMiner/jobs
web/order3.html 外部支付页部署副本
LEGACY-PAYMENT.md 旧渠道接入与部署说明
config.draft.json
trigger.json
tests/gold-miner.test.mjs
tests/gold-miner-postman.test.mjs
postman/gold-miner.postman_collection.json
postman/gold-miner.postman_environment.json
postman/gold-miner.README.md
README.md
```
函数名和 YAML 的 `name` 均与相对 `functions/` 的路径一致,内部引用使用 `@/goldMiner/...`。通用登录、关卡和微信支付入口仍位于原目录,通过导入活动模块接入。目录迁移不改变订单字段、数据库集合、活动期 ID、请求参数或奖励交付标识 `goldMiner.claim`。
本分支已完成目录整理和旧渠道扩展,未部署云函数或删除云端旧入口。发布时需要同步更新客户端调用地址与定时触发器 target;旧平铺函数不会因本地文件移动自动从云端移除。
## 1. 本次实现
- 北京时间 2026-10-01 00:00 起,每 14 天开一期,开放 7 天、冷却 7 天;通过第 41 关后获得资格,该关本身不计数。
- 主线和无尽胜利统一增加 1;去重和进度一起写入玩家期记录,计数封顶,不建事件恢复集合。
- 每期完整配置与任务快照,未付费也能累计,付费后任意领取已达标任务。
- 订单仅新增原生对象字段 `goldMiner`,商品价格与数量由服务端确定。
- 原生 Android/iOS 直购,以及旧 iOS 客服渠道的鉴权预下单、支付链接、转单、商户通知和主动查单恢复。
- 延迟支付有达标奖励时生成原期待发清单;无奖励时顺延紧接下一期,开期自动解锁,仅一次。
- 后端授权 → 前端发货 → 现有接口保存余额 → 后端确认领取。后台从不修改金币余额。
- 到期冻结、待发清单、顺延激活、已确认订单的履约重试、管理员配置和索引入口。
## 2. 公共约定
客户端入口使用 POST,活动接口名称为 `goldMiner/index`。示例中的 uid/token 均为占位值,必须使用真实登录结果。所有活动请求要求有效用户和非空有效 token,`gameName=iaa` 不支持。
成功:`{ code: 1, data, msg }`。失败:`{ code: 0, data: null, errorCode, msg }`。时间为 UTC 毫秒;金额为分;金币为整数。请求超时应重试原 ID,不能生成新的胜利事件或新发货凭证。
`periodId` 格式为 `goldMiner:2026-10-01`。2026-10-01 起仅允许从该日起每隔 14 天的开期日:10-01、10-15、10-29、11-12 等,不按月重置。首期为 `2026-10-01 00:00:00+08:00` 至 `2026-10-08 00:00:00+08:00`,截止端点不包含在内;之后冷却至 10-15 零点。此前历史期继续按周四起开放 4 天、每 7 天一期解析,以保留旧订单及补发。
## 3. 状态查询
```json
{ "action": "info", "uid": "player-id", "token": "login-token" }
```
返回 `serverTime, status, periodId, startsAt, endsAt, configVersion, priceFen, productId, progressWins, maxTarget, tasks`。时间为毫秒时间戳;价格为人民币分。任务按目标关数排列,前端使用 taskId 发起操作,无需 sequence。
活动 `status` 替代原来的 availability、qualified、purchasable 和 entitlement:
| status | 含义 |
| --- | --- |
| unavailable | 休息期或没有有效配置;返回 serverTime、periodId、startsAt、endsAt、空 tasks,不提供商品/进度字段 |
| locked | 未达到参与门槛;返回 serverTime、periodId、空 tasks,不提供商品/进度字段 |
| purchasable | 本期未解锁,允许购买 |
| purchase_disabled | 本期未解锁,后端暂停购买;仍可累计进度 |
| unlocked | 本期已解锁,包括延迟支付顺延;关闭购买开关不影响此状态和已有领取资格 |
每档仅返回 `taskId, targetWins, itemsSnapshot, claimStatus, progress, completed`。`progress=min(progressWins,targetWins)`;`completed` 只表示达标,不代表可领取。
| claimStatus | 含义 |
| --- | --- |
| locked | 未达标 |
| pending_unlock | 已达标,尚未付费解锁 |
| claimable | 当前满足全部条件,可以申请领取 |
| issuing | 已授权发货,等待客户端保存和确认;重试同一 taskId 的 claim 获取原 grantId 并恢复流程,不重复加币 |
| claimed | 已完成客户端保存确认 |
`info` 不再返回 nextStartsAt、nextPeriodId、currency、claimedThrough,以及任务 sequence、claimed、issuing、claimable、blockReason;领取后也不会附带 grantId、发货时间等内部存档字段。configVersion、原有商品/进度/奖励信息继续保留。
这是查询响应的不兼容调整,前端应以 `status === "purchasable"` 显示购买按钮,以 `task.claimStatus === "claimable"` 显示可领取,并单独处理 issuing。数据库中的权益来源、任务顺序、claimedThrough 和原来的领取状态保持不变;`claim`、`confirm_delivery` 的凭证响应不变,仍包含 grantId 和 claimedThrough。
旧期补发通过 `settlements` 单独读取。建议每次登录检查,不能只在当前期开放时查询。顺延目标期开期查询自动激活后返回 unlocked,不再向前端暴露权益来源。
## 4. 通关上报
扩展现有 `userLevel` 的 `action=save`,保留原有参数,新增 `goldMiner` 对象。表单提交时该字段可使用 JSON 字符串。
主线示例:
```json
{
"action": "save", "uid": "player-id", "token": "login-token",
"levelAmount": 42,
"goldMiner": {
"periodId": "goldMiner:2026-09-17", "eventId": "win-deviceA-1001",
"outcome": "win", "mode": "main", "clearedMainLevel": 42
}
}
```
无尽示例(L 表示当前已存档的主线上限,需替换成实际数值):`levelAmount=L, isWuXian="true"`,goldMiner 内容为:
```json
{
"periodId": "goldMiner:2026-09-17", "eventId": "win-deviceA-1002",
"outcome": "win", "mode": "endless", "endlessSequence": 123
}
```
同一次胜利在重试中固定 eventId、模式、序号和 periodId。活动期绑定发生在首次胜利上报,不能在重试时改成下一期,也不能在开局时固定为尚未开放的旧期。无尽序号须唯一且持久化,不能用会重复抽取的关卡模板号代替。
普通存档返回外壳不变,额外在 `data.goldMiner` 返回活动处理结果。例如 `code=1, activityCounted=true, duplicate=false, progressWins=1`。合法重复请求返回 `duplicate=true`;封顶不继续增长。
活动处理失败时普通关卡存档仍成功,活动子结果返回 `code=0,errorCode`。前端必须分别检查两个结果;只有活动内成功写入的进度保留,过期后不回补写入失败的进度。无 goldMiner 参数的旧请求完全不参与活动计数。
## 5. 购买、支付和查单
使用现有 `wx/orderPaySig`(Android)或 `wx/iosorderPaySig`(原生 iOS):
```json
{
"uid": "player-id", "token": "login-token",
"itemid": "gold_miner", "createRequestId": "purchase-deviceA-1001"
}
```
商品 ID 必须为配置中的 `gold_miner` 或 `gold_miner_` 前缀商品。该前缀为本活动保留,不得用于普通金币包。服务端忽略客户端的 itemPrice/itemCount,固定数量 1,按当期快照定价。
每次下单生成新的 outTradeNo,即使账号、期次和 createRequestId 相同也不复用旧订单。签名返回结构沿用现有协议;createRequestId 只用于追踪。首次下单仍锁定本期礼包报价,已解锁后拒绝继续下单。
`wx/payCallBack` 对黄金矿工订单执行正式/测试环境校验、原始消息签名、用户、商品、数量和原价匹配。只有可信回调会写入 `goldMiner.confirmedAt`。之后回调、查单、登录补单和定时任务均可继续同一履约路线。
`wx/getPayInfo`、`wx/iosgetPayInfo`、`wx/getOrderReward` 查询黄金矿工订单时必须携带 uid/token;返回:
```text
code: 1
data: {
pay_state: 2,
goldMiner: { fulfillmentStatus, fulfillmentRoute, targetPeriodId, ... },
rewardDelivery: "goldMiner.claim"
}
```
这里表示活动权益已交付,不表示所有任务金币已发放。通用领取接口不能在支付未确认时将黄金矿工订单直接改为已完成,客户端也不能套用普通商品补发金币。
旧 iOS 客服渠道现通过 `goldMiner/index` 的 `action=create_order, channel=legacy_ios` 创建鉴权订单;详细请求、配置与支付页见 [旧渠道接入说明](LEGACY-PAYMENT.md)。客服入口读取服务端创建的订单,转单保留完整活动快照;商户通知仅接收消息,由游戏查单、登录恢复或定时任务查询微信结果并确认付款后沿用活动履约。登录排除黄金矿工的旧通用补发和过期清单删除,使用专属查单恢复。原生和客服渠道允许同一期未解锁时分别创建新订单,共用玩家期快照和唯一付费权益。
### 支付边界
- 正常期内权益解锁:原期自行领取,期末剩余达标奖励进入待发清单。
- 结束后首次履约:冻结原期进度;有奖励则留原期补发,零奖励则预留紧接下一期。
- 已选路线持久化,回调重试不能改道;已在期内正常解锁的零达标玩家不顺延。
- 顺延目标期开期后,查询、通关和下单均会确保资格生效;不重置该期已有进度。
- 未支付的废弃旧订单不会永久阻止下一期正常购买。若该旧单之后才确认付款,并与目标期已有购买订单冲突,则标记 `manual_review`,不重复授予资格或自动转到第三期。
- 原生渠道查单仍读取本地已确认订单并恢复履约。旧客服渠道新增微信商户 API 主动查单,由查单接口、登录和定时任务触发;结果核对商户、用户、金额、订单和环境,不额外做响应签名校验。超时或信息不匹配时不确认付款、不删除订单,退避重试。
## 6. 领取和前端保存确认
领取授权:
```json
{
"action": "claim", "uid": "player-id", "token": "login-token",
"periodId": "goldMiner:2026-09-17", "taskId": "task_1", "requestId": "claim-1001"
}
```
返回 `grantId, taskId, items, claimStatus, claimedThrough, requiresClientDelivery`。奖励仅从当期快照读取。到期后所有 claim 返回 PERIOD_SETTLEMENT_REQUIRED(服务器正在结算奖励),不再创建或恢复普通领奖授权;数据库写入也限制在结束前。已有授权仍可通过 confirm_delivery 确认,与补发共用发货状态。
前端按 grantId 做本地去重并发货,使用原资源接口(例如 `userCoin.save`)保存发放后的总余额。保存成功后确认:
```json
{
"action": "confirm_delivery", "uid": "player-id", "token": "login-token",
"periodId": "goldMiner:2026-09-17", "taskId": "task_1", "grantId": "claim返回的稳定凭证"
}
```
可任意领取和确认已达标任务;claimedThrough 仅保留从第一档开始连续已确认的数量,不限制领奖。保存失败只重试保存;确认失败只重试确认;已完成任务的重试返回原结果,不重新加币。
`confirm_delivery` 是鉴权后的客户端保存确认,后端不会据此加金币,也没有独立证明本地发货成功。继续保留清档、多设备并发、发货和保存之间中断等既有风险,没有实施通用金币版本协议。
## 7. 服务器到期结算与补发
后台 jobs 和延迟支付履约调用 closePlayer,在玩家期同一文档内冻结进度并给已付费达标的未确认任务统一创建授权。已存在的 grantId 保留不变;新增 settlementPreparedAt 标记结算已准备,旧数据由后台重扫补齐。用户查询不再触发结算,必须部署并启用每分钟触发器。
```json
{"action":"settlements","uid":"player-id","token":"login-token"}
```
返回 `{status,items,nextCursor}`,status 为 pending_delivery / settling / no_pending_rewards。扫描玩家所有已结束期,非仅最后参与期;每个 items 元素为 `{settlementId,periodId,rewards:[{taskId,grantId,items}]}`,只包含尚未确认奖励。已全部确认或没有达标奖励的期不返回。各期奖励按档位顺序排列,金币不由后端增加。
前端不传 limit,后端固定每页扫描 20 条历史玩家期记录,兼容忽略旧 limit。已准备好的期优先返回 pending_delivery 和奖励清单,其他期尚未结算不会隐藏这些奖励。无论 pending_delivery 还是 settling,有 nextCursor 就继续翻页;扫描结束后从第一页复查,仍在结算时稍后再查。no_pending_rewards 表示后端已检查该玩家当前环境下所有已结束期,无待发或待结算记录,items=[]、nextCursor=null;不能仅凭某页空列表结束检查。
前端直接用清单授权发奖并保存资源,不再调用 claim。金币确定保存成功后确认:
```json
{"action":"confirm_settlement_delivery","uid":"player-id","token":"login-token","settlementId":"清单ID","grantIds":["原稳定授权ID"]}
```
返回 `{settlementId,confirmedGrantIds,deliveryStatus}`,deliveryStatus 为 partial / client_saved。支持同一结算单批量确认 1~100 个不重复 grantId,原子校验归属及授权状态,允许非连续任务,重复确认不重复推进。原 confirm_delivery 与新确认共用任务状态。已确认奖励在后续查询自动消失。
旧 ack_settlement 保留为可选展示确认,未全部发完仍返回 DELIVERY_PENDING;新补发流程无需调用它。清单仍可能包含“金币已保存、确认响应丢失”的奖励,前端必须用 grantId 恢复交付记录,不能重新加币。详细字段及恢复流程见 [前端文档](FRONTEND-API.md)。
## 8. 管理、配置与部署
测试服可通过 `publish_test_period` 指定任意开始和结束时间;需同时开启 `PAYMENT_APP_ENV=test` 与 `GOLD_MINER_TEST_PERIODS_ENABLED=true`。详见 [临时期操作说明](TEST-PERIODS.md) 和 [完整请求示例](test-period.publish.example.json)。正式周历保持不变。
`goldMiner/admin` 使用独立环境变量 `GOLD_MINER_ADMIN_TOKEN`,无默认密码。HTTP POST 的 body 传 adminToken,只允许服务端运维使用。
- `action=setup_indexes`:创建新增集合索引,仅黄金矿工订单使用受限的订单唯一索引,不重写旧商品订单。
- `action=publish, config={...}`:校验并发布不可变新版本,publishedAt 由后端设置;effectiveFromPeriodId 必须是未来期。
- `action=set_purchasable, periodId, purchaseEnabled=false`:停止已建立活动期的新购买;不改变配置和已购权益。
[草稿配置](config.draft.json) 的 priceFen/effectiveFromPeriodId 为 null、tasks 为空且 status=draft,不会启用活动。运营必须提供实际数值,填入递增的 targetWins 与正整数金币,发布后才可生成活动期。本期门槛 41。实现保护上限为 100 档任务、最终目标 1000 次,避免单文档去重无界增长。
配置在活动开期时冻结;懒创建活动期只选择开期前已发布且已生效的版本。配置版本更新不会改变已冻结期或玩家快照。
活动存储现只使用 `activityConfigs` 与 `goldMinerPlayerPeriods`,支付仍复用 order。配置与百人赛通过 activityId 区分;运行控制以独立 control 记录保存。玩家期记录内嵌 entitlement、原任务发货状态和整期结算状态,不再维护 goldMinerPeriods/Entitlements/RewardGrants/Settlements/JobCursors 等独立集合。
详细结构、配置选取及发布流程见 [公共配置说明](../activityConfig/README.md)。已有数据必须在维护窗口按 [迁移说明](../activityConfig/MIGRATION.md) 转换;新代码不再回读旧集合。原 grantId、settlementId 和玩家期快照保留。
完整管理请求示例:[黄金矿工配置](config.publish.example.json)(2026-10-01 起,门槛 41、1 元、目标 3/5/7/9/10,奖励 100/200/300/400/500 金币)。日期过期后改为未来合法开期日再发布。示例数值不代表自动开启活动。
部署顺序:
1. 先发布公共内部模块 activityConfig/store,再发布完整共享函数及 YAML:goldMiner/config → goldMiner/service → goldMiner/payment → goldMiner/merchant → goldMiner/legacyPayment → goldMiner/jobs。
2. 发布 goldMiner/index、goldMiner/admin 与 goldMiner/merchantNotify;共享模块及 jobs 的 HTTP methods 为空,不能暴露为玩家入口。
3. 发布改动的 userLevel、login、wx/orderPaySig、wx/iosorderPaySig、wx/payCallBack、wx/getPayInfo、wx/getOrderReward、wx/iosgetPayInfo、wx/KeFuInfo、wx/checkIos。
4. 配置管理员口令、原有支付环境/签名密钥及 [旧渠道环境变量](LEGACY-PAYMENT.md),运行 setup_indexes;生产和测试环境独立操作。旧渠道默认关闭;发布 web/order3.html 到实际支付页地址并完成客户端预下单接入后再开启。
5. 按 [触发器配置](trigger.json) 绑定每分钟运行的 goldMiner/jobs。仅上传 TS/YAML 不等于定时触发器已绑定。
6. 接入兼容客户端并验证,再发布完整的未来期商业配置。
所有共享引用沿用仓库静态 `@/` 导入方式,需先部署依赖。goldMiner/jobs 每次商户查单最多处理 5 条,其他每类最多处理 100 条,不再保存扫描游标,成功记录按业务状态退出队列,失败记录设置 nextRetryAt 退避;并发执行可重复处理但业务幂等。配置故障不阻断旧期关闭扫描。日志中的 job retry/manual_review 需要运维检查。
该分支从后端基线 e9a4d34 创建,没有包含主工作区未提交的登录/小程序福利改动。合并时注意这些改动与 login.ts 的补单接入位置。
## 9. 验证结果
以下为历史版本验证记录;本次集合精简的测试结果以提交说明为准。
前次查询协议调整后,黄金矿工行为测试 58 项、Postman 脚本测试 19 项、支付页测试 4 项通过,共 81 项。新增覆盖暂停购买、发货恢复、任务顺序以及响应字段白名单。支付来源与外部 SDK、Mongo 条件写使用模拟,未连接线上支付或数据库。上一版支付扩展另跑支付路由、新手礼包、限时礼包、月卡和登录补单回归通过;这些是历史验证记录。
上一版完整相关回归共 128 项:120 通过,8 项失败已在未改动的 e9a4d34 基线复现(以下为历史记录,不代表本次全量重跑):
- Jungle 旧测试 6 项:规划表、领取资格、回调状态、价格及 usersAd 等旧断言与当前代码不一致。
- 登录 1 项:ordinary usersAd login does not create migration fields。
- 前端源码检查 1 项:login-wucai-source 从后端目录引用不存在的相对前端路径。
```powershell
$env:TEST_WX_PAY_NOTIFY_URL='https://sor779u2w8.sealoshzh.site/wx/payCallBack'
node --test laf-cloud/functions/goldMiner/tests/gold-miner.test.mjs laf-cloud/tests/payment-routing.test.mjs laf-cloud/tests/rookie-gift.test.mjs laf-cloud/tests/starter-pack.test.mjs laf-cloud/tests/monthly-card-renewal.test.mjs laf-cloud/tests/login-wucai-state.test.mjs laf-cloud/tests/login-wucai-source.test.mjs laf-cloud/tests/login-cat-arr.test.mjs laf-cloud/tests/jungle-treasure.test.mjs
```
黄金矿工 9 个 TypeScript 模块通过定向类型检查(外部 Laf/Node 使用最小声明,保持项目非 strict 设置)。额外启用 noUnusedLocals/noUnusedParameters 时,共享依赖 Utils.ts 的既有 db 未使用报错,已确认 HEAD 中同样存在,未改动无关文件;这不代表旧仓库全量类型检查或云端 SDK 编译已通过。发布前还需验证实际 Mongo 的单文档条件更新、`$expr/$$NOW` 截止边界、原生支付通知及定时任务绑定。
## 公共活动参与开关
activityConfigs 中 recordType=version 的外层 enabled 控制是否允许新玩家参与。publish 请求顶层接受布尔值 enabled(缺省 true);旧记录缺失时为开启。最新适用版本关闭后不会回退旧版本。
关闭后,新玩家 info 返回 unavailable,不能新增进度或下单;已经初始化任务的本期玩家仍可查询、推进和购买,purchaseEnabled 仍单独控制购买。已支付并分配到目标期的权益继续恢复,支付回调、领奖、到期结算不受影响。活动列表携带玩家身份后保留已有玩家的入口,匿名和新玩家不返回关闭期。下一期按该期配置重新检查,不沿用上一期参与资格。
版本仍按期开始时间选择;发布未来版本不会提前改变当前期。运营需要立即停止新参与,可修改当前适用 version 的外层 enabled=false。临时测试期在排期条目外层保存 enabled,语义一致。公共接口及新活动接入约定见 [公共配置说明](../activityConfig/README.md)。
## VIP 六档礼包与任意档位领取
完整发布示例见 [vip-tiers.example.json](vip-tiers.example.json),配置、快照锁定及兼容规则见 [VIP-TIERS.md](VIP-TIERS.md)。前端新增任务状态 pending_unlock(已达标待付费),付费后所有已达标任务均可任意领取和确认。普通周周期及未付费累计规则保持原实现。
## 多次下单升级与索引迁移
更新 goldMiner/payment、goldMiner/legacyPayment、goldMiner/config、goldMiner/jobs 及平台需要重新发布的依赖入口后,调用 `POST /goldMiner/admin`,请求体为 `{"action":"setup_indexes","adminToken":"管理员密钥"}`。必须成功执行后再开放下单:该操作将旧的 `order.goldMiner_player_period` 唯一索引移除,换为 `goldMiner_player_period_lookup` 普通查询索引;订单号及玩家期唯一索引保留。可重复执行;索引权限等错误会返回失败,不会忽略。
新订单在 goldMiner 对象中增加 orderNonce,用于生成随机订单号及旧客服转单恢复。旧订单没有此字段时保留原恢复规则。玩家期增加 paidOrderNo,支付确认时以 revision 条件更新抢占原期付费归属,原期补发和顺延都共用此归属。兼容已解锁及已顺延的历史记录。
旧待付订单不会因新建而自动作废,支付回调仍可确认。多笔订单都实际付款时,只授予一次活动资格,额外付款订单标记 manual_review/ENTITLEMENT_CONFLICT,需人工核对及处理退款;不自动发第二份资格或再次顺延。客户端应使用最新下单结果发起支付,支付结果不确定时先查对应订单。仓库测试使用模拟支付,不代表云端索引、支付配置或微信实际链路已完成部署验证。
## 2026-10-01 周期切换部署
先发布 `goldMiner/config.ts`,再发布 `goldMiner/service.ts`(函数名不变,沿用原 YAML),相关依赖按平台规则刷新;其他业务入口共用该周期函数,无需新建集合或更改任务奖励结构。此版本代码也支持 10 月 1 日前提前部署,不改变此前周历。
推荐在北京时间 2026-10-01 00:00 前通过 `goldMiner/admin` 发布 [VIP 六档配置示例](vip-tiers.example.json),替换管理员口令并核对真实商品、价格和奖励。新版本从 `goldMiner:2026-10-01` 生效。已有适用且启用的配置可以继续被选中,周期不依赖新增配置字段;不能在正式配置中增加 startsAt/endsAt 来覆盖日历。逾期开期后不能补发本期配置,应使用后续合法期日。
保留每分钟 `goldMiner/jobs`,活动截止后按既有规则生成补发授权,冷却期仍可查询并确认补发。测试服已启用且未结束的临时期仍优先于正式日历,需要验证正式周期时先核对临时期窗口。已参与的历史期、订单快照和任务进度不改写;旧代码为 10 月 1 日预留但未初始化的顺延记录,在首次初始化时自动采用七天窗口。历史集合迁移脚本已同步新期的七天时长,仅在原本需要迁移时执行,不要求本次运行。
同步导入新版 Postman collection。客户端展示及倒计时读取接口 startsAt/endsAt,不自行按周四或四天推算。本地修改不等于云端部署或配置发布。
发布前核对数据库中是否存在预先发布的 10-08、10-22 等旧周期开期配置;这些日期现在属于冷却期,不可继续作为新配置的 effectiveFromPeriodId,应为后续合法开期日提前发布新版本。不要直接修改已有玩家或订单中的奖励快照。