MatchMaster/server/laf-cloud/functions/goldMiner/postman/gold-miner.README.md

237 lines
23 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.

# 黄金矿工 Postman 测试
前端字段定义与接入流程见 [前端接口文档 V1.7](../FRONTEND-API.md)。
本文件对应本分支实际实现的 [接口协议](../README.md)。共 48 个请求(47 个 POST JSON、1 个 GET),含响应断言和测试变量传递。配套文件:
- [Collection v2.1](gold-miner.postman_collection.json)
- [环境模板](gold-miner.postman_environment.json)
- [环境变量中文说明](gold-miner.environment.zh-CN.md):逐项说明用途、填写方式、默认值及自动变量。
文件统一位于 `laf-cloud/functions/goldMiner/postman/`,按当前分支代码重新生成。接口地址已适配目录调整:
| 用途 | 地址 |
| --- | --- |
| 公共活动日程 | `GET/POST {{baseUrl}}/activityConfig/list`,无需登录 |
| 玩家活动 | `POST {{baseUrl}}/goldMiner/index` |
| 管理配置 | `POST {{baseUrl}}/goldMiner/admin` |
| 通关、金币及微信支付 | 沿用 `/userLevel`、`/userCoin`、`/wx/*` |
旧文件中的 `/goldMiner` 和 `/goldMinerAdmin` 已不作为本 Collection 的请求地址。普通周活动期 ID 为 `goldMiner:YYYY-MM-DD`,测试临时期为 `goldMiner:test:标识`。两者都必须原样使用服务端返回的 periodId;`goldMiner` 通关参数及 `goldMiner.claim` 奖励交付标识保持不变。
## 导入与运行
1. 在 Postman 中 Import 上述两个 JSON,选择“黄金矿工 - 环境模板”。
2. 填写 `baseUrl`(部署应用地址,无末尾 `/`)。只查第 08 组不需要账号;玩家接口另填 `uid/token`,管理接口另填 `adminToken`。
3. 可以先运行 `08 公共活动日程`,再运行 `01 基础查询与鉴权`。这两组可分别使用 Runner,其余组按场景逐条运行,**不要运行整个 Collection**。
4. 查看每个请求的 Tests 结果。前置变量缺失会跳过发送并在 Console 提示原因,跳过不等于测试通过。
使用支持 [`pm.execution.skipRequest()`](https://learning.postman.com/latest-v-12/docs/tests-and-scripts/write-scripts/postman-sandbox-reference/pm-execution) 的 Postman;本包未验证旧版 Newman 兼容性。变量统一保存在所选环境,避免创建同名全局变量、Collection 变量或 Runner 数据列覆盖它们。
仓库有完整发布示例,但示例不会自动启用活动,数值和生效日期需要自行确认。无已生效配置时 `status=unavailable` 是有效响应,通关/购买成功场景需先完成测试环境部署和配置。`goldMiner/jobs` 是内部定时入口,不提供 HTTP 测试请求。
活动查询已改用单一 `status` 和任务五态 `claimStatus`;请重新导入更新后的 Collection 和环境模板,旧 expectedAvailability、expectedEntitlementSource 变量不再使用。活动内仍是授权、保存、确认,info 不包含领取凭证;活动内 issuing 重试 claim,结束后从 settlements 获取原 grantId。
## 当前接口索引
下面均以 baseUrl 为地址前缀。除公开日程、管理接口和支付通知/票据外,玩家请求使用 uid/token 鉴权。Postman 每个请求内包含场景参数、返回断言和操作前置条件,完整玩家字段定义见 [前端接口文档](../FRONTEND-API.md)。
| 地址 / action | 请求参数(除 uid/token) | 主要返回字段 |
| --- | --- | --- |
| GET/POST activityConfig/list | 无;POST 为 `{}` | schemaVersion、serverNow、windowEndsAt、refreshAt、activities |
| POST goldMiner/index / info | action | status、periodId、tasks;有效且达资格时含时间、商品、价格、progressWins、maxTarget |
| POST goldMiner/index / create_order | channel=legacy_ios、itemid、createRequestId | outTradeNo、periodId、priceFen、productId、quantity、channel、expiresAt、sessionFrom |
| POST goldMiner/index / claim | periodId、taskId、requestId | grantId、taskId、items、claimStatus、claimedThrough、requiresClientDelivery |
| POST goldMiner/index / confirm_delivery | periodId、taskId、grantId | grantId、claimStatus、claimedThrough |
| POST goldMiner/index / settlements | afterId(可选);分页大小由后端控制 | status、items[{settlementId,periodId,rewards}]、nextCursor |
| POST goldMiner/index / confirm_settlement_delivery | settlementId、grantIds(1~100 个不重复 ID) | settlementId、confirmedGrantIds、deliveryStatus |
| POST goldMiner/index / ack_settlement | settlementId | settlementId、acknowledged;仅旧展示确认 |
| POST userLevel / read 或 save | save 时 levelAmount、goldMiner 事件;无尽另带 isWuXian | 主线存档;save 时 data.goldMiner 包含本次活动计数结果 |
| POST userCoin / read 或 save | save 时 coinAmount 为总余额 | coinAmount;不能把奖励增量直接作为总余额保存 |
| POST wx/orderPaySig 或 wx/iosorderPaySig | itemid、createRequestId | outTradeNo、signData、signature、paySig |
| POST wx/getPayInfo、wx/iosgetPayInfo、wx/getOrderReward | outTradeNo | 已支付:pay_state、goldMiner 履约状态、rewardDelivery;未支付:PAYMENT_PENDING |
| POST wx/checkIos | outTradeNo,玩家登录态;外部支付页可用 openid/time 票据 | boolean;true 只说明关联成功 |
| POST goldMiner/admin / setup_indexes | adminToken | code、msg |
| POST goldMiner/admin / publish | adminToken、config(未来周配置) | 冻结配置快照 |
| POST goldMiner/admin / set_purchasable | adminToken、periodId、purchaseEnabled | code、msg |
| POST goldMiner/admin / publish_test_period | adminToken、periodId、startsAt、endsAt、config,可选 nextPeriodId | 周期、顺延目标、configVersion、configSnapshot、configHash |
Collection 还包含 wx/KeFuInfo、wx/payCallBack、goldMiner/merchantNotify 的旧渠道及无效通知场景;有效支付通知必须由可信支付渠道产生,不能用管理员发布接口代替支付。
## activityConfig/list:公共活动日程
第 **08** 组提供 GET 和 POST 两种请求。它不需要 uid/token/adminToken,不读取玩家记录,不会报名、购买或领取奖励。POST 请求体仅 `{}`,不传 action。
成功格式:`{code:1,msg:"ok",data:{schemaVersion,serverNow,windowEndsAt,refreshAt,activities}}`。
| 返回字段 | 类型 | 含义 |
| --- | --- | --- |
| schemaVersion | number | 当前为 1 |
| serverNow | number | 服务器时间,Unix 毫秒 |
| windowEndsAt | number | serverNow + 七天;日程开始时间必须小于此边界 |
| refreshAt | number | 最晚建议刷新时间:30 秒后与最近开始/结束边界取较早值 |
| activities | array | 当前开放及未来七天内开始、尚未结束的活动;可以为空 |
| activities[].activityId | string | goldMiner / cloudRise,用于区分黄金矿工和百人赛 |
| activities[].periodId | string | 期 ID;普通周周期或 goldMiner:test: 临时期等,原样使用 |
| activities[].configVersion | string | 本期选中的配置版本 |
| activities[].startsAt / endsAt | number | 毫秒起止时间,开始包含、结束不包含;百人赛指报名窗口 |
| activities[].unlockLevel | number | 已通过主线关卡的资格门槛,不表示当前玩家已达标 |
| activities[].phase | string | active / upcoming |
| activities[].purchaseEnabled | boolean | 仅黄金矿工有此字段;不表示玩家是否已付费 |
同玩法按 startsAt 倒序、periodId 升序排列;选择当前活动要先过滤 active,不能直接拿第一条 upcoming 当成当前期。临时期开放时优先返回临时期,隐藏当前普通周活动条目,与 info 选期一致。到 refreshAt、开始/结束边界应重新查询。
`code:1, activities:[]` 表示没有日程;`code:0, data:null` 表示查询失败。脚本只在返回结构校验成功后写入 gmActivitySchedule,失败保留原缓存。该变量与 info 的 periodId、gmInfo、领取凭证独立,公共列表不覆盖玩家活动状态。切换应用或账号会清理旧上下文并跳过第一次请求,重新发送即可。
请求附带“临时期日程”“空列表”“查询失败”三个响应示例。完整接口说明见 [首页活动日程文档](../../activityConfig/LIST-API.md)。
## 变量
| 变量 | 用法 |
| --- | --- |
| `baseUrl` | 所有请求必填;模板不包含真实地址 |
| `uid`、`token` | 玩家请求必填;公开日程和管理请求不需要 |
| `expectedStatus` | 可选,指定 `unavailable/locked/purchasable/purchase_disabled/unlocked`;留空仅验证状态结构 |
| `expectedProgressWins` | 可选,查询时额外断言累计通关数;场景切换后清空 |
| `mainLevelAfterWin` | 主线填刚读取的 `currentMainLevel+1`;无尽填 `currentMainLevel`,不能随意覆盖存档 |
| `endlessSequence` | 无尽胜利的唯一正整数序号,同账号同一期不能复用旧序号表示新胜利 |
| `expectedProgressResult` | `counted`(默认)、`qualification`(第 41 关)、`capped`(已封顶) |
| `expiredPeriodId` | 已结束的合法普通期或测试临时期 ID,直接复制原期 ID |
| `expectedPaymentState` | 默认 `pending`;收到真实可信支付通知后改为 `paid` |
| `expectedFulfillmentRoute` | 已支付查单期望值:`current_period/settle_original/carry_next` |
| `expectedTargetPeriodId` | 已支付查单必填;普通/原期补发填订单原期,顺延填实际目标期(默认下一周四,也可能是指定的下一临时期) |
| `openid` | 仅无效签名通知测试需要,填写订单所属账号的真实 openid |
| `claimPeriodId`、`claimTaskId` | 活动内人工选择领取目标;补发选择脚本也会设置这两个字段,但仅供保存金币时核对,不调用 claim |
| `coinAfterDelivery` | 领取后先读金币,再人工填写“当前总余额 + 本次授权金币数”,不是奖励增量 |
| `settlementId` | 选择接口返回的 `settlementId`;不是 periodId,也不是数据库文档的 `_id` |
| `adminToken` | 管理请求专用,对应当前服务端 `ADMIN_TOKEN` |
| `configJson` | 管理发布请求使用的完整配置对象 JSON;默认空,不会填入假定的商业数值 |
| `adminPeriodId`、`purchaseEnabled` | 修改有效配置对应期的购买开关,后者填写文本 `true` 或 `false`,脚本转换为 JSON boolean |
| `expectedListedPeriodId` | 第 08 组可选:断言指定黄金矿工期存在于当前/未来七天日程,留空不限定 |
| `gmActivitySchedule` | 第 08 组缓存的完整成功日程;失败时不覆盖,不会写入玩家 periodId |
| `tempPeriodId/tempStartsAt/tempEndsAt` | 第 06-04 临时期的 ID 与毫秒起止时间;留空首次自动生成,重复请求复用 |
| `tempDurationMinutes` | 未填写结束时间时使用,默认 30 分钟 |
| `tempConfig/tempNextPeriodId` | 临时期完整奖励配置 JSON / 可选顺延目标 |
| `tempDraftBaseUrl` | 临时发布脚本记录的目标环境,用于阻止跨服务器误用草稿 |
`gm*`、`periodId`、`productId`、`priceFen`、`firstTaskId`、`secondTaskId`、`currentMainLevel`、`outTradeNo`、`orderPeriodId`、`grantId`、`coinBeforeDelivery`、`settlementCursor` 由脚本维护。查询当期不会覆盖手选的历史领取目标;切换应用或账号后会清理旧业务上下文并提示重新查询。首次导入环境时将所有运行时变量留空。
`token/adminToken/gmWinBody` 标记为 secret,其中运行后的 `gmWinBody` 包含原请求的 token。运行后的环境导出视为敏感文件,不要提交或共享。
## 场景操作
### 通关和去重
先读活动信息和主线存档,再选 `02` 的主线或无尽新胜利。每次新胜利前重新查询活动信息,断言会用该进度快照检查是否准确增加 1。主线必须顺序推进一关,无尽保留主线关卡数。
新胜利请求生成 eventId;“原事件重试”复用原请求的 periodId、序号、模式和 eventId,刷新登录 token 不改变事件。重复请求应返回 `duplicate=true`、进度不增长。紧接着可用“同一事件 ID 改变通关载荷”检查 `EVENT_PAYLOAD_CONFLICT`,修改仅发生在活动参数中,不会将主线 levelAmount 加一。
第 41 关用例需要初始主线存档为 40、活动已开放配置;设 `expectedProgressResult=qualification`、`mainLevelAfterWin=41`。期望本关不计数,随后查询得到活动资格。封顶用例设 `capped`:旧单档配置或已锁定报价的 VIP 礼包须达到最后一档目标;未创建订单的 VIP 礼包需达到六档中的最高最终目标。资格关和封顶的新事件不会写入去重条目,不能套用重复事件断言。
旧 `userLevel` 的存档和统计仍先执行,再返回 `data.goldMiner` 子结果,测试分别检查两层 code。**无尽重试仍可能增加旧 addLevel 等统计**;这些场景使用独立测试账号,活动去重不代表旧统计也去重。主线一次跨越超过 10 关会被原接口拒绝,本包不会用跳关准备数据。
### 支付
活动查询确认 `status=purchasable` 后,Android/iOS 下单二选一;脚本故意提交 `itemPrice=1/itemCount=999`,检查签名仍使用配置价格及数量 1。创建后,在支付前执行“换 requestId 仍复用同一期订单”,验证订单号不变。
未支付时保持 `expectedPaymentState=pending`,三个查单/通用领取入口均必须返回 `PAYMENT_PENDING`。无效签名回调测试后再次查单,确认仍未解锁。不能仅凭回调返回失败就判定订单状态未变。
实际支付需从客户端完成并收到可信渠道通知;本包不包含签名密钥或伪造成功支付入口。确认后设 `paid` 并填写预期路线/目标期,再查单。查单成功只证明活动权益已交付,金币通过任务领取链路发放。
### 旧 iOS 客服渠道
第 07 组使用独立的未购买账号,先查询可购买的活动,再预下单并重复下单检查订单号。`legacySessionFrom` 自动保存服务端签发的客服票据,标为 secret,切换账号/应用后自动清空。服务端部署前置条件见 [旧渠道说明](../LEGACY-PAYMENT.md)。
第 03 项会真实发送客服消息,仅在填写 `openid`、处于微信客服有效会话窗口并设置 `allowCustomerMessage=true` 后发送;默认跳过。发送成功后在微信打开链接付款。第 04 项使用登录态调用 `checkIos`,可重复调用,**转单成功不等于付款**。第 05、06 项验证无效转单票据、无签名通知被拒绝;第 07 项须在未支付时验证原生渠道不能再开单。
付款后的三个查询入口复用第 03 组“查单”请求。旧渠道通知丢失时可主动查微信商户结果,验签成功才解锁。网络失败、未到查询重试时间等情况不要当作成功;按错误码重试并检查活动状态。本包不模拟成功商户通知,不包含 API v3 密钥。
### 任意档位领奖与金币保存
手填 `claimPeriodId/claimTaskId` 后,逐条执行 `04`:授权 → 重复授权检查 → 读取余额 → 人工填写 `coinAfterDelivery` → 保存总余额 → 确认领取。负向用例使用未付费或已付费未达标状态;04-08 为成功用例,可跳过前档领取已达标任务;不能与成功链路全部连跑。
授权不会加币。保存成功才记录本地 `gmSavedGrantId`,确认请求会检查其匹配当前凭证。重复授权得到相同 grantId,重复确认不推进两次;确认后再次执行活动查询检查下一档状态。测试下一档时重新选择任务,再从授权开始。
第 04 组的余额保存是在隔离测试账号上模拟客户端已有协议,不能和在线客户端或其他设备同时改余额。若保存超时,先核对服务端总余额、原余额及同一 grantId,未确认结果前不能重新加一次奖励。脚本不提供跨设备资产去重保证。若真实客户端已完成发货,不要再次用该模拟保存步骤加币。
### 到期、补发和延迟支付
到期后用 `05` 查询清单,返回 settlementId、periodId 和 rewards;奖励项包含原 grantId,无需调用 claim。使用 05-05 选择授权、04-03/04 保存金币、05-06 确认补发。已准备好的奖励优先返回 pending_delivery,不受其他期结算阻塞。前端不传 limit;有 nextCursor 就继续翻页,包括 settling 响应。扫描结束后从第一页复查,settling 时稍后再查;no_pending_rewards 才表示该玩家当前环境下全部已结束期均无待发或待结算记录。旧 ack_settlement 未全部完成时仍返回 DELIVERY_PENDING,新流程无需调用它。
| 场景 | 前置条件及验收 |
| --- | --- |
| 周期边界 | 普通期校验周四 00:00 开始、持续四天;测试临时期校验指定窗口,不强制周四或四天。边界为 startsAt <= serverTime < endsAt;无活动时设 unavailable |
| 开始前开局、期间结算 | 在活动开放后首次发送成功胜利,预期计入;请求不使用开局时间 |
| 结束后才提交 | 第 02 组过期请求:旧期 ID + 从未记录的序号,活动子结果 `PERIOD_ENDED`;旧存档接口仍可能成功 |
| 已付费到期有达标档 | 读取清单,只有尚未领取且达标的档位待发;逐档保存确认;未达标档失效 |
| 未付费到期 | 不生成可发金币的补发权益,不能结束后新购旧期;下一期开新进度 |
| 延迟支付且原期已达标 | 期内创建订单,结束后首次可信支付履约;查单期望 `settle_original`,target 为原期,原期清单可领取 |
| 延迟支付且原期零达标 | 同样延迟履约,查单期望 `carry_next`,target 为紧接下一期;下一期开启后 info 的 status=unlocked,原期进度不继承;info 不再返回权益来源,顺延路线由支付查单断言验证 |
| 正常下一期 | 首次进入前无新胜利,设 `expectedProgressWins=0`;上一期正常购买不解锁本期 |
时间和支付前置条件需在独立测试部署通过真实时序或服务端测试夹具准备。本 Collection 没有改服务器时间、重置玩家、伪造已支付的隐藏接口;数据库快照冗余、后台并发与定时重试仍由后端专项测试和部署联调验证,不能由 Postman 结构断言替代。
## 管理配置
管理组逐条执行,先配置服务端密钥并创建索引;发布 configJson 时填入已确定的价格、各档目标和金币数。结构如下,尖括号和 null 均须替换,**不是可直接发布的配置**:
```json
{
"configVersion": "gold-miner-v1",
"effectiveFromPeriodId": "goldMiner:<未来周四的 YYYY-MM-DD>",
"unlockPassedLevel": 41,
"timezone": "Asia/Shanghai",
"productId": "gold_miner",
"priceFen": null,
"currency": "CNY",
"tasks": [
{ "taskId": "task_1", "sequence": 1, "targetWins": null, "items": [{ "type": "coin", "count": null }] }
]
}
```
任务档数可增加,sequence 从 1 连续递增,targetWins 严格递增,金币为正整数。购买开关适用于有效配置对应的普通期或已发布临时期;不会创建或改写任务奖励。普通配置 action=publish 仍要求未来周四生效,不能借此中途换奖励。
## 本地验证
业务失败请查看响应 `errorCode` 和 `msg`。当前黄金矿工会把配置错误细化到字段路径,例如 `config.priceFen 必须为大于 0 的安全整数`、`config.tasks[1].targetWins 必须大于前一档目标(3)`;一次返回首个错误,修正后重新提交。临时期时间重叠会返回冲突期,支付配置错误会指出对应环境变量名。Postman 断言仍按 errorCode 判断,不依赖固定的中文 msg。
这部分提示需部署更新后的 `goldMiner/config`、`goldMiner/admin`、`goldMiner/testPeriods`、`goldMiner/service`、`goldMiner/payment`、`goldMiner/merchant`、`goldMiner/legacyPayment` 才会生效,不涉及数据库迁移。
```powershell
node --test laf-cloud/functions/goldMiner/tests/gold-miner-postman.test.mjs
```
检查 JSON 结构、全部脚本语法,并用模拟响应验证进度重试、支付状态断言、余额保存/确认顺序、分页和账号隔离,以及公开日程 GET/POST、空列表、失败缓存、时间排序和临时期发布/重试。该检查不发送网络请求,不代表实际云端接口或真实支付已联调通过。
## V1.4 到期结算联调
先部署新版 goldMiner/service、goldMiner/index、goldMiner/jobs,并确认每分钟触发器已启用。查询不再代替后台结算。
- 05 文件夹 01/02:查询全部历史未确认奖励。前端不传 limit;有 nextCursor 就翻页(包括 settling),本轮结束后从第一页复查。已准备好的奖励优先返回,no_pending_rewards 才表示当前玩家无待发或待结算记录。
- 05 文件夹 05:选择返回的第一个补发授权,保存 settlementId、原 grantId、奖励及所属期;不调用 claim。
- 然后执行 04 文件夹 03/04 读取并保存金币,最后执行 05 文件夹 06 确认补发。脚本仍要求所选 grantId 的金币保存已成功。
- 05 文件夹 07:验证过期普通 claim 返回 PERIOD_SETTLEMENT_REQUIRED。
- 05 文件夹 03/04 的 ack_settlement 仅兼容旧展示确认,不属于新发货流程。
一次补发查询仅返回未确认项。原本已在前端保存金币的 grantId 只能补确认,不能再加金币。需要重试原确认时保留参数;全部确认后重新查询奖励会消失。
## V1.5 公共配置与集合精简
玩家接口仍使用 V1.4 协议,Postman 请求参数不变。发布配置使用 [完整黄金矿工请求示例](../config.publish.example.json);goldMiner/admin 将参数包装到 activityConfigs。切换现有环境前必须完成 [数据迁移](../../activityConfig/MIGRATION.md),先部署 activityConfig/store,后台任务已改为按待处理状态扫描,不再使用游标集合。
## 临时开启测试期
主 Collection 第 **06-04** 已包含 `publish_test_period`,无需再单独导入临时期 Collection。服务器必须同时设置 `PAYMENT_APP_ENV=test`、`GOLD_MINER_TEST_PERIODS_ENABLED=true`。填写 adminToken 后默认立即开 30 分钟,门槛 41、价格 100 分、累计 1/2/3 次胜利奖励 100/200/300 金币,可发送前修改 tempConfig。自动生成的 ID/时间保存到当前环境,重复 Send 不创建新期。
发布后查询 08 日程和 01 info,再继续通关、支付、领奖及补发流程。新建另一临时期时,使用新的 ID 与不重叠的时间;修改 tempDurationMinutes 不会重算已保存的 tempEndsAt。需要重新生成时先清空 tempPeriodId/tempStartsAt/tempEndsAt。跨环境使用另一份环境模板;顺延到另一临时期须先发布下一期。完整规则见 [临时期说明](../TEST-PERIODS.md) 和 [临时期 Postman 参数说明](gold-miner-test-period.README.md)。
## VIP 六档联调
将 [VIP 发布示例](../vip-tiers.example.json) 中的 config 对象填入 configJson,使用 06-02 发布未来周配置。临时期完整请求见 [VIP 临时期发布示例](../vip-test-period.publish.example.json):请求顶层必须有 startsAt/endsAt(Unix 毫秒);使用 06-04 时,把 config 对象填入 tempConfig,把 periodId/startsAt/endsAt 分别填入 tempPeriodId/tempStartsAt/tempEndsAt。六个 productId 必须对应支付渠道中的真实商品。不要把完整发布请求(含 action/adminToken)填入 configJson。
切换测试账号的 users.vip_level 后查询 info,检查服务器选择的价格和任务;缺失或不合法时回退 VIP0,已付费的 VIP0 账号也不被额外拦截。未创建订单前 VIP 变化可刷新礼包,创建订单后锁定。未付费达标为 pending_unlock;付费后每个达标任务都可领取,04-08 测试跳过前档领取。claimedThrough 只是兼容的连续已确认档数,乱序确认时可能不增长或一次增长多档。