# 上线检查清单（Go-Live Checklist）

> docId：`XD-OP-11` ｜ version：`1.0.0` ｜ status：`PUBLISHED`

平台**不提供**沙箱/测试应用/回调模拟器（见 [接入指南 · 联调支持边界](./02-integration-guide.md#10-联调支持边界重要)）。所以**上线前请逐条自检本清单**——每一条都能在你自己的环境里验证，不需要平台配合。全部打勾前不要接真实流量。

## A. 凭证与签名

- [ ] **A1 RSA2 golden 向量自检**：用一个固定的请求（固定 `METHOD`/路径/query/时间戳/nonce/`requestId`/`Content-Type`/body），确认你算出的**规范串**与 [`examples/`](../examples/)（**在公开仓与「下载接入包」内；不在「下载文档包」内**）参考实现**逐字节一致**（含空 query 的空行）。
- [ ] **A2 关键归一化逐条验证**：URL 路径解码一次、query 按 RFC3986 重编码并**按键名排序**、`Content-Type` **小写去 `;` 参数**、body 哈希取**原始字节**。**响应验签侧同样要归一化**（响应头通常是 `application/json; charset=utf-8`，参与签名的是 `application/json`）。
- [ ] **A3 私钥纪律**：私钥只在你自己的服务器/密钥服务；**不在浏览器、不在仓库、不在日志**（grep 一遍构建产物与日志配置）。
- [ ] **A4 时钟**：服务器开启 NTP，与标准时间偏差在容许窗口内（否则会出现「偶发 401」）。
- [ ] **A5 nonce 唯一性**：nonce 由高质量随机源生成且**每次请求都不同**（含重试）。
- [ ] **A6 响应验签**：对带 `X-XD-Response-*` 四头的响应做 `XD-Response-v1` 验签，且**平台公钥来自固定文档页/门户**，不是从响应里取。**鉴权链之前的拒绝（来源 IP 403、请求体门卫 400/413、六头形态 400、验签失败 401、nonce 重放 409）不带这四个头**——代码要按「四头齐备才验」处理，别把缺头当篡改丢弃（**平台签名密钥不可用时的 `503` 也不带四头**）。参考实现见 [`examples/node/verify_response.js`](../examples/node/verify_response.js)（含 `--golden` 自检，不需要密钥；**在公开仓与「下载接入包」内；不在「下载文档包」内**）。
- [ ] **A7 平台公钥入库**：把 [接入指南 · 平台公钥与指纹](./02-integration-guide.md#31-平台公钥与指纹公示) 的公钥**按 `kid` 存进你方配置**（不是每次请求去拉），并本地算一遍指纹与该页公示值逐字符比对。

## B. 下单与幂等

- [ ] **B1 `requestId` 幂等**：重试（超时/5xx）**复用同一个 `requestId` 与同一请求体**；有代码级保证，不是靠人记得。
- [ ] **B2 业务幂等**：`outTradeNo` 由你自己的订单系统生成且稳定；**重试不换号**。
- [ ] **B3 `409` 处理**：收到 `409` 时的动作是「**先查单**」，不是换号重下单（写进你的错误处理代码，别只写在文档里）。
- [ ] **B4 严格请求体**：带请求体的两个端点（创建订单/创建退款）请求体不存在 schema 外字段（多传字段会被 `400` 拒）；**所有 POST 都带 `Content-Type: application/json`**（含「无请求体」的重拉起/关单——它们可以不带请求体，但不能不带这个头）。
- [ ] **B5 `tradeScope` 申报**：按你申报的经营范围正确传参；双申报应用记得必填。

## C. 收款材料与终端

- [ ] **C1 收款材料只从响应取**：`qrCode`/`payUrl` 都直接用响应原值，**不拼接、不改写、不转发第三方**。
- [ ] **C2 官方码防呆复检**：渲染 `qrCode` 之前校验前缀，**非法值不渲染、不报错、不打印**（回退 `payUrl` 中转链）。
- [ ] **C3 过期语义**：理解「查询接口 `qrCode`/`payUrl` 恒空」「重拉起才换新码」，代码里**没有**拿旧码长期展示的分支。
- [ ] **C4 App 宿主内**：自有 App 用**系统浏览器**打开收银链，**没有** WebView 内嵌收银页的路径。
- [ ] **C5 终端矩阵自测**：用 [demo 的终端预览](../demo/h5-cashier/)（**只在公开仓提供，不在门户下载包内**）或真机走一遍 PC / 手机微信外 / 手机微信内三种形态，确认与[矩阵](./06-cashier-integration.md)一致；**先确认你要用的通道与交易形态已放行**（未放行的组合下单返回 `422`，属正常拒绝，不要试探）。
- [ ] **C6 微信外文案**：若你在自己页面复述引导文案，与[逐字文案](./06-cashier-integration.md#4-手机微信外推荐路径逐字引导文案)一致（不要把「复制链接并打开微信」改成别的说法，也不要承诺「点一下就到支付面板」）。

## D. 终态与事件

- [ ] **D1 终态判据**：全代码库搜一遍，确认**没有**任何地方把「收银页回跳 / 页面状态 / 用户点击」当作支付成功。
- [ ] **D2 事件验签**：`XD-Webhook-v1` 用**原始字节**算哈希验签；验签失败**不落账**。
- [ ] **D3 `eventId` 去重**：`eventId` 建**唯一索引**，且**去重行与业务写在同一事务**；重复投递直接丢弃但仍回 `success`。
- [ ] **D4 响应体**：成功时返回 **2xx** 且响应体字节**正好**是 `success`（无 JSON 包装、无多余空白）。
- [ ] **D5 乱序兼容**：用**订单/退款状态机**判新旧（事件体里的 `stateVersion` 当前恒为 `0`，不要用它），**不假设**事件按序到达。
- [ ] **D6 查单补偿**：有一条**定时/触发式**的查单补偿任务（事件丢失、长期未收敛时兜底）。
- [ ] **D7 `UNKNOWN` 不判死**：订单/退款为 `UNKNOWN` 时**不**重新下单、**不**重新发起退款、**不**给买家提示失败。
- [ ] **D8 回调地址**：`notifyUrl` 是绝对 HTTPS、公网可达、**host 属于你已申报的域名**（归属验证可选、不影响生效）、path 非裸 `/`；本地/内网地址不上线；已在门户「应用配置变更」提交并**已生效**（未配置或校验未通过=平台不会产生任何事件）；接口能承受重复投递。

## E. 退款与对账

- [ ] **E1 退款幂等**：`outRefundNo` 稳定；`UNKNOWN` 的退款**不换号重试**。
- [ ] **E2 累计上限**：有本地校验「累计退款 ≤ 实付」，且以平台状态为准。
- [ ] **E3 每单投影入账**：入账使用每单的 `feeProjection`（含 `ruleVersion`），代码里**没有**硬编码费率表。
- [ ] **E4 每日对账**：有一个日对账任务，覆盖「平台成功/我未成功」「我成功/平台未成功」「金额不一致」三类差异。

## F. 安全与运维

- [ ] **F1 IP 白名单**：你的生产出口 IP 已在门户白名单内（**含**灾备/多可用区出口）；来源 IP 校验**默认开启**，可在门户自助关闭（不建议——关闭后任何来源都能用你的密钥调用）。
- [ ] **F2 日志脱敏**：日志里没有私钥、完整签名材料、完整请求体、买家个人信息；排障只留 `requestId`。
- [ ] **F3 浏览器侧**：承载收款材料的页面不引入第三方 CDN/统计/字体，不把材料地址写进 `localStorage`/`sessionStorage`/Cookie。
- [ ] **F4 `returnUrl`**：只用于展示与轮询，**不带**交付内容、不带 token。
- [ ] **F5 退避策略**：`429`/`503` 走指数退避且有上限；`422`（通道未放行）**不重试**。
- [ ] **F6 告警**：对 `401`（签名异常）、`403`（来源/状态）、`502`、事件投递失败率配告警。

## G. 上线动作

- [ ] **G1 首单计划**：安排一次真实小额首单，明确谁盯、看什么指标（订单状态、事件到达、结算视图）。
- [ ] **G2 陪跑申请**：如需平台协助，通过官网反馈渠道提交首单计划（**不承诺 SLA**）。
- [ ] **G3 回滚预案**：明确「关掉下单入口」的开关位置与话术（不要用改配置/改代码的方式紧急止血）。
- [ ] **G4 材料留档**：本次接入的签名 golden 向量、事件验签测试结果、终端矩阵自测记录留档（用于后续变更比对）。

- [ ] **G5 域名归属（建议项，非准入）**：申报清单里的每个域名建议都完成一次归属验证（见 [接入指南 · 域名归属验证](./02-integration-guide.md#2-域名归属验证可选建议完成)）；未验证不影响开通，但验证后归属更明确。

> **下列准入前提是你自己要办好的**（不是平台代劳）：**签署**开放平台协议与合规报送同意书、**出口 IP 白名单**（或你已明确决定关闭来源校验）、**notifyUrl 已提交并已生效**；平台侧只管应用状态、商家状态与通道放行。若上线后发现**新增下单被拒**类错误，先看 [错误码与排障](./04-errors-and-troubleshooting.md) 的 403 组。
