codex基础代码更新

This commit is contained in:
技术老胡
2026-03-20 10:31:13 +08:00
parent 7e545f0621
commit f3919c9899
36 changed files with 5060 additions and 1459 deletions

View File

@@ -1,145 +0,0 @@
# 认证策略设计说明
## 设计理念
采用**策略模式**替代中间件方式处理认证,具有以下优势:
1. **灵活扩展**可以轻松添加新的接口标准如易支付、OpenAPI、自定义标准等
2. **按需使用**:控制器可以根据需要选择认证策略,而不是在路由层面强制
3. **易于测试**:策略类可以独立测试,不依赖中间件
4. **代码复用**:不同接口可以共享相同的认证逻辑
## 架构设计
### 1. 核心接口
**`AuthStrategyInterface`** - 认证策略接口
```php
interface AuthStrategyInterface
{
public function authenticate(Request $request): MerchantApp;
}
```
### 2. 策略实现
#### EpayAuthStrategy易支付认证
- 使用 `pid` + `key` + `MD5签名`
- 参数格式:`application/x-www-form-urlencoded`
- 签名算法MD5(排序后的参数字符串 + KEY)
#### OpenApiAuthStrategyOpenAPI认证
- 使用 `app_id` + `timestamp` + `nonce` + `HMAC-SHA256签名`
- 支持请求头或参数传递
- 签名算法HMAC-SHA256(签名字符串, app_secret)
### 3. 认证服务
**`AuthService`** - 认证服务,负责:
- 自动检测接口标准类型
- 根据类型选择对应的认证策略
- 支持手动注册新的认证策略
```php
// 自动检测
$app = $authService->authenticate($request);
// 指定策略类型
$app = $authService->authenticate($request, 'epay');
// 注册新策略
$authService->registerStrategy('custom', CustomAuthStrategy::class);
```
## 使用示例
### 控制器中使用
```php
class PayController extends BaseController
{
public function __construct(
protected PayOrderService $payOrderService,
protected AuthService $authService
) {
}
public function submit(Request $request)
{
// 自动检测或指定策略类型
$app = $this->authService->authenticate($request, 'epay');
// 使用 $app 进行后续业务处理
// ...
}
}
```
### 添加新的认证策略
1. **实现策略接口**
```php
class CustomAuthStrategy implements AuthStrategyInterface
{
public function authenticate(Request $request): MerchantApp
{
// 实现自定义认证逻辑
// ...
}
}
```
2. **注册策略**
```php
// 在服务提供者或启动文件中
$authService = new AuthService();
$authService->registerStrategy('custom', CustomAuthStrategy::class);
```
3. **在控制器中使用**
```php
$app = $this->authService->authenticate($request, 'custom');
```
## 自动检测机制
`AuthService` 会根据请求特征自动检测接口标准:
- **易支付**:检测到 `pid` 参数
- **OpenAPI**:检测到 `X-App-Id` 请求头或 `app_id` 参数
如果无法自动检测,可以手动指定策略类型。
## 优势对比
### 中间件方式(旧方案)
- ❌ 路由配置复杂,每个接口标准需要不同的中间件
- ❌ 难以在同一路由支持多种认证方式
- ❌ 扩展新标准需要修改路由配置
### 策略模式(新方案)
- ✅ 控制器按需选择认证策略
- ✅ 同一路由可以支持多种认证方式(通过参数区分)
- ✅ 扩展新标准只需实现策略接口并注册
- ✅ 代码更清晰,职责分离
## 路由配置
由于不再使用中间件,路由配置更简洁:
```php
// 易支付接口
Route::any('/submit.php', [PayController::class, 'submit']);
Route::post('/mapi.php', [PayController::class, 'mapi']);
Route::get('/api.php', [PayController::class, 'queryOrder']);
// 所有接口都在控制器内部进行认证,无需中间件
```
## 总结
通过策略模式重构认证逻辑,系统具备了:
- **高扩展性**:轻松添加新的接口标准
- **高灵活性**:控制器可以自由选择认证方式
- **高可维护性**:代码结构清晰,易于理解和维护

View File

