ok
This commit is contained in:
141
plans/free_credits_老用户隐藏评审_1c0ab623.plan.md
Normal file
141
plans/free_credits_老用户隐藏评审_1c0ab623.plan.md
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
name: Free Credits 老用户隐藏评审
|
||||
overview: EventBus 写库确定参加、status 只读展示;在此基础上用环境变量 FREE_CREDITS_ENROLL_REG_AFTER 做注册时间门槛——regTime 晚于该时间的用户才有资格参加,否则一律 status=-1 且 EventBus 跳过写池。
|
||||
todos:
|
||||
- id: env-reg-cutoff
|
||||
content: 新增 FREE_CREDITS_ENROLL_REG_AFTER 环境变量与 FreeCreditsLogic::isEligibleByRegTime(uid) 统一门禁
|
||||
status: completed
|
||||
- id: apply-gate-all-paths
|
||||
content: 在 status、syncHomeWithdrawUnlocked、handleFreeCreditInit、advanceAfterRecharge、claim、firstCashout 入口应用注册时间门禁
|
||||
status: completed
|
||||
- id: fix-docs-lobby
|
||||
content: 修正 FreeCreditsController PHPDoc(含 status=-1 含老用户/未达注册门槛);LobbyController 清理无用 import
|
||||
status: completed
|
||||
- id: guard-claim-cashout
|
||||
content: 无资格或无 player 时 claim/firstCashout 返回明确业务错误
|
||||
status: completed
|
||||
- id: verify-reg-cutoff
|
||||
content: 联调:regTime 早于门槛 status=-1 且 EventBus 不建池;晚于门槛走 win/首充完整流程
|
||||
status: completed
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# Free Credits 老用户隔离:注册时间门槛(计划)
|
||||
|
||||
## 目标
|
||||
|
||||
C 端全量更新后,**注册时间早于活动上线节点的用户视为老用户,不参加、不展示**;**注册时间晚于该节点的新用户**,在现有「EventBus 写库 = 参加」模型下正常走活动。
|
||||
|
||||
「默认参加」含义:**有资格参加**(EventBus 允许建池、status 可读),**不是**无需 EventBus 自动插入 `free_credits_player`。
|
||||
|
||||
---
|
||||
|
||||
## 分层架构(保持不变)
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
gate{regTime > FREE_CREDITS_ENROLL_REG_AFTER?}
|
||||
gate -->|否| block[不参加: status=-1 EventBus return]
|
||||
gate -->|是| eligible[有资格]
|
||||
eligible --> win[EventBus syncHomeWithdrawUnlocked]
|
||||
eligible --> init[EventBus free_credit_init]
|
||||
eligible --> api[status 只读 player 行]
|
||||
win --> pool[(free_credits_player)]
|
||||
init --> pool
|
||||
api --> pool
|
||||
```
|
||||
|
||||
| 路径 | 行为 |
|
||||
| --- | --- |
|
||||
| **读** `status()` | 未达注册门槛 → `status=-1`;达门槛且无 player 行 → `-1`;有行 → `buildStatus` |
|
||||
| **写** EventBus | 未达注册门槛 → 各 Logic 方法开头直接 return,不建池、不定格、不推进 |
|
||||
|
||||
---
|
||||
|
||||
## 实现要点
|
||||
|
||||
### 1. 环境变量
|
||||
|
||||
在 [`.env`](slot_console/.env) / 部署说明中增加(示例):
|
||||
|
||||
```env
|
||||
# 用户注册时间(Unix 或 Y-m-d H:i:s,建议与 TIMEZONE 一致)晚于此值才可参加 Free Credits
|
||||
FREE_CREDITS_ENROLL_REG_AFTER=2026-05-20 00:00:00
|
||||
```
|
||||
|
||||
- 在 [`config/app.php`](slot_console/config/app.php) 或新建 `config/free_credits.php` 读取:`getenv('FREE_CREDITS_ENROLL_REG_AFTER')`,`strtotime` 解析为 `enroll_reg_after_ts`(启动时或首次调用缓存)。
|
||||
- **未配置时的默认策略(已确认)**:`FREE_CREDITS_ENROLL_REG_AFTER` 为空或未配置 → **全员不参加**(`isEligibleByRegTime` 恒 false,`status=-1`,EventBus 不写池)。
|
||||
|
||||
### 2. 统一门禁方法(建议放在 [`FreeCreditsLogic`](slot_console/app/api/logic/FreeCreditsLogic.php))
|
||||
|
||||
```php
|
||||
/**
|
||||
* 是否具备 Free Credits 参与资格(注册时间晚于环境变量门槛)。
|
||||
*/
|
||||
protected function isEligibleByRegTime(int $uid): bool
|
||||
{
|
||||
$cutoff = self::enrollRegAfterTimestamp(); // 0 表示未配置
|
||||
if ($cutoff <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$userInfo = \app\service\user\UserService::getUserInfoEntity($uid);
|
||||
if ($userInfo === null || $userInfo->create_at === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$regTime = strtotime($userInfo->create_at);
|
||||
return $regTime !== false && $regTime > $cutoff; // 严格「晚于」
|
||||
}
|
||||
```
|
||||
|
||||
- **数据来源**:[`app\service\user\UserService::getUserInfoEntity`](slot_console/app/service/user/UserService.php)(调 user 服 `/innerapi/user/info`),与 [`EventBus::registerEvent`](slot_console/app/command/EventBus.php) 等同用法。
|
||||
- **注册时间字段**:[`app\entity\UserInfoEntity::$create_at`](slot_console/app/entity/UserInfoEntity.php)(`Y-m-d H:i:s`),比较前 `strtotime` 为 Unix 秒。
|
||||
- **不用** `UserTagService::tagInfo->regTime`(标签缓存,与账号创建时间可能不一致)。
|
||||
- 备选:若 Logic 内已大量使用 slotLib,可用 `\slotLib\services\UserService::getInstance()->setUid($uid)->getUserInfo()?->regTime`(构造函数内由 `create_at` 解析),但 console 侧优先统一 `app\service\user\UserService`。
|
||||
|
||||
### 3. 调用点(读写对称)
|
||||
|
||||
| 方法 | 未达门槛时 |
|
||||
| --- | --- |
|
||||
| `status()` | 直接 `return ['status' => -1]` |
|
||||
| `syncHomeWithdrawUnlocked()` | `return null` |
|
||||
| `handleFreeCreditInit()` | `return` |
|
||||
| `advanceAfterRecharge()` | `return` |
|
||||
| `claim()` / `firstCashout()` | `throw BusinessException('...')` 或统一文案 |
|
||||
|
||||
**说明**:已达门槛、但库中无 player 行 → 仍为 `status=-1`(尚未被 EventBus 纳入);达门槛且 win 后 → EventBus 建池 → status 非 `-1`。
|
||||
|
||||
### 4. 与「已首充」的关系
|
||||
|
||||
- 注册门槛解决:**老账号 / 老注册** 不进入活动。
|
||||
- 钱包侧 [`maybeSendFreeCreditInit`](slot_wallet/app/api/logic/WalletLogic.php) 仍仅 **首充** 发定格,二者叠加,互不替代。
|
||||
|
||||
### 5. 撤销项
|
||||
|
||||
- 不再单独做 `total_deposit == 0` 的 EventBus 门禁(由注册时间门槛覆盖「老用户」定义)。
|
||||
- 不再要求 `frozen_amount > 0` 才展示(保留 HOME_UNLOCKED 阶段)。
|
||||
|
||||
### 6. 文档与测试
|
||||
|
||||
- 更新 [`FreeCreditsController`](slot_console/app/api/controller/FreeCreditsController.php):`status=-1` = 未参加 / 活动关 / **注册时间早于门槛**。
|
||||
- 单测:mock `regTime` 与 env cutoff,覆盖 eligible / ineligible 的 status 与 freeze 是否被调用。
|
||||
- 联调矩阵见下。
|
||||
|
||||
---
|
||||
|
||||
## 联调矩阵
|
||||
|
||||
| regTime vs 门槛 | win 达门槛 | 首充定格 | status | EventBus 建池 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 早于 | - | - | `-1` | 否 |
|
||||
| 晚于 | 否 | 否 | `-1` | 否 |
|
||||
| 晚于 | 是 | 否 | `1` | sync 建池 |
|
||||
| 晚于 | - | 是 | `3/4` + packages | freeze |
|
||||
|
||||
---
|
||||
|
||||
## 新 C 端约定(不变)
|
||||
|
||||
- **`status === -1`**:隐藏(含老用户、未达注册门槛、未参加)。
|
||||
- **`status !== -1`**:已参加,按 `FreeCreditsPlayerModel` 状态渲染。
|
||||
Reference in New Issue
Block a user