12 KiB
todos:
- id: "user-is-new-user" content: "slot-user:AbstractRegisterService 增加 isNewUser 标志,Mobile/Imei/Name RegisterService 赋值,UserController::register 返回 is_new_user" status: pending
- id: "console-ggame-query" content: "slot-console:GGame 新增按 game_code 查可展示单条游戏方法" status: pending
- id: "console-recommend-logic" content: "slot-console:OnboardingRecommendLogic(center 取池 → 随机 → g_game 组装 → 降级)" status: pending
- id: "console-recommend-api" content: "slot-console:OnboardingController + GET /api/onboarding/recommend-game" status: pending
- id: "update-docs" content: "更新 register_popup_game_entry 文档:前端 is_new_user 条件请求 recommend-game 链路" status: pending
- id: "lobby-auth-types" content: "lobby:AuthResponse 增加 is_new_user;auth.service 注册后按标志决定是否拉 recommend-game" status: pending
- id: "lobby-onboarding-api" content: "lobby:新增 api/console/onboarding.api.ts 调用 GET /slot-console/api/onboarding/recommend-game" status: pending
- id: "lobby-onboarding-popup" content: "lobby:新用户注册成功后展示 OnboardingGamePopup(倒计时 + LET'S PLAY + 关闭)" status: pending isProject: false
is_new_user + console recommend-game 方案
方案评价
该方案推荐采用,理由:
- 符合 SSOT
register_popup_game_entry.md服务边界:user 管身份,console 管展示聚合 - 前端仍直连
slot-user注册,无需改注册入口 MobileRegisterService/ImeiRegisterService已有「账号存在则走登录」逻辑,正好需要is_new_user区分- 老用户误走 register 接口时不会触发 onboarding 弹窗
- 注册主链路不受 center/console 降级影响(推荐游戏失败只影响弹窗)
sequenceDiagram
participant FE as lobby_PWA
participant User as slot_user
participant Console as slot_console
participant Center as slot_center
participant GGame as g_game
FE->>User: POST register
alt 新用户创建
User-->>FE: token + uid + is_new_user=true
FE->>Console: GET recommend-game (Bearer token)
Console->>Center: innerapi onboarding/channel-game
Center-->>Console: game_codes
Console->>GGame: 按 game_code 查可展示游戏
Console-->>FE: onboarding payload
else 老用户登录回退
User-->>FE: token + uid + is_new_user=false
Note over FE: 不请求 recommend-game
end
Part 1:slot-user 增加 is_new_user
涉及仓库:/Users/ray/Documents/project/www/slot/slot_user
现状
MobileRegisterService.php 与 ImeiRegisterService.php 在 check() 返回 false 时会走 MobileLoginService / ImeiLoginService,但 Controller 无法区分「新建」与「登录回退」。
NameRegisterService.php 账号已存在直接返回 null(报错),成功则一定是新用户。
实现方式(最小改动)
在 AbstractRegisterService.php 增加:
/** 本次 register 请求是否真正创建了新用户(false 表示走了登录回退) */
public bool $isNewUser = false;
各 RegisterService 在对应分支赋值:
| 类型 | 新用户创建 | 登录回退 |
|---|---|---|
| mobile | isNewUser = true |
isNewUser = false |
| imei | isNewUser = true |
isNewUser = false |
| name | isNewUser = true |
N/A(失败返回 null) |
在 UserController::register() 响应中追加:
$data['is_new_user'] = $registerService->isNewUser;
login 接口不改(老用户走 login 本就不弹窗)。
注册响应示例
{
"token": "...",
"uid": 1387459,
"expires_in": 1234567890,
"is_new_user": true
}
Part 2:slot-console 实现 recommend-game BFF(03 子需求)
涉及仓库:/Users/ray/Documents/project/www/ray/slot-console
路由
沿用 Webman 自动路由(参照 RewardGrantController):
GET /api/onboarding/recommend-game
需登录(JWT),从 $request->userEntity->uid / $request->userEntity->source 取用户上下文。
核心 Logic(新建)
app/api/logic/OnboardingRecommendLogic.php 编排步骤(对齐需求 §5.1):
- 取
uid、source(source 为空按DEFAULT交给 center 回退) - 经
CenterClient→onboardingChannelGame($source)(SDK 已有:CenterService.php) enabled=false或game_codes为空 → 返回降级 payload- 从
game_codes简单随机选一个;查GGame可展示游戏 - 不可用则剔除后继续随机;全部不可用 →
enabled=false - 组装返回(字段见需求 §6.1)
GGame 扩展
在 GGame.php 新增按 game_code 查单条可展示游戏方法(复用 applyLobbyListableJoinsAndWhere,返回 id/name/icon_url/provider_code/game_code/category)。
可参照 slot-admin OnboardingChannelGameLogic::resolveGamesByGameCodes 的字段映射,但用户侧只返回需求文档定义的 game 结构。
GatewayService(可选薄封装)
app/service/center/CenterGatewayService.php:封装 CenterClient 初始化(host 来自 ShareConfigService::get('centerApiHost'),header server-name),Logic 不直接拼 HTTP。
Controller(新建)
app/api/controller/OnboardingController.php:
recommendGame(Request $request)→ 调 Logic →success($payload)- center 调用失败 / 异常:记录日志,返回
enabled=false(不抛错阻断)
展示字段来源
| 字段 | 来源 |
|---|---|
uid / player_number |
JWT uid |
player_number_display |
number_format($uid) |
platform_name |
ShareConfigService::sourceInfo($source) 或 center 渠道配置(首版可用 config/常量,与运营名对齐) |
trial_bonus_amount |
活动配置常量 20000($20 × 1000,对齐 03_wallet_fund_flow.md) |
countdown_seconds |
有游戏时 3,无游戏时 0 |
game |
GGame 查询结果 |
Part 3:lobby 前端接入(游戏大厅 PWA)
涉及仓库:/Users/ray/Documents/project/www/ray/lobby
这就是你的前端应用:Vue 3 + Vite + Vant,网关前缀通过 VITE_APP_API_BASE_URL 代理到各 slot 服务。
现有注册链路(已确认)
| 项 | 位置 |
|---|---|
| 注册 API | lobby/src/api/user/auth.api.ts → POST /slot-user/api/user/register |
| 注册编排 | lobby/src/services/user/auth.service.ts → setAuth(result) 存 token |
| 类型定义 | lobby/src/types/user/auth.d.ts(目前只有 token 字段,无 is_new_user) |
| Console API 范例 | lobby/src/api/console/console.ts → /slot-console/api/... |
| 注册入口(需统一改) | telregisterbox.vue、emailregisterbox.vue、login/index.vue、auth/telegram-callback/index.vue、register/index.vue |
典型流程(以手机注册为例):
userAuthService.register(...) → setAuth → initializeUserSession() → router.push('/')
弹窗现有模式可参考 WS Notify.popup(notifyPopupPayload.ts + DailySignInBox.vue),但 onboarding 不走 WS,注册成功后 HTTP 主动拉取。
lobby 改动点
1. 类型与 API
AuthResponse增加is_new_user?: boolean、uid?: number- 新建
lobby/src/types/console/onboarding.d.ts(对齐需求 §6.1 payload) - 新建
lobby/src/api/console/onboarding.api.ts:
GET /slot-console/api/onboarding/recommend-game
2. 注册编排(集中在一处,避免各页面重复)
扩展 auth.service.ts:
register(data):
1. result = registerAPI(data)
2. setAuth(result)
3. if result.is_new_user === true:
onboarding = await fetchRecommendGame() // 已 setAuth,request 拦截器会自动带 Authorization
return { ...result, onboarding }
4. return result
recommend-game 失败时 不阻断注册:onboarding.enabled = false,正常进首页。
3. 弹窗 UI
新建组件如 lobby/src/components/OnboardingGamePopup.vue(或 pages/home/components/):
enabled=true时展示:玩家编号、trial_bonus_amount、游戏封面、countdown_seconds倒计时- LET'S PLAY → 用
game.id走现有进游戏链路(game.api.ts/ 首页 launch 逻辑) - 关闭 → 仅关弹窗,不调后端
4. 触发时机
在注册成功且 is_new_user 的分支里,跳转首页前或首页 onMounted 展示弹窗(推荐:注册页拿到 onboarding 后 router.push('/') + 通过 pinia/commonStore 或 route state 传给首页展示,避免路由切换丢状态)。
各注册入口最终都应走 userAuthService.register,无需每个页面单独写 recommend 逻辑。
前端调用链路(lobby)
1. lobby → POST /slot-user/api/user/register
2. is_new_user === true:
lobby → GET /slot-console/api/onboarding/recommend-game
enabled=true → OnboardingGamePopup
3. is_new_user === false → 正常登录,无弹窗
4. initializeUserSession() → 进大厅首页 /
Part 4:文档更新
更新 03_console_recommend_game_bff.md 与父文档 §3.1:明确前端为 lobby PWA,注册后条件请求 recommend-game。
注意:后端不记录弹窗状态;刷新后是否再弹由 lobby 本地逻辑决定(需求 §8.3)。
Part 5:不在本次范围
- user 不调 center / console innerapi(按你确认的方案)
- 不新增
user_onboarding_popup表 - 不实现
mark_shown/mark_entered - login 接口不加
is_new_user(非必须)
验收要点
后端
- 新手机号/新 IMEI 注册 →
is_new_user=true;同账号再次 register →is_new_user=false is_new_user=true时 recommend-game 返回渠道游戏池随机一款(或 DEFAULT 回退)- center 无配置 / 调用失败 →
enabled=false,注册仍成功 game_codes含下架游戏 → 跳过,从剩余随机
lobby 前端
- 老用户走 register 登录回退(
is_new_user=false)→ 不请求 recommend-game,无弹窗 - 新用户注册成功 → 自动请求 recommend-game,
enabled=true时展示 onboarding 弹窗 - 点击 LET'S PLAY → 进入推荐游戏;点击关闭 → 留在大厅,不影响 Trial Balance
- 各注册入口(手机/邮箱/Telegram 等)行为一致(均经
userAuthService.register)