ok
This commit is contained in:
253
plans/WalletLogic-c1c00f01.plan.md
Normal file
253
plans/WalletLogic-c1c00f01.plan.md
Normal file
@@ -0,0 +1,253 @@
|
||||
<!-- c1c00f01-351c-4b81-9a07-dec92aaf4ae2 -->
|
||||
---
|
||||
todos:
|
||||
- id: "phase0-prep"
|
||||
content: "Phase 0:确认 minus() 死代码、补 PHPDoc、更新 README 入口索引"
|
||||
status: pending
|
||||
- id: "phase1-base-query-register"
|
||||
content: "Phase 1:新建 AbstractWalletMutationLogic + WalletQueryLogic + WalletRegisterLogic,WalletLogic 委托 register/query"
|
||||
status: pending
|
||||
- id: "phase2-bet-win"
|
||||
content: "Phase 2:新建 WalletBetWinLogic,迁移 bet/win 及 Redis round 辅助逻辑"
|
||||
status: pending
|
||||
- id: "phase3-recharge"
|
||||
content: "Phase 3:新建 WalletRechargeLogic,迁移 inc/recharge/reward 与 Trial Pool 充值链"
|
||||
status: pending
|
||||
- id: "phase4-withdraw-trial"
|
||||
content: "Phase 4:新建 WalletWithdrawLogic + WalletTrialLogic,修复 switchBonus 路由(如需要)"
|
||||
status: pending
|
||||
isProject: false
|
||||
---
|
||||
# WalletLogic 分阶段拆分方案
|
||||
|
||||
## 现状诊断
|
||||
|
||||
[`slot-wallet/app/api/logic/WalletLogic.php`](slot-wallet/app/api/logic/WalletLogic.php) 当前 **1885 行**,承担了钱包服务几乎全部资金用例编排:
|
||||
|
||||
| 域 | 主要方法 | 约行数 | 已有下沉 |
|
||||
|---|---|---|---|
|
||||
| 路由门面 | `run`, `runRechargeOrder`, `ACTION_METHOD_MAP` | ~80 | — |
|
||||
| 注册 | `register`, `initWalletWithoutMoney` | ~120 | [`RegisterService`](slot-wallet/app/service/wallet/RegisterService.php) |
|
||||
| 下注/派奖 | `bet`, `win`, pending win Redis, bet split | ~450 | [`BetService`](slot-wallet/app/service/wallet/BetService.php), [`WinService`](slot-wallet/app/service/wallet/WinService.php) |
|
||||
| 入账/充值 | `inc`, `recharge`, `rechargeSign`, `reward`, Trial Pool | ~400 | [`RechargeFundLotService`](slot-wallet/app/service/wallet/RechargeFundLotService.php) |
|
||||
| 提现/Bonus 转换 | `withdraw*`, `rollbackWithdraw`, `bonusToDeposit`, `switchBonus` | ~350 | [`WithdrawTaskService`](slot-wallet/app/service/wallet/WithdrawTaskService.php) |
|
||||
| Trial 体验金 | `grantTrial`, `expireTrial` | ~250 | — |
|
||||
| 查询 | `query`, `queryBizLog` (static) | ~70 | — |
|
||||
| 公共能力 | `addLog`, `maxRetry`, `sendConsoleBus`, `getBalance` 等 | ~200 | — |
|
||||
|
||||
**问题**:单文件混合 6+ 业务域,事务边界、幂等、Redis 辅助状态交织,Review 和改动风险都高。
|
||||
|
||||
**已有良好先例**:同目录 [`GrantLogic`](slot-wallet/app/api/logic/GrantLogic.php)、[`PlayerTaskLogic`](slot-wallet/app/api/logic/PlayerTaskLogic.php) 已是「一用例一 Logic」;核心扣款/派奖细节已在 Service 层,Logic 层再拆是合理下一步。
|
||||
|
||||
**额外发现**(非本次必做):`minus()` 未出现在 `ACTION_METHOD_MAP` 且无调用方,疑似历史遗留,可在 Phase 0 确认后删除。
|
||||
|
||||
---
|
||||
|
||||
## 目标架构
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph controller [Controller 不变]
|
||||
WC[WalletController]
|
||||
end
|
||||
|
||||
subgraph facade [门面层]
|
||||
WL[WalletLogic]
|
||||
end
|
||||
|
||||
subgraph domain [子 Logic 按域]
|
||||
WQ[WalletQueryLogic]
|
||||
WRg[WalletRegisterLogic]
|
||||
WBw[WalletBetWinLogic]
|
||||
WRe[WalletRechargeLogic]
|
||||
WWd[WalletWithdrawLogic]
|
||||
WTr[WalletTrialLogic]
|
||||
end
|
||||
|
||||
subgraph shared [共享]
|
||||
Base[AbstractWalletMutationLogic]
|
||||
end
|
||||
|
||||
subgraph service [已有 Service 不动]
|
||||
BS[BetService]
|
||||
WS[WinService]
|
||||
RS[RegisterService]
|
||||
end
|
||||
|
||||
WC --> WL
|
||||
WL --> WRg & WBw & WRe & WWd & WTr
|
||||
GrantLogic --> WQ
|
||||
WL --> WQ
|
||||
WRg & WBw & WRe & WWd & WTr --> Base
|
||||
WBw --> BS & WS
|
||||
WRg --> RS
|
||||
```
|
||||
|
||||
**原则**(对齐 [`backend-layering`](.cursor/rules/backend-layering.mdc)):
|
||||
|
||||
- **Logic 拆用例、Service 保公共能力**:不再新建「只做 Model 转发」的 Service。
|
||||
- **WalletLogic 只做分发 + 缓存清理**:保留 `run()` / `runRechargeOrder()` 对外签名;`ACTION_METHOD_MAP` 改为指向子 Logic 方法。
|
||||
- **Controller 不改**:继续只注入 `WalletLogic`(你已确认)。
|
||||
- **共享状态收敛**:子 Logic 继承抽象基类,统一持有 `WalletUpdateRequestDTO`;`rechargeOrderDto` 仅留在 `WalletRechargeLogic`。
|
||||
|
||||
---
|
||||
|
||||
## 共享基类设计
|
||||
|
||||
新建 [`slot-wallet/app/api/logic/AbstractWalletMutationLogic.php`](slot-wallet/app/api/logic/AbstractWalletMutationLogic.php):
|
||||
|
||||
```php
|
||||
abstract class AbstractWalletMutationLogic
|
||||
{
|
||||
protected WalletUpdateRequestDTO $requestDTO;
|
||||
|
||||
/** 绑定本次 mutation 请求上下文 */
|
||||
protected function bindRequest(WalletUpdateRequestDTO $requestDTO): void { ... }
|
||||
|
||||
/** 写 wallet_log、PWA 流水、乐观锁重试、Console Bus 等 */
|
||||
protected function addLog(...): int { ... }
|
||||
protected function addTransactionRecord(...): void { ... }
|
||||
protected function getBalance(WalletAccountModel $model): int { ... }
|
||||
protected function maxRetry(callable $callback, int $retryCount = 3): WalletEntity { ... }
|
||||
protected function sendConsoleBus(string $type, int $amount): void { ... }
|
||||
protected function initWalletWithoutMoney(): ?WalletAccountModel { ... }
|
||||
}
|
||||
```
|
||||
|
||||
- 从现有 `WalletLogic` **原样迁移**上述 protected/private 方法,避免行为变化。
|
||||
- 子 Logic 方法签名改为显式接收 DTO 或在门面 `bindRequest()` 后调用,**不再依赖 `$this->requestDTO` 隐式全局状态跨文件散落**。
|
||||
|
||||
---
|
||||
|
||||
## 子 Logic 划分
|
||||
|
||||
| 新类 | 职责 | 从 WalletLogic 迁出的方法 |
|
||||
|---|---|---|
|
||||
| `WalletQueryLogic` | 只读查询 | `query`, `queryBizLog` |
|
||||
| `WalletRegisterLogic` | 注册赠金 | `register` |
|
||||
| `WalletBetWinLogic` | 游戏下注/派奖编排 | `bet`, `win`, `executeTrialBet/Win`, `executeFreeSpinPaidBet`, pending win / bet split Redis, `getWinAllocationByRound`, `buildBetSplitRemark` |
|
||||
| `WalletRechargeLogic` | 入账/充值 | `inc`, `executeIncWithTransaction`, `recharge`, `rechargeSign`, `reward`, Trial Pool 扣减链, `resolveRechargeOrderDtoForLots`, `insertRechargeFundLotsIfNeeded` |
|
||||
| `WalletWithdrawLogic` | 提现与 Bonus 桶转换 | `withdraw`, `withdrawFrozen`, `rollbackWithdraw`, `doneWithdraw`, `bonusToDeposit`, `switchBonus` |
|
||||
| `WalletTrialLogic` | Trial 体验金生命周期 | `grantTrial`, `expireTrial`, `resolveTrialAmount`, `makeTrialPoolBizId`, `buildTrialPoolRemark`, `deductTrialPoolInRechargeTransaction`(若仍被 Recharge 调用则保留在 Recharge 或抽 `TrialPoolSupport` trait) |
|
||||
|
||||
**Trial Pool 边界**:`planTrialPoolDeductionForRecharge` / `finalizeTrialPoolAfterRechargeInc` 与充值事务强耦合,建议 **Phase 3 随 RechargeLogic 一起迁**;Trial 发放/过期独立进 `WalletTrialLogic`。
|
||||
|
||||
---
|
||||
|
||||
## 门面 WalletLogic(拆分后 ~150 行)
|
||||
|
||||
```php
|
||||
class WalletLogic
|
||||
{
|
||||
public function __construct(
|
||||
private WalletRegisterLogic $registerLogic,
|
||||
private WalletBetWinLogic $betWinLogic,
|
||||
private WalletRechargeLogic $rechargeLogic,
|
||||
private WalletWithdrawLogic $withdrawLogic,
|
||||
private WalletTrialLogic $trialLogic,
|
||||
) {}
|
||||
|
||||
public function run(WalletUpdateRequestDTO $requestDTO) { /* 分发 + deleteWalletCache */ }
|
||||
public function runRechargeOrder(WalletRechargeRequestDTO $dto) { /* 委托 rechargeLogic */ }
|
||||
|
||||
// 兼容 GrantLogic / 外部 static 调用
|
||||
public static function query(...) { return WalletQueryLogic::query(...); }
|
||||
public static function queryBizLog(...) { return WalletQueryLogic::queryBizLog(...); }
|
||||
}
|
||||
```
|
||||
|
||||
`ACTION_METHOD_MAP` 改为 **Logic 实例 + 方法名** 或 **callable 数组**,例如:
|
||||
|
||||
```php
|
||||
WalletLogModel::BIZ_TYPE_BET => [$this->betWinLogic, 'bet'],
|
||||
```
|
||||
|
||||
Webman DI 需在 [`config/`](slot-wallet/config/) 或现有容器绑定中注册子 Logic(若项目无自动注入,门面构造函数内 `new` 亦可,与当前 `GrantLogic` 风格一致)。
|
||||
|
||||
---
|
||||
|
||||
## 分阶段实施(你已选 phased + facade)
|
||||
|
||||
### Phase 0:准备(低风险)
|
||||
|
||||
- 为 `WalletLogic` 现有 public 方法补全/核对中文 PHPDoc(拆分时会移动代码,趁此对齐 [`php-clean-code`](.cursor/rules/php-clean-code.mdc))。
|
||||
- 确认 `minus()` 无调用后删除(或加 `@deprecated` 注释待下一版删)。
|
||||
- 更新 [`README.md`](slot-wallet/README.md)「实现入口」一节,列出子 Logic 索引。
|
||||
|
||||
### Phase 1:Query + Register + 基类
|
||||
|
||||
- 新建 `AbstractWalletMutationLogic`、`WalletQueryLogic`、`WalletRegisterLogic`。
|
||||
- `WalletLogic::query/queryBizLog` 改为委托;[`GrantLogic`](slot-wallet/app/api/logic/GrantLogic.php) 可继续 `WalletLogic::query()` 不动。
|
||||
- `register` 从 WalletLogic 迁出;`run()` 分发到 `WalletRegisterLogic`。
|
||||
- **验收**:注册接口、余额查询、Grant 通知链路回归。
|
||||
|
||||
### Phase 2:BetWin(最高复杂度)
|
||||
|
||||
- 新建 `WalletBetWinLogic`,迁移 `bet`/`win` 及 Redis round 状态方法。
|
||||
- `WalletController` 的 `bet`/`win` 专用入口仍走 `walletLogic->run()`,行为不变。
|
||||
- **注意**:`win()` 内对 `$requestDTO->fee` 的临时修改必须在 BetWinLogic 内用 `try/finally` 保持,避免泄漏到其他域。
|
||||
- **验收**:下注/派奖、Trial 阶段 bet/win、FreeSpin 代付、中间派奖 `is_end=0`、幂等 hit。
|
||||
|
||||
### Phase 3:Recharge / Inc
|
||||
|
||||
- 新建 `WalletRechargeLogic`,迁移 `inc` 全链路 + `recharge`/`rechargeSign`/`reward`。
|
||||
- `runRechargeOrder` 委托给 RechargeLogic(含 `rechargeOrderDto` 生命周期)。
|
||||
- **验收**:充值主链路、首充 Trial Pool 扣减、Fund Lot 落库、签到充值 `sign`。
|
||||
|
||||
### Phase 4:Withdraw + Trial
|
||||
|
||||
- 新建 `WalletWithdrawLogic`、`WalletTrialLogic`。
|
||||
- 补齐 `ACTION_METHOD_MAP` 中缺失的 `switchBonus` 映射(若 slot-sdk 仍在调 `type=switchBonus`,当前可能未路由到方法——拆分时可一并修复)。
|
||||
- **验收**:提现冻结/成功/失败回滚、Bonus 转 Deposit、Trial 发放/过期。
|
||||
|
||||
---
|
||||
|
||||
## 不建议的做法
|
||||
|
||||
- **不要把子用例再拆成 Logic 型 Service**(如 `WithdrawLogicService`),违反分层红线。
|
||||
- **不要一次性改 Controller 注入多个 Logic**,你已选 facade,保持对外稳定。
|
||||
- **不要把 BetService/WinService 的业务编排再搬回 Logic 后又复制一份**——子 Logic 只做事务、幂等、流水、MQ,核心算法继续调用现有 Service。
|
||||
|
||||
---
|
||||
|
||||
## 预期收益
|
||||
|
||||
- 单文件从 ~1900 行降至 **门面 ~150 行 + 各子 Logic 200–500 行**。
|
||||
- 改动 bet 不再误触 recharge 事务代码,Review 范围清晰。
|
||||
- 与 `GrantLogic` 风格统一,新人可按域定位代码。
|
||||
- 对外 API、`WalletLogic::run()` 签名、SDK 调用路径 **零破坏**。
|
||||
|
||||
---
|
||||
|
||||
## 风险与缓解
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|---|---|
|
||||
| 拆分引入行为回归 | 每 Phase 独立 PR;优先复制代码再删旧代码,不做顺手重构 |
|
||||
| `$requestDTO` 可变状态 | 基类 `bindRequest()` + 子 Logic 不跨用例复用实例 |
|
||||
| Webman 构造注入 | 若无 DI,Phase 1 先在 WalletLogic 内 `new` 子 Logic,后续再接线 |
|
||||
| Trial Pool 跨 Recharge/Trial | Phase 3 完成 Recharge 后再动 Trial;必要时抽 `TrialPoolDeductionSupport` trait 供 Recharge 专用 |
|
||||
|
||||
---
|
||||
|
||||
## 涉及文件
|
||||
|
||||
**新建**(均在 `slot-wallet/app/api/logic/`):
|
||||
|
||||
- `AbstractWalletMutationLogic.php`
|
||||
- `WalletQueryLogic.php`
|
||||
- `WalletRegisterLogic.php`
|
||||
- `WalletBetWinLogic.php`
|
||||
- `WalletRechargeLogic.php`
|
||||
- `WalletWithdrawLogic.php`
|
||||
- `WalletTrialLogic.php`
|
||||
|
||||
**修改**:
|
||||
|
||||
- [`WalletLogic.php`](slot-wallet/app/api/logic/WalletLogic.php) — 瘦身为门面
|
||||
- [`README.md`](slot-wallet/README.md) — 更新入口索引(可选 `.cursor/rules/slot-wallet-prd-and-money.mdc` 一行指向)
|
||||
|
||||
**不改**:
|
||||
|
||||
- [`WalletController.php`](slot-wallet/app/api/controller/WalletController.php)
|
||||
- 现有 `app/service/wallet/*Service.php`
|
||||
Reference in New Issue
Block a user