@@ -1,214 +0,0 @@
# 支付订单表设计说明
## 一、订单表设计原因
### 1.1 订单号设计(双重订单号)
**系统订单号 (`pay_order_id`)**
- **作用**:系统内部唯一标识,用于查询、对账、退款等操作
- **生成规则**`P` + `YYYYMMDDHHmmss` + `6位随机数`P20240101120000123456
- **唯一性**:通过 `uk_pay_order_id` 唯一索引保证
- **优势**
- 全局唯一,不受商户影响
- 便于系统内部查询和关联
- 对账时作为主键
**商户订单号 (`mch_order_no`)**
- **作用**:商户传入的订单号,用于幂等性校验
- **唯一性**:通过 `uk_mch_order_no(merchant_id, mch_order_no)` 联合唯一索引保证
- **优势**
- 同一商户下订单号唯一,防止重复提交
- 商户侧可以自定义订单号规则
- 支持商户订单号查询订单
**为什么需要两个订单号?**
- 系统订单号:保证全局唯一,便于系统内部管理
- 商户订单号:保证商户侧唯一,防止重复支付(幂等性)
### 1.2 关联关系设计
**商户与应用关联 (`merchant_id` + `app_id`)**
- **作用**:标识订单所属商户和应用
- **用途**
- 权限控制(商户只能查询自己的订单)
- 对账统计(按商户/应用维度)
- 通知路由(根据应用配置的通知地址)
**支付通道关联 (`channel_id`)**
- **作用**:记录实际使用的支付通道
- **用途**
- 退款时找到对应的插件和配置
- 对账时关联通道信息
- 统计通道使用情况
**支付方式与产品 (`method_code` + `product_code`)**
- **method_code**支付方式alipay/wechat/unionpay
- 用于统计、筛选、报表
- **product_code**支付产品alipay_h5/alipay_life/wechat_jsapi等
- 由插件根据用户环境自动选择
- 用于记录实际使用的支付产品
### 1.3 金额字段设计
**订单金额 (`amount`)**
- 商户实际收款金额(扣除手续费前)
- 用于退款金额校验、对账
**手续费 (`fee`)**
- 可选字段,记录通道手续费
- 用于对账、结算、利润统计
- 如果不需要详细记录手续费,可以留空或通过 `extra` 存储
**币种 (`currency`)**
- 默认 CNY支持国际化扩展
- 预留字段,便于后续支持多币种
### 1.4 状态流转设计
```
PENDING待支付
├─> SUCCESS支付成功← 收到渠道回调并验签通过
├─> FAIL支付失败← 用户取消、超时、渠道返回失败
└─> CLOSED已关闭← 全额退款后
```
**状态说明**
- **PENDING**:订单创建后,等待用户支付
- **SUCCESS**:支付成功,已收到渠道回调并验签通过
- **FAIL**:支付失败(用户取消、订单超时、渠道返回失败等)
- **CLOSED**:已关闭(全额退款后)
### 1.5 渠道信息设计
**渠道订单号 (`channel_order_no`)**
- 渠道返回的订单号
- 用于查询订单状态、退款等操作
**渠道交易号 (`channel_trade_no`)**
- 部分渠道有交易号概念(如支付宝的 trade_no
- 用于对账、查询等
### 1.6 通知机制设计
**通知状态 (`notify_status`)**
- 0未通知
- 1已通知成功
**通知次数 (`notify_count`)**
- 记录通知次数,用于重试控制
- 配合 `ma_notify_task` 表实现异步通知
### 1.7 扩展性设计
**扩展字段 (`extra`)**
- JSON 格式,存储:
- 支付参数(`pay_params`):前端支付所需的参数
- 退款信息(`refund_info`):退款结果
- 自定义字段:业务扩展字段
**订单过期时间 (`expire_time`)**
- 用于自动关闭超时订单
- 默认 30 分钟,可配置
## 二、索引设计说明
### 2.1 唯一索引
- **`uk_pay_order_id`**:保证系统订单号唯一
- **`uk_mch_order_no(merchant_id, mch_order_no)`**:保证同一商户下商户订单号唯一(幂等性)
### 2.2 普通索引
- **`idx_merchant_app(merchant_id, app_id)`**:商户/应用维度查询
- **`idx_channel_id`**:通道维度查询
- **`idx_method_code`**:支付方式维度统计
- **`idx_status`**:状态筛选
- **`idx_pay_time`**:按支付时间查询(对账、统计)
- **`idx_created_at`**:按创建时间查询(分页、统计)
## 三、可能遗漏的字段(后续扩展)
### 3.1 退款相关字段
如果后续需要支持**部分退款**或**多次退款**,可以考虑添加:
```sql
`refund_amount` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '已退款金额(累计)',
`refund_status` varchar(20) NOT NULL DEFAULT '' COMMENT '退款状态PENDING-退款中, SUCCESS-退款成功, FAIL-退款失败',
`refund_time` datetime DEFAULT NULL COMMENT '最后退款时间',
```
**当前设计**
- 退款信息存储在 `extra['refund_info']`
- 全额退款后订单状态改为 `CLOSED`
- 如果只需要全额退款,当前设计已足够
### 3.2 结算相关字段
如果后续需要**分账/结算**功能,可以考虑添加:
```sql
`settlement_status` varchar(20) NOT NULL DEFAULT '' COMMENT '结算状态PENDING-待结算, SUCCESS-已结算, FAIL-结算失败',
`settlement_time` datetime DEFAULT NULL COMMENT '结算时间',
`settlement_amount` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '结算金额',
```
**当前设计**
- 结算信息可以通过 `extra` 存储
- 如果不需要复杂的结算流程,当前设计已足够
### 3.3 风控相关字段
如果需要**风控功能**,可以考虑添加:
```sql
`risk_level` varchar(20) NOT NULL DEFAULT '' COMMENT '风险等级LOW-低, MEDIUM-中, HIGH-高',
`risk_score` int(11) NOT NULL DEFAULT 0 COMMENT '风险评分',
`risk_reason` varchar(255) NOT NULL DEFAULT '' COMMENT '风险原因',
```
**当前设计**
- 风控信息可以通过 `extra` 存储
- 如果不需要复杂的风控系统,当前设计已足够
### 3.4 其他扩展字段
- **`user_id`**用户ID如果需要关联用户
- **`device_info`**:设备信息(用于风控)
- **`remark`**:备注(管理员备注)
- **`close_reason`**:关闭原因(用户取消/超时/管理员关闭等)
## 四、设计原则总结
1. **幂等性**:通过 `uk_mch_order_no` 保证同一商户下订单号唯一
2. **可追溯性**:记录完整的订单信息、渠道信息、时间信息
3. **可扩展性**:通过 `extra` JSON 字段存储扩展信息
4. **性能优化**:合理的索引设计,支持常见查询场景
5. **业务完整性**:覆盖订单全生命周期(创建→支付→退款→关闭)
## 五、与代码的对应关系
| SQL 字段 | 代码字段 | 说明 |
|---------|---------|------|
| `pay_order_id` | `pay_order_id` | 系统订单号 |
| `merchant_id` | `merchant_id` | 商户ID |
| `app_id` | `app_id` | 应用ID |
| `mch_order_no` | `mch_order_no` | 商户订单号 |
| `method_code` | `method_code` | 支付方式 |
| `product_code` | `product_code` | 支付产品 |
| `channel_id` | `channel_id` | 通道ID |
| `amount` | `amount` | 订单金额 |
| `currency` | `currency` | 币种 |
| `status` | `status` | 订单状态 |
| `channel_order_no` | `channel_order_no` | 渠道订单号 |
| `channel_trade_no` | `channel_trade_no` | 渠道交易号 |
| `extra` | `extra` | 扩展字段JSON |
## 六、注意事项
1. **字段命名统一**SQL 和代码中的字段名必须一致
2. **索引维护**:定期检查索引使用情况,优化慢查询
3. **数据归档**:历史订单数据量大时,考虑归档策略
4. **JSON 字段**`extra` 字段使用 JSON 类型,便于扩展但查询性能略低
5. **时间字段**`pay_time``expire_time` 等时间字段使用 `datetime` 类型,便于查询和统计

View File

@@ -1,485 +0,0 @@
# 支付订单发起流程说明
## 一、业务系统调用统一下单接口
### 1. 接口地址
```
POST /api/pay/unifiedOrder
```
### 2. 请求头(签名认证)
```
X-App-Id: app001 # 应用ID
X-Timestamp: 1704067200 # 时间戳Unix秒
X-Nonce: abc123xyz # 随机字符串
X-Signature: calculated_signature # 签名HMAC-SHA256
Content-Type: application/json
```
### 3. 签名算法
**待签名字符串**
```
app_id={app_id}&timestamp={timestamp}&nonce={nonce}&method=POST&path=/api/pay/unifiedOrder&body_sha256={body_sha256}
```
**计算签名**
```php
$bodySha256 = hash('sha256', json_encode($requestBody));
$signString = "app_id={app_id}&timestamp={timestamp}&nonce={nonce}&method=POST&path=/api/pay/unifiedOrder&body_sha256={bodySha256}";
$signature = hash_hmac('sha256', $signString, $appSecret);
```
### 4. 请求体示例
```json
{
"mch_order_no": "ORDER202401011200001",
"pay_method": "alipay",
"amount": 100.00,
"currency": "CNY",
"subject": "测试商品",
"body": "测试商品描述"
}
```
**字段说明**
- `mch_order_no`:商户订单号(必填,唯一,用于幂等)
- `pay_method`支付方式必填alipay、wechat、unionpay
- `amount`:订单金额(必填,单位:元)
- `currency`币种可选默认CNY
- `subject`:订单标题(必填)
- `body`:订单描述(可选)
### 5. 调用示例cURL
```bash
curl -X POST http://localhost:8787/api/pay/unifiedOrder \
-H "Content-Type: application/json" \
-H "X-App-Id: app001" \
-H "X-Timestamp: 1704067200" \
-H "X-Nonce: abc123xyz" \
-H "X-Signature: calculated_signature" \
-d '{
"mch_order_no": "ORDER202401011200001",
"pay_method": "alipay",
"amount": 100.00,
"subject": "测试商品",
"body": "测试商品描述"
}'
```
### 6. PHP调用示例
```php
<?php
$appId = 'app001';
$appSecret = 'your_app_secret';
$baseUrl = 'http://localhost:8787';
// 准备请求数据
$requestBody = [
'mch_order_no' => 'ORDER202401011200001',
'pay_method' => 'alipay',
'amount' => 100.00,
'subject' => '测试商品',
'body' => '测试商品描述'
];
// 计算签名
$timestamp = time();
$nonce = uniqid();
$bodyJson = json_encode($requestBody);
$bodySha256 = hash('sha256', $bodyJson);
$signString = "app_id={$appId}&timestamp={$timestamp}&nonce={$nonce}&method=POST&path=/api/pay/unifiedOrder&body_sha256={$bodySha256}";
$signature = hash_hmac('sha256', $signString, $appSecret);
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/pay/unifiedOrder');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyJson);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
"X-App-Id: {$appId}",
"X-Timestamp: {$timestamp}",
"X-Nonce: {$nonce}",
"X-Signature: {$signature}",
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
if ($httpCode === 200 && $result['code'] === 200) {
echo "支付订单号:" . $result['data']['pay_order_id'] . "\n";
echo "支付参数:" . json_encode($result['data']['pay_params'], JSON_UNESCAPED_UNICODE) . "\n";
} else {
echo "错误:" . $result['msg'] . "\n";
}
```
## 二、服务端处理流程
### 流程图
```mermaid
sequenceDiagram
participant BizSystem as 业务系统
participant OpenAPI as OpenAPI接口
participant AuthMW as 签名中间件
participant PayService as 订单服务
participant ChannelRouter as 通道路由
participant PluginFactory as 插件工厂
participant Plugin as 支付插件
participant Channel as 第三方渠道
BizSystem->>OpenAPI: POST /api/pay/unifiedOrder
OpenAPI->>AuthMW: 验证签名
AuthMW->>PayService: 调用统一下单
PayService->>PayService: 1. 验证商户应用
PayService->>PayService: 2. 幂等校验
PayService->>PayService: 3. 创建支付订单
PayService->>ChannelRouter: 4. 选择通道
ChannelRouter-->>PayService: 返回通道信息
PayService->>PluginFactory: 5. 实例化插件
PluginFactory-->>PayService: 返回插件实例
PayService->>Plugin: 6. 初始化插件(init)
PayService->>Plugin: 7. 环境检测
PayService->>Plugin: 8. 调用统一下单(unifiedOrder)
Plugin->>Plugin: 8.1 根据环境选择产品
Plugin->>Channel: 8.2 调用第三方接口
Channel-->>Plugin: 返回支付参数
Plugin-->>PayService: 返回支付结果
PayService->>PayService: 9. 更新订单信息
PayService-->>OpenAPI: 返回结果
OpenAPI-->>BizSystem: 返回支付参数
```
### 详细步骤说明
#### 步骤1签名验证中间件
- `OpenApiAuthMiddleware` 验证请求头中的签名
- 验证时间戳5分钟内有效
- 验证签名是否正确
- 将应用信息注入到请求对象
#### 步骤2验证商户应用
- 根据 `app_id` 查询 `ma_merchant_app`
- 检查应用状态是否启用
#### 步骤3幂等校验
- 根据 `merchant_id + mch_order_no` 查询是否已存在订单
- 如果存在,直接返回已有订单信息(支持幂等)
#### 步骤4创建支付订单
- 生成支付订单号(格式:`P20240101120000123456`
- 创建 `ma_pay_order` 记录
- 状态:`PENDING`(待支付)
- 过期时间30分钟后
#### 步骤5通道路由选择
- 根据 `merchant_id + app_id + method_code` 查找可用通道
-`ma_pay_channel` 表中查询
- 选择第一个可用的通道(后续可扩展权重、容灾策略)
#### 步骤6实例化插件
-`PayService` 中根据 `ma_pay_plugin` 注册表解析插件:优先使用表中的 `class_name`,否则按约定使用 `app\common\payment\{Code}Payment` 实例化插件
- 例如:`plugin_code = 'lakala'` → 实例化 `LakalaPlugin`
#### 步骤7初始化插件
- 调用 `$plugin->init($methodCode, $channelConfig)`
- 插件内部切换到指定支付方式的配置和逻辑
- 例如:拉卡拉插件初始化到 `alipay` 模式
#### 步骤8环境检测
- 从请求头 `User-Agent` 判断用户环境
- 环境类型:
- `PC`PC桌面浏览器
- `H5`H5手机浏览器
- `WECHAT`:微信内浏览器
- `ALIPAY_CLIENT`:支付宝客户端
#### 步骤9调用插件统一下单
- 调用 `$plugin->unifiedOrder($orderData, $channelConfig, $env)`
- 插件内部处理:
1. **产品选择**:从通道的 `enabled_products` 中,根据环境自动选择一个产品
- 例如H5环境 → 选择 `alipay_h5`
- 例如:支付宝客户端 → 选择 `alipay_life`
2. **调用第三方接口**:根据产品和支付方式,调用对应的第三方支付接口
- 例如拉卡拉插件的支付宝H5接口
3. **返回支付参数**:返回给业务系统的支付参数
#### 步骤10更新订单
- 更新订单的 `product_code`(实际使用的产品)
- 更新订单的 `channel_id`
- 更新订单的 `channel_order_no`(渠道订单号)
- 保存 `pay_params``extra` 字段
## 三、响应数据格式
### 成功响应
```json
{
"code": 200,
"msg": "success",
"data": {
"pay_order_id": "P20240101120000123456",
"status": "PENDING",
"pay_params": {
"type": "redirect",
"url": "https://mapi.alipay.com/gateway.do?..."
}
}
}
```
### 支付参数类型
根据不同的支付产品和环境,`pay_params` 的格式不同:
#### 1. 跳转支付H5/PC扫码
```json
{
"type": "redirect",
"url": "https://mapi.alipay.com/gateway.do?xxx"
}
```
业务系统需要:**跳转到该URL**
#### 2. 表单提交H5
```json
{
"type": "form",
"method": "POST",
"action": "https://mapi.alipay.com/gateway.do",
"fields": {
"app_id": "xxx",
"method": "alipay.trade.wap.pay",
"biz_content": "{...}"
}
}
```
业务系统需要:**自动提交表单**
#### 3. JSAPI支付微信内/支付宝生活号)
```json
{
"type": "jsapi",
"appId": "wx1234567890",
"timeStamp": "1704067200",
"nonceStr": "abc123",
"package": "prepay_id=wx1234567890",
"signType": "MD5",
"paySign": "calculated_signature"
}
```
业务系统需要:**调用微信/支付宝JSAPI**
#### 4. 二维码支付PC扫码
```json
{
"type": "qrcode",
"qrcode_url": "https://qr.alipay.com/xxx",
"qrcode_data": "data:image/png;base64,..."
}
```
业务系统需要:**展示二维码**
## 四、用户支付流程
### 1. 业务系统处理支付参数
根据 `pay_params.type` 进行不同处理:
```javascript
// 前端处理示例
const payParams = response.data.pay_params;
switch (payParams.type) {
case 'redirect':
// 跳转支付
window.location.href = payParams.url;
break;
case 'form':
// 表单提交
const form = document.createElement('form');
form.method = payParams.method;
form.action = payParams.action;
Object.keys(payParams.fields).forEach(key => {
const input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = payParams.fields[key];
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
break;
case 'jsapi':
// 微信JSAPI支付
WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId: payParams.appId,
timeStamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType,
paySign: payParams.paySign
}, function(res) {
if (res.err_msg === "get_brand_wcpay_request:ok") {
// 支付成功
}
});
break;
case 'qrcode':
// 展示二维码
document.getElementById('qrcode').src = payParams.qrcode_data;
break;
}
```
### 2. 用户完成支付
- 用户在第三方支付平台完成支付
- 第三方平台异步回调到支付中心
### 3. 支付中心处理回调
- 接收回调:`POST /api/notify/alipay``/api/notify/wechat`
- 验签:使用插件验证回调签名
- 更新订单状态:`PENDING``SUCCESS``FAIL`
- 创建通知任务:异步通知业务系统
### 4. 业务系统接收通知
- 支付中心异步通知业务系统的 `notify_url`
- 业务系统验证签名并处理订单
## 五、查询订单接口
### 接口地址
```
GET /api/pay/query?pay_order_id=P20240101120000123456
```
### 请求头(需要签名)
```
X-App-Id: app001
X-Timestamp: 1704067200
X-Nonce: abc123xyz
X-Signature: calculated_signature
```
### 响应示例
```json
{
"code": 200,
"msg": "success",
"data": {
"pay_order_id": "P20240101120000123456",
"mch_order_no": "ORDER202401011200001",
"status": "SUCCESS",
"amount": 100.00,
"pay_time": "2024-01-01 12:00:30"
}
}
```
## 六、完整调用示例Node.js
```javascript
const crypto = require('crypto');
const axios = require('axios');
class PaymentClient {
constructor(appId, appSecret, baseUrl) {
this.appId = appId;
this.appSecret = appSecret;
this.baseUrl = baseUrl;
}
// 计算签名
calculateSignature(method, path, body, timestamp, nonce) {
const bodySha256 = crypto.createHash('sha256').update(JSON.stringify(body)).digest('hex');
const signString = `app_id=${this.appId}&timestamp=${timestamp}&nonce=${nonce}&method=${method}&path=${path}&body_sha256=${bodySha256}`;
return crypto.createHmac('sha256', this.appSecret).update(signString).digest('hex');
}
// 统一下单
async unifiedOrder(orderData) {
const timestamp = Math.floor(Date.now() / 1000);
const nonce = Math.random().toString(36).substring(7);
const method = 'POST';
const path = '/api/pay/unifiedOrder';
const signature = this.calculateSignature(method, path, orderData, timestamp, nonce);
const response = await axios.post(`${this.baseUrl}${path}`, orderData, {
headers: {
'Content-Type': 'application/json',
'X-App-Id': this.appId,
'X-Timestamp': timestamp,
'X-Nonce': nonce,
'X-Signature': signature
}
});
return response.data;
}
// 查询订单
async queryOrder(payOrderId) {
const timestamp = Math.floor(Date.now() / 1000);
const nonce = Math.random().toString(36).substring(7);
const method = 'GET';
const path = `/api/pay/query?pay_order_id=${payOrderId}`;
const signature = this.calculateSignature(method, path, {}, timestamp, nonce);
const response = await axios.get(`${this.baseUrl}${path}`, {
headers: {
'X-App-Id': this.appId,
'X-Timestamp': timestamp,
'X-Nonce': nonce,
'X-Signature': signature
}
});
return response.data;
}
}
// 使用示例
const client = new PaymentClient('app001', 'your_app_secret', 'http://localhost:8787');
// 统一下单
client.unifiedOrder({
mch_order_no: 'ORDER202401011200001',
pay_method: 'alipay',
amount: 100.00,
subject: '测试商品',
body: '测试商品描述'
}).then(result => {
console.log('支付参数:', result.data.pay_params);
// 根据 pay_params.type 处理支付
}).catch(err => {
console.error('下单失败:', err.message);
});
```
## 七、注意事项
1. **幂等性**:相同的 `mch_order_no` 多次调用,返回同一订单信息
2. **签名有效期**时间戳5分钟内有效
3. **订单过期**订单默认30分钟过期
4. **环境检测**系统自动根据UA判断环境选择合适的产品
5. **异步通知**:支付成功后,系统会异步通知业务系统的 `notify_url`
6. **订单查询**:业务系统可通过查询接口主动查询订单状态

View File

@@ -1,182 +0,0 @@
# 支付系统核心实现说明
## 概述
已实现支付系统核心功能,包括:
- 插件化支付通道系统(支持一个插件多个支付方式)
- OpenAPI统一支付网关
- 通道管理与配置
- 订单管理与状态机
- 异步通知机制
## 数据库初始化
执行以下SQL脚本创建表结构
```bash
mysql -u用户名 -p 数据库名 < database/mvp_payment_tables.sql
```
## 核心架构
### 1. 插件系统
- **插件接口**`app/common/contracts/PayPluginInterface.php`
- **抽象基类**`app/common/contracts/AbstractPayPlugin.php`(提供环境检测、产品选择等通用功能)
- **插件类示例**`app/common/payment/LakalaPayment.php`(命名规范:`XxxPayment`
- **插件解析**:由 `PayService``PayOrderService``PluginService` 直接根据 `ma_pay_plugin` 注册表中配置的 `plugin_code` / `class_name` 解析并实例化插件(默认约定类名为 `app\common\payment\{Code}Payment`
**插件特点**
- 一个插件可以支持多个支付方式(如拉卡拉插件支持 alipay/wechat/unionpay
- **支付产品由插件内部定义**,不需要数据库字典表
- 插件根据用户环境PC/H5/微信内/支付宝客户端)自动选择已开通的产品
- 通道配置中,用户只需勾选确认开启了哪些产品(产品编码由插件定义)
- 有些支付平台不区分产品,插件会根据通道配置自行处理
- 通道配置表单由插件动态生成
### 2. 数据模型
- `Merchant`:商户
- `MerchantApp`商户应用AppId/AppSecret
- `PayMethod`支付方式alipay/wechat等
- `PayChannel`:支付通道(绑定到"插件+支付方式",配置已开通的产品列表)
- `PayOrder`:支付订单
- `NotifyTask`:商户通知任务
**注意**:支付产品不由数据库管理,而是由插件通过 `getSupportedProducts()` 方法定义。通道配置中的 `enabled_products` 字段存储的是用户勾选的产品编码数组。
### 3. 服务层
- `PayOrderService`:订单业务编排(统一下单、查询)
- `ChannelRouterService`:通道路由选择
- `NotifyService`:商户通知服务
### 4. API接口
#### OpenAPI对外支付网关
- `POST /api/pay/unifiedOrder`:统一下单(需要签名认证)
- `GET /api/pay/query`:查询订单(需要签名认证)
- `POST /api/notify/alipay`:支付宝回调
- `POST /api/notify/wechat`:微信回调
#### 管理后台API
- `GET /adminapi/channel/plugins`:获取所有可用插件
- `GET /adminapi/channel/plugin/config-schema`获取插件配置表单Schema
- `GET /adminapi/channel/plugin/products`:获取插件支持的支付产品
- `GET /adminapi/channel/list`:通道列表
- `GET /adminapi/channel/detail`:通道详情
- `POST /adminapi/channel/save`:保存通道
## 使用流程
### 1. 创建商户和应用
```sql
INSERT INTO ma_merchant (merchant_no, merchant_name, funds_mode, status)
VALUES ('M001', '测试商户', 'direct', 1);
INSERT INTO ma_merchant_app (merchant_id, app_id, app_secret, app_name, notify_url, status)
VALUES (1, 'app001', 'secret_key_here', '测试应用', 'https://example.com/notify', 1);
```
### 2. 配置支付通道
**配置流程**
1. 创建通道:选择支付方式、支付插件,配置通道基本信息(显示名称、分成比例、通道成本、通道模式、限额等)
2. 配置插件参数:通道创建后,再配置该通道的插件参数信息(通过插件的配置表单动态生成)
通过管理后台或直接操作数据库:
```sql
INSERT INTO ma_pay_channel (
merchant_id, app_id, channel_code, channel_name,
plugin_code, method_code, enabled_products, config_json,
split_ratio, channel_cost, channel_mode,
daily_limit, daily_count, min_amount, max_amount,
status
) VALUES (
1, 1, 'CH001', '拉卡拉-支付宝通道',
'lakala', 'alipay',
'["alipay_h5", "alipay_life"]',
'{"merchant_id": "lakala_merchant", "secret_key": "xxx", "api_url": "https://api.lakala.com"}',
100.00, 0.00, 'wallet',
0.00, 0, NULL, NULL,
1
);
```
**通道字段说明**
- `split_ratio`: 分成比例(%默认100.00
- `channel_cost`: 通道成本(%默认0.00
- `channel_mode`: 通道模式,`wallet`-支付金额扣除手续费后加入商户余额,`direct`-直连到商户
- `daily_limit`: 单日限额0表示不限制
- `daily_count`: 单日限笔0表示不限制
- `min_amount`: 单笔最小金额NULL表示不限制
- `max_amount`: 单笔最大金额NULL表示不限制
### 3. 调用统一下单接口
```bash
curl -X POST http://localhost:8787/api/pay/unifiedOrder \
-H "X-App-Id: app001" \
-H "X-Timestamp: 1234567890" \
-H "X-Nonce: abc123" \
-H "X-Signature: calculated_signature" \
-d '{
"mch_order_no": "ORDER001",
"pay_method": "alipay",
"amount": 100.00,
"subject": "测试订单",
"body": "测试订单描述"
}'
```
### 4. 签名算法
```
signString = "app_id={app_id}&timestamp={timestamp}&nonce={nonce}&method={method}&path={path}&body_sha256={body_sha256}"
signature = HMAC-SHA256(signString, app_secret)
```
## 扩展新插件
1. 创建插件类,继承 `AbstractPayPlugin`,并按照 `XxxPayment` 命名放在 `app/common/payment` 目录:
```php
namespace app\common\payment;
use app\common\contracts\AbstractPayPlugin;
class AlipayPayment extends AbstractPayPlugin
{
public static function getCode(): string { return 'alipay'; }
public static function getName(): string { return '支付宝直连'; }
public static function getSupportedMethods(): array { return ['alipay']; }
// ... 实现其他方法
}
```
2.`ma_pay_plugin` 表中注册插件信息(也可通过后台管理界面维护):
```sql
INSERT INTO ma_pay_plugin (plugin_code, plugin_name, class_name, status)
VALUES ('alipay', '支付宝直连', 'app\\common\\payment\\AlipayPayment', 1);
```
## 注意事项
1. **支付产品定义**:支付产品由插件内部通过 `getSupportedProducts()` 方法定义,不需要数据库字典表。通道配置时,用户只需勾选已开通的产品编码。
2. **环境检测**:插件基类提供 `detectEnvironment()` 方法可根据UA判断环境
3. **产品选择**:插件根据环境从通道已开通产品中自动选择。如果通道配置为空或不区分产品,插件会根据配置自行处理。
4. **通知重试**:使用 `NotifyMerchantJob` 异步重试通知,支持指数退避
5. **幂等性**:统一下单接口支持幂等,相同 `mch_order_no` 返回已有订单
## 后续扩展
- 账务系统(账户、分录、余额)
- 结算系统(可结算金额、结算批次、打款)
- 对账系统(渠道账单导入、差异处理)
- 风控系统(规则引擎、风险预警)

414
doc/project_overview.md Normal file
View File

@@ -0,0 +1,414 @@
# MPay V2 Project Overview
更新日期2026-03-13
## 1. 项目定位
这是一个基于 Webman 的多商户支付中台项目,当前主要目标是:
- 提供后台管理能力,维护商户、应用、支付方式、支付插件、支付通道、订单与系统配置
- 为商户应用提供统一支付能力
- 当前已优先兼容 `epay` 协议,后续可继续扩展更多外部支付协议
- 通过“支付插件 + 通道配置”的方式对接第三方渠道
结合当前代码与数据库,项目已经具备“多商户 -> 多应用 -> 多通道 -> 多插件”的基础骨架。
## 2. 技术栈与运行环境
### 后端技术栈
- PHP `>= 8.1`
- Webman `^2.1`
- webman/database
- webman/redis
- webman/cache
- webman/console
- webman/captcha
- webman/event
- webman/redis-queue
- firebase/php-jwt
- yansongda/pay `~3.7.0`
### 当前环境配置要点
- HTTP 服务监听:`0.0.0.0:8787`
- 数据库MySQL
- 缓存与队列Redis
- 管理后台认证JWT
- 当前 `.env` 已配置远程 MySQL / Redis 地址,开发前需要确认本机网络可达
## 3. 当前环境可调用的 MCP 能力
本次会话中,已确认可以直接用于本项目的 MCP / 环境能力如下:
### MySQL MCP
- 可直接执行 SQL
- 可读取当前开发库表结构与数据
- 已确认能访问 `mpay_admin` 相关表,例如:
- `ma_merchant`
- `ma_merchant_app`
- `ma_pay_channel`
- `ma_pay_order`
- `ma_notify_task`
- `ma_callback_inbox`
- `ma_pay_callback_log`
适合后续继续做:
- 表结构核对
- 初始化数据检查
- 回调与订单状态排查
- 开发联调时快速确认通道配置
### Playwright MCP
- 可进行浏览器打开、点击、表单填写、快照、截图、网络请求分析
- 适合后续验证:
- 管理后台登录流程
- 通道配置页面交互
- 提交支付后的跳转页/表单页
- 回调相关前端可视流程
### MCP 资源浏览
- 可列出 MCP 资源
- 可读取资源内容
- 当前未返回资源模板
### 非 MCP 但对开发有用的本地能力
- Shell 命令执行
- 工作区文件读写
- 代码补丁编辑
## 4. 业务模型总览
### 4.1 商户模型
- 表:`ma_merchant`
- 作用:定义商户主体
- 关键字段:
- `merchant_no`
- `merchant_name`
- `funds_mode`
- `status`
### 4.2 商户应用模型
- 表:`ma_merchant_app`
- 作用:商户可创建多个应用,每个应用具备独立 `app_id` / `app_secret`
- 关键字段:
- `merchant_id`
- `api_type`
- `app_id`
- `app_secret`
- `app_name`
- `status`
当前代码中,`app_id` 既是应用标识,也是外部协议鉴权入口;`epay` 兼容链路直接用它作为 `pid`
### 4.3 支付方式模型
- 表:`ma_pay_method`
- 作用:维护支付方式字典
- 当前库内数据:
- `alipay`
- `wechat`
- `unionpay`
### 4.4 支付插件模型
- 表:`ma_pay_plugin`
- 作用把“支付通道配置”与“PHP 插件实现类”解耦
- 插件需要同时实现:
- `PaymentInterface`
- `PayPluginInterface`
当前代码里已有两个插件类:
- `app/common/payment/LakalaPayment.php`
- `app/common/payment/AlipayPayment.php`
但当前数据库只注册了 `lakala`,还没有把 `alipay` 作为活动插件注册进现网开发库。
### 4.5 支付通道模型
- 表:`ma_pay_channel`
- 作用:把“商户应用 + 支付方式 + 插件 + 参数配置”绑定起来
- 关键字段:
- `merchant_id`
- `merchant_app_id`
- `plugin_code`
- `method_id`
- `config_json`
- `split_ratio`
- `chan_cost`
- `chan_mode`
- `daily_limit`
- `daily_cnt`
- `min_amount`
- `max_amount`
- `status`
- `sort`
这正对应你描述的核心业务特点:一个应用下可配置多个支付通道,每个通道可挂接不同插件与参数。
### 4.6 支付订单模型
- 表:`ma_pay_order`
- 作用:统一存放系统支付订单
- 关键特性:
- 系统订单号:`order_id`
- 商户订单号:`mch_order_no`
- 幂等唯一键:`(merchant_id, merchant_app_id, mch_order_no)`
- `extra` JSON 用于存放 `notify_url``return_url``pay_params`、退款信息等
### 4.7 回调与通知模型
- `ma_callback_inbox`:回调幂等收件箱
- `ma_pay_callback_log`:回调日志
- `ma_notify_task`:商户异步通知任务
这三张表说明项目已经为“渠道回调幂等 + 日志留痕 + 商户通知补偿”预留了比较完整的基础设施。
## 5. 代码分层与关键入口
### 外部接口入口
- `app/http/api/controller/EpayController.php`
- `app/http/api/controller/PayController.php`
### 支付主流程服务
- `app/services/api/EpayProtocolService.php`
- `app/services/api/EpayService.php`
- `app/services/PayService.php`
- `app/services/PayOrderService.php`
- `app/services/ChannelRouterService.php`
- `app/services/PluginService.php`
- `app/services/PayNotifyService.php`
- `app/services/NotifyService.php`
- `app/services/PaymentStateService.php`
### 支付插件契约
- `app/common/contracts/PaymentInterface.php`
- `app/common/contracts/PayPluginInterface.php`
- `app/common/base/BasePayment.php`
### 管理后台接口
- 商户:`MerchantController`
- 商户应用:`MerchantAppController`
- 支付方式:`PayMethodController`
- 插件注册:`PayPluginController`
- 通道:`ChannelController`
- 订单:`OrderController`
- 系统配置:`SystemController`
- 登录认证:`AuthController`
## 6. 当前已落地的对外接口
### 路由现状
当前 `app/routes/api.php` 实际挂载的对外接口为:
- `GET|POST /submit.php`
- `POST /mapi.php`
- `GET /api.php`
- `ANY /notify/{pluginCode}`
### 兼容协议现状
当前真正已打通的是 `epay` 风格接口:
- `submit.php`:页面跳转支付
- `mapi.php`API 下单
- `api.php?act=order`:查单
- `api.php?act=refund`:退款
### OpenAPI 现状
`PayController` 中存在以下方法:
- `create`
- `query`
- `close`
- `refund`
但当前都还是 `501 not implemented`,并且对应路由尚未挂载,因此“通用 OpenAPI”目前仍是预留骨架不是已上线能力。
## 7. 核心支付链路
### 7.1 Epay 下单链路
1. 商户调用 `submit.php``mapi.php`
2. `EpayProtocolService` 负责参数提取与校验
3. `EpayService` 使用 `app_secret` 做 MD5 验签
4. 构造统一内部订单数据
5. `PayOrderService` 创建订单,并通过联合唯一键保证幂等
6. `ChannelRouterService` 根据 `merchant_id + merchant_app_id + method_id` 选取通道
7. `PluginService` 从注册表解析插件类并实例化
8. 插件执行 `pay()`
9. `PayService` 回写:
- `channel_id`
- `chan_order_no`
- `chan_trade_no`
- `fee`
- `real_amount`
- `extra.pay_params`
10. 转换成 `epay` 所需返回结构给调用方
### 7.2 回调处理链路
1. 第三方渠道回调 `/notify/{pluginCode}`
2. `PayNotifyService` 调插件 `notify()` 验签与解析
3. 通过 `ma_callback_inbox` 做幂等去重
4. 状态机更新订单状态
5. 写入回调日志
6. 创建商户通知任务
### 7.3 商户通知链路
1. `NotifyService` 根据订单 `extra.notify_url` 创建通知任务
2. 通知内容写入 `ma_notify_task`
3. `sendNotify()` 使用 HTTP POST JSON 回调商户
4. 若商户返回 HTTP 200 且 body 为 `success`,视为通知成功
## 8. 插件与通道现状
### `LakalaPayment`
状态:示例插件 / mock 插件
现状:
- `pay()` 已实现,但只是返回模拟二维码字符串
- `query()` 未实现
- `close()` 未实现
- `refund()` 未实现
- `notify()` 未实现
这意味着当前库里虽然已经能“创建订单并拿到拉起参数”,但还不能完成真实的拉卡拉闭环。
### `AlipayPayment`
状态:代码层面相对完整
已实现:
- `pay()`
- `query()`
- `close()`
- `refund()`
- `notify()`
特点:
- 基于 `yansongda/pay`
- 支持产品类型:
- `alipay_web`
- `alipay_h5`
- `alipay_scan`
- `alipay_app`
- 可根据环境自动选产品
注意:
- 当前开发库没有注册 `alipay` 插件记录
- 当前通道也没有指向 `AlipayPayment`
所以它虽然写在代码里,但当前数据库并没有真正启用它。
## 9. 管理后台现状
后台已经覆盖以下核心维护能力:
- 验证码登录 + JWT 鉴权
- 商户管理
- 商户应用管理
- 支付方式管理
- 支付插件注册管理
- 支付通道管理
- 订单列表 / 详情 / 退款
- 系统基础配置管理
这部分说明“支付中心后台”已经不是空架子,而是可以承接后续运营配置的。
## 10. 当前开发库快照(基于 2026-03-13 实际查询)
### 数据量
- `ma_admin`: 1
- `ma_merchant`: 1
- `ma_merchant_app`: 1
- `ma_pay_method`: 3
- `ma_pay_plugin`: 1
- `ma_pay_channel`: 2
- `ma_pay_order`: 1
- `ma_notify_task`: 0
- `ma_callback_inbox`: 0
- `ma_pay_callback_log`: 0
### 当前商户与应用
- 商户:`M001 / 测试商户`
- 应用:`1001 / 测试应用-易支付`
- 应用类型:`epay`
### 当前活动插件
- `lakala -> app\\common\\payment\\LakalaPayment`
### 当前通道
- `lakala_alipay`
- `lakala_wechat`
### 当前示例订单
- 订单号:`P20260312160833644578`
- 商户单号:`TEST123`
- 状态:`PENDING`
- 通道:`channel_id = 1`
- `extra.pay_params` 为 mock 二维码
## 11. 当前代码与需求的对应关系
你给出的项目特点,与当前实现的对应情况如下:
### 已匹配的部分
- 多商户:已支持
- 一个商户多个应用:已支持
- 一个应用多个支付通道:已支持
- 通道可绑定支付方式:已支持
- 通道可绑定支付插件:已支持
- 通道可存储插件参数:已支持
- 通道可配置手续费:已支持,当前会参与 `fee` / `real_amount` 计算
- 商户通过 `APPID` 发起支付:已支持,当前主要在 `epay` 兼容链路中落地
- 创建订单并调用第三方插件:已支持
### 仅完成“数据建模”,尚未完全落地执行的部分
- 每日限额:字段已存在,但当前下单/路由流程未校验
- 每日笔数限制:字段已存在,但当前未校验
- 最小/最大金额限制:字段已存在,但当前未校验
- 更复杂的路由策略:当前仅按 `sort` 取第一条可用通道
- 多协议统一 OpenAPI控制器骨架存在但未真正接入
## 12. 后续阅读建议
如果下一次继续开发,建议优先从以下文件继续进入:
- 支付入口:`app/http/api/controller/EpayController.php`
- 协议适配:`app/services/api/EpayProtocolService.php`
- 业务主流程:`app/services/PayService.php`
- 订单创建:`app/services/PayOrderService.php`
- 回调处理:`app/services/PayNotifyService.php`
- 插件管理:`app/services/PluginService.php`
- 拉卡拉插件:`app/common/payment/LakalaPayment.php`
- 支付宝插件:`app/common/payment/AlipayPayment.php`
- 通道配置:`app/http/admin/controller/ChannelController.php`

320
doc/project_progress.md Normal file
View File

@@ -0,0 +1,320 @@
# MPay V2 Development Progress
更新日期2026-03-13
本文档用于记录当前项目完成度、明显缺口和建议推进顺序,方便后续继续开发时快速接手。
## 1. 当前总体判断
项目已经完成了“支付中台基础骨架 + 后台配置能力 + Epay 协议首条链路”的主体搭建。
更准确地说:
- 数据模型已经比较完整
- 后台配置能力已经具备可用性
- 支付流程主链路已经跑通到“下单并返回拉起参数”
- 真正需要继续补的是“真实渠道闭环、规则执行、异步补偿、通用协议扩展”
## 2. 已完成
### 2.1 基础框架与环境
- Webman 项目骨架已搭建
- MySQL / Redis / JWT / Cache / Event / Redis Queue 依赖已接入
- 管理后台与 API 路由已拆分
### 2.2 管理后台能力
- 验证码登录
- JWT 鉴权中间件
- 管理员信息查询
- 菜单与系统配置读取
- 商户 CRUD
- 商户应用 CRUD
- 支付方式 CRUD
- 支付插件注册 CRUD
- 支付通道 CRUD
- 订单列表 / 详情 / 后台发起退款
### 2.3 核心支付数据结构
已建表并落地:
- 商户
- 商户应用
- 支付方式
- 插件注册
- 支付通道
- 支付订单
- 回调日志
- 商户通知任务
- 回调幂等收件箱
### 2.4 下单主链路
已打通:
- Epay 参数校验
- Epay MD5 验签
- 商户应用识别
- 幂等订单创建
- 通道路由
- 插件实例化
- 插件下单
- 订单回写支付参数
- 返回兼容 Epay 的响应结构
### 2.5 支付状态基础设施
- 订单状态机服务已存在
- 成功 / 失败 / 全额退款关单状态迁移已定义
- 回调日志记录能力已存在
- 回调幂等收件箱已存在
- 商户通知任务创建逻辑已存在
### 2.6 插件体系
已建立统一插件契约:
- `PaymentInterface`
- `PayPluginInterface`
- `BasePayment`
说明后续继续接入新渠道时,整体扩展方式已经明确。
## 3. 部分完成
### 3.1 Epay 兼容是“主路径”,但还不是“全量兼容”
当前已实现:
- `submit.php`
- `mapi.php`
- `api.php?act=order`
- `api.php?act=refund`
`doc/epay.md` 中提到的一些能力,如 `query``settle``orders` 等,代码中暂未实现。
### 3.2 支付宝插件代码较完整,但未在当前数据库启用
现状:
- `AlipayPayment.php` 已实现
- 当前开发库 `ma_pay_plugin` 中只有 `lakala`
这意味着支付宝更多处于“代码已写好、配置未接入”的状态。
### 3.3 回调后通知商户的基础逻辑存在,但补偿闭环还不完整
已完成:
- 创建通知任务
- 发送通知
- 失败重试时间计算
待确认 / 待补齐:
- 当前没有看到明确的任务投递入口
- 也没有看到定时调度 `NotifyMerchantJob` 的配置闭环
- `NotifyMerchantJob` 虽然存在,但尚未形成明确的可运行消费链路
更保守地说,商户通知补偿链路还没有真正闭环。
## 4. 待完成
### 4.1 通用 OpenAPI
当前状态:
- `PayController` 只有骨架
- `create/query/close/refund` 都返回 `501`
- `OpenApiAuthMiddleware` 已存在,但未挂到路由
建议判断:这是下一阶段最适合补完的能力之一。
### 4.2 拉卡拉真实对接
当前状态:
- `LakalaPayment::pay()` 只返回 mock 二维码
- `query/close/refund/notify` 全部未实现
影响:
- 现在只能用于打通订单创建流程
- 还不能进行真实线上支付联调
### 4.3 通道路由规则执行
数据库已设计的字段很多,但运行期并未全部生效:
- `daily_limit` 未校验
- `daily_cnt` 未校验
- `min_amount` 未校验
- `max_amount` 未校验
- `split_ratio` 当前只存储,未看到清算分账逻辑
- 路由策略目前只是“按排序取第一条可用通道”
这块是项目从“能下单”走向“可运营”的关键缺口。
### 4.4 Epay 协议映射细节
当前内部支付方式代码使用:
- `alipay`
- `wechat`
但传统 Epay 常见值通常还有:
- `wxpay`
- `qqpay`
当前代码里没有看到统一别名映射层,说明“协议兼容”仍偏接口形态兼容,而不是完整字段语义兼容。
### 4.5 插件注册与初始化数据同步
代码、SQL、数据库现状存在轻微偏差
- `database/dev_seed.sql` 里准备了 `alipay``lakala`
- 当前开发库只看到 `lakala`
建议后续把“代码存在但数据库未启用”的状态统一起来,减少联调歧义。
### 4.6 通道安全与敏感配置
当前通道配置直接存在 `config_json` 中,后续建议补充:
- 敏感字段加密存储
- 后台展示脱敏
- 配置变更审计日志
### 4.7 测试体系
当前仓库里没有看到成体系的:
- 单元测试
- 协议测试
- 插件对接测试
- 回调幂等测试
- 退款回归测试
这会让后续迭代的回归成本越来越高。
## 5. 风险与注意点
### 5.1 当前“多通道”能力更偏配置层,而不是调度层
虽然表结构和后台已经支持多通道,但运行时路由还比较简单,不能完全体现:
- 限额控制
- 金额区间控制
- 通道健康度切换
- 优先级与容灾
### 5.2 退款能力目前偏基础版
当前退款服务已存在,但从实现上看:
- 更适合单次退款 / 全额退款
- 全额退款后直接把订单关闭
- 没有独立退款单模型
- 没有完整的部分退款累计能力
### 5.3 回调成功后的订单与通知一致性要继续加强
当前已经有:
- 幂等收件箱
- 状态机
- 通知任务表
这是很好的基础。
但真正生产级还建议再补:
- 事务边界说明
- 异常重放工具
- 回调人工补单工具
- 通知签名
## 6. 建议优先级
### P0优先补完直接影响可用性
1. 实现真实渠道插件,至少先补完一个可联调通道
2. 补完 OpenAPI 主链路
3. 在路由阶段执行金额限制 / 限额 / 笔数规则
4. 打通商户通知任务的实际调度与重试闭环
### P1补齐可运营能力
1. 增加支付方式别名映射,提升 Epay 兼容度
2.`AlipayPayment` 正式接入插件注册与通道配置
3. 增加后台对通道能力、产品、环境的可视化说明
4. 增加日志检索与问题排查手段
### P2走向平台化
1. 增加更多协议兼容层
2. 增加清算 / 分账 / 对账
3. 增加风控规则
4. 增加监控、告警、报表
## 7. 建议后续开发方向
### 方向一:先做“一个真实可用通道”
建议优先把某一个通道做成完整闭环:
- 下单
- 回调
- 查单
- 关单
- 退款
这样项目就能从“框架完成”升级为“真实可上线联调”。
### 方向二:补通用 OpenAPI
原因:
- 你已经明确后续可能兼容更多接口
- 当前通用控制器和鉴权中间件已经有雏形
- 补完之后,项目会从“单协议适配器”升级为“统一支付网关”
### 方向三:把通道路由做成真正的策略引擎
建议把下面这些字段从“仅存储”升级为“真实执行”:
- 金额范围
- 单日限额
- 单日限笔
- 通道优先级
- 通道健康状态
- 权重或降级策略
### 方向四:补测试与排障工具
优先建议增加:
- 下单幂等测试
- 回调幂等测试
- 退款状态测试
- 协议字段兼容测试
- 一键重发通知工具
## 8. 推荐继续开发顺序
如果下一次直接继续往下做,我建议按这个顺序推进:
1. 选定一个真实渠道作为首个闭环目标
2. 补完该插件的 `notify/query/refund/close`
3. 接入并验证商户通知补偿链路
4.`ChannelRouterService` 前后补齐通道规则校验
5. 正式实现 `PayController`
6. 抽象协议适配层,准备支持更多接口
7. 增加测试与后台排障能力
## 9. 当前一句话结论
这是一个“骨架已经成型、第一条协议已打通、非常适合继续往生产级推进”的支付中台项目;下一阶段的重点不是重写,而是把已有设计真正补成闭环。