--- todos: - id: "wallet-strip-mq" content: "wallet bet/win/FreeSpinBetService 移除 trial MQ 发布;bet 响应增加 is_fs_paid_bet" status: pending - id: "pwa-mq-publisher" content: "PWA 新增 TrialRewardMqPublisher + MQKeyManager 常量(对齐 TrialRewardMQ)" status: pending - id: "pwa-notify-service" content: "PWA 新增 TrialRewardNotifyService(valid_bet / fs_consume / task_completed + 共享配置与 Redis 去重)" status: pending - id: "pwa-hook-wallet" content: "WalletService::bet/win 成功后调用 NotifyService;WalletEntity 补充 is_fs_paid_bet / wallet_created_at" status: pending - id: "verify-flow" content: "docker 内验证四条验收场景;跑 slot-backend 门禁" status: pending isProject: false --- # Trial MQ 从 wallet 迁到 PWA ## 你的三点反馈(代码核对结论) ### 1. 下注金额 PWA 知道,代付留 wallet —— 同意 - PWA 所有厂商下注均经 [`WalletService::bet`](slot-pwa/app/service/WalletService.php),请求里已有 `fee`、`biz_id`、`round_id`、`game_category`、`vendor_game_id`。 - FS 代付判定([`TrialFreeSpinRedisService`](slot-wallet/app/service/trial/TrialFreeSpinRedisService.php))和 `executeFreeSpinPaidBet` **继续留 wallet**。 - PWA 只需 wallet 在 bet 响应里多回一个**是否 FS 代付**标记(如 `is_fs_paid_bet: true`),即可决定: - FS 代付 → `valid_bet_amount = fee` 发 MQ - 常规下注且非试玩期 → `valid_bet_amount = fee` 发 MQ(PWA 侧用 fee,不再依赖 wallet 内部 withdraw/deposit 拆分) - 试玩期纯体验金下注 → 不发 MQ > 说明:wallet 内部 `valid_bet` 原口径是 `withdraw + deposit`(不含 bonus 部分)。若业务接受「充值后用 fee 计入解锁流水」,PWA 可直接用 fee,**无需** wallet 扩展拆分字段。若以后要精确排除 bonus 扣款,再让 wallet 回 `valid_bet_amount` 即可。 ### 2. grantTrial 的 task_completed 留 wallet —— 可接受,但当前无调用 全仓库 **没有任何服务** 调 `type=trial_grant` / `grantTrial()`。 `TrialTaskCompletedMqService` 在 wallet 里实际只有 **一条活路径**: - [`WalletLogic::win()`](slot-wallet/app/api/logic/WalletLogic.php) 试玩期派奖成功后 → `notifyIfBalanceReached` `grantTrial()` 里的 MQ 是**预留死代码**(需求文档里的绑手机/绑邮箱补发体验金,尚未接入)。 ### 3. 注册流程不走 grantTrial —— 你说得对 注册实际路径: ```mermaid sequenceDiagram participant Console as slot_console participant Wallet as slot_wallet Console->>Wallet: POST /api/wallet/update type=register Wallet->>Wallet: WalletLogic.register + RegisterService Note over Wallet: 写 frozen_bonus,不发 trial MQ ``` [`UserRegisterEventService::reward()`](slot-console/app/service/user/UserRegisterEventService.php) 只发 `type=register`,**不**调 `grantTrial`。 `register()` 也**不**发 `task_completed` MQ。 因此:**充值前 $50 门槛任务**,目前是靠 **试玩期 win 派奖** 后 wallet 发 MQ 触发的,不是注册时触发。 --- ## 目标架构 ```mermaid flowchart LR Provider --> PWA PWA -->|"HTTP bet/win fee+game_context"| Wallet Wallet -->|"余额 + is_fs_paid_bet"| PWA PWA -->|"trial_valid_bet / fs_consume / task_completed"| ActivityMQ ActivityMQ --> Activity ``` **wallet 移除(游戏路径)** - [`TrialValidBetNotifyService`](slot-wallet/app/service/trial/TrialValidBetNotifyService.php) 在 `bet()` 的调用 - [`TrialFreeSpinBetService`](slot-wallet/app/service/trial/TrialFreeSpinBetService.php) 内的 `TYPE_FS_CONSUME` MQ 发布 - [`TrialTaskCompletedMqService`](slot-wallet/app/service/trial/TrialTaskCompletedMqService.php) 在 `win()` 试玩期的调用 **wallet 保留** - FS Redis 代付判定与 `executeFreeSpinPaidBet` - `grantTrial()` 内 MQ(死代码,待绑手机/绑邮箱接入时生效) **PWA 新增** - `TrialRewardMqPublisher`(exchange/queue 对齐 [`slot\foundation\Constants\MQ\TrialRewardMQ`](slot-foundation/src/Constants/MQ/TrialRewardMQ.php)) - `TrialRewardNotifyService`:在 [`WalletService::bet/win`](slot-pwa/app/service/WalletService.php) 钱包调用成功后投递 MQ - bet + `!isTrialPhase`(PWA 用 [`UserRechargeStatusService`](slot-pwa/app/service/user/UserRechargeStatusService.php) 判断)→ `trial_valid_bet_accumulate` - bet + `is_fs_paid_bet`(wallet 响应)→ `trial_valid_bet_accumulate`(全额 fee)+ `trial_fs_consume` - win + 试玩期 + 余额达标 → `trial_task_completed`(Redis 48h 去重逻辑从 wallet 迁过来,读共享 Redis 配置) **activity 不变** - [`TrialRewardEventRouter`](slot-activity/app/service/mq/TrialRewardEventRouter.php) 消费格式不变 --- ## 关键改动文件 | 仓库 | 文件 | 动作 | |------|------|------| | slot-wallet | `app/api/logic/WalletLogic.php` | bet/win 删 MQ;bet 响应加 `is_fs_paid_bet` | | slot-wallet | `app/service/trial/TrialFreeSpinBetService.php` | 删 fs_consume MQ,保留 Redis consume | | slot-wallet | `app/entity/WalletEntity.php` | 可选加 `is_fs_paid_bet` 字段 | | slot-pwa | `app/service/MQKeyManagerService.php` | 加 `EXCHANGE_TRIAL_REWARD` / `QUEUE_TRIAL_REWARD` | | slot-pwa | `app/service/mq/TrialRewardMqPublisher.php` | 新建 | | slot-pwa | `app/service/trial/TrialRewardNotifyService.php` | 新建(valid_bet / fs_consume / task_completed) | | slot-pwa | `app/service/trial/TrialRewardShareConfigService.php` | 从 wallet 迁共享 Redis 配置读取 | | slot-pwa | `app/service/WalletService.php` | bet/win 成功后调 NotifyService | --- ## 试玩期判定(PWA 侧) 与 wallet 对齐,不依赖 `isTrialPhase` HTTP 字段: - `!UserRechargeStatusService::hasRecharged(uid)` - 且 wallet 返回的 `wallet_created_at` 在 `validity_hours` 内(需 PWA `WalletEntity` 增加该字段或 bet/win 时顺带读 wallet 接口) --- ## 本阶段明确不做 - 不改 `grantTrial` / 绑手机绑邮箱(无调用方) - 不改 `slot-pay` 的 `first_deposit` / `deposit_accumulate` MQ - 不迁 FS Redis 逻辑到 PWA - 不在 wallet 侧继续发游戏相关 trial MQ --- ## 验收 1. 试玩期下注:wallet 扣 frozen_bonus,**无** trial MQ 2. 充值后常规下注:PWA 发 `trial_valid_bet_accumulate`,activity `valid_bet_amount` 累加 3. FS 代付下注:wallet 不扣余额,PWA 发 `fs_consume` + `valid_bet_accumulate` 4. 试玩期 win 余额达 $50:PWA 发 `trial_task_completed`(48h 去重) 5. 注册 `type=register`:行为不变,仍无 trial MQ