Files
cursor/plans/free_credits_老用户隐藏评审_1c0ab623.plan.md
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

142 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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` 状态渲染。