refactor(payment): 支付插件 - 宿主仅通过 RPC 包加载并保护订单版本

This commit is contained in:
ddCat
2026-09-02 16:15:57 +08:00
parent d6bbdbe27b
commit 38e715ea3f
45 changed files with 1584 additions and 203 deletions

View File

@@ -85,6 +85,18 @@ description: 影策后端核心持久化表与状态边界
- `idx_project_asset_candidates_project_unit_status`、`idx_project_asset_candidates_project_status_category`:章节候选和待确认分类队列。
- `idx_tasks_user_project_created`:项目任务恢复读取。
## 支付与插件版本
| 表 | 用途 | 关键边界 |
| --- | --- | --- |
| `topup_products` | 保存服务端维护的充值商品、金额和积分快照 | 客户端只能提交商品 ID;金额和积分由 service 读取,不能由请求覆盖 |
| `payment_provider_configs` | 保存支付插件某个渠道配置的不可变版本 | `provider_id + version` 唯一;密钥只保存加密密文;`plugin_id` / `plugin_version` 记录配置对应的插件版本 |
| `payment_orders` | 保存充值订单、幂等键、渠道交易号和入账状态 | 创建订单时固定 `plugin_id`、`plugin_version`、配置 ID 与配置版本;回调、查单、关单必须使用同一运行时版本 |
| `payment_notifications` | 保存已验签的支付通知收件箱 | 以渠道事件 ID 幂等;只保存用于异步入账的标准化证据,重复通知不会重复发放积分 |
| `payment_reconciliation_runs` / `payment_reconciliation_items` | 保存渠道账单下载和对账结果 | 账单只能作为发现线索,金额、币种和交易号仍需由插件查单确认;历史订单继续绑定原插件版本 |
支付宝、微信及后续聚合平台都只作为支付插件包提供 `yingce.payment/v1` 适配器,宿主数据库不保存平台专用字段。插件升级不会改写历史订单的 `plugin_version`;存在未完成订单时,原插件版本和配置必须继续可解析通知、查单和关单。
## 模型渠道与目录
| 表 | 用途 | 关键边界 |

View File

@@ -0,0 +1,64 @@
# 支付插件运行时
支付渠道通过 `.yingce-plugin` 包接入。宿主只负责订单、幂等、配置加密、回调收件箱、积分入账和对账;插件负责渠道协议转换。
## 包结构
```text
my-payment.yingce-plugin
├── manifest.json
├── backend/provider
├── assets/icon.svg
└── docs/README.md
```
Manifest 的支付贡献声明 `runtime.backend` 为 `rpc` 或 `wasm`,并通过 `runtime.backendEntry` 指定后端入口。当前版本首先启用 `rpc`:宿主以一次 JSON 请求启动入口进程,进程返回一次 JSON 响应。WASM 使用相同的 `yingce.payment/v1` 数据契约,运行时启用后即可复用插件实现。
## 标准操作
入口进程接收以下操作名:
| 操作 | 返回值 |
| --- | --- |
| `validate_config` | 空数据;失败返回 `ok:false` |
| `create_order` | `Checkout`:`mode`、`value`、`expiresAt` |
| `query_order` | 标准 `Result` |
| `close_order` | 标准 `Result` |
| `verify_notification` | `Notification`,请求体通过 `bodyBase64` 传入 |
| `download_trade_bill` | `BillRecord[]` |
请求固定带有 `version: "yingce.payment/v1"`。插件不得访问宿主数据库,不得自行入账积分。宿主目前控制进程工作目录、环境变量、标准输出大小和 30 秒超时;支付宝、微信实现还会在插件内部校验网关和账单下载域名。通用插件的操作系统级沙箱、签名校验和网络白名单尚未启用,不应直接运行不受信任的支付插件。
## Manifest 示例
```json
{
"apiVersion": "yingce.plugin/v1",
"id": "example-aggregate-payment",
"name": "Example 聚合支付",
"version": "1.0.0",
"author": "Example",
"enabled": true,
"runtime": { "backend": "rpc", "backendEntry": "backend/provider" },
"configuration": {
"fields": [
{ "name": "merchantId", "type": "string", "required": true },
{ "name": "secret", "type": "password", "required": true, "secret": true }
]
},
"contributes": {
"paymentProviders": [{
"id": "example-qr",
"label": "Example 聚合支付",
"icon": "assets/icon.svg",
"checkoutMode": "qr_code",
"identityFields": ["merchantId"],
"expiryPolicy": { "defaultMinutes": 30, "minMinutes": 5, "maxMinutes": 1440 },
"notificationSuccess": { "status": 204 },
"notificationFailure": { "status": 400 }
}]
}
}
```
历史订单绑定插件版本和包哈希。升级不会替换未完结订单所需的运行文件;宿主检测到未完结订单时会拒绝支付插件升级或卸载,直到订单进入终态。签名根、WASM 执行器和通用网络白名单将在后续安全阶段加入。