first commit

This commit is contained in:
ray zhou
2026-05-21 18:16:26 +08:00
commit 033aa0ae69
324 changed files with 24705 additions and 0 deletions

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