This commit is contained in:
ray zhou
2026-06-29 14:51:55 +08:00
parent 225fb2bd28
commit 2dd9f17da9
319 changed files with 29461 additions and 9412 deletions

View File

@@ -0,0 +1,128 @@
<!-- 78ee2e02-349b-4b66-a20c-03e7ee129a45 -->
---
todos:
- id: "rabbitmq-prefetch"
content: "RabbitMqServiceconnect 去掉 prefetch=10getMessage 增加 singleMessagePrefetch 参数并在 true 时 basic_qos(1)"
status: pending
- id: "eventbus-call"
content: "EventBus::execute 调用 getMessage([$this, 'deal'], true)"
status: pending
- id: "consumer-tag"
content: "可选consumer_tag 加 getmypid() 便于管理台区分多进程"
status: pending
- id: "verify-supervisor"
content: "Supervisor numprocs 配置 + RabbitMQ 管理台确认 N consumer 且 Unacked≤1"
status: pending
isProject: false
---
# EventBus 多进程「每进程一次只处理一条」方案
## 现状与问题
[`slot_console/app/service/RabbitMqService.php`](slot_console/app/service/RabbitMqService.php) 在 `connect()` 里写死了:
```php
$this->setExhcange($type)->setBasicQos(null, 10, null)->setQueue()->queueBind();
```
`prefetchCount = 10` 表示:**每个 consumer 最多预取 10 条未 ack 的消息**。Supervisor 开 N 个 `php webman event:bus` 时,理论上最多有 `N × 10` 条消息被「占住」但未必在处理(尤其处理慢时,其余 9 条会堵在该进程本地)。
[`EventBus.php`](slot_console/app/command/EventBus.php) 当前调用:
```php
$rabbitMqService->getMessage([$this, 'deal']);
```
已是 **manual ack**`no_ack = false``deal()` 末尾 `$message->ack()`),只差把 prefetch 改成 1。
```mermaid
sequenceDiagram
participant Q as console_bus
participant P1 as Process1
participant P2 as Process2
Q->>P1: deliver msg1 (prefetch=1)
Q->>P2: deliver msg2
Note over P1: 处理 msg1未 ack 前不再投递
P1->>Q: ack msg1
Q->>P1: deliver msg3
```
## 推荐改动(对齐 slot_pwa / slot_hub 既有模式)
同仓库已有先例:
- [`slot_pwa/app/service/RabbitMqService.php`](slot_pwa/app/service/RabbitMqService.php) — `getMessage($callback, $qos=false)``$qos=true``basic_qos(null, 1, false)`
- [`slot_hub/plugin/slot/hub/WorkerBusiness.php`](slot_hub/plugin/slot/hub/WorkerBusiness.php) — 消费侧 `getMessage(..., true)`
### 1. 改 `RabbitMqService`
文件:[`slot_console/app/service/RabbitMqService.php`](slot_console/app/service/RabbitMqService.php)
- **connect 阶段**:去掉 `setBasicQos(null, 10, null)`(发布端不需要 prefetch消费端在 `getMessage` 里单独设置更明确)。
- **getMessage**:增加第二/along slot_pwa 风格:
```php
public function getMessage(callable $callback, bool $singleMessagePrefetch = false): void
{
if ($singleMessagePrefetch) {
$this->_channel->basic_qos(null, 1, false); // 每 consumer 未 ack 前最多 1 条
}
// basic_consume + wait 循环保持不变
}
```
- **consumer_tag可选但建议**:由固定 `$queueName . 'consumer'` 改为带 pid便于 RabbitMQ 管理台区分多个 Supervisor 进程,例如 `$this->queueName . '_consumer_' . getmypid()`。同一 channel 内唯一即可,多进程各自独立 connection不会冲突。
### 2. 改 `EventBus` 调用
文件:[`slot_console/app/command/EventBus.php`](slot_console/app/command/EventBus.php)
```php
$rabbitMqService->getMessage([$this, 'deal'], true);
```
仅此一处消费 `console_bus` 的入口需要改;其它只 `sendMessage` 的调用不受影响。
### 3. Supervisor 多进程部署(你已选此方式)
每个 worker 仍是独立 PHP 进程 + 独立 AMQP connection**订阅同一队列** `console_bus`[`MQKeyManagerService::QUEUE_CONSOLE_BUS`](slot_console/app/service/MQKeyManagerService.php)。RabbitMQ 默认 round-robin有 3 个 consumer 就 3 路并行,且配合 prefetch=1 后每个 consumer 同时只「持有」1 条未 ack 消息。
示例(进程数按 CPU/吞吐调整):
```ini
[program:slot_console_event_bus]
command=docker exec -w /app/www/slot/slot_console php82 php webman event:bus
process_name=%(program_name)s_%(process_num)02d
numprocs=3
autostart=true
autorestart=true
```
本地联调可开多个终端各跑一条(与 [`slot_console/doc/lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 一致):
```bash
docker exec -w /app/www/slot/slot_console php82 php webman event:bus
```
## 机制说明(为何这样就够)
| 机制 | 作用 |
| --- | --- |
| `basic_qos(0, 1, false)` | 该 consumer 未 ack 前broker 不再向它推第 2 条 |
| `no_ack = false` + `deal()` 末尾 `ack()` | 处理完成后才释放「占用槽位」 |
| 多进程各 `basic_consume` 同一 queue | broker 在多个 consumer 间分发 |
| 每进程独立 connection | 不共享 channel`getInstance` 单例仅进程内有效 |
**不需要** `exclusive = true`(那会变成单 consumer 独占队列,与多进程目标相反)。
## 多进程额外注意(非本次必改,但上线前心里有数)
1. **同 uid 消息顺序**:多 consumer 后,同一用户的两条 bus 消息可能乱序执行;若某类 event 强依赖顺序,需在 Logic 层加锁/幂等(例如按 `uid` 分布式锁),不能单靠 prefetch。
2. **失败重试**:目前仅 `TYPE_FREE_CREDIT_INIT` 在 catch 里 `nack(true)` 重入队;其它类型异常后仍 `ack()`,多进程不会放大这个问题,但重试策略需业务上接受。
3. **验证**RabbitMQ 管理台 → Queues → `console_bus` → Consumers应看到 N 个 consumer压测时每个 consumer 的 **Unacked** 应 ≤ 1。
## 改动范围
- 必改:[`RabbitMqService.php`](slot_console/app/service/RabbitMqService.php)、[`EventBus.php`](slot_console/app/command/EventBus.php)
- 不改Supervisor 配置可在运维侧按 `numprocs` 调整,不必动 PHP 代码
- 不测 RabbitMQ 真连接的单测可保持现状;若有 mock 消费测试,传入第二参数 `true` 即可

View File

@@ -0,0 +1,326 @@
<!-- 46ed22aa-9d18-40e3-a7fb-ed92e69d49a2 -->
---
todos:
- id: "fix-fbc-format"
content: "FbService 增加 resolveFbcForCapiraw fbclid 格式化为 fbccreationTime 优先从 ad_fbp 解析"
status: pending
- id: "fix-purchase-event-id"
content: "purchaseSelf 恢复使用 orderId 作为 event_id 保证幂等"
status: pending
- id: "hash-external-id"
content: "可选registerSelf/purchaseSelf 对 external_id 做 SHA256 哈希,对齐 TikTokDot"
status: pending
- id: "align-user-data"
content: "registerSelf 使用 array_filter解析 4xx 响应 body 写日志;可选异常上抛"
status: pending
- id: "fix-400-debug"
content: "记录 Meta error JSON不含 token日志脱敏 access_token建议轮换已泄露 token"
status: pending
- id: "verify-meta-test-events"
content: "用 test_event_code 在 Meta Test Events 验证 fbc 格式与 Purchase 去重"
status: pending
isProject: false
---
# FbService 像素打点问题分析与修复计划
## 结论:**有问题**,且会影响 FB 广告归因;**400 很可能就是 fbc 格式错误导致**
当前 [`slot_console/app/service/dot/FbService.php`](slot_console/app/service/dot/FbService.php) 的 `registerSelf` / `purchaseSelf` 在重构为 Guzzle 直调 Graph API 后,**把原始 fbclid 当作 `user_data.fbc` 上报**。Meta CAPI 对 `fbc` 有严格格式校验,**不符合 `fb.1.{ms}.{fbclid}` 时会返回 HTTP 400**Graph API error code 100Invalid parameter
---
## 关于「URL 上传来的 fbc/fbclid 没有点」——这是正常的
对照 Meta 官方文档([ClickID and the fbp and fbc Parameters](https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/fbp-and-fbc/)**Updated: Jan 9, 2026**
| 阶段 | 字段 | 格式 | 是否带点 |
|---|---|---|---|
| 广告落地 URL | `fbclid` 查询参数 | 原始 ClickID`IwAR2F4-dbP0l7Mn1IawQQGCINEz7PYXQvwjNwB_qa2ofrHyiLjcbCRxTDMgk` | **否** |
| 浏览器 `_fbc` cookie / CAPI `user_data.fbc` | 格式化 ClickID | `fb.{subdomainIndex}.{creationTimeMs}.{fbclid}` | **是**3 个点分隔 4 段) |
| 浏览器 `_fbp` cookie / CAPI `user_data.fbp` | Browser ID | `fb.{subdomainIndex}.{creationTimeMs}.{random}` | **是** |
官方示例:
- URL`https://example.com/?fbclid=IwAR2F4-dbP0l7Mn1IawQQGCINEz7PYXQvwjNwB_qa2ofrHyiLjcbCRxTDMgk`
- CAPI payload`"fbc": "fb.1.1554763741205.IwAR2F4-dbP0l7Mn1IawQQGCINEz7PYXQvwjNwB_qa2ofrHyiLjcbCRxTDMgk"`
官方明确说明:
> If the `_fbc` cookie is not available ... it is still possible to send the `fbc` event parameter ... if an `fbclid` query parameter is in the URL ... **The formatted ClickID value must be of the form** `version.subdomainIndex.creationTime.fbclid`.
> **creationTime** ... If you don't save the `_fbc` cookie, use the timestamp **when you first observed or received this fbclid value**.
因此:
- **落地页 / 注册侧存 raw fbclid无点是对的**,与你们 [`ImeiRegisterService`](slot_user/app/service/register/ImeiRegisterService.php) 注释一致。
- **问题不在采集,而在 CAPI 发送前缺少格式化**`FbService` 应把 raw fbclid 组装成 `fb.1.{ms}.{fbclid}` 再写入 `user_data.fbc`,而不是原样上报。
- `fbp` 来自浏览器 `_fbp` cookie本身带点`fb.1.1769311259905.2389032359262323`),当前做法正确。
**creationTime 补充**:官方要求用「首次观察到 fbclid 的时间」,不是转化事件发送时间。同一次落地页访问里,`fbp` 已含首访毫秒时间戳,可从中解析作为 `fbc``creationTime`(见下方真实样例)。
---
## 真实生产样例SiteController 日志)
来源:[`SiteController::fb`](slot_user/app/api/controller/SiteController.php) 第 28 行日志。
| 字段 | 实际值 | 说明 |
|---|---|---|
| `post.fbp` | `fb.1.1782099747655.910276663728351279` | 浏览器 `_fbp` cookie**已带点、格式正确**,可直接作为 CAPI `fbp` |
| `post.fbc` | `IwZXh0bgNhZW0BMABhZGlkAAAvy_DRTLVzcnRjBmFwcF9pZAo2NjI4NTY4Mzc5AAEe0aCSkd3i8J9sLoIGWHNcZF4YJuNXtOMXsFspgYX_76nQTzSUrDDtOzE4qJY_aem_gZtG64LnGIXu3gNiyhejkQ` | URL 上的 **raw fbclid无点**,命名虽叫 `fbc` 但不是 CAPI 最终格式 |
| `post.ua` | `...[FBAN/FBIOS;...]` | Facebook iOS 内置浏览器 |
注册后写入用户:`ad_fbc` = 上面 raw fbclid`ad_fbp` = 上面 fbp。
**当前 FbService 错误上报**(原样发送 `ad_fbc`
```json
"fbc": "IwZXh0bgNhZW0BMABhZGlkAAAvy_DRTLVzcnRjBmFwcF9pZAo2NjI4NTY4Mzc5AAEe0aCSkd3i8J9sLoIGWHNcZF4YJuNXtOMXsFspgYX_76nQTzSUrDDtOzE4qJY_aem_gZtG64LnGIXu3gNiyhejkQ"
```
**修复后应上报**(从 `fbp` 解析 `creationTime=1782099747655`,拼接 raw fbclid
```json
"fbc": "fb.1.1782099747655.IwZXh0bgNhZW0BMABhZGlkAAAvy_DRTLVzcnRjBmFwcF9pZAo2NjI4NTY4Mzc5AAEe0aCSkd3i8J9sLoIGWHNcZF4YJuNXtOMXsFspgYX_76nQTzSUrDDtOzE4qJY_aem_gZtG64LnGIXu3gNiyhejkQ",
"fbp": "fb.1.1782099747655.910276663728351279"
```
**creationTime 策略(推荐)**
1. 优先从 `entity.fbp` / `ad_fbp` 解析第 3 段毫秒时间戳(同会话首访时间,符合 Meta 要求)。
2. 解析失败时 fallback 到 `generateFBC()` 当前毫秒时间。
3. 禁止对 fbclid 做大小写变换。
**附带发现(可选后续)**`SiteController` 第 33 行要求 UA 含 `FB_IAB`,但 iOS Facebook 内置浏览器 UA 为 `FBAN/FBIOS`,该条日志在 info 之后可能被 `PARAMS_ERROR` 拒绝、未写入 Redis。若 iOS 用户依赖落地页 Redis 回退取归因,需放宽 UA 校验(如同时接受 `FB_IAB` / `FBAN/`)。客户端直传 fbclid 注册路径不受影响。
---
## HTTP 400 原因分析(结合当前代码)
### 生产报错确认2026-06-22
实际日志(`FbService::registerSelf`uid 3895162
```
Client error: POST https://graph.facebook.com/v24.0/211064574998002/events?access_token=...
resulted in a `400 Bad Request` response:
```
可确认:
- 失败方法:`registerSelf`(注册打点 CompleteRegistration
- Pixel ID`211064574998002`
- API`v24.0/events`
- **响应 body 被 Guzzle 截断/未记录**,日志里看不到 Meta 的 `error.message`(通常为 `Invalid parameter` / `fbc` 相关)
- **安全**`access_token` 完整出现在 ERROR 日志中Guzzle 异常 message 含 query string应在 Meta 后台 **立即轮换 token**,并修复日志脱敏(禁止记录含 token 的 URL
结合同一用户链路(落地页 raw fbclid + 合法 fbp**400 与未格式化的 `user_data.fbc` 高度吻合**。
### 最可能根因:`user_data.fbc` 格式非法(与真实样例直接相关)
当前发送(错误):
```json
"fbc": "IwZXh0bgNhZW0BMABhZGlkAAAvy_DRTLVzcnRj..."
```
Meta 要求([Customer Information Parameters](https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters/)Jan 9, 2026
> The format is: `fb.${subdomain_index}.${creation_time}.${fbclid}`.
未格式化的 raw fbclid **不以 `fb.` 开头**,会被判定为 invalid parameter → **HTTP 400**。这与「采集端无点是对的、发送端必须带点」完全一致。
修复后应发送:
```json
"fbc": "fb.1.1782099747655.IwZXh0bgNhZW0BMABhZGlkAAAvy_DRTLVzcnRj..."
```
### 为什么日志里可能看不清 Meta 具体报错
Guzzle 默认 `http_errors=true`,收到 400 会抛 `ClientException`,当前代码:
```php
} catch (\Throwable $e) {
LoggerService::error(__METHOD__, $e->getMessage());
}
```
- **成功分支的 `LoggerService::info($body)` 不会执行**400 时进 catch
- 只记 `$e->getMessage()`**通常不含 Meta 返回的完整 JSON**`error.message``error_user_msg``error_subcode`)。
- 修复时应从 `$e->getResponse()->getBody()` 解析并记录,便于确认是否为 `Invalid parameter: fbc`
### 其它可能导致 400 的次要因素
| 因素 | 当前代码 | 风险 |
|---|---|---|
| `registerSelf``array_filter` | 可能发送 `"fbc":""` / `"fbp":""` | 空字符串也可能触发参数校验失败 |
| `external_id` 类型不一致 | register 传 `[1689380]`整数purchase 传 `["1689380"]`(字符串) | 部分 Graph 版本对类型敏感,应统一为字符串数组 |
| `client_user_agent` 为空 | `action_source=website` 时 Meta 标注为 required | 若 `ad_ua` 为空仍发送 `""`,可能 400 |
| `Test.php` 测试 | `fbRegister` 未设置 `entity.fbc/fbp` | 本地测试必 400空 fbc |
| access_token / pixel_id 错误 | 配置问题 | 多为 401/403 或 OAuth error不一定是 400 |
**不太可能是 400 的项**`fbp` 格式(你的样例 `fb.1.1782099747655.910276663728351279` 合法)、`currency` 大小写、`event_time` 秒级时间戳。
---
## 数据流(当前)
```mermaid
sequenceDiagram
participant LP as LandingPage
participant User as slot_user注册
participant Dot as FbDot
participant FB as FbService
participant Meta as Meta_CAPI
LP->>User: POST fbp + fbc(实为URL fbclid)
User->>User: ad_fbc = 原始fbclid
Dot->>FB: entity.fbc = ad_fbc
FB->>Meta: user_data.fbc = 原始fbclid
Note over FB,Meta: 错误:应为 fb.1.{ms}.{fbclid}
```
---
## 已确认的问题
### 1. 【严重】`fbc` 格式错误(根因)
- 用户侧 [`slot_user/app/service/register/ImeiRegisterService.php`](slot_user/app/service/register/ImeiRegisterService.php) 明确注释:**落地页 `fbc` 实际是 URL 上的 `fbclid`,直接写入 `ad_fbc`**。
- [`UserInfoEntity::$ad_fbc`](slot_lib/src/entity/user/UserInfoEntity.php) 注释也是「FB点击id」不是 `_fbc` cookie。
- [`FbDot.php`](slot_console/app/command/dot/FbDot.php) 把 `ad_fbc` 赋给 `$entity->fbc` 后,`FbService` 原样上报:
```82:98:slot_console/app/service/dot/FbService.php
$fbc = $entity->fbc;// $this->generateFBC();
$fbp = $entity->fbp ;// $this->generateFPB();
// ...
"user_data" => [
// ...
"fbc" => $fbc,
"fbp" => $fbp
]
```
- Meta 要求 `fbc` 格式:`fb.{subdomainIndex}.{creationTimeMs}.{fbclid}`。
- 类内已有正确实现 [`generateFBC()`](slot_console/app/service/dot/FbService.php)(旧 SDK 代码也在用),但新代码里被注释掉未调用:
```235:244:slot_console/app/service/dot/FbService.php
public function generateFBC()
{
if (!$this->fbclid) return null;
return "fb.1.$creationTime.$this->fbclid";
}
```
- 构造函数已接收 fbclid`FbDot` 传的是 `ad_fbc`),但 `registerSelf`/`purchaseSelf` 完全没用 `$this->fbclid` 和 `generateFBC()`。
### 2. 【中等】Purchase 的 `event_id` 丢失幂等
- 旧 SDK 实现使用 `$entity->orderId` 作为 `event_id`(可去重、可重试)。
- 新 `purchaseSelf` 改为 `uniqid('purchase_', true)`,同一订单重复打点会被 Meta 视为不同事件,**无法幂等**。
```174:182:slot_console/app/service/dot/FbService.php
$eventId = uniqid('purchase_', true);
// 旧代码: ->setEventId($entity->orderId)
```
### 3. 【低】`external_id` 未 SHA256 哈希(官方为 recommended非 required
- 直调 CAPI 当前发送明文 uid`"external_id" => [$entity->uid]` / `["{$entity->uid}"]`。
- [Customer Information Parameters](https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters/)Jan 9, 2026对 `external_id` 写的是 **Hashing recommended**,不是必须。
- 旧 Facebook SDK 的 `UserData::setExternalId()` 会自动哈希;同项目 [`TikTokDot`](slot_console/app/command/dot/TikTokDot.php) 也已哈希。建议对齐,但优先级低于 fbc 格式化。
### 4. 【低】其它可改进点
| 项 | 说明 |
|---|---|
| `registerSelf` 未 `array_filter` | `purchaseSelf` 会过滤空字段,`registerSelf` 可能上报空 `fbc`/`fbp` |
| 响应未校验 | 仅 `LoggerService::info` 打 body不检查 `events_received` / `error` |
| 异常被吞 | `catch` 只记日志不抛出,上层无法感知失败 |
| 死代码 | 大段注释 SDK 代码 + 未使用的 FacebookAds import |
| `FbDot` 命名误导 | `$fbclid = $userInfo->ad_fbc` 逻辑对,但 `$entity->fbc = $fbclid` 易让人误以为已是 `_fbc` 格式 |
`fbp` 侧目前是正确的:来自浏览器 cookie`ad_fbp`),不应服务端 `generateFPB()`。
---
## 修复方案(建议最小改动)
### A. 在 `FbService` 内统一解析 `fbc`(核心)
新增私有方法,例如 `resolveFbcForCapi(string $rawFbclid, string $fbp = ''): ?string`
1. 若 `$rawFbclid` 已匹配 `^fb\.\d+\.\d+\.` → 直接使用(兼容未来若存完整 `_fbc` cookie
2. 否则取 raw fbclid优先 `$rawFbclid`fallback `$this->fbclid`)→ 格式化为 `fb.1.{creationTimeMs}.{fbclid}`。
- `creationTimeMs` **优先从 `$fbp` 解析**(正则 `^fb\.\d+\.(\d+)\.`),与真实样例 `1782099747655` 对齐 Meta「首访观察时间」。
- 解析失败时 fallback 到 `round(microtime(true) * 1000)`。
- 服务端生成时 `subdomainIndex` 固定 `1`(官方推荐)。
3. 无 fbclid 时返回 `null`,配合 `array_filter` 不上报空字段。
4. **禁止修改 fbclid 大小写**官方ClickID is case sensitive
`registerSelf` / `purchaseSelf` 均改为:
```php
$fbc = $this->resolveFbcForCapi($entity->fbc, $entity->fbp);
```
不再直接把 `ad_fbc` 当 `fbc` 上报。
### B. 恢复 Purchase 幂等
```php
"event_id" => $entity->orderId !== '' ? $entity->orderId : uniqid('purchase_', true),
```
优先订单号;仅测试/缺单号时 fallback。
### C. 哈希 `external_id`
```php
"external_id" => [hash('sha256', (string) $entity->uid)],
```
register / purchase 保持一致。
### D. 对齐 `registerSelf` 与 `purchaseSelf` + 改善 400 排障
- `registerSelf` 的 `user_data` 也使用 `array_filter`(空 fbc/fbp/ua 不上报)。
- `external_id` 统一为字符串数组:`[(string) $entity->uid]`。
- Guzzle 请求增加 `'http_errors' => false` **或** catch `ClientException` 时读取 response body**日志禁止输出含 access_token 的完整 URL**(只记 pixel_id、status、body
```php
LoggerService::error(__METHOD__, [
'status' => $resp->getStatusCode(),
'body' => (string) $resp->getBody(),
'pixel_id' => $this->pixelId,
'event_name' => 'CompleteRegistration',
]);
```
- 可选:`events_received < 1` 或 HTTP >= 400 时抛业务异常,让 FbDot 感知失败。
### E. `FbDot` 小清理(可选)
- 变量改名:`$fbclid = $userInfo->ad_fbc` 保留语义。
- `$entity->fbc` 仍可传 raw fbclid由 Service 格式化),或只依赖构造函数 fbclid、entity 不再设 fbc——二选一避免双份来源**推荐只传 raw fbclid 给构造函数entity.fbc 可选**。
---
## 验证方式
1. 用 [`Test.php`](slot_console/app/command/Test.php) 的 `fbRegister` / `fbPurchase`(带 `test_event_code`)在 Meta Events Manager → Test Events 查看:
- `fbc` 应为 `fb.1.{13位毫秒}.{fbclid}` 格式
- `fbp` 保持 `fb.1.{ms}.{random}`
- Purchase 重复同一 `orderId` 不应产生 duplicate 事件
2. 对比修复前后 payload 日志(`registerSelf` / `purchaseSelf` 已有 body 日志)。
3. 跑 slot 后端 completion report改动 PHP 后必跑)。
---
## 改动范围
| 文件 | 改动 |
|---|---|
| [`slot_console/app/service/dot/FbService.php`](slot_console/app/service/dot/FbService.php) | 核心resolve fbc、event_id、external_id 哈希、array_filter、可选响应校验 |
| [`slot_console/app/command/dot/FbDot.php`](slot_console/app/command/dot/FbDot.php) | 可选:变量命名/clarity无业务逻辑必须改 |
**不需要改** `slot_user` 注册写入逻辑(`ad_fbc` 存 raw fbclid 是合理设计,格式化应在 CAPI 发送层完成)。

View File

@@ -0,0 +1,122 @@
<!-- 6b933c7f-da14-42c8-8223-1fd4068c9b61 -->
---
todos:
- id: "unify-pending-query"
content: "WagerTaskModelgetUncompletedTasksVersion2 / getActiveCountVersion2 / lockedTasksV2 统一为 status IN (1,11) AND current_wager < required_wager"
status: pending
- id: "version2-loop-repair"
content: "UpdateWagerTask::version2()needed=0 自动完成 is_completed=1 时纠正并累加打码"
status: pending
- id: "add-unit-tests"
content: "补充单测覆盖 is_completed 脏数据与 required_wager=0 边界"
status: pending
- id: "data-hotfix-optional"
content: "可选uid 1876592 任务1 is_completed 改回 0 作为上线前救火"
status: pending
isProject: false
---
# 修复 version2 有待打码任务却不扣除的问题
## 根因(对应你这两条数据)
解析你贴的数据按表字段顺序
| 字段 | 任务1 `7733765055921637` | 任务2 `7745776340511881` |
|------|--------------------------|--------------------------|
| required_wager | **1000** | 0 |
| current_wager | **0** | 0 |
| is_completed | **1** | 1 |
| status | 1等待中 | 1等待中 |
| brief | 恢复提现额数据 | 提现退回 |
**下注不累加的直接原因**[`UpdateWagerTask::version2()`](slot_wallet/app/command/UpdateWagerTask.php) 调用 [`getUncompletedTasksVersion2()`](slot_wallet/app/model/multi/WagerTaskModel.php)查询条件是
```php
is_completed = 0 AND status IN (1, 11)
```
两条记录 **`is_completed` 都是 1**查询结果 **为空** `empty($tasks)` **直接 return**下注额不会分配
任务1 明明 `current_wager(0) < required_wager(1000)`本应吃打码但因 `is_completed=1` 被排除
```mermaid
flowchart TD
betMQ[下注MQ updateWagerTask] --> version2[version2]
version2 --> query[getUncompletedTasksVersion2]
query --> filter{"is_completed=0 AND status IN 1,11"}
filter -->|任务1 is_completed=1| empty[tasks 为空]
empty --> returnEarly[return 不扣除]
filter -->|正常任务| loop[按 id FIFO 累加 current_wager]
```
## 附带不一致(同一用户会「不能提现」但「也不扣打码」)
version2 提现判断走 [`WalletService::calculateWithdrawAmount()`](slot_wallet/app/service/WalletService.php)
```php
$num = $wagerTaskModel->getActiveCountVersion2($uid); // 只按 status IN (1,11) 计数
if ($num > 0) return 0;
```
[`getActiveCountVersion2()`](slot_wallet/app/model/multi/WagerTaskModel.php) **不看 `is_completed`**两条 `status=1` 都会计入 提现被挡
但打码更新 **看 `is_completed=0`** 不累加
这是典型的 **卡死状态**有任务不能提现打码也不前进
## 代码修复方案(推荐)
### 1. 统一 version2「待打码任务」定义
[`WagerTaskModel`](slot_wallet/app/model/multi/WagerTaskModel.php) version2 待处理任务定义为
> `status IN (STATUS_ON, STATUS_PROGRESS)` **且** `current_wager < required_wager`
理由真正决定是否还需打码的是进度而不是可能脏写的 `is_completed`
**改动点**
- **重写或替换** `getUncompletedTasksVersion2()` `where + whereExp('current_wager', '< required_wager')`或等价 ThinkPHP 写法去掉对 `is_completed=0` 的硬依赖
- **同步** `getActiveCountVersion2()``lockedTasksV2()`使用同一套待打码条件目前 `lockedTasksV2` 也不过滤 `is_completed`与打码查询语义不一致)。
- **同步** [`WalletService::calculateLeftWithdrawNeedBet()`](slot_wallet/app/service/WalletService.php) version2 分支已用 `lockedTasksV2` Model 后自动对齐)。
### 2. 加强 `UpdateWagerTask::version2()` 循环
[`UpdateWagerTask::version2()`](slot_wallet/app/command/UpdateWagerTask.php) foreach 内补充
- `needed == 0` `status` 仍为 ON/PROGRESS 调用 `markTaskCompletedVersion2()` 收尾避免 `required_wager=0` 的脏任务永远占着 `status=1`)。
- `needed > 0` `is_completed=1`脏数据累加打码时顺带把 `is_completed` 纠正为 0或在 `incrementWagerVersion2` 内一并更新避免下次再被旧逻辑挡住
### 3. 单测补充
[`tests/Unit/UpdateWagerTaskContributionTest.php`](slot_wallet/tests/Unit/UpdateWagerTaskContributionTest.php) 或新增 Model 单测覆盖
- `is_completed=1` `current_wager < required_wager` 的任务应被纳入待打码列表
- `required_wager=0` `current_wager=0` 的任务不应纳入对应你的任务2
- `getActiveCountVersion2` 与打码查询计数一致
## 该用户即时数据修复(可选,上线代码前可先救火)
uid `1876592`任务 `7733765055921637`
```sql
UPDATE wager_task_{shard}
SET is_completed = 0
WHERE id = 7733765055921637 AND uid = 1876592;
```
分表名按 uid 取模规则确定。)
任务2 `required_wager=0` 在代码修复后不会再挡打码若仍 `status=1` `is_completed=1`修复 `getActiveCountVersion2` 后也不再挡提现
## 不纳入本次范围
- 不判断 `withdraw_back` 业务倍数应为多少任务2 `required_wager=0` 在修复后的查询里自然不会参与打码分配
- 不追溯任务1为何 `is_completed=1` `completed_at=0`数据脏写来源代码修复以 **自愈脏数据** 为主
## 验收
1. uid 1876592 下注后任务1 `current_wager` 递增
2. `calculateLeftWithdrawNeedBet` 显示的剩余打码与 `current_wager` 同步下降
3. 任务1 打满后 `status=12``is_completed=1``getActiveCountVersion2` 0可提现
4. `slot-backend-completion-report` 门禁通过

167
plans/HTTP-c8f2b444.plan.md Normal file
View File

@@ -0,0 +1,167 @@
<!-- c8f2b444-d26a-4f73-b3e8-317e7228c8ab -->
---
todos:
- id: "redis-keys"
content: "RedisKeyManagerService 增加 duration buckets/sum/count 三个 key 常量"
status: pending
- id: "prometheus-service"
content: "PrometheusService 实现 recordHttpRequestDuration + render histogram 输出"
status: pending
- id: "middleware-timing"
content: "PrometheusMiddleware 计时并在 finally 记录 duration"
status: pending
- id: "grafana-panels"
content: "app_http_services_dashboard.json 增加 P50/P95/P99/Avg 与 route 耗时面板"
status: pending
- id: "verify"
content: "curl /metrics 验证 + 跑 completion-report 门禁"
status: pending
isProject: false
---
# slot_wallet HTTP 响应时长监控
## 现状
当前链路:
```mermaid
sequenceDiagram
participant Client
participant Middleware as PrometheusMiddleware
participant Handler
participant Redis
participant Metrics as MetricsController
Client->>Middleware: HTTP Request
Middleware->>Handler: handler()
Handler-->>Middleware: Response
Middleware->>Redis: hIncrBy requests_total
Middleware-->>Client: Response
Note over Metrics,Redis: Prometheus scrape
Metrics->>Redis: hGetAll
Metrics-->>Client: text/plain metrics
```
- 中间件:[`slot_wallet/app/middleware/PrometheusMiddleware.php`](slot_wallet/app/middleware/PrometheusMiddleware.php) 在 `finally` 中调用 `recordHttpRequest()`,只记请求数。
- 指标服务:[`slot_wallet/app/service/PrometheusService.php`](slot_wallet/app/service/PrometheusService.php) 用 Redis Hash 存 counter经 [`slot_wallet/app/controller/MetricsController.php`](slot_wallet/app/controller/MetricsController.php) 的 `/metrics` 输出。
- Grafana[`slot_wallet/doc/grafana/app_http_services_dashboard.json`](slot_wallet/doc/grafana/app_http_services_dashboard.json) 仅查询 `app_http_requests_total` / `app_business_responses_total`
**结论:可以加响应时长**,且与现有架构兼容;推荐新增标准 Prometheus Histogram而不是改现有 counter。
---
## 目标指标
新增 metric`app_http_request_duration_seconds`histogram
| 子指标 | 含义 |
|--------|------|
| `_bucket{le="..."}` | 各耗时桶累计次数 |
| `_sum` | 累计耗时(秒) |
| `_count` | 观测次数 |
**Labels** 与现有请求 counter 保持一致:`service`, `method`, `route`, `status`,便于在 Grafana 与请求量 join。
**Histogram buckets**Webman API 常用区间):
`0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, +Inf`
---
## 代码改动
### 1. Redis Key — [`slot_wallet/app/service/RedisKeyManagerService.php`](slot_wallet/app/service/RedisKeyManagerService.php)
新增 3 个常量(与现有 `PROMETHEUS_*` 命名一致):
- `PROMETHEUS_HTTP_REQUEST_DURATION_BUCKETS``prometheus:http:duration:buckets`
- `PROMETHEUS_HTTP_REQUEST_DURATION_SUM``prometheus:http:duration:sum`
- `PROMETHEUS_HTTP_REQUEST_DURATION_COUNT``prometheus:http:duration:count`
### 2. 记录耗时 — [`slot_wallet/app/service/PrometheusService.php`](slot_wallet/app/service/PrometheusService.php)
新增 `recordHttpRequestDuration(string $method, string $route, int $status, float $durationSeconds)`
- field 仍用 `json_encode` 存 labelsbucket 额外带 `le`
- `_bucket` / `_count``Redis::hIncrBy(..., 1)`
- `_sum``Redis::hIncrByFloat(..., $durationSeconds)`(避免整数毫秒精度损失)
- 对每个 `le` bucket`$durationSeconds <= le` 则递增;最后递增 `+Inf` bucket
- 抽取私有方法 `buildHttpRequestLabels()`,供 `recordHttpRequest` 与 duration 复用,避免重复 JSON 拼装
扩展 `render()`,在现有 counter 之后输出:
```text
# HELP app_http_request_duration_seconds HTTP request latency in seconds.
# TYPE app_http_request_duration_seconds histogram
app_http_request_duration_seconds_bucket{...,le="0.1"} N
...
app_http_request_duration_seconds_sum{...} X.XXX
app_http_request_duration_seconds_count{...} N
```
### 3. 中间件计时 — [`slot_wallet/app/middleware/PrometheusMiddleware.php`](slot_wallet/app/middleware/PrometheusMiddleware.php)
`process()` 开头 `$startedAt = microtime(true)``finally` 中:
```php
$durationSeconds = microtime(true) - $startedAt;
PrometheusService::recordHttpRequestDuration($method, $route, $status, $durationSeconds);
```
优化:将 `resolveRoute()` 结果缓存到局部变量,避免 `finally` 里重复解析;`recordHttpRequest``recordHttpRequestDuration` 共用同一份 `method/route/status`
耗时口径:**中间件包裹的完整 handler 执行时间**(含业务逻辑,不含 Prometheus 写 Redis 本身;写在 `finally` 末尾,影响极小)。
---
## Grafana 仪表盘扩展
更新 [`slot_wallet/doc/grafana/app_http_services_dashboard.json`](slot_wallet/doc/grafana/app_http_services_dashboard.json)在现有请求量面板下方新增一行「Latency」区域`version` 递增为 3
| 面板 | 类型 | PromQL 示例 |
|------|------|-------------|
| P50 Latency | stat | `histogram_quantile(0.50, sum by (le) (rate(app_http_request_duration_seconds_bucket{service="$service"}[$__rate_interval])))` |
| P95 Latency | stat | 同上 `0.95` |
| P99 Latency | stat | 同上 `0.99` |
| Avg Latency | stat | `sum(rate(..._sum...)) / sum(rate(..._count...))` |
| Latency Trend (P50/P95/P99) | timeseries | 三条 quantile 曲线unit=`s` |
| Top Slow Routes (P95) | bargauge | `topk(10, histogram_quantile(0.95, sum by (route, le) (rate(..._bucket{service="$service"}[$__range]))))` |
| Route Latency Details | table | 合并 route 的 P95、Avg、Requests与现有 Route Request Details 面板并列或扩列) |
所有新面板 `unit` 设为 `s`threshold 可按业务再调。
---
## 数据流(改后)
```mermaid
sequenceDiagram
participant Middleware as PrometheusMiddleware
participant Redis
participant Grafana
Middleware->>Middleware: startedAt = microtime(true)
Middleware->>Middleware: handler()
Middleware->>Redis: incr requests_total
Middleware->>Redis: incr duration buckets/sum/count
Note over Grafana: rate + histogram_quantile
Grafana->>Grafana: P50/P95/P99/Avg
```
---
## 验证步骤
1. 本地发若干 HTTP 请求到 slot_wallet含快/慢接口)。
2. `curl /metrics`,确认出现 `app_http_request_duration_seconds_bucket/_sum/_count`
3. Prometheus scrape 后,在 Grafana 导入更新后的 dashboard JSON选择 `service=slot_wallet`,确认 P50/P95 有数据。
4.`slot-backend-completion-report` 门禁(`php -l` + verify 脚本)。
---
## 注意事项
- **仅改 slot_wallet**(按你的选择);`slot_console` / `slot_pwa` 结构相同,后续可 copy 同一套改动。
- Redis Hash 会随 `route × status × bucket` 增长;与现有 `app_http_requests_total` 同一量级,可接受。
- Histogram 在 Prometheus 侧用 `rate()` + `histogram_quantile()` 算分位Grafana 查询写法与标准 Prometheus 一致。
- 无需改 Prometheus scrape 配置metric 名新增,非替换)。

View File

@@ -0,0 +1,176 @@
<!-- 3a02c714-3517-4fd8-ba3a-0c9172c34575 -->
---
todos:
- id: "parse-fbc-fbclid"
content: "在 insertADTag 回退路径实现 fbc→fbclid 解析与字段映射ad_fbp/ad_ua/ad_ip"
status: pending
- id: "redis-pop-latest"
content: "实现 resolveLatestDotPayloadBySourcezPopMax user:dot:set:{source} + unserialize 校验"
status: pending
- id: "imei-only-guard"
content: "回退逻辑仅 IMEI 新注册触发(覆写 ImeiRegisterService::insertADTag 或在 Abstract 中加平台/类型判断)"
status: pending
- id: "redis-cleanup"
content: "可选SiteController 或 pop 侧增加 ZSet 过期/长度清理"
status: pending
- id: "verify-fbdot"
content: "联调:落地页上报 → IMEI 注册 → 检查 user tag 与 FbDot 注册打点"
status: pending
isProject: false
---
# IMEI 注册 FB 像素归因补写方案评估
## 结论
**方案可行**,且与现有设计意图一致:[`slot_user/app/api/controller/SiteController.php`](slot_user/app/api/controller/SiteController.php) 负责落地页采集,[`slot_user/app/api/controller/UserController.php`](slot_user/app/api/controller/UserController.php) 里已有被注释的 `zPopMax` 回退逻辑,[`slot_user/app/service/register/ImeiRegisterService.php`](slot_user/app/service/register/ImeiRegisterService.php) 在新用户路径调用 `insertADTag`
你已确认范围:**仅 IMEI 新用户注册**(现有 `insertADTag` 调用点),不覆盖老用户登录补写。
---
## 现有数据流
```mermaid
sequenceDiagram
participant Landing as LandingPage_FB_IAB
participant Site as SiteController_fb
participant Redis as Redis_ZSet
participant App as iOS_App
participant Reg as ImeiRegisterService
participant Tag as insertADTag
participant Dot as slot_console_FbDot
Landing->>Site: POST fbp,fbc,ua,source
Site->>Redis: zAdd user:dot:set:{source}
App->>Reg: IMEI register (无 fb 参数)
Reg->>Tag: insertADTag(uid)
Tag->>Redis: 若无 fbclid 则取最新
Tag->>Tag: UserInfoCache 写入 ad_fbc/ad_fbp/ad_ua/ad_ip
Dot->>Tag: 读 ad_fbc 作为 fbclid 打 CompleteRegistration
```
| 环节 | 现状 |
|------|------|
| 落地页采集 | [`SiteController::fb`](slot_user/app/api/controller/SiteController.php) 校验 `FB_IAB` UA写入 `user:dot:set:{source}`member 为 `serialize(fbp,fbc,ua,ip,source)`score 为 `microtime` |
| IMEI 注册 | [`ImeiRegisterService::run()`](slot_user/app/service/register/ImeiRegisterService.php) 新用户分支 L115 调用 `insertADTag` |
| 写入用户标签 | [`insertADTag`](slot_user/app/service/register/AbstractRegisterService.php) 当前固定用 `$this->fbclid``ad_fbc`iOS 客户端通常为空 |
| FB 正式打点 | [`FbDot`](slot_console/app/command/dot/FbDot.php) 读 `ad_fbc`[`FbService::generateFBC()`](slot_console/app/service/dot/FbService.php) 用 fbclid 生成 fbc/fbp |
---
## 方案为何可行
1. **基础设施已就绪**Redis key [`USER_DOT_SET_KEY`](slot_user/app/service/RedisKeyManagerService.php)、落地页写入、注册侧回退思路UserController 注释代码)均已存在。
2. **iOS 场景匹配**iOS 包拿不到 WebView cookie但 FB 广告落地页在 `FB_IAB` 内可拿到 `fbp`/`fbc`,先上报再装 App 是合理补偿路径。
3. **与 PWA 不冲突**PWA 仍优先用请求里的 `fbclid`;仅当 `$this->fbclid`(及关联 fb 字段)为空时才回退 Redis。
4. **打点链路可通**`FbDot` 只要求 `ad_fbc` 非空;存入正确 fbclid 后现有 `FbService` 可继续生成 CAPI 所需 fbc/fbp。
---
## 必须处理的 4 个技术点
### 1. 字段映射(最关键)
当前 `insertADTag` 写:
```348:352:slot_user/app/service/register/AbstractRegisterService.php
protected function insertADTag(int $uid)
{
// ...
$userInfo->setInfo(['ad_fbc' => $this->fbclid, 'ad_fbp' => $this->fbp, ...], '');
}
```
Redis 里存的是落地页 **`fbc`/`fbp`**,不是 `fbclid`。而 `FbService` 期望 `ad_fbc` 存 **原始 fbclid**(见测试数据与 `generateFBC()` 实现)。
**实现要求**:从 Redis 取出 `fbc` 后,需解析出 fbclid
- `fbc` 格式:`fb.{subdomainIndex}.{creationTime}.{fbclid}`
- 取最后一个 `.` 之后的片段作为 fbclid 写入 `ad_fbc`
- `ad_fbp`、`ad_ua`、`ad_ip` 直接使用 Redis 中的值(比服务端随机生成 fbp 更准确)
- 若 `fbc` 为空SiteController 允许),则无法补 attribution应跳过写入并打 warn 日志
### 2. 取「最新」的方式
- 使用 `ZPOPMAX user:dot:set:{source} 1`(与注释代码一致),**消费**一条,避免同一条数据被下一个用户重复使用。
- 若 `insertADTag` 后续 `setInfo` 失败,可考虑不 pop 或失败写回(当前 `insertADTag` 有 try/catch失败只记日志pop 后丢失风险可接受,或改为「先 ZREVRANGE 再 ZREM 成功后再写」)。
### 3. 同渠道并发碰撞(已知局限)
按 `source` 取全局最新一条,**无法 100% 保证**「这条 fbc 就是当前这台设备」。同渠道短时间多用户注册可能串 attribution。
可接受的 MVP与当初 UserController 注释方案一致。若要提升准确率,后续可加:
- 时间窗口(如 30 分钟内)
- IP 辅助匹配(落地页 IP vs 注册 IP不完全可靠
- 落地页生成 `dot_token` 透传到 App需客户端配合改动更大
### 4. Redis 集合维护
当前 `zAdd` **无 TTL、无上限**,长期会膨胀。建议实现时顺带:
- 写入时 `ZREMRANGEBYSCORE` 清理超过 N 天(如 7 天)的旧 member
- 或按 source 限制 ZSet 最大长度
---
## 推荐改动位置(实现阶段)
不在 `UserController::register` 做(你已选 register_only + insertADTag 内聚),建议:
**主改文件**[`slot_user/app/service/register/AbstractRegisterService.php`](slot_user/app/service/register/AbstractRegisterService.php)
- 新增私有方法,例如 `resolveLatestDotPayloadBySource(string $source): ?array`
- `Redis::zPopMax(RedisKeyManagerService::getDotSetKey($source), 1)`
- `unserialize` + 校验必需字段(至少 `fbp` 非空;`fbc` 非空才能解析 fbclid
- 改造 `insertADTag`
- 若 `$this->fbclid` 为空,调用上述方法补全 `fbclid/fbp/ua/ip`
- 若补全后仍无 fbclid`return`(不写空 tag
- 否则按现有逻辑 `setInfo`
**可选**:若希望仅 IMEI 走回退、不影响 Name 注册,可把回退逻辑放在 [`ImeiRegisterService`](slot_user/app/service/register/ImeiRegisterService.php) 覆写 `insertADTag`,而非改 Abstract 基类。
---
## 前置条件(产品/客户端)
方案生效依赖用户路径:
1. 用户从 FB 广告进入落地页UA 含 `FB_IAB`
2. 落地页成功调用 `SiteController::fb`(带正确 `source`
3. 用户在合理时间窗口内完成 iOS 首次 IMEI 注册,且 `source` 与落地页一致
若用户跳过落地页直接装包注册,仍无法归因——这是架构固有限制,不是实现 bug。
---
## 风险清单
| 风险 | 级别 | 说明 |
|------|------|------|
| fbc 为空 | 中 | 落地页允许空 fbc补写无效FbDot 仍会报 fbclid 为空 |
| 同 source 串号 | 中 | 多用户并发时可能拿错上一条 fbc |
| pop 后写失败 | 低 | 数据丢失,仅影响单次 attribution |
| ad_fbp 未被 FbDot 直接使用 | 低 | 当前 FbDot 用 fbclid 重新 generate fbp落地页 fbp 写入 user tag 但 CAPI 仍用生成值。MVP 可接受;若要最佳 attribution 需后续改 FbDot 优先用 `ad_fbp`/真实 `fbc` |
---
## 验证建议
1. 落地页 mockPOST `SiteController::fb`,确认 Redis `user:dot:set:{source}` 有 member
2. IMEI 新用户注册(不带 fb 参数),查 `UserInfoCache` / user tag 中 `ad_fbc`、`ad_fbp`、`ad_ua`
3. 触发 `slot_console` 注册打点,确认 `FbDot::registerEvent` 不再报 fbclid 为空
4. 并发两条落地页 + 两次注册,观察是否出现串号(评估是否需加时间窗)
---
## 总结
**可行,且是 iOS 上架场景下合理的补偿方案。** 实现重点不是「能不能取 Redis」而是
1. 正确从 `fbc` 解析 fbclid 再写入 `ad_fbc`
2. 仅在客户端无 fb 参数时回退
3. 用 `zPopMax` 消费最新一条
4. 接受同渠道并发下的 attribution 碰撞,或后续迭代匹配策略
按你确认的范围,**只改 IMEI 新注册 `insertADTag` 即可**,无需动登录链路。

View File

@@ -0,0 +1,132 @@
<!-- 4459211d-83e4-4bc9-9a52-2fc0b9f1f467 -->
---
todos:
- id: "create-base-models"
content: "新建 app/model/GmStatSummaryModel.php 与 app/model/SlotUserModel.php表映射 + @property"
status: pending
- id: "tenant-extends"
content: "租户 Model 改为 Tenant* 继承基类,迁移统计/分页方法"
status: pending
- id: "update-imports"
content: "更新 DashboardLogic、MarketLogic 的 use 与实例化"
status: pending
- id: "docs-sync"
content: "同步 00/03 文档中的 Model 路径约定"
status: pending
- id: "verify"
content: "php -l + Logic 冒烟 + verify-slot-backend"
status: pending
isProject: false
---
# 统一数据表 Model 到 app/model 层
## 结论
**可以,且与项目既有约定一致。** [00-总览与公共约定.md](saas6.x/docs/商户后台/00-总览与公共约定.md) §4.3 已写明订单复用 `app\model\RechargeOrderModel` / `WithdrawalOrderModel``GameServerModel` 也已在 `app/model` 并被租户 Logic 直接调用。
当前实际是「**半统一**」:
| 表 | 现状 | 目标 |
|---|---|---|
| `s_pay.recharge_order` | 基类 [`app/model/RechargeOrderModel`](saas6.x/server/app/model/RechargeOrderModel.php) + 租户扩展 [`TenantRechargeOrderModel`](saas6.x/server/app/tenant/model/order/TenantRechargeOrderModel.php) | 保持不变(已是最佳实践) |
| `s_pay.withdrawal_order` | 同上 `WithdrawalOrderModel` + `TenantWithdrawalOrderModel` | 保持不变 |
| `s_common.game_server` | 已在 `app/model/GameServerModel` | 保持不变 |
| `s_statistics.gm_stat_summary` | 全在 [`app/tenant/model/market/GmStatSummaryModel`](saas6.x/server/app/tenant/model/market/GmStatSummaryModel.php) | **拆分**:基类上移到 `app/model` |
| `slot_all.user` | 全在 [`app/tenant/model/user/SlotUserModel`](saas6.x/server/app/tenant/model/user/SlotUserModel.php) | **拆分**:基类上移到 `app/model` |
```mermaid
flowchart TB
subgraph app_model [app/model 表映射层]
GmStatSummaryModel
SlotUserModel
RechargeOrderModel
GameServerModel
end
subgraph tenant_model [app/tenant/model 租户扩展层]
TenantGmStatSummaryModel
TenantSlotUserModel
TenantRechargeOrderModel
TenantWithdrawalOrderModel
end
subgraph tenant_logic [app/tenant/logic]
DashboardLogic
MarketLogic
end
GmStatSummaryModel --> TenantGmStatSummaryModel
SlotUserModel --> TenantSlotUserModel
RechargeOrderModel --> TenantRechargeOrderModel
TenantGmStatSummaryModel --> DashboardLogic
TenantGmStatSummaryModel --> MarketLogic
TenantSlotUserModel --> DashboardLogic
```
## 分层原则(你选的 base_only 方案)
### 放 `app/model`(共享表映射)
- `$table` / `$pk` / `$json`
- 完整 `@property` PHPDoc对齐 DDL
- **与业务场景无关**的基础查询:按 `source+date` 查单行、通用 scope 等
- **不**放 `organization + channels` 租户隔离逻辑(隔离仍在 Logic/Controller
### 保留 `app/tenant/model`(租户扩展)
- `extends app\model\*Model`
- 商户后台专用统计方法,例如:
- `paginateDailyRows()` / `listChannelSummaryRows()`(市场数据)
- `sumDailyPrecompute()` / `sumTotals()`(首页)
- `countRegisterByWindow()`(首页注册数)
- `sumSuccessByPayTime()`(订单统计,已有)
### 关键约束:不要误用 `BaseSourceModel`
[`BaseSourceModel`](saas6.x/server/app/model/BaseSourceModel.php) 带 `Source` 请求头全局 scope适用于 **admin 总后台**`RechargeOrderModel` 等)。
`GmStatSummaryModel` / `SlotUserModel`**直接 `extends think\Model`**(与现网一致),**不要**继承 `BaseSourceModel`,否则租户请求可能被错误的 `Source` header 隐式过滤。
租户数据隔离仍由以下保证(迁 Model 位置**不改变**
- `MerchantBaseController::ensureMerchantChannels()`
- Logic 入参显式 `organization` + `channels`
- `restrictRequestSourceByChannels()` 收敛请求 `source`
## 建议的文件变更
### 1. 新建 `app/model/GmStatSummaryModel.php`
- 从现有 tenant 版抽出:`$table = s_statistics.gm_stat_summary`、完整 `@property`
- 可保留 1~2 个中性方法:`findBySourceAndDate(string $source, string $date): ?self`
### 2. 新建 `app/model/SlotUserModel.php`
- 表映射 `slot_all.user` + 完整 `@property`(对齐 [03-用户管理.md](saas6.x/docs/商户后台/03-用户管理.md) 字段)
- 文档写的是 `UserAllModel`,代码可统一命名为 `SlotUserModel`(与表库名一致)或按文档改为 `UserAllModel`(二选一,建议 `SlotUserModel` 减少重命名面)
### 3. 租户扩展改名/改继承
| 现文件 | 调整后 |
|---|---|
| `app/tenant/model/market/GmStatSummaryModel.php` | 重命名为 `TenantGmStatSummaryModel.php``extends app\model\GmStatSummaryModel`,保留 `paginateDailyRows` / `listChannelSummaryRows` / `sumDailyPrecompute` / `sumTotals` |
| `app/tenant/model/user/SlotUserModel.php` | 重命名为 `TenantSlotUserModel.php``extends app\model\SlotUserModel`,保留 `countRegisterByWindow` |
### 4. 更新引用
- [`DashboardLogic.php`](saas6.x/server/app/tenant/logic/dashboard/DashboardLogic.php)`TenantGmStatSummaryModel` / `TenantSlotUserModel`
- [`MarketLogic.php`](saas6.x/server/app/tenant/logic/market/MarketLogic.php)`TenantGmStatSummaryModel`
### 5. 文档同步(小改)
- [00-总览与公共约定.md](saas6.x/docs/商户后台/00-总览与公共约定.md) §4.3:补充「`app/model` 放表映射,租户扩展放 `app/tenant/model`
- [03-用户管理.md](saas6.x/docs/商户后台/03-用户管理.md)Model 路径改为 `app/model/SlotUserModel` + `app/tenant/model/user/TenantSlotUserModel`
## 不在本次范围
- 不改 `RechargeOrderModel` / `WithdrawalOrderModel`(已符合模式)
- 不把租户 Logic 里的 `organization/channels` 过滤下沉到 Model global scope避免与 admin 混用)
- 不新建无业务价值的 `*Service` 中转层
## 验收
- `php -l` 全部改动 PHP 通过
- `DashboardLogic` / `MarketLogic` 行为不变(冒烟:`paginateDailyList``buildOverviewSummary`
- verify-slot-backend 门禁 PASS

View File

@@ -0,0 +1,53 @@
<!-- 921d6aef-b550-4dca-b907-d43c81593092 -->
---
todos:
- id: "move-logic"
content: "将 FirmwareLogic、UpgradeRecordQueryLogic 迁到 app/admin/logicnamespace 改为 app\\admin\\logic"
status: pending
- id: "move-validate"
content: "将 FirmwareCreateValidate、FirmwareListValidate、UpgradeRecordListValidate 迁到 app/admin/validatenamespace 改为 app\\admin\\validate"
status: pending
- id: "update-controllers"
content: "更新 FirmwareController、UpgradeRecordController 的 use 语句指向新命名空间"
status: pending
- id: "update-doc"
content: "同步 docs/requirements/OTA-admin.md §9 实现落点路径"
status: pending
- id: "verify"
content: "跑 php -l 与后端门禁脚本校验迁移结果"
status: pending
isProject: false
---
# OTA 后台专属 Logic/Validate 按应用拆分
## 背景与判断
这是 webman 多应用结构,控制器已按应用拆(`app/admin/controller/``app/internal/controller/`),但 Logic/Validate 仍堆在共用目录。`FirmwareLogic` / `UpgradeRecordQueryLogic` 与 3 个 Validate 只被 `app/admin/controller/*` 使用,属后台专属,挪到 `app/admin/` 下符合现有约定。`app\ → ./app` 的 PSR-4 映射使 `app\admin\logic` / `app\admin\validate` 自动加载,无需改 composer。
## 迁移清单(仅改 namespace + 路径,类体不动)
- Logic`namespace app\logic``app\admin\logic`
- `app/logic/FirmwareLogic.php``app/admin/logic/FirmwareLogic.php`
- `app/logic/UpgradeRecordQueryLogic.php``app/admin/logic/UpgradeRecordQueryLogic.php`
- Validate`namespace app\validate``app\admin\validate`
- `app/validate/FirmwareCreateValidate.php``app/admin/validate/FirmwareCreateValidate.php`
- `app/validate/FirmwareListValidate.php``app/admin/validate/FirmwareListValidate.php`
- `app/validate/UpgradeRecordListValidate.php``app/admin/validate/UpgradeRecordListValidate.php`
## 引用更新
- `app/admin/controller/FirmwareController.php``use app\logic\FirmwareLogic;``use app\admin\logic\FirmwareLogic;``use app\validate\FirmwareCreateValidate;` / `FirmwareListValidate;``app\admin\validate\...`
- `app/admin/controller/UpgradeRecordController.php``use app\logic\UpgradeRecordQueryLogic;``app\admin\logic\...``use app\validate\UpgradeRecordListValidate;``app\admin\validate\...`
## 不改动
- 内部专属 `OtaCheckLogic``OtaReportLogic` 与进程专属 `OtaRecordExpireLogic` 保留在 `app/logic/`(本次范围只动后台 CRUD
- DTO`OtaCheckDTO`/`OtaReportDTO`、Model、tests 不涉及这些类,无需改。
## 文档同步
- `docs/requirements/OTA-admin.md` §9 实现落点:把 `app/logic/FirmwareLogic.php``app/logic/UpgradeRecordQueryLogic.php` 改为 `app/admin/logic/...``app/validate/*` 改为 `app/admin/validate/*`
## 收尾校验
- 迁移后对 5 个新文件与 2 个控制器跑容器内 `php -l`,并执行后端门禁脚本 `~/.cursor/skills/slot-backend-completion-report/scripts/report.sh`,确认删除的旧类名不在其它已改文件中出现。

View File

@@ -0,0 +1,180 @@
<!-- 454dc363-a500-4be5-a576-c2dd86e5515a -->
---
todos:
- id: "remove-prewallet-check"
content: "Phase 1: 删除 executeBetWalletTransfer 中 getWallet 预检,改由 wallet bet 返回映射余额不足"
status: pending
- id: "defer-ledger-query"
content: "Phase 1: finalizeSuccessfulTransfer 去掉同步 queryBizLogmarkWalletSuccess(0) + 异步 ledger 回填"
status: pending
- id: "wallet-return-ledger"
content: "Phase 2: slot-wallet update 响应增加 ledger_idPOP 直接写入 provider_tx"
status: pending
- id: "merge-db-updates"
content: "Phase 3可选: 合并 callback_log / provider_tx 多次 UPDATE并加分段耗时监控"
status: pending
isProject: false
---
# POP modifyFee 性能分析与队列化建议
## 结论(直接回答)
**是的,同步路径偏重,但不宜把「整单回调」丢进队列。**
- Controller [`slot-pwa/app/pop/controller/CashController.php`](slot-pwa/app/pop/controller/CashController.php) 本身很薄,性能问题在 [`slot-pwa/app/pop/logic/CashLogic.php`](slot-pwa/app/pop/logic/CashLogic.php)。
- POP 协议要求 **同步返回最新 `balance`**,且 **钱包扣款/派奖必须在响应前完成**,否则厂商会重试或判失败。
- 相比 jdb/quick/gasea只做 wallet + Redis 幂等 + 异步流水POP 额外引入了 **callback_log、provider_tx、game_round** 三套分表状态机,单次成功回调大约 **6~10 次 DB 写 + 2~3 次 wallet HTTP**
- **已有异步**:用户交易流水(`TransactionLogService::log``pwa_transaction_log` worker、局终事件`GameRoundEventService::publishFinalSettled`)、试玩活动(`TrialRewardNotifyService` MQ publish
因此:**可以队列化的是「不影响 POP 响应正确性的旁路写/追踪」****不能队列化的是幂等、钱包、局状态校验**。
---
## 当前同步链路(成功路径 BET
```mermaid
sequenceDiagram
participant POP
participant MW as ProviderCallbackLogMiddleware
participant Logic as CashLogic
participant DB as ShardDB
participant Wallet as slot_wallet
participant MQ as RabbitMQ
POP->>MW: TransferInOut
MW->>DB: insert callback_log
MW->>Logic: modifyTransferInOut
Logic->>DB: update callback_log parse/in_progress
Logic->>DB: createOrGet provider_tx
Logic->>DB: loadOrCreate game_round
Logic->>DB: markProcessing / markWalletCalling
Logic->>Wallet: getWallet (BET 余额预检)
Logic->>Wallet: update bet
Logic->>Wallet: queryBizLog
Logic->>DB: markWalletSuccess + round update
Logic->>MQ: TransactionLog (async)
Logic->>DB: markProcessSuccess
Logic->>POP: balance
```
对比 legacy [`slot-pwa/app/quick/service/CashService.php`](slot-pwa/app/quick/service/CashService.php)**无 callback_log / provider_tx / game_round**wallet 成功后只发 MQ 写流水,同步面小很多。
---
## 同步步骤分类
| 步骤 | 位置 | 是否必须同步 | 说明 |
|------|------|-------------|------|
| callback_log 收包落库 | Middleware | 建议保留同步 | 审计与 trace但可合并多次 update |
| provider_tx create-or-get | `resolveProviderTx` | **必须** | 幂等键,防双花;必须在 wallet 前 |
| game_round load/create/validate | `RoundService` | **必须** | 后续 WIN/FINAL 依赖局状态 |
| 风控 evaluate + applyRisk | `handleTransferRiskEvaluation` | **必须**(接入真实风控后) | HOLD/REJECT 需在 wallet 前 |
| getWallet 余额预检 | `executeBetWalletTransfer` | **可优化掉** | wallet 本身会拒余额不足,多 1 次 RTT |
| WalletService bet/win | `invokeWalletBetOrWin` | **必须** | 响应 balance 来源 |
| queryBizLog | `finalizeSuccessfulTransfer` | **可移出热路径** | 仅回填 `wallet_ledger_id`;已有补偿 [`ProviderTxCompensationService`](slot-pwa/app/service/game/ProviderTxCompensationService.php) |
| game_round applyBet/Win/Final | `applyRoundUpdateAfterSuccess` | **必须** | 同局后续回调校验 |
| Redis round 缓存 | `updateRoundStateInfo` | 可弱一致异步 | 有 DB fallback但异步需防乱序 |
| TransactionLog | `TransactionLogService::log` | **已异步** | worker 内还做 VIP/日报/big win |
| callback_log 终态 | `markProcessSuccess` | 可延迟 | 不影响 POP 响应;影响实时排障 |
| UserProfit / RTP stat | `WalletService::bet/win` 内 | 可异步 | Redis 统计,非 POP 协议字段 |
---
## 主要性能瓶颈(按收益排序)
### 1. 冗余 wallet HTTP最高收益、最低风险
**BET 路径双查钱包:**
```686:711:slot-pwa/app/pop/logic/CashLogic.php
$currentWallet = WalletService::getWallet($userInfo->uid, $userInfo->currency);
if ($currentWallet->balance < $feeAmount) {
// ... markRejected ...
}
// ...
return $this->invokeWalletBetOrWin($walletCommand, true);
```
- 先 `getWallet`,再 `updateWallet(bet)`**多 1 次完整 HTTP 往返**。
- 建议:删除预检,直接 `bet()`,按 wallet 返回/错误码映射 `CODE_INSUFFICIENT_FUNDS`(与 legacy 一致)。
**成功后二次查询 ledger**
```829:839:slot-pwa/app/pop/logic/CashLogic.php
$ledgerQuery = $this->walletGatewayService->queryBizLog(
$transferContext->uid(),
$finalizeContext->walletRequestId,
ProviderTxService::resolveWalletBizType($finalizeContext->txType)
);
$walletLedgerId = (int) ($ledgerQuery['ledger_id'] ?? 0);
$this->providerTxService->markWalletSuccess(..., $walletLedgerId);
```
- 钱包 `update` 响应 [`WalletEntity`](slot-pwa/app/entity/WalletEntity.php) **不含 `ledger_id`**,故又调 `queryBizLog`**再多 1 次 HTTP**。
- 两条路(二选一或组合):
- **A推荐**:扩展 [`slot-wallet`](slot-wallet/app/api/logic/WalletLogic.php) `update` 响应带 `ledger_id`POP 直接写入,去掉热路径 `queryBizLog`。
- **B低改动**:热路径 `markWalletSuccess(ledger_id=0)`,通过现有 `ProviderTxWalletCompensate` 或新建轻量 MQ consumer 异步回填 `wallet_ledger_id`(与 reward_grant 文档中 queryBizLog 补偿模式一致)。
### 2. 多次分表状态机 UPDATE中等收益
单次回调对 `callback_log`、`provider_tx` 分别多次 `UPDATE`parse → in_progress → wallet_calling → successmiddleware 还有 insert。可考虑
- 合并 `markParseSuccess` + `markProcessInProgress` 为一次写(需改 Model SQL
- provider_tx 状态迁移合并processing + wallet_calling 若对排障非强依赖可合并)。
- **注意**:这是 DB 优化,不是 MQ队列化这些状态反而增加一致性复杂度。
### 3. 适合队列、且不影响 POP 响应的旁路
| 候选 | 做法 | 风险 |
|------|------|------|
| `wallet_ledger_id` 回填 | MQ / 定时补偿 | 低;审计字段短暂为 0 |
| `callback_log` 终态写 | 响应后 defer 或 MQ | 中;实时查 log 延迟 |
| `UserProfitService` / `GameUserRechargeRtpStatService` | 挪到 TransactionLog worker | 低;统计延迟秒级 |
| Redis round 缓存更新 | 响应后 MQ | 中;需 uid+round 有序消费 |
**不适合队列:**
- 整个 `modifyFee` / wallet bet-win厂商等 balance
- `provider_tx` 幂等创建(必须先于 wallet
- `game_round` 聚合更新(同局后续回调依赖)
---
## 与「全异步回调」方案的边界
若把 wallet 也异步化:
- POP 无法立即拿到 balance → **协议不满足**
- 失败重试会与幂等、局状态、钱包状态产生 **竞态**,需大量补偿与对账
现有设计已采用更合理模式:**同步关键路径 + 异步旁路**流水、局终事件。POP 的问题是 **关键路径上叠了审计表 + 多余 HTTP**,而非「异步做得不够」。
---
## 建议实施顺序(若后续要改代码)
### Phase 1 — 热路径减负(推荐先做,改动集中在 slot-pwa
1. 去掉 BET 前 `getWallet` 预检,统一由 wallet 拒单。
2. `finalizeSuccessfulTransfer` 去掉同步 `queryBizLog``markWalletSuccess(ledger_id=0)` + 触发异步回填(复用 `ProviderTxCompensationService` 或新增 `provider_tx_ledger_backfill` 队列)。
3. 补充 Feature 测试余额不足、幂等重复、wallet 成功但 ledger 延迟回填。
### Phase 2 — 跨服务优化(需 slot-wallet 配合)
1. `POST /api/wallet/update` 响应增加 `ledger_id`bet/win 写入后返回)。
2. slot-pwa 优先读响应字段,补偿任务作兜底。
### Phase 3 — DB/观测优化(可选)
1. 合并 callback_log / provider_tx 多次 UPDATE。
2. 对 `modifyTransferInOut` 加分段耗时 metricsmiddleware / provider_tx / round / wallet / finalize用数据验证 Phase 1/2 收益。
---
## 预期收益(量级)
- Phase 1BET 成功路径 **减少 1~2 次 wallet HTTP**(通常 20~80ms/次,视网络与 wallet 负载)。
- Phase 2WIN/FINAL 成功路径再 **减少 1 次 queryBizLog**
- 队列化旁路ledger 回填、统计):**不缩短 POP 感知 RTT 的主矛盾**,但降低峰值时 wallet/DB 叠加压力。
**不能指望**:把 callback_log / provider_tx / game_round 全部异步后 POP RTT 接近 quick/jdb——这三张表是 POP 架构的有意同步成本,用于幂等、审计、局聚合。

146
plans/PRD-9774f234.plan.md Normal file
View File

@@ -0,0 +1,146 @@
<!-- 9774f234-db58-4d1d-a960-14f15586ebc9 -->
---
todos:
- id: "user-input"
content: "用户下一条消息提供:变更一句话、涉及仓库、原因、数据影响、优先级"
status: pending
- id: "draft-prd"
content: "按 docs/requirements 体例撰写变更 PRD含变更前后对比表与验收标准"
status: pending
- id: "index-link"
content: "若属已有需求体系,更新 README/父文档索引并链到新文档"
status: pending
- id: "user-review"
content: "根据用户反馈修订开放问题与验收项"
status: pending
isProject: false
---
# 协作撰写变更需求 PRD
## 可以做什么
可以帮你写**变更需求Change RequestPRD**,结构对齐你仓库里已有规范,例如:
- 父文档:[docs/requirements/game_gateway_risk_prd_v_2.md](docs/requirements/game_gateway_risk_prd_v_2.md)
- 子需求:[docs/requirements/game_gateway/01_launch_session.md](docs/requirements/game_gateway/01_launch_session.md)
这些文档已包含:**目标与范围In/Out scope**、**依赖与边界**、**业务流程**、**数据表/接口**、**验收标准**——与你选择的「标准 PRD」一致。
---
## 当前阻塞:需要你补充变更说明
你已选择:**其它主题** + **变更需求** + **下一条消息文字说明**。在 Plan 模式下还缺少以下最小信息(建议下一条回复用 510 行写完):
| 必填 | 示例 |
|------|------|
| 变更一句话 | 「渠道创建时编号由运营手填改为系统生成」 |
| 涉及系统/仓库 | `slot-admin``slot-admin-vue``slot_wallet` 等 |
| 变更原因 | 运营误填、编号冲突、对接要求 |
| 是否影响线上数据 | 仅新数据 / 需迁移历史 |
| 期望上线时间或优先级 | P0 / 本迭代 / 可排期 |
可选但有助于写准:
- 相关页面或接口路径
- 已知约束(不能改表、必须兼容某厂商等)
- 是否需挂到现有父文档(如 Game Gateway 系列)
---
## 变更需求 PRD 文档结构(将按此产出)
在标准 PRD 基础上,**变更类**会额外突出「前后差异」,建议章节如下:
```mermaid
flowchart TB
input[你提供的变更说明]
code[可选:对照现有代码/表结构]
draft[撰写 PRD 初稿]
review[你确认/修订]
output[Markdown 落库或对话交付]
input --> code
code --> draft
draft --> review
review --> output
```
### 1. 文档元信息
- 标题、版本(如 V1.1-change、日期、作者/评审人
- 关联父文档(若属于 Game Gateway 等已有体系)
### 2. 背景与变更动机
- 现状问题As-Is
- 变更目标To-Be
- 不做的范围Out of scope
### 3. 变更摘要(核心)
| 维度 | 变更前 | 变更后 |
|------|--------|--------|
| 业务规则 | … | … |
| 界面/交互 | … | … |
| 接口/字段 | … | … |
| 数据/缓存 | … | … |
### 4. 功能需求(按角色或模块)
- 管理端 / 用户端 / innerapi / 跨服务slot_sdk分项
- 每条需求:**描述 + 规则 + 异常/边界**
### 5. 接口与数据(如涉及)
- API 路径、请求/响应字段变更(新增/废弃/只读)
- 表字段、索引、Redis key、MQ若有
- 幂等、事务、兼容性说明
### 6. 非功能需求
- 性能、安全、日志、监控、回滚策略
### 7. 验收标准(可测试)
- Given / When / Then 或检查清单
- 回归范围(哪些旧功能不能坏)
### 8. 实施与发布建议(可选)
- 涉及仓库与大致文件(实施阶段再细化)
- 发布顺序、配置开关、数据迁移步骤
### 9. 风险与开放问题
- 待产品/技术确认项列表
---
## 撰写时我会怎么做(确认计划后执行)
1. **读你提供的变更说明**必要时只读检索相关代码Controller / Logic / Model / Vue保证 PRD 与实现或意图一致。
2. **对齐仓库体例**表格元信息、In/Out scope、mermaid/文本流程图,与 [01_launch_session.md](docs/requirements/game_gateway/01_launch_session.md) 风格一致。
3. **落盘位置**(默认,你可改):
- 独立变更:`docs/requirements/<模块>/<简短英文名>_change.md`
- 若属 Game Gateway 体系:在 [game_gateway/README.md](docs/requirements/game_gateway/README.md) 索引中增加一行,并链到父文档
4. **交付方式**:默认写入仓库;若你只希望对话里预览,说明「不要写文件」即可。
**不会**在未经你确认前修改业务代码Plan 阶段仅产出文档。
---
## 与「反推 PRD」的区别
你选的是**变更需求**,不是从零或纯反推。若变更其实已部分落地(例如 [GameServerLogic.php](slot-admin/app/game/logic/GameServerLogic.php) 里渠道编号自动生成),可在 PRD 中标注 **「已实现 / 待实现」**,便于评审与补测。
---
## 你确认计划后的下一步
请在下一条消息直接粘贴变更说明(不必等再点选)。收到后我将:
1. 定文档标题与存放路径
2. 输出完整 PRD 初稿Markdown
3. 请你审阅「开放问题」与验收项,再按需修订一版
若变更属于 Game Gateway / 渠道 / 钱包等已有域,请点名,我会自动挂接对应父文档索引。

157
plans/Plan-0abba57d.plan.md Normal file
View File

@@ -0,0 +1,157 @@
<!-- 0abba57d-3d88-4972-ad6e-96d899cbee65 -->
---
todos:
- id: "expiry-service-mark-only"
content: "TrialBalanceExpiryService新增 markTrialExpiredIfNeeded / isTrialPlayBlocked / ensureCanLaunchGame停止对外清零编排"
status: pending
- id: "ws-connect"
content: "TrialBalanceExpiryConnectService仅打 tag + 弹窗,移除 clearExpiredTrialBalanceIfNeeded"
status: pending
- id: "entry-logic"
content: "TrialRewardEntryLogic移除全路径清零修正 trial_balance_expired 判定"
status: pending
- id: "game-launch-guard"
content: "GameLogic + GameController::login体验过期未充值时 BusinessException 拦截"
status: pending
- id: "constants-copy"
content: "TrialRewardEntryConstants更新弹窗与 launch 拒绝文案"
status: pending
- id: "verify"
content: "docker php -l + slot-backend-completion-report 自检"
status: pending
isProject: false
---
# 体验到期:仅标识、不清余额、禁止进游戏
## 背景与现状
当前 [`TrialBalanceExpiryConnectService`](slot-console/app/service/trial/TrialBalanceExpiryConnectService.php) 在 WS 连接时:
1. 调用 `clearExpiredTrialBalanceIfNeeded` → wallet `expireTrialBalance` + activity 删 `trial_reward_record`
2. 打 user tag `trial_bonus_expired`
3. 推送弹窗文案写「Trial balance has been cleared」
[`TrialRewardEntryLogic`](slot-console/app/api/logic/TrialRewardEntryLogic.php) 在 entry/status/withdraw-click 三条路径同样调用清零。
这与需求文档 [`03_wallet_fund_flow.md`](docs/requirements/trial_withdrawal/03_wallet_fund_flow.md)「不再产生 `TRIAL_BONUS_EXPIRE`」不一致。wallet 侧 [`isTrialPhase`](slot-wallet/app/service/WalletService.php) 在超期后已返回 `false`,体验金留在 `frozen_bonus` 但无法用于试玩下注;需在 **console 启动接口** 显式拦截。
## 目标行为
```mermaid
flowchart TD
subgraph wsConnect [WS连接事件]
A[未充值且体验期已过] --> B[打 user tag trial_bonus_expired]
B --> C[推送 WS 弹窗一次]
A --> D[不调用 wallet expireTrialBalance]
A --> E[不调用 activity trial-balance/expire]
end
subgraph gameLaunch [game/launch 与 game/login]
F[未充值且体验期已过] --> G[拒绝启动 BusinessException]
H[已充值或仍在体验期内] --> I[正常 launch]
end
```
| 场景 | 余额 | activity 记录 | user tag | 进游戏 |
|------|------|---------------|----------|--------|
| 体验期内、未充值 | 保留 | 保留 | 无 | 允许 |
| 体验过期、未充值 | **保留 frozen_bonus** | **保留** | 标记过期 | **拒绝** |
| 已充值 | 按首充规则 | 按首充规则 | 不处理 | 允许 |
## 实现步骤
### 1. 收敛「到期处理」到仅标识(`TrialBalanceExpiryService`
文件:[`slot-console/app/service/trial/TrialBalanceExpiryService.php`](slot-console/app/service/trial/TrialBalanceExpiryService.php)
- 新增 `markTrialExpiredIfNeeded(int $uid, string $source, string $currency, int $organization): bool`
- 已充值 → 直接返回 `false`
- `resolveWalletSnapshot` + `resolveTrialBalanceExpiry` 未过期 → `false`
- 已过期 → 仅 `markTrialBonusExpiredUserTag($uid)`,返回 `true`
- **不**调用 `expireTrialBalance`、**不**调用 `markActivityTrialBalanceExpired`
- 新增 `isTrialPlayBlocked(int $uid, string $source, string $currency, int $organization): bool`(供 launch 守卫复用):
- 逻辑:`!has_recharged && resolveTrialBalanceExpiry(...).expired`
- 新增 `ensureCanLaunchGame(...)`:当 `isTrialPlayBlocked` 为真时 `throw new BusinessException(...)`
- `clearExpiredTrialBalanceIfNeeded` 保留方法体但 **删除所有调用方**(避免误用);类注释改为「到期判定与标识」,去掉「清零」表述
- `markActivityTrialBalanceExpired` 可保留 private 方法(历史兼容),但本需求下不再被调用
### 2. 改写 WS 连接处理
文件:[`slot-console/app/service/trial/TrialBalanceExpiryConnectService.php`](slot-console/app/service/trial/TrialBalanceExpiryConnectService.php)
- 删除 `clearExpiredTrialBalanceIfNeeded``wasBalanceCleared` / `hadNoTrialBalance` 分支
- 流程简化为:
1. user tag 已标记 → return幂等防重复弹窗
2. 已充值 → return
3. 未过期 → return
4. `markTrialBonusExpiredUserTag` + `WsService::notifyClientPOP` + info 日志
- 更新类 PHPDoc「检测试玩到期打 user tag、推送弹窗不清零余额
### 3. 入口 Logic 停止清零并修正 `trial_balance_expired`
文件:[`slot-console/app/api/logic/TrialRewardEntryLogic.php`](slot-console/app/api/logic/TrialRewardEntryLogic.php)
-`buildEntryPayload` / `buildStatusPayload` / `resolveWithdrawClick` 中:
- 移除 `clearExpiredTrialBalanceIfNeeded` 调用及 `trialBalanceBeforeClear` 相关刷新逻辑
- `trial_balance_expired` 改为:`$trialExpiry['expired'] && !$walletSnapshot['has_recharged']`(不再依赖 `bonus_amount <= 0`
- 删除 private `clearExpiredTrialBalanceIfNeeded` 方法
- 移除对 [`TrialExpiredBalanceClearCommand`](slot-console/app/api/dto/TrialExpiredBalanceClearCommand.php) 的 useDTO 可保留文件以免大范围删除,但无引用)
### 4. game/launch 与 game/login 拦截
文件:[`slot-console/app/api/logic/GameLogic.php`](slot-console/app/api/logic/GameLogic.php)
- 构造注入或懒加载 `TrialBalanceExpiryService`
- `launch()` 开头调用 `ensureCanLaunchGame($dto->uid, source, currency, organization)`
- source/currency/organization 从 `GameLaunchDTO``userEntity` 读取(与 wallet 快照现有参数对齐)
- [`GameController::login`](slot-console/app/api/controller/GameController.php) 在调用 `SlotPlatformService::login` 前同样守卫deprecated 路径仍可能被 `launchByGameId` 使用)
错误处理:抛 `Webman\Exception\BusinessException`,消息使用新常量;[`api/exception/Handler`](slot-console/app/api/exception/Handler.php) 已注册,前端 `useGameLaunch` 会 toast 该 message。
### 5. 常量与文案
文件:[`slot-console/app/constants/TrialRewardEntryConstants.php`](slot-console/app/constants/TrialRewardEntryConstants.php)
- 更新 `POPUP_MESSAGE_TRIAL_BALANCE_EXPIRED`去掉「balance has been cleared」改为体验期结束、需充值后才能继续游戏英文与产品口径一致
- 新增 `GAME_LAUNCH_BLOCKED_MESSAGE`launch 拒绝文案,可与弹窗语义一致)
`CLEAR_SOURCE_*` 常量暂保留activity 接口仍存在,仅本链路不再调用)。
### 6. 不改动的服务
- **slot-wallet**:不删 `expireTrialBalance` API历史兼容本需求不再调用
- **slot-activity**`trial-balance/expire` innerapi 保留,本需求不再调用
- **slot-pwa**:按你的选择不拦截
- **lobby**:依赖 launch API 错误 message 即可,无需必改
## 关键代码对照
WS 连接当前清零调用(将删除):
```65:75:slot-console/app/service/trial/TrialBalanceExpiryConnectService.php
$clearOutcome = $this->trialBalanceExpiryService->clearExpiredTrialBalanceIfNeeded(
new TrialExpiredBalanceClearCommand(
$uid,
$channelSource,
$currency,
$organization,
$walletSnapshot,
[]
),
TrialRewardEntryConstants::CLEAR_SOURCE_WS_CONNECT
);
```
入口当前过期判定(将修改):
```112:112:slot-console/app/api/logic/TrialRewardEntryLogic.php
'trial_balance_expired' => $walletSnapshot['bonus_amount'] <= 0 && $trialExpiry['expired'],
```
## 验证要点
1. 模拟未充值用户、`wallet.created_at` 超过配置 `validity_hours`WS 连接一次 → user tag 写入、收到弹窗、**bonus 余额不变**、无 `TRIAL_BONUS_EXPIRE` 流水
2. 再次 WS 连接 → 无重复弹窗tag 幂等)
3. 同用户调用 `POST /api/game/launch` → BusinessException不返回 url
4. 同用户 `GET /api/trial-reward/entry` → `trial_balance_expired=true``trial_balance` 仍 > 0
5. 已充值用户超体验窗口 → launch 正常、WS 不弹窗
6. 收尾跑 `slot-backend-completion-report` 与 verify 脚本

View File

@@ -0,0 +1,77 @@
<!-- 214f69a5-3175-4601-b838-a7982eb9d190 -->
---
todos:
- id: "group-model"
content: "WalletFundLotGroupModel 扩展 SOURCE_TYPE_* 覆盖券/会员/活动/直接发奖,并加 createSingleMemberGroup 便捷封装(中文常量注释)"
status: pending
- id: "recharge-group"
content: "RechargeFundLotService纯 Deposit / 纯 Bonus 也建单成员组并写 group_norequired_wager=该 Lot 所需)"
status: pending
- id: "register-group"
content: "RegisterServicefee>0 且 bonus=0 时建单成员 Deposit 组Trial(fee=0) 保持不建"
status: pending
- id: "grant-group"
content: "GrantBonusService注入组模型直接发奖 Bonus 建单成员组并写 group_no"
status: pending
- id: "win-unify"
content: "WinService去掉未分组结算路径统一 finalizeGroup补全 deposit-only/bonus-only 退化组的 Completed/PlayedOut 语义"
status: pending
- id: "bet-cash"
content: "BetService确认/清理 Cash→FIFO progress_group 计入逻辑,移除未分组丢弃相关死分支与注释"
status: pending
- id: "task-display"
content: "PlayerTaskQueryService以组为唯一任务结构未分组分支降为历史兜底或移除"
status: pending
- id: "migration"
content: "新增回填 command将存量进行中未分组 Lot 迁为单成员组(按 uid 分片、幂等)"
status: pending
- id: "doc-update"
content: "更新 docs/requirements/钱包系统V2.md §7/§10/§11人人有组 + Cash 计入 progress_group"
status: pending
- id: "tests"
content: "WalletGroupWageringTest 补单成员组与 Cash 计入打码进度用例"
status: pending
- id: "verify"
content: "收尾跑 verify-slot-backend.sh 门禁 + docker php -l输出检测报告"
status: pending
isProject: false
---
# 钱包打码组统一(路线 A人人有组
## 目标与硬约束
- 真金每笔 `wallet_fund_lot` 都归入一个 `wallet_fund_lot_group`**不再有 `group_no=''` 的真金 Lot**(单 Lot = 单成员退化组)。
- **Cashwithdraw有效投注必须计入当前 FIFO `progress_group`**(修掉「只有未分组 Lot 时 Cash 白打」的缺陷)。
- **Trial 体验金永远独立**:不建 Lot、不建组、不进 `BetService/WinService`(已天然满足,仅需保证不破坏)。
- 复用现有三表,**不改表结构**;仅做数据回填迁移。
## 现状关键事实(已核对)
- 建组只在「Deposit+Bonus 同时存在」时发生:`RechargeFundLotService::resolveRechargeGroupNo``RegisterService::resolveRegisterGroupNo``deposit<=0 || bonus<=0` 返回空串)。
- 纯发奖 Bonus 永远未分组:`GrantBonusService::insertDirectRewardBonusLot``insertFundLot` 不带 `group_no`)。
- Cash 投注归属:`BetService::accumulateGroupWager``withdrawValidBet` 计入 `lockEarliestActiveGroup`**无 Active 组时直接丢弃**(缺陷根因)。
- 结算双路径:`WinService::execute` 同时跑 `finalizeActiveGroups` + `finalizeUngroupedLots`
- 展示双路径:`PlayerTaskQueryService::queryTaskProgress` 返回 `groups` + 未分组 `bonus_tasks/deposit_tasks`
## 设计决定
- 单成员组:`group_no` 复用来源键(`order_no` / 注册 `biz_id` / grant `wallet_request_id``deposit_amount`/`bonus_amount` 一侧为该 Lot 金额、另一侧 0`required_wager = lot.required_wager`
- `WalletFundLotGroupModel` 扩展 `SOURCE_TYPE_*`,覆盖券/会员/活动/直接发奖(现仅 REGISTER=1、RECHARGE=4
- `BetService`:成员投注计入自身 `group_no`、Cash 计入 FIFO 最早 Active 组——逻辑不变但因「人人有组」Cash 不再丢失;`consumeForBet` 仍累加 Lot 级 `current_wager` 供明细展示。
- `WinService`:去掉未分组结算路径,统一走 `finalizeGroup`;补全**单边退化组**deposit-only / bonus-only的 Completed / PlayedOut 语义。
- 迁移期可保留 `finalizeUngroupedLots` 作为历史兜底,回填完成后再删。
## 影响文件
- `slot-wallet/app/model/multi/WalletFundLotGroupModel.php`:加 `SOURCE_TYPE_*`;可加 `createSingleMemberGroup()` 便捷封装。
- `slot-wallet/app/service/wallet/RechargeFundLotService.php`:纯 Deposit、纯 Bonus 也建单成员组并写 `group_no`
- `slot-wallet/app/service/wallet/RegisterService.php``fee>0 & bonus=0` 建单成员 Deposit 组。
- `slot-wallet/app/service/wallet/GrantBonusService.php`:注入组模型,直接发奖 Bonus 建单成员组并写 `group_no`
- `slot-wallet/app/service/wallet/WinService.php`:统一结算路径,处理退化组终态。
- `slot-wallet/app/service/wallet/BetService.php`:清理「未分组 Cash 丢弃」相关分支与注释,确认 Cash→FIFO 组生效。
- `slot-wallet/app/service/wallet/PlayerTaskQueryService.php`:以组为唯一任务结构;未分组分支降为历史兜底或移除。
- 迁移:新增 command参照 `app/command/InitDB.php`)回填存量「进行中」未分组 Lot 为单成员组。
- 文档:`docs/requirements/钱包系统V2.md` §7 / §10 / §11 改为「人人有组 + Cash 计入 progress_group」。
- 测试:`slot-wallet/tests/Feature/WalletGroupWageringTest.php` 补单成员组与 Cash 计入用例。
## 风险 / 待确认
- 退化组 PlayedOutdeposit-only 组资金耗尽未达标时 Deposit 成员状态如何置(现 `markGroupBonusPlayedOut` 只处理 Bonus
- 存量回填在分表上的批量与幂等(按 `uid` 分片,`createGroupIfAbsent` 幂等)。
- 是否一并采纳 V2「整笔只计 progress_group」成员投注也归 FIFO 组而非自身组)——本方案默认**不改**,保留现有「成员计自身组 + Cash 计 FIFO 组」,单组场景下二者等价。
- 是否同时调整扣款顺序为 V2 的「Cash 最后扣」——**默认不在本次范围**。

View File

@@ -0,0 +1,67 @@
<!-- 4459211d-83e4-4bc9-9a52-2fc0b9f1f467 -->
---
todos:
- id: "arch"
content: "修订第 4.2/8/8.1-8.4/21/22/26/27 章app/tenant 改为 webman 多应用 + 继承 TenantController + 注解挂中间件 + 前端 App-Id 说明"
status: pending
- id: "datascope"
content: "修订第 9.1-9.3 章:删除 TenantDataScopeService改复用 TenantController 的 organization/channels/restrictRequestSourceByChannels新增 channels==['all'] 防御"
status: pending
- id: "orders"
content: "修订第 3/4.3/6/13.1/14.1/14.7/22.4/22.5/26/27 章:订单改直连 s_pay + Logic 层 org+source 过滤与字段白名单,补单表无归档限制"
status: pending
- id: "firstpay"
content: "修订第 10.2 章并波及 10.6/11.3/11.4:去掉今日首充金额,处理 frist_pay_cash_amount 引用"
status: pending
- id: "enum"
content: "修订第 14.4 审核状态补 0/1/2/3新增 slot_all.user 与 gm_stat_summary 字段核对说明"
status: pending
- id: "crossrepo"
content: "修订第 12.10/15/16 章DDL/索引/PHPDoc 标注为跨团队协调项,不在 saas6.x 执行"
status: pending
isProject: false
---
# 商户后台文档修订计划
仅修订 [saas6.x/docs/商户后台.md](saas6.x/docs/商户后台.md),不改任何代码。依据已确认的 5 项决策对齐现网实现。
## 已确认决策(贯穿全文)
- 鉴权与数据权限:复用 Saimulti tenant 体系,控制器继承 `plugin\saimulti\basic\TenantController``plugin/saimulti` 一行不改。
- 应用形态:真正的 webman 多应用目录 `server/app/tenant/`(命名空间 `app\tenant\`),默认路由 `/tenant/*`
- 订单数据:复用现网直连 `s_pay``app\model\RechargeOrderModel` / `WithdrawalOrderModel`,在 `app/tenant` Logic 层强制 `organization + source` 过滤并裁敏感字段;不走 slot-sdk、不改 slot-pay。
- 渠道隔离:数据治理 + 代码防御双管(商户配真实渠道、禁 `['all']`;商户后台遇 `channels==['all']` 拒绝/返回空)。
- 首页去掉"今日首充金额",保留首充人数。
## 具体章节改动
### 1. 架构归属(第 4.2、8、8.1-8.4、21、22、26、27 章)
-`server/app/tenant` 明确为 **webman 多应用**`app\tenant\` 命名空间,自动路由 `/tenant/...`),并说明依据:框架 `App::guessControllerAction()` 支持 `app\<app>\controller\...`
- 新增"基类约定"`app\tenant\controller\MerchantBaseController extends plugin\saimulti\basic\TenantController`,基类用 `#[Middleware(CheckTenantLogin::class, CheckTenantAuth::class, TenantLog::class)]` 挂鉴权(与现网 [FundController](saas6.x/server/app/controller/fund/FundController.php) 同构)。
- 说明前端 `tenant-vue``/tenant/*` 需带 `Authorization` + `App-Id``TenantController::checkSite()` 校验)。
- 权限用方法注解 `#[Permission('名称','slug')]`,由 `CheckTenantAuth` 校验。
### 2. 数据权限:删除 TenantDataScopeService第 9.1-9.3 章)
- 删除自建 `TenantDataScopeService`,改为复用 [TenantController](saas6.x/server/plugin/saimulti/basic/TenantController.php) 已有的 `$this->organization``$this->channels``restrictRequestSourceByChannels()`,渠道展开复用 `SystemOrganizationLogic::resolveEffectiveChannelCodes()`
- 新增 `channels==['all']` 防御要求(商户后台拒绝/返回空)。
### 3. 订单改直连 s_pay第 3、4.3、6、13.1、14.1、14.7、22.4、22.5、26、27 章)
- 把"slot-sdk → slot-pay / 禁直连 s_pay"改为"复用现网 `s_pay` 直连模型Logic 层强制 `organization+source` + 字段白名单"。
- 14.7 敏感字段:由"在 slot-pay 端剔除"改为"在 `app/tenant` Logic 层 `field()` 白名单只选可展示字段"。
- 补充限制说明:现网 `RechargeOrderModel`/`WithdrawalOrderModel``s_pay` 单表、不含按月归档表,跨月历史订单查询范围受限。
### 4. 首页首充金额(第 10.2 章,并波及 10.6 / 11.3 / 11.4
- 删除 10.2 "今日首充金额 SUM(frist_pay_cash_amount)"行,保留首充人数 `first_recharge_num`
- 同步标注:凡引用 `frist_pay_cash_amount`(市场明细 11.3、汇总 11.4 的"首充金额")首期一并去除或标注脏值风险,保留首充人数与首充转化率。
### 5. 枚举与口径修正
- 14.4 审核状态补齐为实表 4 值0 未审核 / 1 通过 / 2 拒绝退钱 / 3 拒绝扣钱(对齐 [WithdrawalOrderModel](saas6.x/server/app/model/WithdrawalOrderModel.php))。
- 新增"字段核对"说明:`slot_all.user` 确含 `organization`/`currency`/`first_pay_date`(建表与 alter 已证实);`gm_stat_summary` 确含 `refund_amount`/`recharge_channel_fee`/`withdrawal_channel_fee`Summary 脚本写入)。
### 6. 跨仓库事项标注(第 12.10、15、16 章)
-`gm_stat_summary``uk_source_date`、改 `create_time`/加 `update_time``slot_all.user``recharge_order/withdrawal_order` 加索引、以及相关 Model PHPDoc 补全,统一标注为 **跨团队协调项**(库属 `s_statistics`/`slot_all`/`s_pay`,由 slot-console/slot-user/slot-pay 执行),按工作区规则不在 saas6.x 仓库改。
## 不做
- 不写任何 PHP/前端代码。
- 不改 `plugin/saimulti/**` 及 slot-* 仓库。
- 不执行任何 DDL。

122
plans/Plan-8f4c095a.plan.md Normal file
View File

@@ -0,0 +1,122 @@
<!-- 8f4c095a-8532-442e-9af9-213dc997b6aa -->
# 新增平台后,游戏列表在哪里?
## 直接回答
**新增一个平台后,这个平台自己的游戏列表在 `g_game_platform_mapping`管理端「映射列表」Tab不在 `g_platform` 或 `g_game` 里。**
刚建完平台时,这个列表是**空的**——`g_platform` 只存平台元数据code / name / config**不会自动带出上游游戏**。需要后续:
1. **手动新增映射**(映射列表 → 新增映射 → 选该平台)
2.**跑平台游戏导入/同步**slot-pwa 有 POP 导入命令saas6.x 尚未接入)
所以不是缺 `g_game_platform` 表,而是:**平台实体与平台游戏池是两张逻辑表,且 UI 没有把两者串起来。**
---
## 三张表各自管什么
```mermaid
flowchart LR
subgraph platformMeta [平台主数据]
g_platform["g_platform\n平台代码/配置"]
end
subgraph platformGames [平台游戏池]
mapping["g_game_platform_mapping\n该平台上的上游游戏\n含 game_id=0 待关联"]
end
subgraph lobbyGames [大厅游戏]
g_game["g_game\n大厅展示游戏\nactive_platform_id"]
end
g_platform -->|"platform_id"| mapping
g_game -->|"game_id 绑定后"| mapping
g_platform -->|"active_platform_id"| g_game
```
| 你想看的 | 存在哪 | 管理端入口 | 新建平台后 |
|---|---|---|---|
| **这个平台有哪些上游游戏**(含待绑定) | `g_game_platform_mapping` where `platform_id = X` | 游戏库 → **映射列表** → 筛「平台」 | **空**,需导入或手建 |
| **大厅里哪些游戏走这个平台** | `g_game` where `active_platform_id = X` | 游戏库 → **游戏列表** → 筛「当前生效平台」 | **空**,需先有大厅游戏并指定平台 |
| **平台本身配置** | `g_platform` | 游戏库 → **平台列表** | 只有这一条平台记录 |
### `game_id = 0` 就是「平台游戏池」
`g_game_platform_mapping``game_id = 0` 的记录,表示**上游已导入、尚未绑定大厅游戏**的条目POP 导入后的默认状态)。
因此 **`g_game_platform_mapping` 同时承担「平台游戏目录 + 绑定关系」**,不需要再建 `g_game_platform`
slot-pwa 导入逻辑见 [`PopGameImportService`](../../ray/slot-pwa/app/service/game/PopGameImportService.php)
> 从 pop_provider.php 导入 POP 游戏至 **g_game_platform_mapping**(不自动新建 g_game
---
## 为什么你会觉得「没地方看」
当前 saas6.x 游戏库是 4 个平级 Tab[`gameLibrary/index.vue`](admin-vue/src/views/admin/gameAccess/gameLibrary/index.vue)
- 游戏列表
- 分类列表
- **映射列表** ← 平台游戏实际在这里
- **平台列表** ← 只有平台配置,无游戏子列表、无跳转
缺口是 **UX / 流程**,不是表结构:
1. 平台 Tab 没有「查看该平台游戏」入口
2. 平台 Tab 没有显示映射数量
3. saas6.x **没有**平台游戏导入/同步能力(老项目靠 slot-pwa 命令写入 mapping
4. 「映射列表」命名不直观,不像「平台游戏池」
---
## 推荐改进(若要做)
### 方案 A最小改动只改 UI不动表
在 [`platform-tab.vue`](admin-vue/src/views/admin/gameAccess/gameLibrary/modules/platform-tab.vue)
- 增加列:`映射总数` / `待关联数` / `已绑定数`(聚合 `g_game_platform_mapping`
- 操作列增加 **「查看游戏」**:切到映射 Tab 并带上 `platform_id` 筛选(可用 `usePageTabs` 跨 Tab 传参或 query
后端:在 [`GPlatformController::index`](server/app/controller/game/GPlatformController.php) 列表响应里批量附加统计字段(一次 `GROUP BY platform_id` 查询,避免 N+1
### 方案 B补导入流程与老项目对齐
- 移植或封装 slot-pwa 的 `PopGameImportService` / `PopGameCatalogSyncService`
- 管理端平台行增加 **「同步上游游戏」** 按钮(或独立命令行入口)
- 同步结果写入 `g_game_platform_mapping``game_id` 先为 0运营再在映射里绑定 `g_game`
### 方案 C不推荐 — 新建 `g_game_platform` 表
会把「平台游戏目录」与「绑定关系」拆成两张表,与 slot 全链路admin / pwa / console不一致`g_game_platform_mapping` 已覆盖该职责。除非有**租户级平台开通实例**等新需求,否则不建议。
---
## 运营侧标准流程(现有模型下)
```mermaid
sequenceDiagram
participant Op as 运营
participant Platform as g_platform
participant Mapping as g_game_platform_mapping
participant Game as g_game
Op->>Platform: 1. 新增平台 code/config
Note over Mapping: 此时为空
Op->>Mapping: 2a. 手动新增映射 或 2b. 跑导入同步
Note over Mapping: game_id=0 待关联
Op->>Game: 3. 新建/选择大厅游戏
Op->>Mapping: 4. 编辑映射绑定 game_id
Op->>Game: 5. 设置 active_platform_id
Note over Game: 大厅可走该平台启动
```
---
## 结论
| 问题 | 答案 |
|---|---|
| 新平台的游戏列表在哪? | **`g_game_platform_mapping`**,管理端 **映射列表** 按平台筛选 |
| 为什么新建后是空的? | 平台创建 ≠ 游戏导入;需映射或同步 |
| 需要 `g_game_platform` 吗? | **不需要**mapping 表就是平台游戏池 |
| 真正缺什么? | **平台页与映射页的串联** + **(可选)上游游戏导入** |

162
plans/Plan-95f2e196.plan.md Normal file
View File

@@ -0,0 +1,162 @@
<!-- 95f2e196-ce33-4253-ace0-0a2ba260a0c2 -->
---
todos:
- id: "finalize-article-schema"
content: "course_article 增加 content_json含 nameList/skipWords正文不再依赖 course_article_sentence"
status: pending
- id: "nce-import-command"
content: "NCE_*.json → course + course_article导入时写入 skipWords/nameList人名/地名免敲)"
status: pending
- id: "article-api"
content: "GET 课文 APIcontent_json 直出 TypeWords Article DTOnameList 供默写/听写跳过)"
status: pending
- id: "article-vocab-api"
content: "课文生词 APIcourse_article_vocab词头+ vocab_sense + course_word_sense与正文分离"
status: pending
- id: "content-patch-admin"
content: "低频勘误PATCH content_json 的 text/translate/skipWords或单课重导"
status: pending
isProject: false
---
# 课文内容存储方案建议(修订 v2
## 结论
- **课文正文**`course_article.content_json`(几乎不改,偶发勘误)
- **课文生词**:关系表(`course_article_vocab` + `course_word_sense`
- **人名/地名免敲**:写在 `content_json`**`skipWords`**API 层映射为 TypeWords 的 `nameList`
---
## 人名 / 地名:练习时不用敲
### 需求
默写或听写课文时,**人名、地名**应预先标注,练习流程 **自动跳过**,不要求学生输入(如 `Silbury``Pinhurst``James``Scott`)。
### TypeWords 已有能力(可直接复用)
[`TypingArticle.vue`](TypeWords/packages/core/src/components/article/TypingArticle.vue) 已支持 `article.nameList`
- 命中 `nameList` 的 token 在 `next()`**自动跳过**
- 内置跳过:`Mr` / `Mrs` / `Ms` / `Dr` / `Miss`
- 多词条目 `"James Scott"` 会拆成 `james``scott` 分别匹配
**不需要**在正文里加 `{Silbury}` 这类 inline 标记;**维护一份免敲词表**即可。
### 在 `content_json` 里怎么存
推荐 **两层字段**(存库清晰 + 对接 TypeWords 零改动):
```json
{
"title": "No wrong numbers",
"text": "Mr.James Scott has a garage in Silbury ...",
"textTranslate": "...",
"audioSrc": "/sound/article/nce2-1/No wrong numbers.mp3",
"lrcPosition": [[15.45, 24.87]],
"skipWords": [
{ "token": "James", "type": "person" },
{ "token": "Scott", "type": "person" },
{ "token": "Silbury", "type": "place" },
{ "token": "Pinhurst", "type": "place" }
]
}
```
| 字段 | 用途 |
|------|------|
| `skipWords[]` | collin **权威存储**`type`: `person` / `place`(可扩展 `org` |
| `nameList` | **API 输出** 时由 `skipWords[].token` 去重生成为 TypeWords 字段(可不落库重复存) |
Lesson5 示例映射:
```
skipWords → nameList: ["James", "Scott", "Silbury", "Pinhurst"]
Mr 已由 TypeWords 内置跳过)
```
### 练习端行为
```mermaid
flowchart LR
API["GET 课文 API"]
Map["skipWords → nameList"]
TW["TypeWords TypingArticle"]
Skip["isNameWord 自动 next"]
API --> Map --> TW --> Skip
```
- **默写 / 听写**:同一套 `nameList` 逻辑
- **UI 可选增强**(后续):按 `skipWords.type` 在课文预览里给人名/地名不同样式(不影响是否跳过)
### 导入时谁维护 skipWords
1. **人工标注**(推荐 MVP导入 NCE 时在源 JSON 或 Excel 补一列「免敲词」
2. **半自动**:导入脚本从 `text` 匹配已知的本课 `course_article_vocab` 之外的专名词表(准确度有限)
3. **勘误**:只改 `content_json.skipWords``content_version + 1`
**不要**单独建 `course_article_skip_token` 表 — 与「几乎不改」的 JSON 方案一致,免敲词随课文打包即可。
---
## 课文正文content_json不变
| 层级 | 存储 |
|------|------|
| 正文 | `course_article.content_json` |
| 元数据 | `course_article` 列:`lesson_no`, `title`, `audio_url`, `status` |
| 生词 | 关系表(一词一行 + 义项) |
| 词典 | `word` / `dict` |
`content_json` **不含** `newWords`**含** `skipWords`(人名/地名)。
完整示例:
```json
{
"title": "A private conversation",
"titleTranslate": "私人谈话",
"text": "...",
"textTranslate": "...",
"audioSrc": "...",
"lrcPosition": [],
"skipWords": [
{ "token": "theatre", "type": "place" }
],
"quote": null,
"question": null
}
```
---
## 与 TypeWords 字段对照
| TypeWords `Article` | collin 来源 |
|---------------------|-------------|
| `title`, `text`, `textTranslate`, `lrcPosition`, `audioSrc` | `content_json` |
| `nameList` | API 由 `skipWords[].token` 生成 |
| `sections` | 前端 `genArticleSectionData(text)` |
| 生词 | 独立 API不进 JSON |
---
## 对迁移 / API 的调整
1. `course_article.content_json` 文档化 **`skipWords`** 结构
2. `ArticleApiService`:读 JSON → 填充 `nameList` → 返回 TypeWords DTO
3. NCE 导入 Command支持从源文件 `nameList` 迁移,或从 sidecar 配置读 `skipWords`
4. 废弃 `course_article_sentence`(正文不再用句子表)
---
## 实施优先级
1. 定稿 `content_json` schema`skipWords`
2. NCE 导入 + 首批课文手工标注免敲词
3. GET 课文 API`skipWords``nameList`
4. 生词 API与正文分离
5. 勘误PATCH `text` / `translate` / `skipWords`

240
plans/Plan-b5e97267.plan.md Normal file
View File

@@ -0,0 +1,240 @@
<!-- b5e97267-b1d5-4ef9-9217-ebd91392307c -->
---
todos:
- id: "ddl-mail-tables"
content: "在 slot-notification 新增 mail_configSMTP 直字段)/ mail_template / mail_send_log 表 DDL"
status: pending
- id: "mail-module"
content: "实现 app/mail 模块Model、Entity、Cache、MailService、SmtpMail SDK"
status: pending
- id: "notification-api"
content: "新增 EmailController + MailConfigAdminController 与 route 注册"
status: pending
- id: "sdk-client"
content: "扩展 slot-lib / slot-sdk 的 MailService 客户端方法"
status: pending
- id: "console-migrate"
content: "slot-console CommonController 改调 notification废弃本地 MailService"
status: pending
- id: "admin-ui"
content: "slot-admin 后端 + slot-admin-vue 邮件配置管理页"
status: pending
- id: "data-migration"
content: "编写 mail_config 从 slot-console 配置组到表的幂等迁移脚本"
status: pending
- id: "verify"
content: "跑 verify-slot-backend.sh验证发信/验码/后台 CRUD 链路"
status: pending
isProject: false
---
# slot-notification 邮件配置表化(对齐短信)
## 现状与结论
当前两套通知渠道配置方式不一致:
| 能力 | 短信(已收口) | SMTP 邮件(未收口) |
|---|---|---|
| 配置存储 | [`slot-notification/app/sms/model/SmsConfigModel.php`](slot-notification/app/sms/model/SmsConfigModel.php) → `sms_config` 表 | [`slot-console/app/service/lib/MailService.php`](slot-console/app/service/lib/MailService.php) → `ConfigService::getGroupData('mail_config')` |
| 发送服务 | [`slot-notification/app/sms/services/SmsService.php`](slot-notification/app/sms/services/SmsService.php) | `slot-console` 本地 `MailService` + PHPMailer |
| 验证码 API | `/innerapi/sms/sendVerifyCode` | `slot-console` `CommonController::sendEmailCode` |
| 后台管理 | slot-admin → slot-lib → notification `/innerapi/admin/*` | slot-admin 通用配置页 `email_config`(另一套) |
**结论:应该建表。** 你已选择「完整对齐短信」,建议把 SMTP 邮件作为 slot-notification 的第二条外发渠道,与短信保持同一套「配置表 + 发送日志 + innerapi + 后台管理 + SDK 客户端」模式。
注意slot-notification 里现有 [`MailController`](slot-notification/app/innerapi/controller/MailController.php) / [`EmailService`](slot-notification/app/message/service/EmailService.php) 实际是**站内消息**兼容别名,不是 SMTP。新 SMTP 能力应使用独立命名空间(建议 `app/mail/*`)和独立路由前缀(建议 `/innerapi/email/*`),避免与 `/innerapi/mail/*`(站内消息)冲突。
```mermaid
flowchart LR
subgraph before [当前]
lobby1[Lobby] --> console1[slot-console CommonController]
console1 --> config1["ConfigService mail_config"]
console1 --> mail1[MailService PHPMailer]
end
subgraph after [目标]
lobby2[Lobby] --> console2[slot-console 薄代理]
console2 --> sdk[slot-lib MailService]
sdk --> notif[slot-notification EmailController]
notif --> table["mail_config 表"]
notif --> smtp[SmtpMail PHPMailer]
notif --> log["mail_send_log 表"]
end
```
---
## 表结构设计(邮件用直字段,短信保留 JSON
`s_message`(与 `sms_config` 同库)新增两张表。
### 为什么邮件不用 JSON、短信用 JSON
| 对比 | 短信 `sms_config.config` | 邮件 `mail_config` |
|---|---|---|
| 字段形态 | 各平台差异大Buka 要 appId/senderIdAnt/Chuanglan 字段不同) | SMTP 标准字段固定,截图与代码一致 |
| 后台表单 | 按 `platform` 动态展示不同表单项 | 固定 6~8 个输入框,与现有配置页一一对应 |
| 查询/校验 | 结构不统一,适合 JSON | 可直接列级校验、索引、迁移映射 |
**结论:邮件配置用直接字段更好;不必为了「和短信表长得像」而强行 JSON。**
### 当前邮件配置项(来自截图,仅 SMTP 连接)
截图中的 6 项即为 `mail_config` 配置组现有字段,与 [`MailService`](slot-console/app/service/lib/MailService.php) 读取项一致。**这就是邮件配置表应存的全部内容**
| 配置项 | 列名建议 | 说明 |
|---|---|---|
| smtp host | `smtp_host` | 如 `email-smtp.us-east-1.amazonaws.com` |
| 用户名 | `username` | SMTP 登录账号 |
| 密码 | `password` | SMTP 密码/应用专用密码 |
| 端口 | `port` | 如 `587` |
| 发件人地址 | `from_address` | 原 `from` |
| 发件人名称 | `from_name` | 如 `TOGOO` |
加密方式(`tls`/`ssl`**不单独落库**:发送时按 `port` 推断即可(`587` → STARTTLS`465` → SSL与现网行为一致。
### 邮件模板(独立概念,不属于 mail_config
验证码邮件的标题/正文来自 `email_template` 配置组(`title``binding_email`),属于**发送模板**,不是 SMTP 连接配置。
发送邮件时需要两张表配合:
```mermaid
flowchart LR
sendMail[MailService 发信] --> mailConfig["mail_config\nSMTP 连接"]
sendMail --> mailTemplate["mail_template\n标题/正文模板"]
```
### `mail_config`(仅 SMTP 连接,直字段)
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | bigint PK | 主键 |
| `platform` | varchar(32) | 渠道标识,如 `AwsSes``Zoho` |
| `status` | tinyint | 1 启用 / 2 禁用 |
| `num` | int | 排序,降序优先 |
| `smtp_host` | varchar(255) | SMTP 主机 |
| `username` | varchar(128) | SMTP 用户名 |
| `password` | varchar(512) | SMTP 密码 |
| `port` | int | SMTP 端口 |
| `from_address` | varchar(255) | 发件人邮箱 |
| `from_name` | varchar(128) | 发件人显示名 |
| `create_time` / `update_time` | datetime | 审计字段 |
### `mail_template`(邮件发送模板,独立表)
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | bigint PK | 主键 |
| `template_code` | varchar(64) | 模板编码,如 `bindingEmail``authEmail` |
| `template_name` | varchar(128) | 模板名称 |
| `title` | varchar(255) | 邮件标题模板 |
| `body` | text | 邮件正文模板,支持 `{code}` 等变量 |
| `status` | tinyint | 1 启用 / 2 禁用 |
| `create_time` / `update_time` | datetime | 审计字段 |
首期迁移:把 `email_template` 配置组中的 `title` + `binding_email` 迁入 `mail_template``template_code=authEmail` 或按业务拆分)。
**注意**`message_template` 是站内消息模板,与 SMTP 外发邮件模板是不同业务,不混用。
### `mail_send_log`(发送日志,放 `s_common`
镜像 [`sms_send_log`](slot-notification/app/sms/model/SmsSendLogModel.php)
- `unique_sn`, `email`, `platform`, `subject`, `content`, `status`, `type`, `retry_num`, `create_time`
---
## 后端实现slot-notification
### 1. 数据层
新建 `app/mail/` 模块,参照 `app/sms/`
- `MailConfigModel` / `MailSendLogModel`
- `MailConfigEntity`(后台 CRUD复用短信 Entity 分页模式)
- 在 [`initDB.php`](slot-notification/app/command/initDB.php) 补充 DDL另提供 `db/mail_config.sql` 便于手工执行
### 2. 发送层
- `composer.json` 增加 `phpmailer/phpmailer`
- `MailService`:从 `mail_config` 取 SMTP 连接,从 `mail_template` 取标题/正文 → PHPMailer 发信 → 写 `mail_send_log`
- `app/mail/services/sdk/BaseMail.php` + `SmtpMail.php`(首期只实现 SMTP结构与 `BaseSms` 一致,便于后续扩展 SendGrid 等)
- `MailCache`:验证码 Redis 缓存(镜像 `SmsCache`key 规则与 slot-console [`EmailCodeLibService`](slot-console/app/service/lib/EmailCodeLibService.php) 保持一致,避免迁移期验证码失效
### 3. API 层
新增路由([`config/route.php`](slot-notification/config/route.php)
- `POST /innerapi/email/send-verify-code`
- `POST /innerapi/email/verify-code`
- `POST /innerapi/admin/mail-config/index|save|update|destroy`
- `POST /innerapi/admin/mail-template/index|save|update|destroy`(模板 CRUD与配置分开
新建 `EmailController`(发送/校验)与 `MailConfigAdminController`(配置 CRUD**不要**复用现有站内消息 `MailController`
### 4. 渠道选择策略
首期与短信一致:按 `status=启用` + `num desc` 取第一条;预留后续 failover注释掉的短信轮询逻辑可一并参考
---
## 跨服务改造
### slot-lib / slot-sdk
在 [`slot-lib/src/services/notification/`](slot-lib/src/services/notification/) 新增 `MailService`(或 `EmailService`
- `sendVerifyCode(email, type)`
- `verifyCode(email, code, type)`
- `getMailConfigPageList` / `saveMailConfig` / `updateMailConfig` / `destroyMailConfig`
同步扩展 [`slot-sdk/src/service/notification/NotificationService.php`](slot-sdk/src/service/notification/NotificationService.php)。
### slot-console调用方改造
[`CommonController::sendEmailCode`](slot-console/app/api/controller/CommonController.php) / `verifyEmailCode`
- 改为调用 slot-lib `MailService`,不再直接依赖本地 `MailService` + `ConfigService`
- 本地 [`MailService`](slot-console/app/service/lib/MailService.php) 标记废弃或删除(确认无其他引用后)
限流、参数校验仍留在 slot-console Controller 层(与现有短信 napi 模式一致)。
### slot-admin + slot-admin-vue
镜像短信后台:
- 后端:[`slot-admin/app/game/controller/SmsController.php`](slot-admin/app/game/controller/SmsController.php) → 新建 `MailController`
- 前端:新建 `mail/config/` 页,仅 6 个 SMTP 字段 + platform/status/num另建 `mail/template/` 页管理标题/正文模板
- 菜单/权限:新增 `mailConfig` 路由与按钮权限
---
## 数据迁移
新增一次性迁移脚本(建议 `slot-notification/app/command/MigrateMailConfig.php`
1.`s_config` 读取 `mail_config` 配置组 → 写入 `mail_config`6 个 SMTP 字段)
2.`s_config` 读取 `email_template` 配置组 → 写入 `mail_template` 表(`title` + `binding_email`
3. 幂等插入(已存在则跳过)
迁移完成后,`slot-console``mail_config` / `email_template` 配置组可保留只读一段时间,确认无回退需求后再清理。
---
## 风险与边界
- **命名冲突**`/innerapi/mail/*` 继续保留给站内消息SMTP 统一走 `/innerapi/email/*`
- **验证码兼容**`MailCache` 的 Redis key 必须与 slot-console 现有 `ShareRedisKeyManagerService::emailCode()` 一致
- **模板范围**:本期只迁移验证码邮件模板(`binding_email`/`title`);充值/提现等 MQ 站内邮件模板(`message_template` 配置组)不在本次范围
- **多 SMTP failover**:表结构支持,首期实现「取第一条启用配置」即可
---
## 验收标准
1. slot-admin 可 CRUD `mail_config`,与短信配置页体验一致
2. Lobby 发/验邮箱验证码链路走 slot-notification功能与迁移前一致
3. 发送成功/失败均写入 `mail_send_log`
4. slot-console 不再读取 `ConfigService::getGroupData('mail_config')`
5. 执行 `verify-slot-backend.sh` 通过

197
plans/Plan-feefd0f2.plan.md Normal file
View File

@@ -0,0 +1,197 @@
<!-- feefd0f2-a6ca-459e-a4b4-e16317795bfd -->
---
todos:
- id: "define-rate-semantics"
content: "确定贡献率字段名、取值范围0-100、默认值 100 与 effective_wager 计算公式,写入 MQ 对接文档"
status: pending
- id: "wallet-v2-consume"
content: "slot_walletUpdateWagerTask 解析 MQ 中 wager_contribution_rate仅 version2 使用 effective_wager"
status: pending
- id: "mq-contract-doc"
content: "输出 slot_pwa 对接说明:在现有 wager_task_update MQ 上增加 wager_contribution_rate 字段"
status: pending
- id: "compat-test"
content: "slot_wallet 单测MQ 无 rate 默认 100、version1 不变、version2 部分贡献"
status: pending
isProject: false
---
# slot_wallet 打码贡献率方案(仅 slot_wallet 改动)
## 范围约束
- **本方案只改 [`slot_wallet`](slot_wallet)**,不改动 slot_pwa / slot_sdk 等其它服务代码。
- 已确认:**仅 version2 打码**应用贡献率version1 保持 1:1。
- **打码 MQ 仍由 slot_pwa 发送**现有架构不变wallet 只改 **消费端**
---
## 现网链路(正确理解)
打码触发方一直是 **slot_pwa**,不是 slot_wallet
```mermaid
sequenceDiagram
participant Pwa as slot_pwa
participant Wallet as slot_wallet
participant TxMQ as transaction_log_MQ
participant TxLog as slot_pwa_TransactionLog
participant WagerMQ as wager_task_update_MQ
participant Consumer as slot_wallet_UpdateWagerTask
Pwa->>Wallet: POST /api/wallet/update type=bet 扣款
Pwa->>TxMQ: 写入用户交易流水
TxMQ->>TxLog: 消费 BET 流水
TxLog->>WagerMQ: 发 MQ uid/fee/currency
WagerMQ->>Consumer: UpdateWagerTask::version2
Note over Consumer: current_wager += min(fee, needed)
```
关键代码(**发送方在 pwa消费方在 wallet**
- 发送:[`slot_pwa/app/process/TransactionLog.php`](slot_pwa/app/process/TransactionLog.php) → `updateWagerTask()`,消息体 `{uid, fee, currency}`
- 消费:[`slot_wallet/app/command/UpdateWagerTask.php`](slot_wallet/app/command/UpdateWagerTask.php) → `version2()`,按下注额 **100%** 计入
- wallet 下注:[`slot_wallet/app/api/logic/WalletLogic.php`](slot_wallet/app/api/logic/WalletLogic.php) 只扣款,**不发** 打码 MQ`//todo 更新打码任务` 未实现)
因此:**贡献率应加在 PWA 发出的 MQ 里**slot_wallet 侧只需让 `UpdateWagerTask` 读懂新字段。
---
## 结论:仅改 slot_wallet 时做什么
| 谁改 | 做什么 |
|---|---|
| **slot_wallet本仓库** | `UpdateWagerTask` 消费 MQ 时读取 `wager_contribution_rate`version2 按 rate 计算有效打码额 |
| **slot_pwa他人开发** | 在**现有** `updateWagerTask()` 发出的 MQ 中增加 `wager_contribution_rate`rate 由 pwa 按游戏/厂商配置在下注流程中确定 |
**不需要** wallet 在下注 API 接参、也 **不需要** wallet 改发 MQ——那会与 pwa 现有职责冲突,且可能造成双计。
---
## slot_wallet 改动(仅此一处核心逻辑)
### 文件
[`slot_wallet/app/command/UpdateWagerTask.php`](slot_wallet/app/command/UpdateWagerTask.php)
### 贡献率语义
| 项 | 约定 |
|---|---|
| MQ 字段名 | `wager_contribution_rate` |
| 含义 | 有效打码占比;**100 = 全额计入**(与现网一致) |
| 缺省 | MQ 无此字段 → **100** |
| 校验 | 消费端 clamp 到 `0~100` |
| 计算公式 | `effective_wager = intdiv(fee * rate, 100)`(厘,向下取整) |
| 作用范围 | 仅 `version2()``version1()` 仍用原始 `fee` |
### 伪逻辑
```php
// deal() 解析 MQ body
$betAmount = (int)($body['fee'] ?? 0);
$rate = max(0, min(100, (int)($body['wager_contribution_rate'] ?? 100)));
// updateWagerTasks()
if (ShareConfigService::isVersion2($uid)) {
$effectiveWager = intdiv($betAmount * $rate, 100);
if ($effectiveWager <= 0) return;
$this->version2($uid, $effectiveWager, $currency);
return;
}
$this->version1($uid, $betAmount, $currency); // version1 忽略 rate
```
### 可选增强(非必须)
-`deal()` / `updateWagerTasks()` 补中文 PHPDoc
- 单测覆盖:无 rate、rate=50、rate=0、version1 不受影响
**不改动**`WalletUpdateRequestDTO``WalletLogic` 下注接口(与打码 MQ 链路无关)。
---
## MQ 对接约定(给 slot_pwa 同事wallet 不写 pwa 代码)
### 现有消息today
```json
{
"uid": 123,
"fee": 1000,
"currency": "INR"
}
```
### 目标消息pwa 在 `TransactionLog::updateWagerTask` 增加字段)
```json
{
"uid": 123,
"fee": 1000,
"currency": "INR",
"wager_contribution_rate": 50
}
```
- `fee`:仍为实际下注扣款额(不变)
- `wager_contribution_rate`pwa 按 game_id / 游戏类型 / 厂商配置赋值;未配置游戏传 `100`
- wallet 先上线 consumer兼容无 ratepwa 再发带 rate 的消息即可灰度
### pwa 侧职责(他人实现)
1. 下注时解析该游戏的贡献率配置
2. 在**原有**打码 MQ 中附带 `wager_contribution_rate`
3. **无需**关闭或迁移 MQ 发送点——仍走 `TransactionLog::updateWagerTask`
---
## 目标架构
```mermaid
sequenceDiagram
participant Pwa as slot_pwa
participant Wallet as slot_wallet
participant WagerMQ as wager_task_update_MQ
participant Consumer as UpdateWagerTask
Pwa->>Wallet: bet 扣款
Pwa->>WagerMQ: uid fee currency wager_contribution_rate
WagerMQ->>Consumer: version2 effective_wager
```
---
## 风险与约束
### 兼容
- pwa 未发 `wager_contribution_rate`wallet consumer 默认 100**与现网完全一致**。
- wallet 可先单独上线,不破坏现网。
### 安全
- rate 由 pwa 写入 MQwallet 消费端做范围 clamp**不在 wallet 内校验游戏配置**(本期 scope 不含配置表)。
### 其它
- `total_bet` 仍按 wallet 扣款 `fee` 统计,与有效打码额分离。
- 无打码回滚逻辑;本需求不新增。
---
## slot_wallet 验收要点
1. MQ `{fee:100, wager_contribution_rate:50}` → version2 用户 `current_wager` +50。
2. MQ 无 rate 字段 → version2 仍 +100fee=100
3. version1 用户:即使 MQ 带 rate仍按 fee 全额计入。
4. `effective_wager=0`rate=0→ 不更新打码。
---
## 不在本方案范围
- slot_pwa 改 MQ 发送由他人完成wallet 只提供对接约定)
- wallet 下注 API 增加 `wager_contribution_rate`(与现链路无关,非必须)
- wallet 改发打码 MQ
- 游戏贡献率配置表 / 后台
- version1 贡献率、打码回滚

106
plans/Plan-ffd1b7b6.plan.md Normal file
View File

@@ -0,0 +1,106 @@
<!-- ffd1b7b6-16e7-4f41-9f8b-a22ab65c6a00 -->
---
todos:
- id: "ddl"
content: "patch_wallet_phase_game_stat.sql + InitDB 分片建表"
status: pending
- id: "model-service"
content: "WalletPhaseGameStatModel + WalletPhaseGameStatServiceinc + 首充标记)"
status: pending
- id: "wire-logic"
content: "WalletLogic bet/win/首充同事务挂载写入"
status: pending
isProject: false
---
# 充值前后游戏统计表(精简版)
## 目标
一张表回答四个数:**充值前下注、充值前派奖、充值后下注、充值后派奖**。RTP 读时算,不存库。钱包怎么通知 activity **后面再说**
---
## 表结构
**表名**`wallet_phase_game_stat`
**分片**:与 `wallet_stat` 一致,`wallet_{db}.wallet_phase_game_stat_{table}`
**主键**`(uid, currency)`
```sql
CREATE TABLE `wallet_phase_game_stat_{t}` (
`uid` BIGINT NOT NULL,
`currency` CHAR(5) NOT NULL DEFAULT 'rp',
`first_recharge_at` DATETIME NULL COMMENT '首充时间NULL=尚未充值',
`pre_bet_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '充值前累计下注,*1000',
`pre_win_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '充值前累计派奖,*1000',
`post_bet_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '充值后累计下注,*1000',
`post_win_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '充值后累计派奖,*1000',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`uid`, `currency`)
) COMMENT='用户充值前后游戏统计';
```
**刻意不做的字段**(需要时再加):
- 笔数 `*_count`
- `post_valid_bet_amount` / FS 分项
- `first_recharge_order_no`
- `last_bet_at` 等时间戳
---
## 阶段判定
**边界 = 是否已首充**,看 `first_recharge_at``RechargeExchangeService::isRecharge(uid)`
- 未首充 → 累加 `pre_*`
- 已首充 → 累加 `post_*`
---
## 写入口径
与 [`WalletLogic`](slot-wallet/app/api/logic/WalletLogic.php) 现有路径对齐,**仅在 biz_id 幂等通过、新写入流水时**同事务累加:
| 动作 | 未首充 | 已首充 |
|------|--------|--------|
| 试玩下注 `executeTrialBet` | `pre_bet += fee` | — |
| 试玩派奖 `executeTrialWin` | `pre_win += fee` | — |
| 真金下注 `BetService` / FS代付 | — | `post_bet += fee` |
| 真金派奖 `WinService``is_end=1` | — | `post_win += fee` |
| 首充 commit | 写 `first_recharge_at` | — |
中间派奖(`is_end=0`)不写。
---
## RTP
读时计算,不入库:
```
pre_rtp = pre_win_amount / pre_bet_amount (bet=0 → null)
post_rtp = post_win_amount / post_bet_amount
```
---
## 代码落点
| 文件 | 内容 |
|------|------|
| `slot-wallet/db/patch_wallet_phase_game_stat.sql` | DDL |
| `slot-wallet/app/model/multi/WalletPhaseGameStatModel.php` | 分片 + `inc` |
| `slot-wallet/app/service/wallet/WalletPhaseGameStatService.php` | 判定阶段、累加、首充标记 |
| `WalletLogic::bet()` / `win()` / 首充 | 同事务调用 |
**本轮不改**`TrialValidBetNotifyService`、activity、MQ。
---
## 验收
1. 首充前只涨 `pre_*`,首充后只涨 `post_*`
2. 幂等重入不重计
3. 四个金额 + 两个 RTP 可查询

138
plans/RTP-ffd1b7b6.plan.md Normal file
View File

@@ -0,0 +1,138 @@
<!-- ffd1b7b6-16e7-4f41-9f8b-a22ab65c6a00 -->
---
todos:
- id: "ddl"
content: "新增 slot-pwa/db/game_user_recharge_rtp_stat.sql用户 DDL 原样)"
status: pending
- id: "service-model"
content: "GameUserRechargeRtpStatModel + GameUserRechargeRtpStatService + UserRechargeStatusService"
status: pending
- id: "wire-wallet-service"
content: "WalletService bet/win 成功后挂载累计与 RTP 重算"
status: pending
- id: "redis-key"
content: "RedisKeyManagerService 补充 recharge:exchange key"
status: pending
isProject: false
---
# game_user_recharge_rtp_statslot-pwa
## 变更范围
- **表**:按你提供的 DDL不做额外字段
- **服务**[`slot-pwa`](slot-pwa) 统一处理(游戏回调 → 调 wallet 的入口)
- **不做**wallet 侧改表、移除 `TrialValidBetNotifyService`、activity 同步(后续再定)
---
## 表结构(原样采用)
库:`s_common`(与 [`game_launch_session`](slot-pwa/db/game_launch_session.sql) 同库)
```sql
CREATE TABLE `game_user_recharge_rtp_stat` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`uid` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户ID',
`before_recharge_bet_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '充值前累计下注金额金额扩大1000倍',
`before_recharge_payout_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '充值前累计派奖金额金额扩大1000倍',
`before_recharge_rtp_rate` DECIMAL(10, 6) NOT NULL DEFAULT 0.000000 COMMENT '充值前RTPpayout / bet',
`after_recharge_bet_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '充值后累计下注金额金额扩大1000倍',
`after_recharge_payout_amount` BIGINT NOT NULL DEFAULT 0 COMMENT '充值后累计派奖金额金额扩大1000倍',
`after_recharge_rtp_rate` DECIMAL(10, 6) NOT NULL DEFAULT 0.000000 COMMENT '充值后RTPpayout / bet',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_uid` (`uid`),
KEY `idx_before_rtp_bet` (`before_recharge_rtp_rate`, `before_recharge_bet_amount`),
KEY `idx_after_rtp_bet` (`after_recharge_rtp_rate`, `after_recharge_bet_amount`),
KEY `idx_before_bet` (`before_recharge_bet_amount`),
KEY `idx_after_bet` (`after_recharge_bet_amount`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='用户充值前后下注派奖RTP累计统计表';
```
DDL 文件:[`slot-pwa/db/game_user_recharge_rtp_stat.sql`](slot-pwa/db/game_user_recharge_rtp_stat.sql)
---
## 为什么在 slot-pwa
所有厂商下注/派奖最终都走 [`WalletService::bet()`](slot-pwa/app/service/WalletService.php) / `win()`pop / quick / jsgame / jdb / self / gasea / bbgt 等),与现有 [`UserProfitService`](slot-pwa/app/service/user/UserProfitService.php) 挂载点一致,**一处写入、全覆盖**。
```mermaid
flowchart LR
Provider[厂商回调] --> PwaCash[pop/quick/... CashLogic]
PwaCash --> WalletSvc[WalletService bet/win]
WalletSvc --> WalletApi[slot-wallet API]
WalletSvc --> RtpStat[GameUserRechargeRtpStatService]
RtpStat --> Db[(game_user_recharge_rtp_stat)]
```
---
## 阶段判定(充值前 / 充值后)
读 wallet 同款 Redis 充值标记([`RechargeExchangeService::isRecharge`](slot-wallet/app/service/wallet/RechargeExchangeService.php)
- Key`recharge:exchange:{uid % 10}`field = `uid``recharge > 0`**充值后**
- 否则 → **充值前**
在 slot-pwa 新增薄封装 `UserRechargeStatusService`(读 default Rediskey 规则与 wallet 一致),**不新增表字段**。
---
## 写入口径
挂载点:[`WalletService::bet()`](slot-pwa/app/service/WalletService.php) / `win()`,在 **`updateWallet()` 成功返回非 null 之后** 写统计(比现有 `UserProfitService` 更早调用更安全,避免 wallet 失败仍累加)。
| 动作 | 条件 | 更新字段 |
|------|------|----------|
| bet 成功 | 未充值 | `before_recharge_bet_amount += fee` |
| bet 成功 | 已充值 | `after_recharge_bet_amount += fee` |
| win 成功 | `is_end === 1` 且未充值 | `before_recharge_payout_amount += fee` |
| win 成功 | `is_end === 1` 且已充值 | `after_recharge_payout_amount += fee` |
**派奖仅计 `is_end=1`**:与 wallet 实际入账一致(中间派奖 `is_end=0` 只写 Redis pending不落库
**RTP 重算**(同事务内 SQL 更新):
```
before_recharge_rtp_rate = before_bet > 0
? ROUND(before_payout / before_bet, 6) : 0
after_recharge_rtp_rate = after_bet > 0
? ROUND(after_payout / after_bet, 6) : 0
```
**幂等**:依赖 slot-pwa 已有 `provider_tx` 幂等(同一 biz 不会重复调 wallet不在本表再存 biz_id。
**fee=0**跳过累加zero win 等场景)。
---
## 代码落点
| 文件 | 职责 |
|------|------|
| `slot-pwa/db/game_user_recharge_rtp_stat.sql` | 建表 |
| `slot-pwa/app/model/game/GameUserRechargeRtpStatModel.php` | ThinkORM Model + 完整 PHPDoc |
| `slot-pwa/app/service/game/GameUserRechargeRtpStatService.php` | `accumulateBet` / `accumulatePayout`、RTP 重算、upsert by uid |
| `slot-pwa/app/service/user/UserRechargeStatusService.php` | 读 Redis 判断是否已充值 |
| `slot-pwa/app/service/WalletService.php` | bet/win 成功后调用 Service |
| `slot-pwa/app/service/RedisKeyManagerService.php` | 补充 `getRechargeExchangeKey`(与 wallet 一致) |
---
## 与 wallet / activity 的关系(后续)
- 本表成为 **充值前后 bet/payout/RTP 权威数据源**
- activity 的 `valid_bet_amount` / 4→5 解锁、移除 `trial_valid_bet_accumulate` MQ → **下一阶段**,本计划不改动
---
## 验收
1. 未充值用户游戏:只涨 `before_*`RTP 随 bet/win 更新
2. 首充后:只涨 `after_*`
3. `is_end=0` 的中间 win 不计入 payout
4. wallet 调用失败时不写表
5. 风控可按 `idx_before_rtp_bet` / `idx_after_rtp_bet` 扫异常 RTP

View File

@@ -0,0 +1,115 @@
<!-- 2a311123-9045-4246-b265-7e37ecfbf924 -->
---
todos:
- id: "ddl"
content: "编写 reward_pool / reward_pool_item 建表 DDLAUTO_INCREMENT 主键、status 1/2、可选审计字段"
status: pending
- id: "constants"
content: "新建 RewardPoolConstants / RewardPoolRewardType钱包类复用 foundation 数值,新增 COUPON=3"
status: pending
- id: "models"
content: "新建 RewardPoolModel、RewardPoolItemModel完整类 PHPDoc + @property + 查询方法)"
status: pending
- id: "draw-shared"
content: "下沉加权随机算法为可复用方法,供奖池与 TrialPrizeDrawService 共用"
status: pending
- id: "entity"
content: "新建 RewardPoolDrawResultEntity 及列表/汇总 Entity禁止 Logic 返回 array"
status: pending
- id: "draw-logic"
content: "实现 app/innerapi/logic/RewardPoolDrawLogic::drawByPoolCode只读、无副作用"
status: pending
- id: "admin-crud"
content: "slot-activity app/adminRewardPool(Item)Controller/Logic/Validatesaithink 范式)+ admin 路由"
status: pending
- id: "validate"
content: "奖池/奖项校验reward_type 约束 + 优惠券模板存在性 + 启用校验 + pool_code 不可改"
status: pending
- id: "sdk"
content: "ActivityService 增 admin/reward-pool(-item)/* SDK 方法adminXxx 同套路)"
status: pending
- id: "admin"
content: "saas6.x/server operation RewardPoolController + RewardPoolGatewayService 代理(#[Permission]"
status: pending
- id: "admin-vue"
content: "admin-vue 增奖池管理页面与菜单(奖池列表/编辑/启停 + 奖项配置页)"
status: pending
- id: "verify"
content: "运行 slot-backend-completion-report 门禁并粘贴检测结果"
status: pending
isProject: false
---
# 通用奖池 V1 实施方案
落点服务:`slot-activity`(核心 + 数据)、`slot-sdk`(跨服务客户端)、`saas6.x/server`(运营后台代理)+ `saas6.x/admin-vue`(后台前端)。沿用现有「活动管理」后台范式(`operation` 控制器 + `*GatewayService` 封装 slotsdk
> 注意:后台代码不在 `slot-admin`,而在独立仓库 `~/Documents/project/www/tenant/saas6.x`(用户明确指定)。
> 子需求文档SSOT 拆分):[docs/requirements/generic_reward_pool/README.md](docs/requirements/generic_reward_pool/README.md)01 表结构 / 02 抽奖 / 03 后台)。
## 关键决策(已确认 + 需注意的派生项)
- 奖励类型按《奖池.md V1》原口径`reward_type` = `1 可提现释放 / 2 Bonus / 3 充值优惠券`,券用 `coupon_template_id`(不对齐 foundation 数值、不引入 FS
- 新建 `app/constants/RewardPoolRewardType``WITHDRAWABLE_RELEASE=1` / `BONUS=2` / `COUPON=3`)。
- 业务方按抽奖结果发奖时,由**业务侧**显式把 `reward_type` 映射到钱包/券接口(如 `slot-foundation\RewardGrantRewardType` 或 user_coupon奖池本身不做发放。
- 表名冲突风险:现有 `docs/requirements/reward_pool/`(大转盘超集设计)也用 `reward_pool` / `reward_pool_item`。实施前需决策本 V1 是否改用独立表名或与之合并(见子需求 README「重要前提」
- 抽奖算法复用:把 [`TrialPrizeDrawService::pickWeightedRandom()`](slot-activity/app/service/trial/TrialPrizeDrawService.php) 的加权累加逻辑下沉为可复用方法(`random_int(1,total)` + `sort ASC,id ASC` 累加),奖池抽奖与转盘共用,不再写第二份。
- 运营后台(`saas6.x/server`)经 `slot_sdk` 调 slot-activity `innerapi`/`admin`,参照 `saas6.x/server/app/controller/operation/ActivityController.php` + `app/service/activity/ActivityGatewayService.php``proxyActivity()` + `*GatewayService` 范式,不直连 activity 库。
## 一、数据库reward_pool / reward_pool_item
按文档 §6 建表,修订:
- 主键改 `BIGINT UNSIGNED NOT NULL AUTO_INCREMENT`(与现有 Model "自增主键" 一致)。
- `status` 统一为 `1启用 2停用`(文档已是;与 prize_pool 的 enabled 1/0 不强行统一,但 Model 注释写清)。
- `reward_pool_item.pool_code` 为快照;约定 `pool_code` 创建后不可改(编辑接口禁止改 code保证 `(pool_id,item_code)` 快照一致。
- 可选增 `created_by`/`updated_by`(后台操作审计)。
## 二、slot-activity 核心(数据 + 抽奖)
- Model`app/model/RewardPoolModel.php``app/model/RewardPoolItemModel.php`
- 完整类 PHPDoc + `@property`(对齐 DDL COMMENT状态常量带中文注释。
- 查询方法:`findEnabledByPoolCode()``listEnabledItemsByPoolId()``sumEnabledWeight()``existsItemCode()` 等(命名表达意图,禁止 getData/getList
- 常量:`app/constants/RewardPoolConstants.php`status、reward_type 复用 foundation + COUPON
- 抽奖业务逻辑(供本服务/业务内部调用,第一期不强制开 HTTP`app/innerapi/logic/RewardPoolDrawLogic.php::drawByPoolCode(string $poolCode): RewardPoolDrawResultEntity`,编排文档 §8.1 十步:查池→校验启用→取启用且 `weight>0` 奖项→`total_weight`→加权随机→返回快照。只读、无副作用、无幂等幂等由业务方负责PHPDoc 写明)。
- Entity`app/entity/rewardpool/RewardPoolDrawResultEntity.php`抽中快照extends `BaseEntity`),列表用 `RewardPoolListEntity` / `RewardPoolItemListEntity` 包装(禁止 Logic 返回 array / `Xxx[]`)。
## 三、slot-activity 后台app/admin非 innerapi
沿用 `app/admin` saithink 范式(参照 `app/admin/controller/ActivityController.php` + `app/admin/logic/ActivityLogic.php` + `app/admin/validate/ActivityValidate.php`,基类 `app/admin/base/AdminController``$this->success()` 返回):
- Controller`app/admin/controller/RewardPoolController.php`(奖池 index/read/save/changeStatus`app/admin/controller/RewardPoolItemController.php`(奖项 index/save/changeStatus/destroy/sort
- Logic`app/admin/logic/RewardPoolLogic.php``app/admin/logic/RewardPoolItemLogic.php`search/getList + 保存/启停/排序;多表写入走 activity 库事务)。
- Validate`app/admin/validate/RewardPoolValidate.php``RewardPoolItemValidate.php`,覆盖文档 §11.1~§11.4reward_type∈{1,2,3};非 COUPON 时 `reward_amount>0 && coupon_template_id=0`COUPON 时 `reward_amount=0 && coupon_template_id>0` 且校验模板存在;启用奖池需至少 1 个启用奖项且 `weight` 合计 > 0`pool_code` 创建后不可改)。
- 路由:按现有 admin 路由约定接入 `admin/reward-pool/*``admin/reward-pool-item/*`(与 `admin/activity/*` 同套路)。
## 四、slot-sdk
- [slot-sdk/src/service/activity/ActivityService.php](slot-sdk/src/service/activity/ActivityService.php) 增方法POST/GET 到 `admin/reward-pool/*``admin/reward-pool-item/*`(与现有 `adminActivityIndex/adminSave/adminUpdate/adminChangeStatus/adminDestroy` 命名同套路):`rewardPoolIndex/Read/Save/ChangeStatus``rewardPoolItemIndex/Save/ChangeStatus/Destroy/Sort`
## 五、saas6.x 运营后台
后端 `saas6.x/server`
- `app/controller/operation/RewardPoolController.php`extends `OperationController`,方法加 `#[Permission('奖池...','saimulti:operation:rewardPool:xxx')]``proxyActivity()` 统一封装)。
- `app/service/activity/RewardPoolGatewayService.php`(封装 slotsdk `ActivityClient`host 取 `ShareConfigService::get('activityApiHost')`,与 `ActivityGatewayService` 同构)。
- 入参轻校验可放控制器或 `app/validate/`,复杂判断仍在 slot-activity 侧。
前端 `saas6.x/admin-vue`
- 运营管理 → 奖池管理页(列表/新增/编辑/启停/进入奖项配置)+ 奖项配置页(新增/编辑/启停/排序)。
- 新增对应 `api/` 请求模块与菜单/权限项(与活动页同套路)。
## 六、收尾自检(强制)
改完 `app/**/*.php` 后按 `agent-completion-gate` 执行 `~/.cursor/skills/slot-backend-completion-report/scripts/report.sh`(含 verify 门禁 + docker `php -l`),最终回复粘贴"检测结果"章节。
## 调用关系
```mermaid
flowchart LR
Vue[saas6.x admin-vue] --> Server[saas6.x server operation]
Server -->|slot_sdk ActivityClient| AdminApi[slot-activity app/admin reward-pool]
AdminApi --> AdminLogic[admin RewardPoolLogic / ItemLogic]
AdminLogic --> Model[(reward_pool / reward_pool_item)]
Biz[业务活动 Logic] -->|drawByPoolCode| Draw[RewardPoolDrawLogic]
Draw --> Model
Biz -->|按 reward_type 发放| Wallet[slot-wallet / user_coupon]
```

View File

@@ -0,0 +1,121 @@
<!-- 23416728-def1-424f-ba2f-16a110d1f084 -->
---
todos:
- id: "internal-layer"
content: "新建 internal DeviceController + 迁移 logic/dto/validateDTO 含 user_id"
status: pending
- id: "cleanup-api"
content: "从 api DeviceController 移除绑定三接口并删除 api 侧绑定文件"
status: pending
- id: "remove-user-auth"
content: "删除 UserAuth、UserRequestContext 及无引用错误码"
status: pending
- id: "docs-update"
content: "更新 device.md §10、03-user-binding.md、06-internal-api.md 路径与调用方说明"
status: pending
- id: "verify"
content: "docker php -l + slot-backend-completion-report"
status: pending
isProject: false
---
# SR-3 设备绑定迁入 internal 应用
## 架构判断(同意你的方向)
与 [device.md](device/docs/requirements/device.md) 中已有分层一致:
| 应用 | 调用方 | 鉴权 | 职责 |
|------|--------|------|------|
| **api** | 物理设备 | `device_sn` + 签名 | 激活、心跳、OTA 入口 |
| **admin** | 后台 BFF / admin-service | `Authorization`(骨架) | 产品/型号/设备档案管理 |
| **internal** | user-service、message-service、ota-service 等 | `X-Internal-Token` | 跨服务读写设备主数据 |
绑定关系是 **device-service 的领域数据**,但 **用户登录态不应在本服务校验**——应由 user-service或 App BFF完成 session/JWT 校验后,再调用 device-service 的 internal 接口写入绑定。这与 §4.3「后台 → BFF → device-service」模式同构。
```mermaid
sequenceDiagram
participant User as 用户App
participant UserSvc as user_service_BFF
participant Device as device_service_internal
User->>UserSvc: 扫码绑定 device_sn
Note over UserSvc: 校验登录态,解析 user_id
UserSvc->>Device: POST /internal/device/bind
Note over Device: X-Internal-Token + user_id + device_sn
Device-->>UserSvc: code=0
UserSvc-->>User: 绑定成功
```
**结论**SR-3 应落在 **internal**,而不是 api当前 [DeviceController.php](device/app/api/controller/DeviceController.php) 上的 `#[Middleware(UserAuth)]` + `UserRequestContext` 应移除。
---
## 目标接口默认路由id 走 body/query
| 方法 | 路径 | 入参 |
|------|------|------|
| POST | `/internal/device/bind` | `user_id`, `device_sn` |
| POST | `/internal/device/unbind` | `user_id`, `device_id` |
| GET | `/internal/device/list` | `user_id`query |
鉴权:应用级 [InternalTokenAuth](device/app/middleware/InternalTokenAuth.php)(已挂在 `internal`**不再**使用 [UserAuth](device/app/middleware/UserAuth.php)。
---
## 代码迁移步骤
### 1. 新建 internal 分层(从 api 平移)
- 新增 [app/internal/controller/DeviceController.php](device/app/internal/controller/DeviceController.php)`extends InternalController`
- `bind` / `unbind` / `list` 三个 action
- 将以下文件 **改 namespace 为 `app\internal\*`**(逻辑基本不变):
- [app/api/logic/DeviceBindLogic.php](device/app/api/logic/DeviceBindLogic.php) → `app/internal/logic/DeviceBindLogic.php`
- [app/api/dto/DeviceBindDTO.php](device/app/api/dto/DeviceBindDTO.php) → 增加 `userId` 字段
- [app/api/dto/DeviceUnbindDTO.php](device/app/api/dto/DeviceUnbindDTO.php) → 增加 `userId` 字段
- [app/api/validate/DeviceBindValidate.php](device/app/api/validate/DeviceBindValidate.php) → 增加 `user_id` 规则(`require|integer|gt:0`)及 validation 文案
Controller 从 DTO 读取 `userId`**不再**调用 `UserRequestContext::getUserId()`
### 2. 清理 api 应用
- 从 [app/api/controller/DeviceController.php](device/app/api/controller/DeviceController.php) 删除 `bind` / `unbind` / `list``DeviceBindLogic``DeviceBindValidate``UserAuth` 相关 use/构造注入
- 删除 api 侧已迁移的 logic/dto/validate 文件
### 3. 删除用户鉴权骨架(若无其它引用)
- 删除 [app/middleware/UserAuth.php](device/app/middleware/UserAuth.php)
- 删除 [app/support/UserRequestContext.php](device/app/support/UserRequestContext.php)
- `OtaErrorCode::USER_AUTH_FAILED (1004)` 可保留翻译条目(无害),或一并移除——以「无引用」为准
### 4. Logic 行为
[DeviceBindLogic](device/app/api/logic/DeviceBindLogic.php) 业务规则 **不变**(幂等、唯一约束、状态校验);仅入参来源从「上下文 user_id」改为「请求体/Query 显式 `user_id`」。
**安全说明**(写入 SR-3/SR-6 文档internal 信任「调用方已在网关/BFF 完成用户鉴权」;`user_id` 由调用方传入device-service 只负责绑定域规则。与 SR-6 §5「服务间 token」一致。
### 5. 需求文档同步
- [03-user-binding.md](device/docs/requirements/device/03-user-binding.md):路径改为 `/internal/device/*`,注明调用方为 user-service/BFF
- [device.md](device/docs/requirements/device.md) §10同上§10 标题可改为「用户绑定(内部接口,由 user-service 暴露给 App
- [06-internal-api.md](device/docs/requirements/device/06-internal-api.md):补充 bind/unbind/list 三条(扩展 SR-6 范围或交叉引用 SR-3
### 6. 调用方 SDK可选本仓库外
按 [cross-service-sdk](.cursor/rules/cross-service-sdk.mdc),若 user-service 在 monorepo 内,后续在 `slot_sdk` 增加 `DeviceClient`(或 `DeviceBindService`)方法指向上述三条 internal 路径;**本次 device 仓库内可不实现**,仅在计划中标注为调用方跟进项。
---
## 不涉及
- `DeviceBindModel`、错误码 `4208`/`4209`、翻译文案:已存在,无需改业务码
- SR-6 只读查询(单设备档案/批量/在线状态):可另 PR 实现,与本次迁移独立
- 「查询设备绑定用户」admin 详情已只读;若 internal 需要可加 `GET /internal/device/bind-owner?device_id=`**非本次必须**,除非你要求一并做
---
## 验收
1. `api` 仅保留 `activate``heartbeat`(及后续 OTA
2. `internal` 三条绑定接口带 `X-Internal-Token` 可通,缺 token 返回 `1001` + HTTP 403
3. 绑定/解绑/列表业务行为与现 SR-3 验收要点一致
4. `docker php -l` + completion-report 通过

View File

@@ -0,0 +1,136 @@
<!-- b36a4d72-3fa9-424d-8f16-d5d3a861c06d -->
---
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 新增 TrialRewardNotifyServicevalid_bet / fs_consume / task_completed + 共享配置与 Redis 去重)"
status: pending
- id: "pwa-hook-wallet"
content: "WalletService::bet/win 成功后调用 NotifyServiceWalletEntity 补充 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` 发 MQPWA 侧用 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 删 MQbet 响应加 `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 余额达 $50PWA 发 `trial_task_completed`48h 去重)
5. 注册 `type=register`:行为不变,仍无 trial MQ

View File

@@ -0,0 +1,175 @@
<!-- d451269e-1f41-4d6f-ad1f-e7ac88a4925f -->
---
todos:
- id: "constants"
content: "TrialRewardConstantsACTIVITY_CODE + ext 键;移除 center CONFIG_KEY_*"
status: pending
- id: "model"
content: "ActivityModel::findActiveByCode(activity_code, source, now)"
status: pending
- id: "resolver"
content: "新增 TrialRewardActivityResolver从 activity.ext 解析 threshold/cap"
status: pending
- id: "logic"
content: "TrialFirstDepositLogic / queryRecord 改用 resolver去掉 ShareConfig trialReward"
status: pending
- id: "center-cleanup"
content: "删除 slot-center share_config activity.trialReward 块"
status: pending
- id: "seed-sql"
content: "新增 activity 表 patchtrial_reward + ext JSON"
status: pending
- id: "test-e2e"
content: "补 resolver 单测 + 联调验证(不依赖 center 业务配置)"
status: pending
isProject: false
---
# 试玩活动配置center 迁出,按 activity_code 解析
## 结论(对你问题的回应)
**我同意你的方向**,且比当前联调实现更贴合项目既有模式:
- **center 不应承载** `deposit_threshold``trial_withdrawal_cap``activity_id` 等业务参数;它只适合 `walletApiHost` 等基础设施。
- **活动服决定业务规则**:阈值、上限、开关、时间窗应来自 [`activity`](slot-activity/app/model/ActivityModel.php) 表(运营在 slot-admin 维护),与 [`DepositBonusLogic`](slot-activity/app/innerapi/logic/DepositBonusLogic.php) / [`SignInLogic`](slot-activity/app/api/logic/SignInLogic.php) 读 `ext` 的方式一致。
- **按 `activity_code` 定位**:代码里固定 `trial_reward`(你已选 PHP 常量),各环境 DB 里 `activity_id` 可以不同,**发版/切环境不依赖 center 改数字 ID**。
当前临时方案的问题:
```74:82:slot-center/config/share_config.php
'activity' => [
'trialReward' => [
'activity_id' => 9001,
'activity_code' => 'trial_reward',
'deposit_threshold' => 50,
'trial_withdrawal_cap' => 500,
],
],
```
[`TrialFirstDepositLogic`](slot-activity/app/innerapi/logic/TrialFirstDepositLogic.php) 通过 `ShareConfigService` 读上述键,与「活动服自治」冲突。
---
## 目标架构
```mermaid
sequenceDiagram
participant Pay as slot_pay
participant Act as slot_activity
participant DB as activity_table
participant Wal as slot_wallet
Pay->>Act: first_deposit(uid, source, order_no, ...)
Act->>DB: findActiveByCode(trial_reward, source, now)
DB-->>Act: activity_id + ext(deposit_threshold, cap, ...)
Act->>Wal: clearTrialBonusForPool
Act->>Act: persist trial_reward_record(uid, activity_id)
```
| 配置项 | 现位置 | 目标位置 |
|---|---|---|
| activity 身份 | center `trialReward.activity_id` | `activity.activity_code = trial_reward` → 得到 `activity_id` |
| deposit_threshold | center | `activity.ext.deposit_threshold`(美元,入库 *1000 |
| trial_withdrawal_cap | center | `activity.ext.trial_withdrawal_cap` |
| activity_code 常量 | center | [`TrialRewardConstants::ACTIVITY_CODE`](slot-activity/app/constants/TrialRewardConstants.php) |
center 保留:`walletApiHost`[`TrialWalletGatewayService`](slot-activity/app/service/wallet/TrialWalletGatewayService.php) 仍需要)。
---
## 实现步骤
### 1. 定义活动编码与 ext 键slot-activity
改 [`TrialRewardConstants.php`](slot-activity/app/constants/TrialRewardConstants.php)
- 新增 `ACTIVITY_CODE = 'trial_reward'`PHP 常量,跨环境稳定)
- 新增 ext 字段键名常量:`EXT_DEPOSIT_THRESHOLD`、`EXT_TRIAL_WITHDRAWAL_CAP` 等
- **删除** 指向 center 的 `CONFIG_KEY_ACTIVITY_ID / CODE / DEPOSIT_THRESHOLD / WITHDRAWAL_CAP`
- 保留 `DEFAULT_DEPOSIT_THRESHOLD`、`DEFAULT_WITHDRAWAL_CAP` 作为 **ext 缺省兜底**(与 SignIn 读 ext 缺字段时给默认值一致)
### 2. ActivityModel 增加按 code 查询
在 [`ActivityModel.php`](slot-activity/app/model/ActivityModel.php) 新增(对齐现有 `findMatchedSignInBySource` / `findActiveByIdForDeposit` 风格):
```php
public static function findActiveByCode(string $activityCode, string $source, string $now): ?self
```
条件:`activity_code` 精确匹配 + `status=1` + 时间窗 + `source_list` 命中(`all` 或 `$source`)。
可选后续:在 `slot-foundation` 增加 `ActivityType::TRIAL_WITHDRAWAL`admin 筛选用;**本期不强制**code 已足够唯一标识。
### 3. 抽取活动配置解析(避免 Logic 堆 ext 解析)
新增小类,例如 [`TrialRewardActivityResolver.php`](slot-activity/app/service/trial/TrialRewardActivityResolver.php)
- 输入:`source`(来自 [`TrialFirstDepositDto`](slot-activity/app/innerapi/dto/TrialFirstDepositDto.php)
- 输出:`activity_id`、`activity_code`(快照用)、`deposit_threshold`*1000、`trial_withdrawal_cap`*1000
- 活动不存在/未启用/未命中渠道 → 抛业务异常或返回明确 reason如 `activity_not_found`**禁止静默用 center 默认值**
解析规则:
- `activity_id` / `activity_code` 来自 DB 行
- 阈值从 `ext` 读,缺省用 `TrialRewardConstants::DEFAULT_*`,再 `MoneyTool::bigUnitToSmallUnit`
### 4. 改造 TrialFirstDepositLogic
改 [`TrialFirstDepositLogic.php`](slot-activity/app/innerapi/logic/TrialFirstDepositLogic.php)
- `handleFirstDeposit()`:先 `resolveActivity($dto->source)`,再用返回的 `activity_id` 查/建 `trial_reward_record`
- `persistPool()``activity_code`、阈值、cap 均来自 resolver**移除所有 `ShareConfigService::get(trialReward.*)`**
- `queryRecord()`:同样按 `ACTIVITY_CODE` resolve 后再 `findByUidActivity`
- `resolveThresholdAmount()` / `resolveWithdrawalCap()`:改为接收已解析的 Activity 或 config DTO不再读 center
失败语义建议:
| reason | 含义 |
|---|---|
| `activity_not_found` | 无生效的 trial_reward 活动 |
| `wallet_clear_failed` | wallet 清零失败(保持现有) |
| `duplicate` / `success` | 不变 |
### 5. 移除 center 试玩业务配置
改 [`slot-center/config/share_config.php`](slot-center/config/share_config.php)
- **删除整个 `activity.trialReward` 块**(不是只删 threshold
- 重启 center本地 dev 已习惯 `php webman restart -d`
### 6. 联调/上线数据activity 表种子
新增 SQL 补丁,例如 [`slot-activity/db/patch_trial_reward_activity.sql`](slot-activity/db/patch_trial_reward_activity.sql)(插入/更新 `activity` 行,`activity_code=trial_reward`
```json
{
"deposit_threshold": 50,
"trial_withdrawal_cap": 500,
"trial_bonus_amount": 20
}
```
字段建议:`status=1`、`new_user_only=1`、`first_deposit_only=0`(首充事件另管 Pool、`source_list=["all"]`、合理 `start_time/end_time`。`activity_id` 自增即可,**各环境可以不同**。
### 7. 测试调整
- 单测 [`TrialFirstDepositStatusTest`](slot-activity/tests/Unit/Logic/TrialFirstDepositStatusTest.php):纯状态机不变
- 新增 resolver 单测mock `ActivityModel` 或测 ext 解析私有方法ext 有/无字段、美元→*1000
- 联调:在 **slotMysql.s_activity** 执行 activity 种子后,重跑首充 happy-path不再依赖 center trialReward
---
## 不变更范围(刻意不做)
- **slot-pay**:仍只调 `/innerapi/trial-reward/first-deposit`,不传 `activity_id`符合「pay 只报事件activity 解析活动」)
- **slot-wallet / slot-sdk**:无改动
- **slot-admin 后台表单**:本期可先用 SQL 种子 + ext JSON完整 07 子需求的可视化配置可后续单独做
---
## 风险与注意
1. **必须先有 activity 行**:删掉 center 配置后,若 DB 无 `trial_reward` 活动,首充会 `activity_not_found`(比误用 9001 更安全)。
2. **历史联调数据**:若 `trial_reward_record` 里是 `activity_id=9001`,新环境 activity 自增 ID 不同;新用户无影响,老测试 uid 需清数据或对齐 activity_id。
3. **ShareConfigService 仍保留**:仅用于 `walletApiHost` 等,与试玩业务解耦。

View File

@@ -0,0 +1,222 @@
<!-- 95f2e196-ce33-4253-ace0-0a2ba260a0c2 -->
---
todos:
- id: "backend-catalog-api"
content: "collinCourseSeries/Course 列表 API + CORS 中间件"
status: pending
- id: "scaffold-collin-web"
content: "新建 collin-webVite + Vue3 + Element Plus + Router + axios"
status: pending
- id: "catalog-pages"
content: "实现系列 / 册别 / 课文列表三页Element Plus"
status: pending
- id: "integrate-typing-core"
content: "alias 引入 @typewords/coreArticle adapter + PracticeView + TypingArticle"
status: pending
- id: "static-audio-proxy"
content: "配置 /sound 静态资源与 VITE_MEDIA_BASE 联调"
status: pending
- id: "e2e-nce-lesson5"
content: "端到端验收 nce-2 第 5 课听写/默写"
status: pending
isProject: false
---
# TypeWords → Element Plus + collin 迁移计划MVP课文练习
## 目标与边界
**第一版做:**
- 课程系列 / 册别选择
- 课文列表(按 `lesson_no` 排序)
- 课文听写、默写(复用 TypeWords 练习引擎)
**第一版不做:**
- 单词独立练习、FSRS、登录、云同步、词本、查词 UI
- 仍用 TypeWords 本地 IndexedDB 存**练习进度/设置**(可选,与 collin 无关)
```mermaid
flowchart LR
subgraph ui [collin-web Element Plus]
SeriesPage --> CoursePage --> LessonList --> PracticePage
end
subgraph core [TypeWords packages/core]
TypingArticle --> genArticleSectionData
end
subgraph api [collin Webman]
SeriesAPI --> CourseAPI --> ArticleAPI
end
PracticePage --> ArticleAPI
PracticePage --> TypingArticle
ArticleAPI --> genArticleSectionData
```
---
## 推荐架构
| 层 | 技术 | 说明 |
|----|------|------|
| 新前端 | Vue 3 + Vite + **Element Plus** + Pinia + Vue Router | 新建 [`english/collin-web/`](english/collin-web/),与 [`collin/`](english/collin/) 分离 |
| 练习内核 | 复用 [`TypeWords/packages/core`](TypeWords/packages/core) | 只引课文相关:`TypingArticle.vue``hooks/article.ts``hooks/sound.ts`、必要 stores |
| 壳层 UI | Element Plus | 布局、表格、导航、设置抽屉;**练习区不用 EP 重写** |
| 后端 | 现有 [`CourseArticleController`](collin/app/controller/api/CourseArticleController.php) + 少量新接口 | Webman 默认路由,不加 `route.php` 业务路由 |
**为何不全量迁 Nuxt 应用:** [`TypeWords/apps/nuxt`](TypeWords/apps/nuxt) 绑定 Nuxt4、14 语言、用户/VIP/SupabaseMVP 只需 [`apps/vscode-web`](TypeWords/apps/vscode-web) 那种「Vite SPA + 引用 core」模式更贴合 Element Plus。
---
## 后端MVP 需补的 3 块
现有课文 API 已够用([`database/README.md`](collin/database/README.md)
- `GET /api/course-article/index?courseId=`
- `GET /api/course-article/show-by-lesson?courseId=&lessonNo=`
- `GET /api/course-article/show?articleId=`
**还需新增P0**
1. **课程系列列表**`CourseSeriesController::index`
- 路由:`GET /api/course-series/index`
- 返回 `course_series``status=1`,按 `sort`
- 新建:`CourseSeriesLogic` + `CourseSeriesListEntity`
2. **课程列表**`CourseController::index`
- 路由:`GET /api/course/index?seriesCode=nce`
- 返回该系列下所有 `course``pep-9-1``nce-2` 等)
- 新建:`CourseLogic` + `CourseListEntity`
3. **CORS 中间件** — [`config/middleware.php`](collin/config/middleware.php) 注册
- 开发:`http://localhost:5173`
- 允许 `GET/PATCH/OPTIONS`,响应头与 collin `ApiResponse` 一致
**可选 P1MVP 可跳过):** `GET /api/course-article/vocab` 已在后端,第一版练习不展示生词侧栏即可。
---
## 前端colin-web 结构
```
collin-web/
├── package.json # vue, element-plus, pinia, vue-router, axios
├── vite.config.ts # alias @typewords/core → ../TypeWords/packages/core
├── src/
│ ├── api/collin.ts # axios 封装baseURL 指向 collin
│ ├── adapters/article.ts # TypeWordsArticleEntity → Article
│ ├── router/index.ts
│ ├── stores/setting.ts # 精简版(音效、快捷键),可抄 core/setting 子集
│ ├── views/
│ │ ├── SeriesView.vue # el-row / el-card 选系列
│ │ ├── CourseView.vue # 选册nce-2 / pep-9-1
│ │ ├── LessonListView.vue # el-tablelessonNo、title、contentVersion
│ │ └── PracticeView.vue # 嵌入 TypingArticle
│ └── App.vue # el-container 侧边栏
```
### Article 适配(关键一步)
collin 返回 [`TypeWordsArticleEntity`](collin/app/entity/article/TypeWordsArticleEntity.php) 已含 `text``nameList``lrcPosition` 等;练习前客户端补全 TypeWords 运行时字段:
```ts
// adapters/article.ts 思路
import { genArticleSectionData } from '@typewords/core/hooks/article'
import type { Article } from '@typewords/core/types'
export function toPracticeArticle(dto): Article {
const article: Article = {
...dto,
sections: [],
newWords: [], // MVP 空数组即可
audioFileId: '',
questions: dto.question ? [dto.question] : [],
}
genArticleSectionData(article) // text → sectionsTypeWords 原文逻辑)
return article
}
```
参考:[`TypeWords/packages/core/src/hooks/article.ts`](TypeWords/packages/core/src/hooks/article.ts) 中 `genArticleSectionData`
### 复用 core 的最小依赖集
从 [`packages/core`](TypeWords/packages/core) 引入(通过 Vite alias参照 [`apps/vscode-web`](TypeWords/apps/vscode-web)
- 组件:`components/article/TypingArticle.vue``TypingWord.vue``ArticleAudio.vue`
- 依赖 stores`runtime``setting`(练习态 + 音效)
- hooks`sound.ts``article.ts`
- 类型:`types/types.ts``types/enum.ts`
**不要**引入Supabase、`useInit` 全量同步、dict 词书、FSRS。
若 Pinia store 耦合过重,可在 `PracticeView` 里只 mount `TypingArticle` 并注入精简 storevscode-web 已验证可行)。
---
## 静态资源(音频)
NCE 音频路径在 DB 中为 `/sound/article/nce2-1/...`(见 [`nce2-skip-words`](collin/database/data/nce2-skip-words.json) 与导入 JSON
- **开发:** Vite `server.proxy``public/sound` 软链到 [`english/sound/`](english/sound/)
- **生产:** Nginx 同一域名挂载 `/sound/`,或与 API 分 CDN
TypeWords 侧用 `resolveMediaUrl()`[`packages/core/src/config/env.ts`](TypeWords/packages/core/src/config/env.ts))— 在 collin-web 设 `VITE_MEDIA_BASE=/` 即可。
---
## 页面流Element Plus
| 页面 | EP 组件 | 数据 |
|------|---------|------|
| 选系列 | `el-card` / `el-menu` | `course-series/index` |
| 选册 | `el-table` | `course/index?seriesCode=` |
| 课文列表 | `el-table` + `lessonNo` 列 | `course-article/index?courseId=` |
| 练习 | `el-page-header` + 全屏 `TypingArticle` | `show-by-lesson` → adapter |
路由示例:
- `/` → 系列
- `/courses/:seriesCode` → 册别
- `/courses/:seriesCode/lessons/:courseId` → 课文列表
- `/practice/:courseId/:lessonNo` → 练习
---
## 实施顺序
### Phase 1 — collin API 补全12 天)
- `CourseSeriesController` / `CourseController` + Logic + Entity
- CORS 中间件
- 更新 [`database/README.md`](collin/database/README.md) API 表
### Phase 2 — collin-web 脚手架1 天)
- Vite + Vue3 + Element Plus + Router + Pinia
- axios + 统一 `{ code, msg, data }` 处理
- 系列 / 册别 / 课文列表三页(仅 EP无练习
### Phase 3 — 接入练习内核23 天)
- Vite alias 接 `@typewords/core`
- `toPracticeArticle` + `PracticeView`
- 音效、键盘、nameList 跳过逻辑验证Lesson 5 有 skipWords
### Phase 4 — 联调与部署1 天)
- dockercollin Webman + 前端 `pnpm build` 静态资源或独立 dev
- curl / 浏览器验证:`nce-2` 第 5 课
---
## 风险与对策
| 风险 | 对策 |
|------|------|
| core 依赖 Nuxt 宏 / 大量 auto-import | 参照 vscode-web 的 polyfill仅 import 明确路径 |
| core store 与 collin 数据模型不一致 | MVP 课文数据只从 API 进 PracticeView不写入 baseStore.dict |
| 无登录 | MVP 匿名使用;进度仍放 IndexedDB与 TypeWords 相同) |
| 后续扩展单词/词本 | DB 已有 `user_wordbook*``dict`;第二版再加 API + EP 页面 |
---
## 验收标准MVP
1. 浏览器打开 collin-web选「新概念英语 → nce-2 → 第 5 课」
2. 进入练习,`nameList` 中人名/地名自动跳过
3. 听写/默写键盘与音效与 TypeWords 一致(同一 `TypingArticle`
4. 数据全部来自 collin API不再 fetch CDN 上的 `NCE_2.json`

View File

@@ -0,0 +1,48 @@
<!-- 3895e6da-dd34-4ce4-b39b-e1e4ccf1c60c -->
---
todos:
- id: "sec2-4"
content: "改 §2 差异 bullet 与 §4.1deposit_balance/frozen_bonus 语义、不变量拆两条、移除差异 note、展示口径三桶"
status: pending
- id: "sec5-6"
content: "改 §5 对应关系补聚合桶映射§6.1 入账改为 deposit_balance += 本金、frozen_bonus += bonus"
status: pending
- id: "sec10-11"
content: "改 §10.4 扣款分桶、§11.3 派奖按命中侧落 deposit_balance / frozen_bonus"
status: pending
- id: "sec12-13"
content: "改 §12 整组解锁拆 Deposit/Bonus 分桶转 Cash§13.1 PlayedOut 表述"
status: pending
- id: "sec15-19"
content: "改 §15 Account 更新规则分桶、§16 不变量、§19 总结条款 2/3"
status: pending
isProject: false
---
# 钱包系统V2.md恢复 frozen_bonus 分桶记账
仅修订 [docs/requirements/钱包系统V2.md](docs/requirements/钱包系统V2.md) 中与"聚合余额落桶"相关的章节。打码组推进、消耗顺序、派奖命中归属、Completed/PlayedOut、`fund_detail` JSON、Redis 命中摘要等核心逻辑**保持不变**。
## 修订内容
- 三处不变量/语义:`deposit_balance = Σ 进行中 Deposit Lot.remaining``frozen_bonus ⊇ Σ 进行中组内 Bonus Lot.remaining`(含 Trial/其它发奖,超集)。
- 派奖落桶:命中 Deposit → `deposit_balance += payout`;命中 Bonus → `frozen_bonus += payout`
- 整组解锁:`group_remaining` 拆 Deposit 侧(扣 `deposit_balance`+ Bonus 侧(扣 `frozen_bonus`),合并进 `withdraw_balance`(对应现网 `moveDepositToWithdraw` + `moveBonusToWithdraw`)。
- 前端"锁定可玩/Locked Play"如需整体展示,须从 Lot/Group 聚合算组内 Bonus不能直接取 `frozen_bonus`(默认口径:展示为 Locked Deposit + Bonus Credits 两项,可玩 = 三桶和)。
## 待改小节(逐节)
- 第 42 行 §2 差异 bullet删除"充值 Bonus 进 deposit_balance"这条差异(改回后与现网一致)。
- §4.1`deposit_balance` 语义改为"仅 Deposit 本金 + Deposit 侧派奖"`frozen_bonus` 语义改为"组内 Bonus + Trial 体验金 + 其它发奖";不变量拆两条;移除第 120-121 行"与现网差异"note展示口径调整为三桶。
- §5 对应关系补注聚合桶映射Deposit 侧→`deposit_balance`、Bonus 侧→`frozen_bonus`)。
- §6.1:改为 `deposit_balance += 100``frozen_bonus += 50`;删除"不更新 frozen_bonus"与差异 note。
- §10.4:扣款分桶改为 扣 Deposit Lot→`deposit_balance--`、扣 Bonus Lot→`frozen_bonus--`、扣 Cash→`withdraw_balance--`
- §11.3:命中 Deposit→`deposit_balance += payout`、命中 Bonus→`frozen_bonus += payout`(各自累加对应 Lot remaining
- §12 打码完成:`group_remaining` 拆 Deposit/Bonus 分桶扣减后合并进 `withdraw_balance`
- §13.1 PlayedOutBonus Lot 置 PlayedOut 时 `frozen_bonus` 对应部分已为 0无需额外扣。
- §15 Account 更新规则15.1 / 15.2 / 15.4 / 15.6 改为分桶表述。
- §16 不变量、§19 总结条款 2、3同步为分桶口径。
## 不改动
- §9 局生命周期、§10.1-10.3 进度归属与扣款顺序、§11.1-11.2 命中归属与终态降级、§4.4 `fund_detail` JSON、§18 回滚不做。
- Q4「下线 win 状态路由与比例拆分」结论不变(命中 Bonus 记 `frozen_bonus` 不复活比例拆分)。

View File

@@ -0,0 +1,80 @@
<!-- 740abbc4-5a59-41be-9318-5927550e6875 -->
---
todos:
- id: "sql"
content: "新建 slot_console/db/migrate_vip_bet_bonus_rate.sqlALTER 加列 bet_bonus_rate decimal(5,2) + UPDATE 写入 VIP1-15 初始值"
status: pending
- id: "console-logic"
content: "改 UserGameStatistics::switchBonus() 按 VIP 等级取 bet_bonus_rateVIP0/空配置不转换,补日志上下文"
status: pending
- id: "console-model"
content: "slot_console UserVipConfigModel 补 @property bet_bonus_rate"
status: pending
- id: "admin-model-validate"
content: "slot_admin UserVipConfigModel @property + UserVipConfigValidate rule/message/scene 增加 bet_bonus_rate"
status: pending
- id: "vue"
content: "slot_admin_vue edit.vue 与 index.vue 增加解锁流速字段与列"
status: pending
- id: "verify"
content: "按门禁跑 verify-slot-backend.sh 与 docker php -l输出检测报告"
status: pending
isProject: false
---
## 背景
`slot_console` 每日统计在用户亏损时把冻结金额转为可领取金额,当前用全局固定费率:
```147:148:slot_console/app/command/UserGameStatistics.php
$gameBaseInfo = ConfigService::getInstance()->getGroupData('game_base');
$bonus = intval($gameBaseInfo['bet_bonus_rate'] * $lose/100);
```
需求:解锁流速按 VIP 等级阶梯VIP1=0.5% … VIP15=2.0%),后台可配置。`user_vip_config` 现无此字段(已有的 `lose_rate` 是「亏损奖励」另一活动,不复用)。
## 决策(已确认)
- 全栈实现DB 列 + slot_admin/vue 后台可配 + slot_console 按等级取值。
- 新列 `bet_bonus_rate``decimal(5,2)`,单位 %。
- VIP0 比例为 0不再转换冻结金额
## 改动点
### 1. DB 迁移(新建 SQL
新建 [slot_console/db/migrate_vip_bet_bonus_rate.sql](slot_console/db/migrate_vip_bet_bonus_rate.sql)
- `ALTER TABLE s_common.user_vip_config ADD COLUMN bet_bonus_rate decimal(5,2) NOT NULL DEFAULT 0 COMMENT '冻结金额解锁流速(%)按VIP等级' AFTER lose_rate;`
- 按需求 `UPDATE` 写入 VIP1-15 初始值0.5/0.6/.../1.8/2.0VIP15=2.0)。
### 2. slot_console 取值逻辑
改 `switchBonus()`[slot_console/app/command/UserGameStatistics.php](slot_console/app/command/UserGameStatistics.php)
- 用 `VipService::getVipLevelConfig($userInfoEntity->vip_level)` 取 VIP 配置(已有 Redis 缓存)。
- VIP0 / 配置为空 / 费率<=0 直接 return不转换
- `$bonus = intval($vipConfig->bet_bonus_rate * $lose / 100);` 取代 game_base 读取。
- 日志补 `vip_level`、`bet_bonus_rate`。
模型 PHPDoc 加 `@property` 字段:[slot_console/app/model/UserVipConfigModel.php](slot_console/app/model/UserVipConfigModel.php)。
### 3. slot_admin 后台
- [model/UserVipConfigModel.php](backend/slot_admin/app/model/UserVipConfigModel.php)`@property` 增加 `bet_bonus_rate`。
- [validate/UserVipConfigValidate.php](backend/slot_admin/app/game/validate/UserVipConfigValidate.php)`rule`/`message`/`scene(save,update)` 增加 `bet_bonus_rate => require`。
- 该字段为百分比小数,直接存储,不走 `setNumberFormat`(控制器 `format()` 无需改)。
### 4. slot_admin_vue 前端
- [edit.vue](backend/slot_admin_vue/src/views/game/userVipConfig/edit.vue)`formData` + `rules` + 新增「解锁流速(%)」`a-form-item field="bet_bonus_rate"`。
- [index.vue](backend/slot_admin_vue/src/views/game/userVipConfig/index.vue)`columns` 增加「解锁流速」列。
## 数据流
```mermaid
flowchart LR
admin[slot_admin 配置bet_bonus_rate] --> db[(s_common.user_vip_config)]
admin --> cache[(redis vip:config:level:*)]
console[slot_console switchBonus] --> vipsvc[VipService.getVipLevelConfig]
vipsvc --> cache
vipsvc --> db
console --> wallet[switchBonus 转可领取]
```
## 注意
- `game_base.bet_bonus_rate` 配置改为不再被 `switchBonus` 使用(保留配置项,不删除)。
- Redis 缓存存 `model->toArray()`新列自动随后台保存刷新TTL 600s
- 完成前按门禁跑 `verify-slot-backend.sh` 与 docker `php -l`,并对照 php-clean-code 输出检测报告。

View File

@@ -0,0 +1,253 @@
<!-- c1c00f01-351c-4b81-9a07-dec92aaf4ae2 -->
---
todos:
- id: "phase0-prep"
content: "Phase 0确认 minus() 死代码、补 PHPDoc、更新 README 入口索引"
status: pending
- id: "phase1-base-query-register"
content: "Phase 1新建 AbstractWalletMutationLogic + WalletQueryLogic + WalletRegisterLogicWalletLogic 委托 register/query"
status: pending
- id: "phase2-bet-win"
content: "Phase 2新建 WalletBetWinLogic迁移 bet/win 及 Redis round 辅助逻辑"
status: pending
- id: "phase3-recharge"
content: "Phase 3新建 WalletRechargeLogic迁移 inc/recharge/reward 与 Trial Pool 充值链"
status: pending
- id: "phase4-withdraw-trial"
content: "Phase 4新建 WalletWithdrawLogic + WalletTrialLogic修复 switchBonus 路由(如需要)"
status: pending
isProject: false
---
# WalletLogic 分阶段拆分方案
## 现状诊断
[`slot-wallet/app/api/logic/WalletLogic.php`](slot-wallet/app/api/logic/WalletLogic.php) 当前 **1885 行**,承担了钱包服务几乎全部资金用例编排:
| 域 | 主要方法 | 约行数 | 已有下沉 |
|---|---|---|---|
| 路由门面 | `run`, `runRechargeOrder`, `ACTION_METHOD_MAP` | ~80 | — |
| 注册 | `register`, `initWalletWithoutMoney` | ~120 | [`RegisterService`](slot-wallet/app/service/wallet/RegisterService.php) |
| 下注/派奖 | `bet`, `win`, pending win Redis, bet split | ~450 | [`BetService`](slot-wallet/app/service/wallet/BetService.php), [`WinService`](slot-wallet/app/service/wallet/WinService.php) |
| 入账/充值 | `inc`, `recharge`, `rechargeSign`, `reward`, Trial Pool | ~400 | [`RechargeFundLotService`](slot-wallet/app/service/wallet/RechargeFundLotService.php) |
| 提现/Bonus 转换 | `withdraw*`, `rollbackWithdraw`, `bonusToDeposit`, `switchBonus` | ~350 | [`WithdrawTaskService`](slot-wallet/app/service/wallet/WithdrawTaskService.php) |
| Trial 体验金 | `grantTrial`, `expireTrial` | ~250 | — |
| 查询 | `query`, `queryBizLog` (static) | ~70 | — |
| 公共能力 | `addLog`, `maxRetry`, `sendConsoleBus`, `getBalance` 等 | ~200 | — |
**问题**:单文件混合 6+ 业务域事务边界、幂等、Redis 辅助状态交织Review 和改动风险都高。
**已有良好先例**:同目录 [`GrantLogic`](slot-wallet/app/api/logic/GrantLogic.php)、[`PlayerTaskLogic`](slot-wallet/app/api/logic/PlayerTaskLogic.php) 已是「一用例一 Logic」核心扣款/派奖细节已在 Service 层Logic 层再拆是合理下一步。
**额外发现**(非本次必做):`minus()` 未出现在 `ACTION_METHOD_MAP` 且无调用方,疑似历史遗留,可在 Phase 0 确认后删除。
---
## 目标架构
```mermaid
flowchart TB
subgraph controller [Controller 不变]
WC[WalletController]
end
subgraph facade [门面层]
WL[WalletLogic]
end
subgraph domain [子 Logic 按域]
WQ[WalletQueryLogic]
WRg[WalletRegisterLogic]
WBw[WalletBetWinLogic]
WRe[WalletRechargeLogic]
WWd[WalletWithdrawLogic]
WTr[WalletTrialLogic]
end
subgraph shared [共享]
Base[AbstractWalletMutationLogic]
end
subgraph service [已有 Service 不动]
BS[BetService]
WS[WinService]
RS[RegisterService]
end
WC --> WL
WL --> WRg & WBw & WRe & WWd & WTr
GrantLogic --> WQ
WL --> WQ
WRg & WBw & WRe & WWd & WTr --> Base
WBw --> BS & WS
WRg --> RS
```
**原则**(对齐 [`backend-layering`](.cursor/rules/backend-layering.mdc)
- **Logic 拆用例、Service 保公共能力**:不再新建「只做 Model 转发」的 Service。
- **WalletLogic 只做分发 + 缓存清理**:保留 `run()` / `runRechargeOrder()` 对外签名;`ACTION_METHOD_MAP` 改为指向子 Logic 方法。
- **Controller 不改**:继续只注入 `WalletLogic`(你已确认)。
- **共享状态收敛**:子 Logic 继承抽象基类,统一持有 `WalletUpdateRequestDTO``rechargeOrderDto` 仅留在 `WalletRechargeLogic`
---
## 共享基类设计
新建 [`slot-wallet/app/api/logic/AbstractWalletMutationLogic.php`](slot-wallet/app/api/logic/AbstractWalletMutationLogic.php)
```php
abstract class AbstractWalletMutationLogic
{
protected WalletUpdateRequestDTO $requestDTO;
/** 绑定本次 mutation 请求上下文 */
protected function bindRequest(WalletUpdateRequestDTO $requestDTO): void { ... }
/** 写 wallet_log、PWA 流水、乐观锁重试、Console Bus 等 */
protected function addLog(...): int { ... }
protected function addTransactionRecord(...): void { ... }
protected function getBalance(WalletAccountModel $model): int { ... }
protected function maxRetry(callable $callback, int $retryCount = 3): WalletEntity { ... }
protected function sendConsoleBus(string $type, int $amount): void { ... }
protected function initWalletWithoutMoney(): ?WalletAccountModel { ... }
}
```
- 从现有 `WalletLogic` **原样迁移**上述 protected/private 方法,避免行为变化。
- 子 Logic 方法签名改为显式接收 DTO 或在门面 `bindRequest()` 后调用,**不再依赖 `$this->requestDTO` 隐式全局状态跨文件散落**。
---
## 子 Logic 划分
| 新类 | 职责 | 从 WalletLogic 迁出的方法 |
|---|---|---|
| `WalletQueryLogic` | 只读查询 | `query`, `queryBizLog` |
| `WalletRegisterLogic` | 注册赠金 | `register` |
| `WalletBetWinLogic` | 游戏下注/派奖编排 | `bet`, `win`, `executeTrialBet/Win`, `executeFreeSpinPaidBet`, pending win / bet split Redis, `getWinAllocationByRound`, `buildBetSplitRemark` |
| `WalletRechargeLogic` | 入账/充值 | `inc`, `executeIncWithTransaction`, `recharge`, `rechargeSign`, `reward`, Trial Pool 扣减链, `resolveRechargeOrderDtoForLots`, `insertRechargeFundLotsIfNeeded` |
| `WalletWithdrawLogic` | 提现与 Bonus 桶转换 | `withdraw`, `withdrawFrozen`, `rollbackWithdraw`, `doneWithdraw`, `bonusToDeposit`, `switchBonus` |
| `WalletTrialLogic` | Trial 体验金生命周期 | `grantTrial`, `expireTrial`, `resolveTrialAmount`, `makeTrialPoolBizId`, `buildTrialPoolRemark`, `deductTrialPoolInRechargeTransaction`(若仍被 Recharge 调用则保留在 Recharge 或抽 `TrialPoolSupport` trait |
**Trial Pool 边界**`planTrialPoolDeductionForRecharge` / `finalizeTrialPoolAfterRechargeInc` 与充值事务强耦合,建议 **Phase 3 随 RechargeLogic 一起迁**Trial 发放/过期独立进 `WalletTrialLogic`
---
## 门面 WalletLogic拆分后 ~150 行)
```php
class WalletLogic
{
public function __construct(
private WalletRegisterLogic $registerLogic,
private WalletBetWinLogic $betWinLogic,
private WalletRechargeLogic $rechargeLogic,
private WalletWithdrawLogic $withdrawLogic,
private WalletTrialLogic $trialLogic,
) {}
public function run(WalletUpdateRequestDTO $requestDTO) { /* 分发 + deleteWalletCache */ }
public function runRechargeOrder(WalletRechargeRequestDTO $dto) { /* 委托 rechargeLogic */ }
// 兼容 GrantLogic / 外部 static 调用
public static function query(...) { return WalletQueryLogic::query(...); }
public static function queryBizLog(...) { return WalletQueryLogic::queryBizLog(...); }
}
```
`ACTION_METHOD_MAP` 改为 **Logic 实例 + 方法名****callable 数组**,例如:
```php
WalletLogModel::BIZ_TYPE_BET => [$this->betWinLogic, 'bet'],
```
Webman DI 需在 [`config/`](slot-wallet/config/) 或现有容器绑定中注册子 Logic若项目无自动注入门面构造函数内 `new` 亦可,与当前 `GrantLogic` 风格一致)。
---
## 分阶段实施(你已选 phased + facade
### Phase 0准备低风险
-`WalletLogic` 现有 public 方法补全/核对中文 PHPDoc拆分时会移动代码趁此对齐 [`php-clean-code`](.cursor/rules/php-clean-code.mdc))。
- 确认 `minus()` 无调用后删除(或加 `@deprecated` 注释待下一版删)。
- 更新 [`README.md`](slot-wallet/README.md)「实现入口」一节,列出子 Logic 索引。
### Phase 1Query + Register + 基类
- 新建 `AbstractWalletMutationLogic``WalletQueryLogic``WalletRegisterLogic`
- `WalletLogic::query/queryBizLog` 改为委托;[`GrantLogic`](slot-wallet/app/api/logic/GrantLogic.php) 可继续 `WalletLogic::query()` 不动。
- `register` 从 WalletLogic 迁出;`run()` 分发到 `WalletRegisterLogic`
- **验收**注册接口、余额查询、Grant 通知链路回归。
### Phase 2BetWin最高复杂度
- 新建 `WalletBetWinLogic`,迁移 `bet`/`win` 及 Redis round 状态方法。
- `WalletController``bet`/`win` 专用入口仍走 `walletLogic->run()`,行为不变。
- **注意**`win()` 内对 `$requestDTO->fee` 的临时修改必须在 BetWinLogic 内用 `try/finally` 保持,避免泄漏到其他域。
- **验收**:下注/派奖、Trial 阶段 bet/win、FreeSpin 代付、中间派奖 `is_end=0`、幂等 hit。
### Phase 3Recharge / Inc
- 新建 `WalletRechargeLogic`,迁移 `inc` 全链路 + `recharge`/`rechargeSign`/`reward`
- `runRechargeOrder` 委托给 RechargeLogic`rechargeOrderDto` 生命周期)。
- **验收**:充值主链路、首充 Trial Pool 扣减、Fund Lot 落库、签到充值 `sign`
### Phase 4Withdraw + Trial
- 新建 `WalletWithdrawLogic``WalletTrialLogic`
- 补齐 `ACTION_METHOD_MAP` 中缺失的 `switchBonus` 映射(若 slot-sdk 仍在调 `type=switchBonus`,当前可能未路由到方法——拆分时可一并修复)。
- **验收**:提现冻结/成功/失败回滚、Bonus 转 Deposit、Trial 发放/过期。
---
## 不建议的做法
- **不要把子用例再拆成 Logic 型 Service**(如 `WithdrawLogicService`),违反分层红线。
- **不要一次性改 Controller 注入多个 Logic**,你已选 facade保持对外稳定。
- **不要把 BetService/WinService 的业务编排再搬回 Logic 后又复制一份**——子 Logic 只做事务、幂等、流水、MQ核心算法继续调用现有 Service。
---
## 预期收益
- 单文件从 ~1900 行降至 **门面 ~150 行 + 各子 Logic 200500 行**
- 改动 bet 不再误触 recharge 事务代码Review 范围清晰。
-`GrantLogic` 风格统一,新人可按域定位代码。
- 对外 API、`WalletLogic::run()` 签名、SDK 调用路径 **零破坏**
---
## 风险与缓解
| 风险 | 缓解 |
|---|---|
| 拆分引入行为回归 | 每 Phase 独立 PR优先复制代码再删旧代码不做顺手重构 |
| `$requestDTO` 可变状态 | 基类 `bindRequest()` + 子 Logic 不跨用例复用实例 |
| Webman 构造注入 | 若无 DIPhase 1 先在 WalletLogic 内 `new` 子 Logic后续再接线 |
| Trial Pool 跨 Recharge/Trial | Phase 3 完成 Recharge 后再动 Trial必要时抽 `TrialPoolDeductionSupport` trait 供 Recharge 专用 |
---
## 涉及文件
**新建**(均在 `slot-wallet/app/api/logic/`
- `AbstractWalletMutationLogic.php`
- `WalletQueryLogic.php`
- `WalletRegisterLogic.php`
- `WalletBetWinLogic.php`
- `WalletRechargeLogic.php`
- `WalletWithdrawLogic.php`
- `WalletTrialLogic.php`
**修改**
- [`WalletLogic.php`](slot-wallet/app/api/logic/WalletLogic.php) — 瘦身为门面
- [`README.md`](slot-wallet/README.md) — 更新入口索引(可选 `.cursor/rules/slot-wallet-prd-and-money.mdc` 一行指向)
**不改**
- [`WalletController.php`](slot-wallet/app/api/controller/WalletController.php)
- 现有 `app/service/wallet/*Service.php`

View File

@@ -0,0 +1,170 @@
---
name: Agent 自检报告机制
overview: 通过 **Rule强制收尾+ Skill报告模板与步骤+ Hook/脚本(可自动化的硬检查)** 三层配合,让 Agent 写完 PHP 后端代码后自动跑检测并输出结构化报告;不是单靠 Skill 或单靠 Hook 就能完全覆盖。
todos:
- id: create-skill
content: 新建 ~/.cursor/skills/slot-backend-completion-report/SKILL.md步骤 + 报告模板php -l 按工作区/git 仓库动态映射容器 -w不写死 slot-xxx
status: completed
- id: update-gate-rule
content: 更新 agent-completion-gate.mdc收尾必须执行 Skill 并输出检测报告章节
status: completed
- id: extend-verify-script
content: 可选verify-slot-backend.sh 增加 const 注释检查 + 修复 grep pipefail
status: completed
- id: project-copy
content: (可选)复制 Skill 到 www/ray/.cursor/skills/ 供仓库共享
status: completed
isProject: false
---
# Agent 写完代码后自动自检出报告:怎么配
## 你现在已经有什么
你其实**已经有一半机制**,只是还没有「结构化报告」这一层:
| 机制 | 文件 | 现在做什么 | 缺什么 |
|------|------|------------|--------|
| **RulealwaysApply** | [`~/.cursor/rules/agent-completion-gate.mdc`](/Users/ray/.cursor/rules/agent-completion-gate.mdc) | 要求收尾前跑 `verify-slot-backend.sh`、回复里贴 `PASS/FAIL`、写 `PHPDoc: checked` | 没规定报告格式(表格、分层检查、语法检查) |
| **Rule** | [`~/.cursor/rules/php-clean-code.mdc`](/Users/ray/.cursor/rules/php-clean-code.mdc) | §8 自查清单常量注释、Logic 编排等) | 靠 Agent **自觉对照**,脚本不检查 |
| **Hookstop** | [`~/.cursor/hooks.json`](/Users/ray/.cursor/hooks.json) → `verify-slot-backend.sh` | Agent **结束时会自动跑**门禁脚本;`FAIL` 会注入 followup 要求继续修 | 只输出 `PASS/FAIL`,不会生成你看到的 Markdown 报告 |
| **脚本** | [`~/.cursor/hooks/verify-slot-backend.sh`](/Users/ray/.cursor/hooks/verify-slot-backend.sh) | 扫 git diffbanlist、BaseController、RuntimeException 等 | **不检查** PHPDoc、常量注释、Vue 改动 |
所以你上面看到的那种报告,主要是 Agent **按 Rule 手动执行 + 人工对照规范**,不是某个 Skill 或 Hook 自动生成的。
```mermaid
flowchart TB
subgraph now [当前]
WriteCode[Agent 写代码]
RuleGate[agent-completion-gate Rule]
HookStop[stop Hook 跑 verify 脚本]
ManualReport[Agent 自觉出 Markdown 报告]
WriteCode --> RuleGate
WriteCode --> HookStop
RuleGate --> ManualReport
end
subgraph target [目标]
WriteCode2[Agent 写代码]
SkillReport[completion-report Skill]
ScriptHard[verify 脚本硬检查]
RuleMust[Rule 强制用 Skill 收尾]
WriteCode2 --> SkillReport
SkillReport --> ScriptHard
RuleMust --> SkillReport
SkillReport --> StructuredReport[固定格式检测报告]
end
```
---
## 三种方式分别适合什么
### 1. Rule —— 适合「必须做,否则不能说完成」
- **作用**每次对话都生效Agent 不能跳过
- **适合写**:「收尾前必须跑 X」「最终回复必须含 Y 格式的报告」
- **不适合**:很长的操作步骤(会占 context、难维护
你已有 [`agent-completion-gate.mdc`](/Users/ray/.cursor/rules/agent-completion-gate.mdc),只需**加一条**:收尾章节必须按 `slot-backend-completion-report` Skill 输出。
### 2. Skill —— 适合「怎么做 + 报告长什么样」
- **作用**Agent 在收尾阶段读取,按步骤跑命令、填模板
- **适合写**
- 执行顺序verify → docker php -l → 对照 §8 自查)
- **固定报告模板**(就是你上面看到的:门禁脚本 / 语法 / PHPDoc / 分层 / 结论)
- 按改动类型分支(只改 Vue / 只改 Logic / 改 Model 等)
- **路径建议**`~/.cursor/skills/slot-backend-completion-report/SKILL.md`(个人全局)或 `www/ray/.cursor/skills/...`(项目共享)
Skill **不会自动执行**,需要 Rule 或用户说「按规范检测」触发。
### 3. Hook + 脚本 —— 适合「能机器判定的硬规则」
- **作用**Agent 结束时自动跑(你已有 `stop` hook
- **适合写**git diff 里新增 `const` 无上一行 `/**`、新增 public 方法无 PHPDoc 等
- **不适合**Logic 是否编排清晰、命名是否达意(需 Agent 读代码判断)
Hook 只能 **FAIL 并追问**,不能像 Skill 那样输出完整 Markdown 报告。
---
## 推荐方案(三层,不重复造轮子)
### 层 1新建 Skill报告模板 + 步骤)
创建 [`~/.cursor/skills/slot-backend-completion-report/SKILL.md`](~/.cursor/skills/slot-backend-completion-report/SKILL.md),内容包括:
1. **触发**:修改 `app/**/*.php` 或用户说「按规范检测 / 检测代码」
2. **必跑命令**(路径均**动态解析**,禁止写死 `slot-xxx``/app/www/ray/...`
- **门禁脚本**`SLOT_ROOT="${SLOT_ROOT:-$WORKSPACE_ROOT}" ~/.cursor/hooks/verify-slot-backend.sh`
- `SLOT_ROOT` 默认为**当前 Cursor 工作区根目录**(用户可能在 `www/ray``www/slot` 等不同 monorepo 根下工作)
- **PHP 语法检查**(对每个 git diff 中的改动 `.php`
1. 取该文件所在 git 仓库根:`repo=$(git -C "$(dirname "$f")" rev-parse --show-toplevel)`
2. 宿主机项目挂载根 → 容器根(见 `dev-environment`):默认 `SLOT_DOCKER_HOST_ROOT=/Users/ray/Documents/project``SLOT_DOCKER_CONTAINER_ROOT=/app`
3. 容器内工作目录:`container_wd="${SLOT_DOCKER_CONTAINER_ROOT}${repo#$SLOT_DOCKER_HOST_ROOT}"`
4. 执行:`docker exec -w "$container_wd" php82 php -l "${f#$repo/}"`
- 示例(工作区在 `www/ray`、改 `slot-admin` 时):`-w /app/www/ray/slot-admin`;工作区在 `www/slot`、改 `slot_wallet` 时:`-w /app/www/slot/slot_wallet`——**由当前仓库路径推导,不手写服务名**。
3. **必做人工对照**(写进报告表格):
- `php-clean-code` §3 常量规则、§8 自查
- 改 Logic 时§3 参数与日志、聚合 DTO
- `backend-layering` 分层
4. **固定输出模板**(与你看到的报告一致):
- 门禁脚本完整输出
- PHPDoc / 常量 / 分层 / 结论
- 末行 `PHPDoc: checked`
可选Skill 内引用 [`scripts/report.sh`](/Users/ray/.cursor/skills/slot-backend-completion-report/scripts/report.sh) 统一跑 verify + php -l。脚本职责
- 读取 `WORKSPACE_ROOT` / `SLOT_ROOT`(当前工作区)
- 从 git diff 收集改动 PHP按上文规则计算 `container_wd`
- 输出结构化片段供 Agent 粘贴进报告
**用户级 Skill 约束**:不得假设固定 monorepo 路径(如 `www/ray`);所有宿主机/容器路径通过「工作区 + git 仓库根 + Docker 挂载映射」推导;挂载根可在 Skill 中 documented 为可配置 env默认对齐 [`dev-environment.mdc`](/Users/ray/.cursor/rules/dev-environment.mdc)。
### 层 2改 Rule强制收尾用 Skill
在 [`agent-completion-gate.mdc`](/Users/ray/.cursor/rules/agent-completion-gate.mdc) 增加:
- 改动 PHP 后,收尾前 **必须读取并执行** `slot-backend-completion-report` Skill
- 最终回复 **必须包含** Skill 规定的「检测结果」章节,不得只写「已完成」
### 层 3增强 verify 脚本(可选,提高自动化比例)
在 [`verify-slot-backend.sh`](/Users/ray/.cursor/hooks/verify-slot-backend.sh) 追加(仅扫 diff 新增行):
- 新增 `const` 前一行不是 `/** ... */` → FAIL
- 修复已知 bug`diff_added_lines` 在纯删除 diff 时 `grep` 退出导致脚本 silent fail你之前遇到过
这样 Hook 的 `stop` 能拦住**常量无注释**PHPDoc 方法级仍靠 Skill + Agent 报告。
---
## 不是 Skill alone也不是 Hook alone
| 你想要的效果 | 用什么 |
|--------------|--------|
| 每次写完必跑 verify | 已有 Rule + stop Hook |
| 固定格式的 Markdown 报告 | **Skill + Rule 强制引用** |
| 常量/PHPDoc 等硬规则自动 FAIL | **扩展 verify 脚本** |
| Logic 可读性、分层是否合理 | Skill 里的 §8 自查 + Agent 表格 |
---
## 你怎么用
配置完成后:
1. **默认**Agent 改 PHP 后收尾会自动读 Skill、跑脚本、出报告Rule 驱动)
2. **手动**:任意对话里说「按规范检测代码」→ Agent 读同一 Skill 即可
3. **Hook 兜底**:即使 Agent 忘了说完成,`stop` 仍会跑 verifyFAIL 会再追问一轮
---
## 实施顺序(若你确认要做)
1. 新建 `slot-backend-completion-report` Skill模板 + 命令 + 自查表)
2. 更新 `agent-completion-gate.mdc` 指向该 Skill
3. (可选)扩展 `verify-slot-backend.sh`:常量注释 + 修复 pipefail
4. (可选)项目级复制 Skill 到 `www/ray/.cursor/skills/` 便于团队共享
**工作量**Skill + Rule 约 30 分钟;脚本增强约 12 小时。

View File

@@ -0,0 +1,58 @@
<!-- 0ecc7d51-c1e6-4993-8d68-d7293c40524d -->
---
todos:
- id: "const"
content: "GameServerModel 增加 WAGERING_MODEL_TRANSPARENT=2 常量(中文注释)"
status: pending
- id: "logic-switch"
content: "GameServerLogic 增加 batchSwitchToTransparent() 批量刷透明并返回改动 source 列表"
status: pending
- id: "logic-reset"
content: "GameServerLogic 增加 resetUsersWagerTaskBySource() 按渠道分批跑用户 offTask 整理"
status: pending
- id: "command"
content: "新建 ChannelTransparent 命令,支持 --source/--dry-run编排上面两步"
status: pending
- id: "register"
content: "确认/登记 config/command.php 命令注册"
status: pending
- id: "gate"
content: "跑后端门禁脚本并附检测结果"
status: pending
isProject: false
---
# 渠道自动转透明 + 用户数据整理
## 背景结论
- 透明模式判定全系统统一为 `extend_data.wagering_model == 2``1` 或未设置 = 非透明(见 [ShareConfigService.php](slot_wallet/app/service/ShareConfigService.php) L113-118、[GameServerService.php](slot_console/app/service/GameServerService.php) L46-52
- 渠道数据在 `s_common.game_server`,由 [GameServerLogic](backend/slot_admin/app/game/logic/GameServerLogic.php) 维护,保存后 `sync()` 刷新缓存。
- 原数据整理slot_admin [Test.php](backend/slot_admin/app/command/Test.php) L39-66 按 `source` 分批捞 [UserModel](backend/slot_admin/app/model/UserModel.php),逐用户 `WalletService::offTask($uid,$currency)` → slot_wallet [SiteController::offTask](slot_wallet/app/api/controller/SiteController.php) L44-129 重算提现要求/失效历史打码任务/补建恢复任务。
## 方案(按用户确认:新建 CLI 命令;改完渠道后只对本次切换的渠道用户跑整理)
### 1. 渠道侧常量
在 [GameServerModel.php](backend/slot_admin/app/model/GameServerModel.php) 增加:
- `/** 打码模式-透明(version2) */ const WAGERING_MODEL_TRANSPARENT = 2;`
### 2. GameServerLogic 编排(两个新 public 方法,含中文 PHPDoc
- `batchSwitchToTransparent(): array`:查 `status > 0` 的全部渠道,遍历 decode `extend_data`,对 `wagering_model != 2` 的设为 2、`json_encode` 回写、调用 `sync($source)` 刷缓存;返回本次实际改动的 `source` 列表(已是 2 的跳过,天然幂等)。
- `resetUsersWagerTaskBySource(string $source): int`:复用 Test::offTask 的分批逻辑——按 `source``id > $lastId` 游标分页(1000/批)捞 `UserModel(id,currency,source)`,逐个 `WalletService::offTask($uid,$currency)`,返回处理用户数;关键节点写日志。
### 3. 新建命令 [backend/slot_admin/app/command/ChannelTransparent.php]
- `protected static $defaultName = 'channelTransparent';`
- 可选参数 `--source`(只处理指定渠道,便于灰度/测试)、`--dry-run`(只列出将变更的渠道,不写库不整理)。
- execute 流程:调用 `batchSwitchToTransparent()` 拿到改动 source 列表 → 输出列表 → 对每个 source 调 `resetUsersWagerTaskBySource()` → 输出每渠道处理用户数与总计。
- 命令为薄编排,业务逻辑全部落在 GameServerLogic。
### 4. 命令注册
确认 `config/command.php` 是否需手动登记(参照现有 `test` 命令注册方式),若需要则追加 `ChannelTransparent::class`
## 执行方式
```bash
docker exec -w /app/www/slot/backend/slot_admin php82 php webman channelTransparent --dry-run # 先预览
docker exec -w /app/www/slot/backend/slot_admin php82 php webman channelTransparent # 正式执行
```
## 注意
- 数据整理对 wallet 是逐用户同步 HTTP渠道用户多时耗时较长与现有 Test 脚本一致);保留 `--source` 可分渠道执行。
- 收尾前按门禁跑 `~/.cursor/skills/slot-backend-completion-report/scripts/report.sh` 并附检测结果。

View File

@@ -0,0 +1,118 @@
---
name: Console innerapi 架构说明
overview: 说明 slot_console 在本项目中的双重角色C 端 BFF + 活动域服务slot_sdk ConsoleClient 仅封装 `/innerapi/*` 供后端互调;若要坚持「纯 BFF 不被后端调用」,需拆分活动域或改异步回调。
todos: []
isProject: false
---
# slot_console 为何可被 slot_sdk 调用?
## 结论(先答你的疑问)
**可以给别人调,但调的不是「给 App 用的 BFF 接口」,而是同一进程里的 `/innerapi/*` 内部契约。**
在本仓库里,`slot_console` **不是纯 BFF**,而是:
| 路由前缀 | 中间件 | 谁调用 | 职责 |
| --- | --- | --- | --- |
| `/api/*` | `AuthMiddleware`JWT | **C 端 App/PWA** | BFF聚合 user/wallet/agent暴露 Lucky Rewards 等 C 端 API |
| `/innerapi/*` | `InnerAuthMiddleware` | **其它后端**agent、admin、pwa… | 活动域/内部能力:统计、邮件、游戏历史、**邀请回调** |
| `/napi/*` | `NAuthMiddleware` | 大厅等 | 非 C 端 JWT 的另一套入口 |
[`slot_sdk` 的 `ConsoleClient`](slot_sdk/src/service/console/ConsoleClient.php) 注释已写明:**「slot_console 内部 API 客户端」**,封装的是 `innerapi/...`,不是 `api/lucky-reward/spin` 这类 C 端路径。
```mermaid
flowchart LR
subgraph clients [调用方]
App[C端App]
Agent[slot_agent]
Admin[slot_admin]
end
subgraph console [slot_console]
ApiLayer["/api/* BFF"]
InnerLayer["/innerapi/* 域服务"]
Logic[LuckyRewardInviteLogic等]
end
App --> ApiLayer
Agent -->|"ConsoleClient via slot_sdk"| InnerLayer
Admin --> InnerLayer
ApiLayer --> Logic
InnerLayer --> Logic
```
---
## slot_sdk 里 console 接口是干什么的?
当前 [`ConsoleService`](slot_sdk/src/service/console/ConsoleService.php) 只有三类 **innerapi**
1. `innerapi/free-credits/statistics|list`**slot_admin** 后台统计代理
2. `innerapi/lucky-reward/invite-bind-callback`**slot_agent** 邀请绑定后回调转盘助力
**实际调用方**(仓库内):
- [`LuckyRewardInviteCallbackGatewayService`](slot_agent/app/service/LuckyRewardInviteCallbackGatewayService.php) → agent 调 console
- [`ConsoleAPIService`](backend/slot_admin/app/service/api/ConsoleAPIService.php) / Free Credits 统计 → admin 调 console
- [`slot_pwa` ConsoleService](slot_pwa/app/service/console/ConsoleService.php) → `innerapi/game/update-history`
C 端 **不会****不应该** 通过 slot_sdk 调 consoleC 端直接打 `consoleApiHost``/api/*`
---
## 为什么 agent 要调 console而不是反过来
这是 Lucky Rewards 需求里**刻意**定的边界(见 [01 文档](docs/requirements/lucky_rewards/01_slot_agent邀请回调对接方案.md)、[00 §1](docs/requirements/lucky_rewards/00_整体技术方案.md)
- **agent**:只管邀请关系、代理树、绑码奖励(通用裂变)
- **console**:拥有转盘业务状态(`lucky_reward_player`、Spin、helper、弹窗
- 邀请绑定成功后agent 广播「关系已建立」→ console **裁决**是否算转盘有效助力并发 Spin
所以不是「BFF 被乱调」,而是 **活动域挂在 console 上**agent 通过 innerapi 触发 console 内的 [`LuckyRewardInviteLogic::handleInviteBind()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)。
`/api``/innerapi` 可以共用同一套 Logicinvite 回调与 C 端 invite-link 都走 `LuckyRewardInviteLogic`),只是入口和鉴权不同。
---
## 「console 是 BFF」和现状如何对齐
更准确的说法:
- **对 C 端**console 的 `/api/*` 承担 BFF薄 Controller + Logic 编排 + 调 user/wallet/agent SDK
- **对活动数据**console 同时是 **活动域 owner**(表在 `s_common`,逻辑在 console历史上 Free Credits、签到、红包等同构
- **innerapi** = 把「活动域能力」暴露给 **trusted backend**,不是给浏览器/App
因此 slot_sdk 出现 `ConsoleClient` 与「console 有 BFF 职责」**不矛盾**——SDK 封装的是 **服务间** 调用,符合 [cross-service-sdk 规则](.cursor/rules/cross-service-sdk.mdc)(调用方用 slot_sdk被调方实现 innerapi Controller/Logic
---
## 若你认为「BFF 绝不能被后端调」——可选演进(非现状)
只有当你要把 console **严格降级为纯 BFF** 时,才需要改架构;代价是拆服务或改通信方式:
| 方案 | 做法 | 优缺点 |
| --- | --- | --- |
| **A. 拆 slot_activity** | 转盘域独立服务console 只转发 C 端agent 调 activity 而非 console | 边界最清晰;迁移成本高 |
| **B. MQ 替代 HTTP 回调** | agent 发 `lucky_reward_invite_bind` MQconsole 消费 | 解耦、可重试;需 MQ 契约与消费幂等 |
| **C. 维持现状** | console = BFF + 活动域innerapi 仅 trusted 服务 | **当前实现**;与现网 Free Credits innerapi 一致 |
**建议**:除非全站统一「活动全部拆独立服务」,否则 **C 方案是本项目既定模式**,不必因 slot_sdk 有 ConsoleClient 而视为设计错误。
---
## 安全与边界(现状)
- innerapi 走 [`InnerAuthMiddleware`](slot_console/app/middleware/InnerAuthMiddleware.php)(内网 + 日志;生产通常靠网络隔离 + `server-name` 头标识调用方)
- agent 回调带 `server-name: agent`(见 [deploy 文档](slot_console/doc/lucky_reward_deploy.md)
- **禁止**:在 agent/user 等业务代码里手写 `consoleApiHost + path` 字符串;应走 slot_sdk与 wallet/user 一致)
---
## 无需改代码时的认知对齐
1. **slot_sdk ConsoleClient ≠ C 端调 console**
2. **console `/api` = BFF`/innerapi` = 活动域对后端开放**
3. **agent → console** 是转盘需求文档明确的服务边界,不是临时 hack
若你后续希望 **agent 不再 HTTP 调 console**,再单独立项做方案 BMQ或方案 A拆服务当前代码与文档是一致的。

View File

@@ -0,0 +1,118 @@
---
name: Console innerapi 架构说明
overview: 说明 slot_console 在本项目中的双重角色C 端 BFF + 活动域服务slot_sdk ConsoleClient 仅封装 `/innerapi/*` 供后端互调;若要坚持「纯 BFF 不被后端调用」,需拆分活动域或改异步回调。
todos: []
isProject: false
---
# slot_console 为何可被 slot_sdk 调用?
## 结论(先答你的疑问)
**可以给别人调,但调的不是「给 App 用的 BFF 接口」,而是同一进程里的 `/innerapi/*` 内部契约。**
在本仓库里,`slot_console` **不是纯 BFF**,而是:
| 路由前缀 | 中间件 | 谁调用 | 职责 |
| --- | --- | --- | --- |
| `/api/*` | `AuthMiddleware`JWT | **C 端 App/PWA** | BFF聚合 user/wallet/agent暴露 Lucky Rewards 等 C 端 API |
| `/innerapi/*` | `InnerAuthMiddleware` | **其它后端**agent、admin、pwa… | 活动域/内部能力:统计、邮件、游戏历史、**邀请回调** |
| `/napi/*` | `NAuthMiddleware` | 大厅等 | 非 C 端 JWT 的另一套入口 |
[`slot_sdk` 的 `ConsoleClient`](slot_sdk/src/service/console/ConsoleClient.php) 注释已写明:**「slot_console 内部 API 客户端」**,封装的是 `innerapi/...`,不是 `api/lucky-reward/spin` 这类 C 端路径。
```mermaid
flowchart LR
subgraph clients [调用方]
App[C端App]
Agent[slot_agent]
Admin[slot_admin]
end
subgraph console [slot_console]
ApiLayer["/api/* BFF"]
InnerLayer["/innerapi/* 域服务"]
Logic[LuckyRewardInviteLogic等]
end
App --> ApiLayer
Agent -->|"ConsoleClient via slot_sdk"| InnerLayer
Admin --> InnerLayer
ApiLayer --> Logic
InnerLayer --> Logic
```
---
## slot_sdk 里 console 接口是干什么的?
当前 [`ConsoleService`](slot_sdk/src/service/console/ConsoleService.php) 只有三类 **innerapi**
1. `innerapi/free-credits/statistics|list`**slot_admin** 后台统计代理
2. `innerapi/lucky-reward/invite-bind-callback`**slot_agent** 邀请绑定后回调转盘助力
**实际调用方**(仓库内):
- [`LuckyRewardInviteCallbackGatewayService`](slot_agent/app/service/LuckyRewardInviteCallbackGatewayService.php) → agent 调 console
- [`ConsoleAPIService`](backend/slot_admin/app/service/api/ConsoleAPIService.php) / Free Credits 统计 → admin 调 console
- [`slot_pwa` ConsoleService](slot_pwa/app/service/console/ConsoleService.php) → `innerapi/game/update-history`
C 端 **不会****不应该** 通过 slot_sdk 调 consoleC 端直接打 `consoleApiHost``/api/*`
---
## 为什么 agent 要调 console而不是反过来
这是 Lucky Rewards 需求里**刻意**定的边界(见 [01 文档](docs/requirements/lucky_rewards/01_slot_agent邀请回调对接方案.md)、[00 §1](docs/requirements/lucky_rewards/00_整体技术方案.md)
- **agent**:只管邀请关系、代理树、绑码奖励(通用裂变)
- **console**:拥有转盘业务状态(`lucky_reward_player`、Spin、helper、弹窗
- 邀请绑定成功后agent 广播「关系已建立」→ console **裁决**是否算转盘有效助力并发 Spin
所以不是「BFF 被乱调」,而是 **活动域挂在 console 上**agent 通过 innerapi 触发 console 内的 [`LuckyRewardInviteLogic::handleInviteBind()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)。
`/api``/innerapi` 可以共用同一套 Logicinvite 回调与 C 端 invite-link 都走 `LuckyRewardInviteLogic`),只是入口和鉴权不同。
---
## 「console 是 BFF」和现状如何对齐
更准确的说法:
- **对 C 端**console 的 `/api/*` 承担 BFF薄 Controller + Logic 编排 + 调 user/wallet/agent SDK
- **对活动数据**console 同时是 **活动域 owner**(表在 `s_common`,逻辑在 console历史上 Free Credits、签到、红包等同构
- **innerapi** = 把「活动域能力」暴露给 **trusted backend**,不是给浏览器/App
因此 slot_sdk 出现 `ConsoleClient` 与「console 有 BFF 职责」**不矛盾**——SDK 封装的是 **服务间** 调用,符合 [cross-service-sdk 规则](.cursor/rules/cross-service-sdk.mdc)(调用方用 slot_sdk被调方实现 innerapi Controller/Logic
---
## 若你认为「BFF 绝不能被后端调」——可选演进(非现状)
只有当你要把 console **严格降级为纯 BFF** 时,才需要改架构;代价是拆服务或改通信方式:
| 方案 | 做法 | 优缺点 |
| --- | --- | --- |
| **A. 拆 slot_activity** | 转盘域独立服务console 只转发 C 端agent 调 activity 而非 console | 边界最清晰;迁移成本高 |
| **B. MQ 替代 HTTP 回调** | agent 发 `lucky_reward_invite_bind` MQconsole 消费 | 解耦、可重试;需 MQ 契约与消费幂等 |
| **C. 维持现状** | console = BFF + 活动域innerapi 仅 trusted 服务 | **当前实现**;与现网 Free Credits innerapi 一致 |
**建议**:除非全站统一「活动全部拆独立服务」,否则 **C 方案是本项目既定模式**,不必因 slot_sdk 有 ConsoleClient 而视为设计错误。
---
## 安全与边界(现状)
- innerapi 走 [`InnerAuthMiddleware`](slot_console/app/middleware/InnerAuthMiddleware.php)(内网 + 日志;生产通常靠网络隔离 + `server-name` 头标识调用方)
- agent 回调带 `server-name: agent`(见 [deploy 文档](slot_console/doc/lucky_reward_deploy.md)
- **禁止**:在 agent/user 等业务代码里手写 `consoleApiHost + path` 字符串;应走 slot_sdk与 wallet/user 一致)
---
## 无需改代码时的认知对齐
1. **slot_sdk ConsoleClient ≠ C 端调 console**
2. **console `/api` = BFF`/innerapi` = 活动域对后端开放**
3. **agent → console** 是转盘需求文档明确的服务边界,不是临时 hack
若你后续希望 **agent 不再 HTTP 调 console**,再单独立项做方案 BMQ或方案 A拆服务当前代码与文档是一致的。

View File

@@ -0,0 +1,107 @@
---
name: Console Redis 在线推送
overview: 不建议在 slot_game 新增「用户是否在线」接口;邀请成功弹窗的在线判断应放在 slot_console复用 EventBus 已维护的 Redis 在线集合,在 PendingPopupService 入队后「在线才 WS 即时推送、离线靠 HomeEvent 补弹」。
todos:
- id: user-online-service
content: 新增 UserOnlineService::isUserOnline读 Redis getUserOnlineKey+ 单测
status: completed
- id: pending-popup-online-gate
content: PendingPopupService::enqueue 在线才 notifyClientPOP离线仅持久化
status: completed
- id: docs-verify-online
content: 更新 07 文档 enqueue 说明;跑 verify + 相关单测
status: in_progress
isProject: false
---
# 在线判断方案:不建议 slot_game采用 slot_console Redis
## 结论(对你问题的直接回答)
**不建议在 [`slot_game`](slot_game) 新增控制器做在线判断。**
| 服务 | 职责 | 是否适合判断「大厅弹窗在线」 |
|------|------|------------------------------|
| **slot_game** | 游戏 WebSocket 网关spin/bet/进游戏) | 否 — 用户在大厅连的是 **slot_hub**,不一定连 slot_game |
| **slot_hub** | 大厅 WS + `Gateway::isUidOnline($uid)`(见 [`BaseLogic`](slot_hub/plugin/slot/hub/logic/BaseLogic.php) | 最准,但需跨服务 HTTP/RPC07 文档一期未接 |
| **slot_console** | 弹窗入队、EventBus 维护 Redis 在线集合 | **合适** — 数据已有,无跨服务调用 |
当前邀请成功链路(已实现):
```mermaid
sequenceDiagram
participant Logic as LuckyRewardInviteLogic
participant Popup as PendingPopupService
participant Redis as Redis_online_set
participant WS as WsService_MQ
participant Home as HomeEvent
Logic->>Popup: enqueue 邀请人弹窗
Popup->>Popup: 写 user_pending_popup
Popup->>WS: notifyClientPOP当前始终发送
Note over Home: 离线/游戏中靠 home flush 补弹
```
你已选择 **slot_console + Redis** 方案:与 [07 待弹窗方案](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md) 一致 — **持久化必做WS 仅 best-effort**
---
## 推荐实现(小改动,不改 slot_game
### 1. 封装在线查询slot_console
在 [`RedisKeyManagerService`](slot_console/app/service/RedisKeyManagerService.php) 或新建 `UserOnlineService`(公共能力,非 Logic 型业务编排):
```php
public static function isUserOnline(int $uid): bool
{
if ($uid <= 0) {
return false;
}
return (bool) Redis::sIsMember(self::getUserOnlineKey(), (string) $uid);
}
```
数据来源:[`EventBus::websocketConnectEvent`](slot_console/app/command/EventBus.php) / `websocketUnconnectEvent` 已对 `getUserOnlineKey()``sAdd` / `sRem`
**语义说明**Redis 在线 = **有 WebSocket 连接**,不等于「一定在大厅」;游戏内是否弹仍由**客户端忽略 WS** + **HomeEvent 仅非 enter_game 时 flush** 保证PRD 4.2)。
### 2. 调整 [`PendingPopupService::enqueue`](slot_console/app/service/PendingPopupService.php)
- **不变**:幂等写 `user_pending_popup`(离线也必须写,否则丢通知)
- **变更**:仅当 `isUserOnline($uid)` 为 true 时调用 `WsService::notifyClientPOP`
- 离线:跳过 WS等 [`HomeEvent::appendLuckyRewardHomePopups`](slot_console/app/command/event/HomeEvent.php) 补弹
```php
if (UserOnlineService::isUserOnline($enqueueDto->uid)) {
WsService::notifyClientPOP(...);
}
```
此改动作用于**所有**走 `PendingPopupService` 的定向弹窗(含邀请成功 `lucky_reward_invite_success`),符合 F 通用机制。
### 3. 测试
- 单元测:`isUserOnline` 对 Redis mock 或集成测 sAdd/sIsMember
- 可选:集成测 invite_bind 成功后 pending 记录存在;在线/离线 WS 行为(若难 mock MQ至少单测 PendingPopupService 分支)
### 4. 文档
- [07 用户定向弹窗通知机制方案](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md) §4 `enqueue` 说明补一句:**即时 WS 仅在 Redis 在线集合命中时发送**
- [`LuckyRewardInviteLogic`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 的 `notifyInviterInviteSuccess` PHPDoc 注明依赖 PendingPopupService 在线 gateLogic 内**不再**单独查在线
---
## 若将来需要 HTTP「查在线」给其他服务
- 优先 **slot_console `innerapi`**(如 `GET /innerapi/user/is-online?uid=`),读同一 Redis 集合
-**slot_hub innerapi**`Gateway::isUidOnline`(需 GatewayClient 配置,跨进程)
- **仍不建议 slot_game** — 除非明确要查「是否在游戏 WS 连接中」(与大厅弹窗无关)
---
## 不在本次范围
- slot_game 新 Controller
- slot_hub Gateway 跨服务封装(除非 Redis 与 Gateway 长期不一致再评估)
- 区分「大厅 vs 游戏中」的服务端精确状态(仍靠客户端 + HomeEvent `from`

View File

@@ -0,0 +1,192 @@
---
name: Free Credits 部署文档
overview: 为「后续档瀑布拆分 + 每档新增累计充值解锁」编写上线部署文档,覆盖 DB 迁移、服务发布顺序、存量兼容、验收与回滚。
todos:
- id: write-deploy-md
content: 确认后将本文档写入 slot_console/doc/FreeCredits瀑布分档部署说明.md
status: completed
- id: commit-and-pr
content: slot_console / slot_admin / slot_admin_vue 提交并提 PR merge
status: pending
- id: run-db-migrate
content: 各环境先执行 migrate_free_credits_release_tiers.sql 再发 console
status: pending
- id: post-deploy-verify
content: 按 §6 验收新定格 + 存量 grandfather + 后台配置
status: pending
isProject: false
---
# Free Credits 瀑布分档 — 部署文档
## 1. 变更摘要
| 项 | 说明 |
|---|---|
| 需求 | 首充定格后,剩余金额按 10/20/30/50/100 瀑布拆分;后续档按「每档新增累计充值」解锁 |
| 影响服务 | **slot_console**(核心)、**slot_admin** + **slot_admin_vue**(后台配置文案/校验) |
| 不影响 | slot_wallet定格/冻结/Claim、slot_pay第一档提现、第一档 $20 / 累计 $50 解锁规则 |
| 分支 | `fix/upActivity`(待 merge |
---
## 2. 发布前检查
- [ ] 代码已 merge 到目标分支并通过 CI
- [ ] 单测已通过:
```bash
docker exec -w /app/www/slot/slot_console php82 \
./vendor/bin/phpunit tests/Unit/FreeCreditsLogicAmountTest.php \
tests/Unit/FreeCreditsAdvanceUnlockTest.php
```
- [ ] 确认线上是否存在**在途 Free Credits 用户**(已定格、未完成全部档位)
- [ ] 与产品确认:存量用户走 grandfather`unlock_recharge_qf=0` 仍用旧单笔解锁规则)
---
## 3. 数据库迁移(必须先于代码)
**库**`s_common`
**脚本**[`slot_console/db/migrate_free_credits_release_tiers.sql`](slot_console/db/migrate_free_credits_release_tiers.sql)
```sql
ALTER TABLE s_common.free_credits_package
ADD COLUMN unlock_recharge_qf bigint unsigned NOT NULL DEFAULT 0
COMMENT '解锁本档所需新增累计真实充值(千分位),自上一档解锁后起算'
AFTER amount_qf;
ALTER TABLE s_common.free_credits_player
ADD COLUMN recharge_baseline_qf bigint unsigned NOT NULL DEFAULT 0
COMMENT '后续档计数起点wallet.totalRecharge 快照(千分位)'
AFTER first_cash_amount_qf;
```
### 3.1 执行方式
```bash
# 示例:容器内 MySQL
docker exec -i goMysql mysql -uroot -p<password> < migrate_free_credits_release_tiers.sql
```
### 3.2 迁移后校验
```sql
-- 列存在且默认 0
SHOW COLUMNS FROM s_common.free_credits_package LIKE 'unlock_recharge_qf';
SHOW COLUMNS FROM s_common.free_credits_player LIKE 'recharge_baseline_qf';
-- 存量数据应为 0旧规则兼容
SELECT COUNT(*) FROM s_common.free_credits_package WHERE unlock_recharge_qf != 0;
-- 上线前应为 0新定格用户上线后才会有非 0 值
```
### 3.3 注意事项
- **先 DDL、后发代码**:新代码会读写 `unlock_recharge_qf` / `recharge_baseline_qf`;缺列会导致定格/解锁失败
- 新装环境直接用 [`slot_console/db/install.sql`](slot_console/db/install.sql)(已含两列)
- 迁移**幂等**:若列已存在会报错,勿重复执行;可用 `information_schema` 先查再执行
---
## 4. 代码发布顺序
```mermaid
flowchart LR
db[1_DB迁移]
console[2_slot_console]
admin[3_slot_admin]
vue[4_slot_admin_vue]
db --> console --> admin --> vue
```
| 顺序 | 仓库 | 变更要点 |
|---|---|---|
| 1 | DB | 执行 §3 迁移 |
| 2 | **slot_console** | `FreeCreditsLogic` 瀑布拆分 + 增量解锁Model`install.sql` |
| 3 | **slot_admin** | `ActivityValidate::checkFreeCreditsExt` — `package_amount` / `subsequent_min_recharge` 改为可选 |
| 4 | **slot_admin_vue** | 活动编辑页废弃提示列表页展示「10/20/30/50/100 瀑布」 |
**无需重启/发布**slot_wallet、slot_pay、slot_pwa本次无接口字段变更C 端 `unlock_recharge_amount` 为可选增强,未做)
---
## 5. 存量用户兼容Grandfather
| 用户类型 | 拆分规则 | 解锁规则 |
|---|---|---|
| **上线前已定格** | 保持原档位行不变 | `unlock_recharge_qf=0` → 仍按 `subsequent_min_recharge` **单笔**解锁 |
| **上线后新定格** | `buildReleasePackages()` 瀑布拆分 | 按 `unlock_recharge_qf` + `recharge_baseline_qf` 增量累计解锁 |
无需对存量数据做 backfill。
若运营希望存量也切新规则,需单独产品决策 + 数据修复脚本(**不在本次范围**)。
---
## 6. 上线后验收
### 6.1 新用户定格(核心)
1. 测试账号:注册 → 赢取门槛 → 首充定格(如定格 $78.50,第一档 $20
2. 查库:
```sql
SELECT package_no, amount_qf, unlock_recharge_qf, status
FROM s_common.free_credits_package
WHERE player_id = ?
ORDER BY package_no;
```
3. 期望 release 档:`10000×3, 20000, 8500`unlock`9000, 9000, 9000, 19000, 8000`
4. 查 player`recharge_baseline_qf` = 定格时 wallet 累计充值
### 6.2 解锁链路
1. 累计充满 $50 → 第一档变 ready规则未变
2. 第一档解锁后 `recharge_baseline_qf` 更新为当前 totalR
3. 再新增累计 $9 → 第一个 $10 release 档变 readybaseline 再次前移
4. 尾档:面额 $8.50 时 unlock 为 $88000 qf
### 6.3 后台
- 新建/编辑 Free Credits 活动:可不填「解锁拆分金额」「后续解锁最小充值」
- 活动列表显示「分档规则: 10/20/30/50/100 瀑布(新定格)」
### 6.4 回归
- 存量用户(`unlock_recharge_qf=0`)单笔充值解锁仍正常
- Claim 入账、第一档提现、金额守恒 `sum(release) = frozen - first_cash` 不变
---
## 7. 回滚方案
| 场景 | 操作 |
|---|---|
| **代码有问题、DB 已迁移** | 回滚 slot_console 到上一版本;**保留 DB 新列**(默认 0旧代码忽略即可 |
| **仅后台有问题** | 单独回滚 slot_admin / slot_admin_vue |
| **误发新代码但未迁移** | 立即补跑 §3 迁移,或回滚代码 |
**不建议** DROP 新列(除非确认无新定格用户且已回滚代码)。
---
## 8. 监控与告警
上线后关注:
- slot_console 日志Free Credits 定格失败、解锁异常
- 业务指标:新定格用户的 package 行数分布(应与瀑布规则一致,不再全是 $10 均分)
- 客诉:「再充多少解锁下一档」— 当前 C 端未返回 `unlock_recharge_amount`,需 help 文案说明
---
## 9. 相关文档
- 需求:[`docs/requirements/首充前免费余额定格与分档释放需求文档.md`](docs/requirements/首充前免费余额定格与分档释放需求文档.md) §5.7、§5.8
- 实现计划:[首充剩余分档规则](/Users/ray/.cursor/plans/首充剩余分档规则_509262bd.plan.md)
---
## 10. 落盘路径
[`slot_console/doc/FreeCredits瀑布分档部署说明.md`](slot_console/doc/FreeCredits瀑布分档部署说明.md)
同目录已有 [`slot_console/doc/首充前免费余额定格与分档释放需求部署说明.md`](slot_console/doc/首充前免费余额定格与分档释放需求部署说明.md)(首版上线 checklist本文档专述**瀑布分档 + 增量解锁**增量变更,二者并存。

View File

@@ -0,0 +1,160 @@
---
name: InviteBind 规范与弹窗
overview: 重构 `LuckyRewardInviteLogic::handleInviteBind` 以符合 php-clean-code 分层写法并在有效助力成功时可靠入队邀请人「Claim Now」弹窗在线 WS 即时推送 + 离线/游戏中 HomeEvent 补弹),对齐 PRD 4.2 与子需求 F/D 文档。
todos:
- id: invite-bind-context-dto
content: 新增 InviteBindProcessContextDTOfetchUserProfile 改为返回 LuckyRewardUserProfileEntity
status: completed
- id: refactor-handle-invite-bind
content: 拆分 handleInviteBind 为编排 + private 步骤(校验/上下文/事务/弹窗/日志)
status: completed
- id: inviter-popup-prd-42
content: notifyInviterInviteSuccess成功必入队补全 PRD 4.2 payload去掉 spin_reward>0 早退
status: completed
- id: tests-docs-verify
content: 增强 InviteBind 集成测 payload 断言;更新 05 文档;跑 verify + phpunit
status: completed
isProject: false
---
# LuckyRewardInviteLogic handleInviteBind 重构与邀请人弹窗
## 现状与问题
[`handleInviteBind`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 约 160 行,单方法内堆叠:参数校验、活动/轮次解析、幂等判断、事务写 helper/grant/player、弹窗入队、日志。
**编码规范偏差(对照 `php-clean-code`**
| 问题 | 现状 |
|------|------|
| 方法过长 | `handleInviteBind` 远超 50 行建议 |
| 编排不清晰 | 校验 / 发奖 / 弹窗混在一个方法 |
| 返回值不规范 | `fetchUserProfile()` 返回 `array{nickname,avatar}`,同模块已有 [`LuckyRewardUserProfileEntity`](slot_console/app/entity/luckyReward/LuckyRewardUserProfileEntity.php)[`LuckyRewardLogic`](slot_console/app/api/logic/LuckyRewardLogic.php) 已使用) |
| 弹窗条件偏窄 | [`enqueueInviterSuccessPopup`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 在 `inviterSpinReward <= 0` 时直接 return有效助力成功但配置为 0 时不入队 |
**弹窗能力已存在但未在编排层显式表达:**
- 成功路径已调用 `enqueueInviterSuccessPopup` → [`PendingPopupService::enqueue`](slot_console/app/service/PendingPopupService.php) → 写 `user_pending_popup` + [`WsService::notifyClientPOP`](slot_console/app/service/WsService.php)(在线即时推送)
- 离线/游戏中:`HomeEvent::appendLuckyRewardHomePopups` 从待弹队列补弹([`05 邀请方案 §5`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md)、[`07 待弹窗中心`](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md)
- 集成测已断言 pending 记录存在([`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php)),但未覆盖「成功必入队 + payload 结构」
PRD [4.2 邀请成功](docs/requirements/转盘活动-功能需求文档.md):被邀请人注册成功后,**邀请人**收到 LUCKY YOU / 1 Free Spin / Claim Now仅回大厅弹、游戏内禁弹由客户端忽略 WS + HomeEvent flush 保证)。
```mermaid
sequenceDiagram
participant Agent as slot_agent_MQ
participant Logic as handleInviteBind
participant DB as s_common
participant Popup as PendingPopupService
participant WS as WsService
participant Home as HomeEvent
Agent->>Logic: invite_bind callback
Logic->>DB: helper + grant + player
Logic->>Popup: enqueue inviter popup
Popup->>DB: user_pending_popup
Popup->>WS: notifyClientPOP
Note over WS: 在线大厅即时弹
Home->>Popup: fetchPending on home
Popup->>WS: 补弹离线/回大厅
```
---
## 目标结构
### `handleInviteBind` 编排public读流程
```php
public function handleInviteBind(InviteBindCallbackDTO $callbackDto): InviteBindResultEntity
{
$earlyResult = $this->resolveInviteBindSkipResult($callbackDto);
if ($earlyResult !== null) {
return $earlyResult;
}
$processContext = $this->resolveInviteBindProcessContext($callbackDto);
if ($processContext instanceof InviteBindResultEntity) {
return $processContext; // activity closed 等
}
if ($this->isInviteHelperAlreadyProcessed($processContext->cycleId, $callbackDto->inviteeUid)) {
return $this->buildInviteBindResult(STATUS_ALREADY_PROCESSED, ...);
}
$this->persistInviteHelperInTransaction($callbackDto, $processContext);
$this->notifyInviterInviteSuccess($callbackDto, $processContext);
$this->logInviteBindSuccess($callbackDto, $processContext);
return $this->buildInviteBindResult(STATUS_SUCCESS, ...);
}
```
### 新增编排上下文 DTO
[`InviteBindProcessContextDTO`](slot_console/app/dto/luckyReward/InviteBindProcessContextDTO.php)readonly承载本用例多步共享字段避免 private 方法重复挂标量:
- `resolvedSource`, `cycleId`, `inviterSpinReward`, `inviteeSpinReward`
- `inviterBizId`, `inviteeBizId`, `popupBizId`
### 拆分 private 方法(均有中文 PHPDoc
| 方法 | 职责 |
|------|------|
| `resolveInviteBindSkipResult` | 参数非法 / 自邀 / 老用户 / 非 wheel 来源 → early return Entity |
| `resolveInviteBindProcessContext` | 解析活动配置与活跃轮次;失败返回 `InviteBindResultEntity` |
| `isInviteHelperAlreadyProcessed` | 封装 `LuckyRewardHelperModel::findByCycleAndInvitee` |
| `persistInviteHelperInTransaction` | 事务:写 helper、发 inviter/invitee grant、更新 player |
| `createInviteHelperRecord` | 写 helper 行 |
| `grantInviterSpinForHelper` | inviter grant + player spin/valid_invite_count |
| `grantInviteeSpinForHelper` | invitee grant + player spin |
| `notifyInviterInviteSuccess` | **PRD 4.2**:有效助力成功后入队 + WS委托 `PendingPopupService` |
| `logInviteBindSuccess` | 成功业务日志 |
### 弹窗行为调整PRD 4.2
- **成功即入队**`notifyInviterInviteSuccess``STATUS_SUCCESS` 路径**始终**调用(去掉 `inviterSpinReward <= 0` 早退);`payload.spin_reward` 仍传配置值(可为 0
- **payload 对齐前端**(在现有字段基础上补全,不破坏已对接字段):
- 保留:`invitee_uid`, `invitee_nickname`, `invitee_avatar`, `spin_reward`, `cycle_id`
- 新增PRD 文案,便于客户端少写死):`title`=`LUCKY YOU!`, `content`=`You've received 1 Free Spin`, `button_text`=`Claim Now`, `priority`
- **在线推送**:继续复用 `PendingPopupService::enqueue`(内部已 WSLogic 不重复调 `WsService`
- **离线/游戏中**:依赖已有 `user_pending_popup` + `HomeEvent::appendLuckyRewardHomePopups`,无需 Logic 判断在线
### 用户资料返回 Entity
- `fetchUserProfile(int $uid): LuckyRewardUserProfileEntity` 替换 array 返回
- `enqueueInviterSuccessPopup` / `buildSupportInvitePopup` 同步改用 Entity 字段(后者可顺带改,范围小)
---
## 测试
| 用例 | 文件 |
|------|------|
| 现有 early-return 单测 | [`LuckyRewardInviteLogicUnitTest`](slot_console/tests/Unit/LuckyRewardInviteLogicUnitTest.php) 保持 |
| 集成:成功写 helper + pending popup | 已有;**增强**断言 `popup_type``payload``title/content/spin_reward` |
| 集成:第二次回调幂等不入队新 popup | 已有 `already_processed`;确认 popup 仍仅 1 条 |
运行:`RUN_DB_TESTS=1``LuckyRewardInviteBindIntegrationTest` + 现有 Unit 测。
---
## 文档
- 更新 [`docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §5 payload 示例(若新增 title/content 字段)
- 无需改 plan 文件
---
## 不在本次范围
- `buildSupportInvitePopup` 改返回 Entity可选后续本次仅改其用到的 `fetchUserProfile`
- 服务端精确判断「是否在大厅/是否在线」07 文档一期不做,依赖 WS + home flush
- slot_hub / 客户端弹窗 UI 实现
---
## 自检
- `verify-slot-backend.sh` + docker `php -l`
- 对照 Logic §3/§8方法长度、中文 PHPDoc、无 Logic 返回 array、编排 DTO 不双份拷贝

View File

@@ -0,0 +1,279 @@
<!-- 09c08dbd-5e66-4d08-b29e-090a18ddb10d -->
---
todos:
- id: "user-is-new-user"
content: "slot-userAbstractRegisterService 增加 isNewUser 标志Mobile/Imei/Name RegisterService 赋值UserController::register 返回 is_new_user"
status: pending
- id: "console-ggame-query"
content: "slot-consoleGGame 新增按 game_code 查可展示单条游戏方法"
status: pending
- id: "console-recommend-logic"
content: "slot-consoleOnboardingRecommendLogiccenter 取池 → 随机 → g_game 组装 → 降级)"
status: pending
- id: "console-recommend-api"
content: "slot-consoleOnboardingController + 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: "lobbyAuthResponse 增加 is_new_userauth.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`](docs/requirements/register_popup_game_entry.md) 服务边界user 管身份console 管展示聚合
- 前端仍直连 `slot-user` 注册,无需改注册入口
- `MobileRegisterService` / `ImeiRegisterService` 已有「账号存在则走登录」逻辑,正好需要 `is_new_user` 区分
- 老用户误走 register 接口时不会触发 onboarding 弹窗
- 注册主链路不受 center/console 降级影响(推荐游戏失败只影响弹窗)
```mermaid
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 1slot-user 增加 `is_new_user`
**涉及仓库**[`/Users/ray/Documents/project/www/slot/slot_user`](/Users/ray/Documents/project/www/slot/slot_user)
### 现状
[`MobileRegisterService.php`](/Users/ray/Documents/project/www/slot/slot_user/app/service/register/MobileRegisterService.php) 与 [`ImeiRegisterService.php`](/Users/ray/Documents/project/www/slot/slot_user/app/service/register/ImeiRegisterService.php) 在 `check()` 返回 false 时会走 `MobileLoginService` / `ImeiLoginService`,但 Controller 无法区分「新建」与「登录回退」。
[`NameRegisterService.php`](/Users/ray/Documents/project/www/slot/slot_user/app/service/register/NameRegisterService.php) 账号已存在直接返回 null报错成功则一定是新用户。
### 实现方式(最小改动)
在 [`AbstractRegisterService.php`](/Users/ray/Documents/project/www/slot/slot_user/app/service/register/AbstractRegisterService.php) 增加:
```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()`](`/Users/ray/Documents/project/www/slot/slot_user/app/api/controller/UserController.php) 响应中追加:
```php
$data['is_new_user'] = $registerService->isNewUser;
```
**login 接口不改**(老用户走 login 本就不弹窗)。
### 注册响应示例
```json
{
"token": "...",
"uid": 1387459,
"expires_in": 1234567890,
"is_new_user": true
}
```
---
## Part 2slot-console 实现 recommend-game BFF03 子需求)
**涉及仓库**[`/Users/ray/Documents/project/www/ray/slot-console`](/Users/ray/Documents/project/www/ray/slot-console)
### 路由
沿用 Webman 自动路由(参照 [`RewardGrantController`](slot-console/app/api/controller/RewardGrantController.php)
```text
GET /api/onboarding/recommend-game
```
需登录JWT`$request->userEntity->uid` / `$request->userEntity->source` 取用户上下文。
### 核心 Logic新建
`app/api/logic/OnboardingRecommendLogic.php` 编排步骤(对齐需求 §5.1
1.`uid``source`source 为空按 `DEFAULT` 交给 center 回退)
2.`CenterClient``onboardingChannelGame($source)`SDK 已有:[`CenterService.php`](slot_sdk/src/service/center/CenterService.php)
3. `enabled=false``game_codes` 为空 → 返回降级 payload
4.`game_codes` **简单随机**选一个;查 [`GGame`](slot-console/app/model/common/GGame.php) 可展示游戏
5. 不可用则剔除后继续随机;全部不可用 → `enabled=false`
6. 组装返回(字段见需求 §6.1
### GGame 扩展
在 [`GGame.php`](slot-console/app/model/common/GGame.php) 新增按 `game_code` 查单条可展示游戏方法(复用 `applyLobbyListableJoinsAndWhere`,返回 `id/name/icon_url/provider_code/game_code/category`)。
可参照 slot-admin [`OnboardingChannelGameLogic::resolveGamesByGameCodes`](slot-admin/app/game/logic/OnboardingChannelGameLogic.php) 的字段映射,但用户侧只返回需求文档定义的 `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`](docs/requirements/trial_withdrawal/03_wallet_fund_flow.md) |
| `countdown_seconds` | 有游戏时 `3`,无游戏时 `0` |
| `game` | GGame 查询结果 |
---
## Part 3lobby 前端接入(游戏大厅 PWA
**涉及仓库**[`/Users/ray/Documents/project/www/ray/lobby`](/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`](lobby/src/api/user/auth.api.ts) → `POST /slot-user/api/user/register` |
| 注册编排 | [`lobby/src/services/user/auth.service.ts`](lobby/src/services/user/auth.service.ts) → `setAuth(result)` 存 token |
| 类型定义 | [`lobby/src/types/user/auth.d.ts`](lobby/src/types/user/auth.d.ts)(目前只有 token 字段,**无** `is_new_user` |
| Console API 范例 | [`lobby/src/api/console/console.ts`](lobby/src/api/console/console.ts) → `/slot-console/api/...` |
| 注册入口(需统一改) | [`telregisterbox.vue`](lobby/src/pages/sign-in/components/telregisterbox.vue)、[`emailregisterbox.vue`](lobby/src/pages/sign-in/components/emailregisterbox.vue)、[`login/index.vue`](lobby/src/pages/login/index.vue)、[`auth/telegram-callback/index.vue`](lobby/src/pages/auth/telegram-callback/index.vue)、[`register/index.vue`](lobby/src/pages/register/index.vue) |
典型流程(以手机注册为例):
```text
userAuthService.register(...) → setAuth → initializeUserSession() → router.push('/')
```
弹窗现有模式可参考 WS `Notify.popup`[`notifyPopupPayload.ts`](lobby/src/utils/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`
```ts
GET /slot-console/api/onboarding/recommend-game
```
**2. 注册编排(集中在一处,避免各页面重复)**
扩展 [`auth.service.ts`](lobby/src/services/user/auth.service.ts)
```text
register(data):
1. result = registerAPI(data)
2. setAuth(result)
3. if result.is_new_user === true:
onboarding = await fetchRecommendGame() // 已 setAuthrequest 拦截器会自动带 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`](lobby/src/api/game/game.api.ts) / 首页 launch 逻辑)
- 关闭 → 仅关弹窗,不调后端
**4. 触发时机**
在注册成功且 `is_new_user` 的分支里,**跳转首页前或首页 onMounted** 展示弹窗(推荐:注册页拿到 onboarding 后 `router.push('/')` + 通过 pinia/commonStore 或 route state 传给首页展示,避免路由切换丢状态)。
各注册入口最终都应走 `userAuthService.register`,无需每个页面单独写 recommend 逻辑。
### 前端调用链路lobby
```text
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`](docs/requirements/register_popup_game_entry/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`(非必须)
---
## 验收要点
**后端**
1. 新手机号/新 IMEI 注册 → `is_new_user=true`;同账号再次 register → `is_new_user=false`
2. `is_new_user=true` 时 recommend-game 返回渠道游戏池随机一款(或 DEFAULT 回退)
3. center 无配置 / 调用失败 → `enabled=false`,注册仍成功
4. `game_codes` 含下架游戏 → 跳过,从剩余随机
**lobby 前端**
5. 老用户走 register 登录回退(`is_new_user=false`)→ 不请求 recommend-game无弹窗
6. 新用户注册成功 → 自动请求 recommend-game`enabled=true` 时展示 onboarding 弹窗
7. 点击 LET'S PLAY → 进入推荐游戏;点击关闭 → 留在大厅,不影响 Trial Balance
8. 各注册入口(手机/邮箱/Telegram 等)行为一致(均经 `userAuthService.register`

View File

@@ -0,0 +1,64 @@
<!-- bc83d927-425a-451f-a178-e2ee0317eb13 -->
---
todos:
- id: "create-04"
content: "新增 docs/requirements/register_popup_game_entry/04_lobby_welcome_popup.md覆盖 10 点需求、uid 起始值 1257832、launch_url 预取、接口/字段/异常/测试/代码对照"
status: pending
- id: "update-parent"
content: "更新父文档 register_popup_game_entry.mdgame 增加 launch_url 字段、点击行为补充、uid 起始值说明、索引与版本号"
status: pending
- id: "update-readme"
content: "更新 register_popup_game_entry/README.md新增 04 子需求行与代码对照表条目"
status: pending
isProject: false
---
# 新用户大厅欢迎弹窗 — 需求文档(子需求 04
## 背景与现状对照
需求 10 点中,多数已在现有代码落地,仅 2 点为新增能力。文档需如实标注「已落地 / 待做」。
- 已落地(前端 `[lobby/src/components/OnboardingGamePopup.vue](lobby/src/components/OnboardingGamePopup.vue)` + 后端 `[slot-console/app/api/logic/OnboardingRecommendLogic.php](slot-console/app/api/logic/OnboardingRecommendLogic.php)`
- 注册成功进入大厅弹欢迎窗(点 1、欢迎信息点 2、平台第几位玩家 `player_number`(点 3`player_number = uid`(点 4、推荐游戏图片 `cover_url`(点 6、3 秒倒计时自动进入 `countdown_seconds`(点 7、点击 LET'S PLAY 立即进入(点 8、关闭按钮关闭且停倒计时 `closePopup()``stopCountdown()`(点 9
- 待做(本需求核心):
- 点 5真实注册 uid 发号起始值 = `1257832``slot-user`)。
- 点 10`recommend-game` 接口提前返回 `launch_url`,前端进入时直接使用(`slot-console` + `lobby`)。
## 交付物(仅 Markdown 文档)
### 1. 新增 `docs/requirements/register_popup_game_entry/04_lobby_welcome_popup.md`
子需求 04结构对齐既有 01/02/03表头元信息 + 目标/范围 + 链路 + 接口 + 规则 + 异常 + 测试 + 代码对照)。核心章节:
- 元信息表:版本 V1.0、序号 04、涉及仓库 `lobby``slot-console``slot-user``slot-pwa`launch
- 需求点 → 实现映射表:把 10 点逐条映射到「位置 / 状态(已落地/待做)」。
- 弹窗交互规格(点 1-4、6-9触发时机注册响应 `is_new_user === true`)、文案、`player_number_display` 千分位、倒计时、确认/关闭/遮罩点击行为;引用现有 `OnboardingGamePopup.vue`
- 点 5 uid 起始值 = 1257832
- 现状:`[slot-user/.../AbstractRegisterService.php](slot-user/app/service/register/AbstractRegisterService.php)` `generateUid()` = `USER_UUID_POOL`(来自 `config/txt/uuid.txt` 洗牌) `+ (repeat+1)*1000000`;池由 `[slot-user/app/command/Uuid.php](slot-user/app/command/Uuid.php)` 载入。
- 需求:首个发放 uid = `1257832`,后续按发号规则递增、保持唯一。
- 实现方案(文档给出建议,标注需研发确认):将发号改为以 `1257832` 为基准的顺序自增计数(如新增 `USER_UUID_BASE` 常量 + incr 计数 key或重建 `uuid.txt`/池基准使首个映射值落在 1257832二选一避免与现有洗牌池产生小于基准的 uid。
- 影响与校验:`player_number = uid` 自动满足点 3/4新环境从 1257832 起,已上线环境只对增量生效(写明灰度/存量说明)。
- 点 10 launch_url 提前返回:
- 接口 `GET /slot-console/api/onboarding/recommend-game``game` 节点新增字段 `launch_url`
- 后端:`OnboardingRecommendLogic::buildRecommendPayload()` 选中游戏后,复用现有 launch 链路(`[slot-console/app/api/logic/GameLogic.php](slot-console/app/api/logic/GameLogic.php)``SlotPlatformService::launch($uid,$game_code,$ip)` → pwa预取 `url` 填入 `game.launch_url`;失败降级为 `launch_url=""` 不阻断弹窗。
- 前端:`OnboardingGamePopup.vue` 进入游戏时,若 `game.launch_url` 非空则直接写 game store 跳转(跳过再次 `/api/game/launch`),为空时回退现有 `launchByCode(game_code)`
- 注意点launch 走 pwa Session 链路(`[slot-pwa/.../GameLaunchSessionLogic.php](slot-pwa/app/api/logic/GameLaunchSessionLogic.php)` 有短窗口 dedup预取与点击进入复用同一 session文档说明幂等/有效期与不阻断注册首页的降级。
- 返回示例(含 `launch_url`)、字段说明表、异常与降级表、测试用例、与已实现代码对照表。
### 2. 更新父文档 `docs/requirements/register_popup_game_entry.md`
- §6.1 console 返回示例与字段说明:`game` 增加 `launch_url` 字段。
- §8.2 点击行为:补充「优先使用预取 launch_url」。
- 新增小节或在 §1.3 In Scope 标注uid 发号起始值 = 1257832指向 04
- 文首子需求索引行追加 04 链接,版本号自增(如 V1.5,附变更说明)。
### 3. 更新 `docs/requirements/register_popup_game_entry/README.md`
- 子需求列表新增 04 行lobby 大厅欢迎弹窗 + uid 起始值 + launch_url 预取)。
- 「与已实现代码对照」表追加弹窗组件已落地、uid 起始值待做、launch_url 预取待做。
## 不在本次范围
- 不实际改 PHP/Vue 代码(本次只交付需求文档)。
- 不改 center 渠道配置与 admin 后台(见 01/02
- Trial Balance 发放仍属父活动(钱包)。

View File

@@ -0,0 +1,285 @@
---
name: Lucky Reward 双弹窗分析
overview: 被邀请人 Support Invite 应从 HomeEvent 迁到 lucky_reward_invite_bind 成功时 WS 即时推送只弹一次HomeEvent 仅保留邀请人 Claim Nowpending_spin_count可重复补弹。这样同一 uid 在 HomeEvent 不再同时命中两种 Lucky Rewards 弹窗。
todos:
- id: diagnose-no-helper
content: 按日志/SQL 排查 invite_bind 全链路,定位 helper 未落库的具体 status/reason
status: pending
- id: move-support-invite-to-bind
content: invite_bind success 后ensureInviteeAutoOpenBox + buildSupportInvitePopup + WsService::notifyClientPOPHomeEvent 移除被邀请人逻辑
status: pending
- id: update-tests-docs-yapi
content: 更新集成测、05 方案文档、YApi #109 WS 弹窗示例Claim Now 仍走 HomeEvent
status: pending
- id: confirm-product-rule
content: 确认产品规则:双角色用户允许两种弹窗,还是同一 flush 只保留一种(及优先级)
status: cancelled
- id: implement-mutex-if-needed
content: 若需互斥:在 LuckyRewardInviteLogic 抽 resolveHomePopupsHomeEvent 只 merge 一种;补互邀集成测
status: cancelled
- id: support-invite-once
content: (可选)若 Support Invite 应只弹一次:增加 consume/已读状态,与互斥分开评估
status: cancelled
isProject: false
---
# Lucky Rewards 同一人两种弹窗 — 根因与可选改法
## 现象对应代码
[`HomeEvent::appendLuckyRewardHomePopups`](slot_console/app/command/event/HomeEvent.php) 对**同一个** `$uid` 顺序做两件事,**互不排斥**
```437:455:slot_console/app/command/event/HomeEvent.php
protected function appendLuckyRewardHomePopups(array &$popList, int $uid, UserInfoEntity $userInfoEntity): void
{
// ...
$inviteLogic->ensureInviteeAutoOpenBox($uid, $source);
$supportInvitePop = $inviteLogic->buildSupportInvitePopup($uid, $source);
if ($supportInvitePop !== false) {
$luckyRewardPopups[] = $supportInvitePop;
}
$inviterClaimNowPop = $inviteLogic->buildInviterClaimNowPopup($uid, $source);
if ($inviterClaimNowPop !== null) {
$luckyRewardPopups[] = $inviterClaimNowPop->toHomePopListItem();
}
$popList = array_merge($luckyRewardPopups, $popList);
}
```
两种弹窗判定维度不同:
| 弹窗 | type | 判定方法 | 核心条件(同一 uid |
| --- | --- | --- | --- |
| Support Invite | `lucky_reward_support_invite` | [`buildSupportInvitePopup`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) | `lucky_reward_helper` 存在 **invitee_uid = uid** 且 **已开箱** |
| Claim Now | `lucky_reward_invite_success` | [`buildInviterClaimNowPopup`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) | `pending_spin_count > 0` 且存在 **未领的 GRANT_TYPE_INVITER grant** |
需求文档 [`05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) 表格里写的是「邀请人 / 被邀请人」两种**角色**,但代码**没有**写「同一 uid 只能占一种角色」。
```mermaid
flowchart TD
homeFlush["HomeEvent flush uid=X"]
openBox["ensureInviteeAutoOpenBox(X)"]
checkInvitee["buildSupportInvitePopup(X)\nhelper.invitee_uid=X ?"]
checkInviter["buildInviterClaimNowPopup(X)\npending_spin_count>0 ?"]
popSupport["lucky_reward_support_invite"]
popClaim["lucky_reward_invite_success"]
merge["array_merge 两种都进 popList"]
homeFlush --> openBox --> checkInvitee
checkInvitee -->|是| popSupport
checkInvitee -->|否| checkInviter
popSupport --> checkInviter
checkInviter -->|是| popClaim
popClaim --> merge
checkInviter -->|否| merge
```
## 为什么「一个人」会同时有两种?
**正常单链邀请A 邀 B不会出现**A 只有 Claim NowB 只有 Support Invite见 [`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php))。
**同一 uid 双角色时会出现**,典型场景:
1. **互邀 / 双链**A 邀 BB 也邀 A同一 `cycle_id`,均新注册有效助力)
- A`helper(invitee=A)` → Support Invite`pending_spin_count>0` → Claim Now
- B同理
2. **先被邀、后又成功邀别人**:用户 C 邀了 AA 为被邀请人);之后 A 又邀了 DA 为邀请人且未 claim→ 回大厅两种都满足
3. **邀请人未 claim 的重复提醒 + 被邀请身份长期有效**Claim Now 在 `pending_spin_count>0` 期间**每次回大厅都弹**Support Invite 在 helper 存在且已开箱后**每次回大厅都弹**(无 consume/已读标记)→ 双角色用户会**持续**收到两个 pop
`ensurePlayerRow` 会在 invite_bind 时为**邀请人**创建 player 行(不必先开箱),因此「邀请人侧 Claim Now」与「被邀请人侧 Support Invite」在数据上可以并存。
## 这不是 invite_bind 写错
[`persistInviteHelperInTransaction`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 只给**邀请人**写 grant + `pending_spin_count`;被邀请人**不再**写 invitee grant测试也断言 `invite_invitee:` grant 为 null。双弹窗来自 **HomeEvent 合并逻辑**,不是一次回调写了两种状态。
## 若产品期望「同一时刻只弹一种」
~~需产品定优先级,再在 HomeEvent 加互斥~~ **已按产品意见调整方案**:被邀请人弹窗**不再走 HomeEvent**,见下文 §「被邀请人弹窗迁出 HomeEvent」HomeEvent 只留邀请人 Claim Now从架构上消除「同一人两种 Lucky Rewards 弹窗」。
---
# 被邀请人 Support Invite 迁出 HomeEvent产品定案
## 背景
- **被邀请人**IMEI 进游戏即注册,`invite_bind` 发生时用户**在线**Support Invite **只弹一次**,不存在「离线补弹」。
- **邀请人**:可能正在玩游戏/离线Claim Now 须 **`pending_spin_count` + 每次回大厅重复弹**,继续走 HomeEvent。
当前实现把两者都塞进 [`appendLuckyRewardHomePopups`](slot_console/app/command/event/HomeEvent.php),导致:
- 被邀请人**每次回大厅重复弹** Support Invite无 consume
- 双角色用户同一 flush 可能同时出现两种 type
## 目标架构
```mermaid
sequenceDiagram
participant Agent as agent_invite_bind
participant ConsoleBus as console_bus
participant Logic as LuckyRewardInviteLogic
participant WS as WsService_notifyClientPOP
participant Home as HomeEvent
Agent->>ConsoleBus: lucky_reward_invite_bind
ConsoleBus->>Logic: handleInviteBind success
Logic->>Logic: ensureInviteeAutoOpenBox(invitee)
Logic->>Logic: buildSupportInvitePopup(invitee)
Logic->>WS: 即时推送 invitee 仅一次
Note over Home: 邀请人路径不变
Home->>Logic: buildInviterClaimNowPopup(inviter)
Home->>WS: home flush popList
```
| 弹窗 | 触发点 | 下发方式 | 重复策略 |
| --- | --- | --- | --- |
| Support Invite | `lucky_reward_invite_bind` → `status=success` 后 | `WsService::notifyClientPOP(inviteeUid, [...])` | **一次**bind 幂等保证不重复推) |
| Claim Now | HomeEvent flush | 合并进 `popList` | **未 claim 前每次回大厅** |
## 代码改动要点
### 1. [`EventBus::luckyRewardInviteBindEvent`](slot_console/app/command/EventBus.php)
`handleInviteBind` 返回 `success` 后新增(建议封装为 `LuckyRewardInviteLogic::pushInviteeSupportInvitePopup()`
1. `ensureInviteeAutoOpenBox($inviteeUid, $source)` — 从 HomeEvent **挪到这里**(弹窗需要 `my_amount`
2. `buildSupportInvitePopup($inviteeUid, $source)`
3. 非 false 则 `WsService::notifyClientPOP($inviteeUid, [$popup])`
`already_processed` / 各类 `skipped_*` **不推送**。
### 2. [`HomeEvent::appendLuckyRewardHomePopups`](slot_console/app/command/event/HomeEvent.php)
**删除**
- `ensureInviteeAutoOpenBox`
- `buildSupportInvitePopup` 及 merge
**保留**
- `buildInviterClaimNowPopup` → Claim Now
方法可重命名为 `appendInviterClaimNowPopup` 或保持原名但注释只服务邀请人。
### 3. 测试
- [`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php)`testEnsureInviteeAutoOpenBoxAndSupportInvitePopup` 改为断言 bind 成功路径mock/spy `WsService` 或抽 `pushInviteeSupportInvitePopup` 返回值)
- 新增bind 幂等第二次不推 WS
- HomeEvent 单测:被邀请人 uid flush **不应**再含 `lucky_reward_support_invite`
### 4. 文档
- [`05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §5 表格拆分触发点
- YApi #109 WS popup 示例补 Support Invite 即时推送说明
## 边界说明
| 点 | 处理 |
| --- | --- |
| MQ 消费略晚于注册完成 | 产品认定被邀请人在线;仍走 WS 即时推。若 hub 未连上,**不做 HomeEvent 补弹**(与「只弹一次、无离线」一致) |
| 游戏内禁弹 | bind 发生在注册链路,通常不在 `enter_game`;若需硬约束可后续加 hub 侧 scene 判断 |
| openBox 失败 | 记录 error不推 Support Invite无 my_amount |
| 双角色用户 | HomeEvent 仅可能出 Claim NowSupport Invite 仅在作为被邀请人 bind 当时推一次 |
## 与「没有 helper」排查的关系
Support Invite 迁出 **不解决** helper 未落库;须先保证 `handleInviteBind` → `success` 写 helper再在 success 分支推 WS。
---
# 「没有助力」DB 无 lucky_reward_helper— 排查结论
> 你已确认:**不是弹窗问题**,而是 `lucky_reward_helper` 没有新记录 / `valid_invite_count` 不涨。
## 有效助力必须满足的链路
```mermaid
sequenceDiagram
participant User as slot_user注册
participant AgentMQ as agent_bus
participant Agent as slot_agent_EventBus
participant Gateway as LuckyRewardInviteCallbackGateway
participant ConsoleMQ as console_bus
participant Console as slot_console_EventBus
participant Logic as handleInviteBind
User->>AgentMQ: TYPE_INVITE_BIND\nshare_origin=wheel\nis_new_register=1
Agent->>Agent: ref_invite_relation 新建?
Agent->>Gateway: 仅 isNewInviteRelation=true 时调用
Gateway->>Gateway: lucky_reward_callback_enabled\nshare_origin=wheel
Gateway->>ConsoleMQ: TYPE_LUCKY_REWARD_INVITE_BIND
Console->>Logic: handleInviteBind
Logic->>Logic: 无 skip 则写 helper + inviter grant
```
**任意一环失败 → DB 无 helper。**
## 按概率排序的常见原因
### 1. 用了 Agent 中心短码,不是转盘 wheel 短码(最常见误用)
- **agent 网关硬过滤**[`LuckyRewardInviteCallbackGatewayService`](slot_agent/app/service/LuckyRewardInviteCallbackGatewayService.php) 仅 `share_origin=wheel` 才投递 console_bus`user_agent` → `reason=skipped_not_wheel_origin`**console 根本收不到消息**。
- **console 侧也会再拦**[`resolveInviteBindSkipResult`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) `share_origin !== wheel` → `skipped_not_wheel`。
- **正确链接**:须来自 `GET /api/lucky-reward/invite-link` 或 `Gift/createShareUrl from=wheel`(绑定当前 `lucky_reward_cycle` 的 `share_url.origin=wheel`)。
### 2. wheel 短码已过期(「以前有,现在没有」高概率)
- 轮次轮转后,旧短码 `share_url.biz_id` 指向**已结束 cycle**,与当前 active cycle 不一致 → console 返回 [`STATUS_SKIPPED_EXPIRED_CYCLE`](slot_console/app/entity/luckyReward/InviteBindResultEntity.php)**不写 helper**(见集成测 `testHandleInviteBindSkipsWhenShareCycleMismatchActiveCycle`)。
- **处理**:邀请人重新拉 `invite-link`,用**本轮**短码测。
### 3. 被邀请人不是「本次新注册」
- console 要求 `is_new_register=1`;老 IMEI 登录 / 手动绑码 → `is_new_register=0` → `skipped_old_user`。
- IMEI 路径:仅 [`ImeiRegisterService::run`](slot_user/app/service/register/ImeiRegisterService.php) **新建账号**时 `notifyAgentInviteBind`;已存在 IMEI 走 login**不发 invite_bind**。
- 手动绑码 [`UserController`](slot_user/app/innerapi/controller/UserController.php) 固定 `is_new_register=0`,且返回体**未带** `share_origin`MQ 里为空)→ agent 网关 wheel 过滤失败。
### 4. 活动未开启或无 active cycle
- 种子数据默认 [`lucky_reward_config.status=2`(关闭)](backend/slot_admin/db/lucky_reward.sql)。
- console `resolveInviteBindProcessContext` 活动关闭 → `activity_closed`。
- 弹窗/开宝箱也依赖开启配置,与 helper 同源。
### 5. agent 仅「首次 ref_invite_relation」才回调 console
[`slot_agent EventBus::inviteBindEvent`](slot_agent/app/command/EventBus.php)
```php
if ($isNewInviteRelation) {
LuckyRewardInviteCallbackGatewayService::...->notifyFromInviteBindEntity($entity);
}
```
若该 `invitee_uid` 在 `ref_invite_relation` **已有行**(历史任何来源绑过),**不会再投递** `lucky_reward_invite_bind`,即使本次 MQ 仍处理 agent 奖励。
### 6. MQ / 开关 / 进程
| 检查项 | 位置 |
| --- | --- |
| `lucky_reward_callback_enabled=1` | center → agent |
| `php webman event:bus` 消费 agent_bus | slot_agent |
| `php webman event:bus` 消费 console_bus | slot_console |
| agent 日志 `luckyRewardCallback` | `dispatched` / `reason` |
| console 日志 `luckyRewardInviteBindEvent` | `status` 字段 |
## 建议排查步骤(按顺序执行)
1. **复现一次邀请注册**,记录:邀请短码、`share_url.origin`、`share_url.biz_id`、当前 `lucky_reward_cycle.id`。
2. **查 agent 日志** `inviteBindEvent` + `luckyRewardCallback`
- 无 `luckyRewardCallback` → 看 `isNewInviteRelation` 或 MQ 未进 agent。
- `reason=skipped_not_wheel_origin` → 短码/来源不对。
- `reason=callback_disabled` → center 开关。
3. **查 console 日志** `EventBus::luckyRewardInviteBindEvent` 的 `status`
- 无日志 → console_bus 未消费或 agent 未投递。
- `skipped_expired_cycle` / `skipped_old_user` / `activity_closed` / `skipped_not_wheel` → 对号入座。
4. **SQL 验证**(替换 uid/cycle
- `SELECT * FROM lucky_reward_helper WHERE invitee_uid=? ORDER BY id DESC LIMIT 5;`
- `SELECT * FROM ref_invite_relation WHERE invitee_uid=?;`
- `SELECT id,status,cycle_no,end_at FROM lucky_reward_cycle WHERE source='default' ORDER BY id DESC LIMIT 3;`
- `SELECT short_code,origin,biz_type,biz_id FROM share_url WHERE short_code='?';`
## 若日志 status=success 仍无 helper
才考虑事务异常/库连接错误(少见);查 console `LuckyReward inviteBind failed` error 日志。
## 与弹窗问题的关系
helper **未落库**时:`valid_invite_count` 不涨、Record/helpers 为空、Claim Now / Support Invite **都不会出现**(弹窗是 helper/grant 的下游展示)。应先修 invite_bind 链路,再谈弹窗互斥。

View File

@@ -0,0 +1,212 @@
---
name: Lucky Reward 奖池迁移
overview: 采用全平台统一的 reward_pool / reward_pool_item以 pool_code = lucky_reward 承载大转盘手动 Spin 奖项;外层仅 prize_type 表达类型lucky_reward 业务参数(含 unlockInviteCount一律进 config逐步替换 lucky_reward_prize_config。
todos:
- id: ddl-seed
content: s_common 建 reward_pool / reward_pool_item含 prize_type 外层字段seed pool_code=lucky_reward编写从 lucky_reward_prize_config 的迁移脚本
status: completed
- id: console-draw
content: slot_consoleRewardPoolItemModel + ConfigService/DrawService/LuckyRewardLogic 改读 lucky_reward 奖池Draw 读 prize_type 列
status: completed
- id: admin-crud
content: slot_admin替换 LuckyRewardPrizeConfig CRUD 为 lucky_reward 奖池项管理,更新菜单权限
status: completed
- id: test-docs-cleanup
content: 单测/集成测、需求文档更新、删除旧 Model 与 lucky_reward_prize_config 表
status: completed
isProject: false
---
# Lucky Reward 奖池方案评估与迁移计划
## 结论:`pool_code = lucky_reward` 可行,推荐做
**方向正确**:把「可复用奖池」与「活动专用抽奖/入账」拆开,比继续扩 [`lucky_reward_prize_config`](docs/requirements/lucky_rewards/02_管理后台方案.md) 更适合后续其它活动复用同一套表结构。
**与你已确认的前提对齐**
- 全平台 **一个** 奖池:`pool_code = 'lucky_reward'`
- **替换** 现有 [`lucky_reward_prize_config`](slot_console/app/model/common/LuckyRewardPrizeConfigModel.php)(非并存长期双写)
- **外层仅 `prize_type` 表达奖项类型**lucky_reward 业务参数(含开放条件)**一律进 `config`**,避免个别字段外置导致表结构膨胀
```mermaid
flowchart LR
subgraph admin [slot_admin]
PoolCRUD[RewardPoolItem CRUD]
end
subgraph db [s_common]
RP[reward_pool pool_code=lucky_reward]
RPI["reward_pool_item prize_type + config"]
end
subgraph console [slot_console]
Draw[LuckyRewardDrawService]
Spin[LuckyRewardLogic.executeManualSpin]
end
PoolCRUD --> RPI
RP --> RPI
RPI --> Draw
Draw --> Spin
```
---
## 核心设计:`prize_type` 外层 + 业务参数全进 `config`
**字段分层原则**
| 层级 | 字段 | 说明 |
| --- | --- | --- |
| 表通用列 | `pool_id``pool_code``item_code``item_name``prize_type``weight``display_text``icon_url``status``sort` | 奖池项元数据,各 pool 共用 |
| `config` JSON | lucky_reward 及后续各 pool 的**业务参数** | 含开放条件、金额区间等;**禁止**再拆个别业务字段到表列 |
| 禁止 | 表列 `unlock_invite_count` 等 lucky_reward 专用字段 | 与「通用奖池表 + pool 级 config 约定」冲突 |
### 1. 表字段调整(相对你初版 DDL
原 DDL 中的 `reward_type` **改为 `prize_type`**TINYINT奖项命中语义。不同 `pool_code` 可约定不同枚举;`lucky_reward` 池定义如下:
| prize_type | 含义 | 抽奖 | 入账行为(与现网一致) |
| --- | --- | --- | --- |
| 1 | 随机金额 | 参与权重 | My Amount 增加(封顶至 target |
| 2 | 1x Spin | 参与权重 | spin_available +1 |
| 3 | Cash Out | 参与权重 | playerStatus → 可提取 |
| 4 | Jackpot 展示 | **不参与**weight=0 或 Draw 过滤) | 无入账,仅转盘 UI 展示 |
常量命名沿用现有 [`LuckyRewardPrizeConfigModel::PRIZE_TYPE_*`](slot_console/app/model/common/LuckyRewardPrizeConfigModel.php),迁移到 `RewardPoolItemModel`(或共用常量类),保证 [`lucky_reward_spin_record.prize_type`](docs/requirements/lucky_rewards/02_管理后台方案.md) 与 [`DrawResultEntity::prizeType`](slot_console/app/entity/luckyReward/DrawResultEntity.php) **数值不变**
### 2. `lucky_reward` 池 `config` 结构SSOT
**禁止** config 内写 `prizeType`(类型只看外层列)。按 `prize_type` 校验必填/可选字段admin Validate + 文档):
**各类型共有可选字段**(参与抽奖的类型 1/2/3 常用):
| config 字段 | 说明 |
| --- | --- |
| `unlockInviteCount` | 开放命中所需有效邀请人数,默认 0无需 |
**各类型专有字段**
| prize_type | 专有 config 字段 | 说明 |
| --- | --- | --- |
| 1 随机金额 | `amountMinQf`, `amountMaxQf` | 千分位区间min ≤ max |
| 2 1x Spin | — | 可无专有字段 |
| 3 Cash Out | — | 可无专有字段;开放条件用 `unlockInviteCount` |
| 4 Jackpot | `displayAmountQf` | 展示用金额(千分位) |
示例:
```json
// prize_type = 1需 3 个有效邀请后才开放
{ "unlockInviteCount": 3, "amountMinQf": 100, "amountMaxQf": 500 }
// prize_type = 3Cash Out 需 5 个邀请
{ "unlockInviteCount": 5 }
// prize_type = 4
{ "displayAmountQf": 6666000 }
```
### 3. 外层列(不进 config
仅保留奖池项**通用**列,不含 lucky_reward 业务参数:
| 字段 | 说明 |
| --- | --- |
| `weight` | 抽取权重 |
| `display_text` / `icon_url` / `sort` | 前端展示与排序 |
`reward_pool_item` 建议 DDL 片段(相对初版变更点):
```sql
`prize_type` TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '奖项类型lucky_reward池见 PRIZE_TYPE_* 常量',
`config` JSON NOT NULL COMMENT 'pool 业务参数lucky_reward见文档 SSOT',
-- 删除 reward_type不新增 unlock_invite_count 等 pool 专用列
```
### 4. 全平台单池
所有 source 共用 `pool_code = lucky_reward` 一套转盘格子和权重;[`LuckyRewardConfigService::listEnabledPrizeConfigs($configId)`](slot_console/app/service/luckyReward/LuckyRewardConfigService.php) 改为按 `pool_code` 加载,**不再依赖** `lucky_reward_config.id`
活动 per-source 配置(开关、周期、分层开宝箱、目标金额)不变。
### 5. DDL 其它细节
| 项 | 建议 |
| --- | --- |
| 主键 | 确认 ID 策略:若无雪花发号,补 AUTO_INCREMENT |
| 时间字段 | Model 层映射 `created_at`/`updated_at` |
| 库 | **s_common** |
| 索引 | item 表增加 `KEY idx_pool_code_status (pool_code, status)``KEY idx_prize_type (prize_type)` |
### 6. 常量约定
```php
/** Lucky Rewards 大转盘手动 Spin 奖池编码 */
public const POOL_CODE_LUCKY_REWARD = 'lucky_reward';
```
`prize_type` 常量(中文注释必填)与现网 1/2/3/4 对齐。
---
## 迁移与实现步骤
### Phase 1 — 表结构与数据迁移
1.`s_common` 执行 `reward_pool``reward_pool_item` DDL`prize_type` + `config`,无 `reward_type`、无 `unlock_invite_count` 列)
2. Seed`pool_code = lucky_reward``pool_name = Lucky Rewards Wheel``status = 1`
3. 迁移 `lucky_reward_prize_config``reward_pool_item`
- `prize_type` ← 旧 `prize_type`(直迁)
- `weight``sort``status` 直迁
- `config`:写入 `unlockInviteCount`(← 旧 `unlock_invite_count`+ 类型专有字段amountMinQf/MaxQf 或 displayAmountQf
- `item_code`:建议 `lr_prize_{old_id}`
4. 验证通过后 drop 旧表(或先 rename `_bak`
### Phase 2 — slot_console 读新池抽奖
| 文件 | 变更 |
| --- | --- |
| 新建 `RewardPoolModel` / `RewardPoolItemModel` | `listEnabledByPoolCode()` |
| [`LuckyRewardConfigService`](slot_console/app/service/luckyReward/LuckyRewardConfigService.php) | `listLuckyRewardPoolItems()`,固定 `POOL_CODE_LUCKY_REWARD` |
| [`LuckyRewardDrawService`](slot_console/app/service/luckyReward/LuckyRewardDrawService.php) | 读列 `prize_type`;过滤读 `config.unlockInviteCount`(缺省 0随机金额读 `config.amountMinQf/MaxQf`Jackpot(4) 仍排除 |
| [`DrawResultEntity`](slot_console/app/entity/luckyReward/DrawResultEntity.php) | 增加 `poolItemId``prizeType` 来自 item 的 `prize_type` 列 |
| [`LuckyRewardLogic::executeManualSpin`](slot_console/app/api/logic/LuckyRewardLogic.php) | 切换数据源spin_record.prize_type 仍写 Draw 结果 |
**行为不变**:随机封顶、+1 Spin、Cash Out 改状态、spin_record 写入。
### Phase 3 — slot_admin 后台替换 CRUD
| 现状 | 目标 |
| --- | --- |
| [`LuckyRewardPrizeConfigController`](backend/slot_admin/app/game/controller/LuckyRewardPrizeConfigController.php) 等 | Lucky Reward 奖池项管理scoped `pool_code=lucky_reward` |
| Validate | 校验外层 `prize_type`、按类型校验 config`unlockInviteCount`、金额区间)、权重 |
| [`menu-lucky-rewards.sql`](backend/slot_admin/db/menu-lucky-rewards.sql) | 路由指向新 Controller |
表单:美元展示 → 写入 config 内 `_qf``unlockInviteCount` 表单项写入 config`prize_type` 下拉与现网四类一致。
### Phase 4 — 文档、测试、清理
- 更新 [`02_管理后台方案.md`](docs/requirements/lucky_rewards/02_管理后台方案.md)`reward_pool_item.prize_type` 枚举 + config 结构 SSOT
- 更新 [`LuckyRewardDrawServiceTest`](slot_console/tests/Unit/LuckyRewardDrawServiceTest.php) fixturepool item 含 `prize_type` 列 + 精简 config
- 删除 `LuckyRewardPrizeConfigModel` 及旧表引用
---
## 风险与规避
| 风险 | 规避 |
| --- | --- |
| 运营迁移窗口改旧表 | 迁移前冻结编辑;脚本完成后立即切读新表 |
| Jackpot 无 C 端拉取 | 后台仍配 prize_type=4后续如需动态转盘再补接口 |
| 其它 pool_code 的 prize_type 语义冲突 | 按 pool 文档约定枚举;通用表结构复用,语义由 pool_code + 文档定义 |
| config 误写 prizeType | Validate 拒绝;迁移脚本不写入 prizeType |
| 业务字段外置导致表膨胀 | 约定:除 `prize_type` 外 lucky_reward 参数一律 config其它 pool 同理 |
---
## 总体评价
- **赞成** `pool_code = lucky_reward` 作为大转盘唯一奖池编码。
- **采纳**:类型语义 **外层 `prize_type`****`unlockInviteCount` 等业务参数进 config**,与通用奖池表设计一致。
- 其它活动复用 `reward_pool_item` 时,同一 `prize_type` 数值在不同 pool 可代表不同含义,需在各自 pool 文档中定义lucky_reward 池先用 1/2/3/4 四态)。
确认本计划后,按 Phase 1→4 落地。

View File

@@ -0,0 +1,60 @@
<!-- 3c4f5bff-252e-46d9-942c-7d9b3f38c0c4 -->
---
todos:
- id: "hash-code"
content: "§5/§6.5account_hash 前缀与示例改用 codeusdt/paypal/cashapp保留 USDT 地址不转小写"
status: pending
- id: "schema"
content: "§7.1/§7.2/§7.3method_type 改 VARCHAR(32)=payment_method.code枚举表改编码表+payment_method 依赖说明"
status: pending
- id: "api"
content: "§8.1/§8.2/§8.4/§9列表/新增/提现使用/快照里的 method_type 改 code 值method_name 取自 payment_method.name"
status: pending
- id: "validate-summary"
content: "§12/§18/§20校验改为引用 payment_method 启用且支持提现的 code汇总条目更新"
status: pending
- id: "payment-method-dep"
content: "新增「与 payment_method 关系」说明:新增 paypal/cashapp 行、加提现方向字段、充值 all() 过滤;并写明下单 code→pay_type(usdt=3/paypal=6/cashapp=1)+pay_net 映射归属订单模块"
status: pending
isProject: false
---
# method_type 对齐 PaymentMethodModel.code
仅改需求文档 [用户提现账户管理需求文档.md](slot-pay/docs/requirements/用户提现账户管理需求文档.md);同时把对 `payment_method` 表与提现订单映射的依赖写进文档(实际建表/代码后续单独实现)。
## 核心决策
- 账户表方式字段对齐 `PaymentMethodModel.code``usdt` / `paypal` / `cashapp`(字符串)。
- 字段类型 `TINYINT``VARCHAR(32)`;字段名保留 `method_type`(存 code 值),文档注明「= payment_method.code」如需更直观可改名 `method_code`,作为可选项注明)。
- `method_name``payment_method.name` 提供,删除「按整数枚举硬编码映射」。
- `account_hash` 前缀改用 code`sha256("usdt|USDT|TRC20|address")``sha256("paypal|email小写")``sha256("cashapp|cashtag小写")`
## payment_method 前置依赖(写入文档「服务边界/与 payment_method 关系」)
- 现状:`payment_method.code` 仅 usdt/bank/alipay无 paypal/cashapp无方向字段`PaymentMethodModel::all()`[CashierController.php](slot-pay/app/innerapi/controller/CashierController.php) L101给**充值**收银台用。
- 需新增 `paypal``cashapp` 两行status=1
- 需增加「方向/场景」字段(如 `scene` 位标记或 `support_recharge`/`support_withdraw`),区分充值/提现方式。
- 充值侧 `PaymentMethodModel::all()` 须过滤为充值方式,避免 paypal/cashapp 泄漏到充值收银台;提现方式列表用「按提现方向过滤」的查询(前端「选择提现方式」据此渲染)。
## 下单映射(保留并明确,写入 §6.6/§8.4
- PayService 用**整数 pay_type** 路由 SDK[PayService.php](slot-pay/app/service/PayService.php) L86 + [config/pay.php](slot-pay/config/pay.php) `withdrawalTypes`usdt=3、paypal=6、cashapp=1
- 账户表只存 code**提现订单模块**创建订单时把 `method_type(code) → pay_type 整数 + pay_net(网络)` 映射后再调 PayService。文档明确该映射归属订单模块。
## 文档改动点(逐节)
- §5 字段设计hash 前缀示例改 code。
- §6.5 防重复:`sha256(method_type + "|" + key)` 用 code示例与大小写规则保持USDT address 不转小写)。
- §7.1 建表 SQL`method_type VARCHAR(32)` 注释「= payment_method.code取值 usdt/paypal/cashapp」索引保持 `(uid, method_type)``(uid, method_type, account_hash)`
- §7.2 字段说明method_type 改为 code 字符串说明。
- §7.3 枚举:整数枚举表 → 「提现方式编码(引用 payment_method.code」usdt/paypal/cashapp + payment_method 依赖说明。
- §8.1 列表:请求/响应 `method_type` 改 code 值,`method_name` 注明来自 payment_method.name。
- §8.2 新增:三种请求体 `method_type``"usdt"/"paypal"/"cashapp"`;后端生成 hash 用 code。
- §8.4 提现使用:读取 method_type(code),补 code→pay_type 映射归属订单模块。
- §9 快照:`method_type` 改 code 值,保留 method_name。
- §12 校验method_type 必须是「payment_method 中启用且支持提现的 code」。
- §18 关系 / §20 汇总:第 10 条「名称由 method_type 映射」改「由 payment_method.name 提供」;补 code 对齐与 code→pay_type 映射两条规则。
## 不改动
- 删除/状态(status=3)、单活跃账户、每方式最多 10、软件层唯一校验、仅 USDT 脱敏、amount×1000、uid 来源等既有决策保持不变。

View File

@@ -0,0 +1,119 @@
<!-- 215d598c-9837-4e65-a3e9-850d78cd5f00 -->
## 月返水Monthly Cashback实现方案
与周返水完全同构,仅「周」改「月」。需求见 [月返水.md](slot_console/doc/月返水.md);结构镜像 [DailyRebateLogic.php](slot_console/app/api/logic/DailyRebateLogic.php) 与周返水两份计划(核心 + 统计)。
### 需要改动的服务
- slot_lib常量。
- slot_console表 / 模型 / 服务 / Logic / Controller / Validator / 命令 / 路由 / 活动配置入口 / 部署文档。
- backend/slot_admin+ vue后台「每月返水统计」页。
- slot_wallet仅确认流水类型 69 打码归【活动赠送 Y3】。
- slot_pwa无需改动复用 `rebate_bet`)。
### 周期与口径(与周返水差异)
- 统计月:每月 1 日 00:00:00 ~ 月末 23:59:59服务器时区。
- `month_start = date('Y-m-01')`;上月 = `first day of last month`;上上月 = `first day of 2 months ago`;过期时间 = 下月 1 日。
- 月有效投注 = 当月每日 `rebate_bet` 之和(仅充值用户,沿用 pwa 现有口径)。
- VIP 取月末最后一刻(结算下月 1 日读当前 VIP`floor` 取整到厘。
### 数据流
```mermaid
flowchart TD
pwa["slot_pwa 已累加 rebate_bet"] --> redis["redis user:profit:Ymd TTL7天"]
accrue["monthlyRebateAccrue 每天00:05 处理昨日"] --> redis
accrue --> rec["monthly_rebate_record 当月Pending bet累加 + vip/rate快照"]
settle["monthlyRebateSettle 每月1日00:15"] --> rec
settle --> vip["读当前VIP rate=vip_rates level"]
settle --> expirePrev["上上月 Claimable -> Expired"]
claim["C端 claim 上月"] --> wallet["WalletService gift 类型69 打码Y3"]
admin["后台 每月返水统计"] --> rec
```
### 落库方案 B幂等
- `monthly_rebate_record``last_accrued_date`date
- `monthlyRebateAccrue`(每天)处理**昨日**key 仅 1 天,在 TTL 内):遍历昨日 profit 哈希,充值用户且 `rebate_bet>0` → 定位昨日所属月记录(无则建 Pending→ 若 `last_accrued_date < 昨日``bet_amount += rebate_bet` 且更新 `last_accrued_date`;同时写入当前 `vip_level`/`rate_snapshot`(供后台对待定行展示费率)。
- C 端 This Month = `record.bet_amount` + 今日 redis 实时 `rebate_bet`
### 结算/过期(每月 1 日)
- `monthlyRebateSettle`:上月 Pending → 读当前 VIP → `rebate=floor(bet*rate/100)``rebate>0` 置 Claimable`claimable_at=本月1日``expire_at=下月1日`;同次将上上月 `Claimable 且 expire_at<=now` 置 Expired。
- `monthlyRebateExpire`:兜底,`Claimable 且 expire_at<=now -> Expired`
- 顺序accrue 先于 settle。
### 复用 vs 新建(计费 = VIP 费率单乘,不复用 tiers
- 复用骨架:领取短事务 CAS + 钱包入账失败回滚 + 结算结构化日志 + `RechargedUidSetService`/`UserProfitEntity`/四态 + `statusLabel`/Controller/Validator 形态。
- 新建:`MonthlyRebateCalcService::calcRebateLi(betLi, ratePercent)=floor(betLi*ratePercent/100)``MonthlyRebateConfigService`(解析 `vip_rates`/`maxRate`/`rateForVip`/`canonicalExtConfigForStorage`)。
### 文件清单
slot_lib
- [Consts.php](slot_lib/src/common/const/Consts.php)`ACTIVITY_TYPE_MONTHLY_REBATE=14``TRANSACTION_TYPE_MONTHLY_REBATE=69`(若周返水未先上,取下一空位即可)。
slot_console
- 模型 `app/model/common/MonthlyRebateRecordModel.php`(四态 + `findByUidAndMonth`)。
- [RechargeGiftConfigModel.php](slot_console/app/model/common/RechargeGiftConfigModel.php)`TYPE_MONTHLY_REBATE=14` + `getMonthlyRebateActiveInfo/...ByExactSource`(镜像每日返水方法)。
- 服务 `app/service/MonthlyRebateCalcService.php``app/service/MonthlyRebateConfigService.php`
- Logic `app/api/logic/MonthlyRebateLogic.php`info/claim/accrue/settle/expire
- Controller `app/api/controller/MonthlyRebateController.php`、Validator `app/api/validator/MonthlyRebateValidator.php`claim 场景,可选 month_start
- 命令 `app/command/MonthlyRebateAccrue.php``MonthlyRebateSettle.php``MonthlyRebateExpire.php`
- 路由:注册 monthly-rebate info/claim。
- SQL `db/monthly_rebate.sql`(含 `month_start date``last_accrued_date`、唯一键 `uniq_uid_month``vip_level``rate_snapshot`)。
- 活动配置入口 [ActivityConfigEntity.php](slot_console/app/entity/activity/ActivityConfigEntity.php) 对 `TYPE_MONTHLY_REBATE``MonthlyRebateConfigService::canonicalExtConfigForStorage`
- 部署文档 `doc/monthly_rebate_deploy.md`
backend/slot_admin后台统计镜像 [FreeCreditsStatsLogic.php](backend/slot_admin/app/game/logic/FreeCreditsStatsLogic.php)
- 模型 `app/game/model/common/MonthlyRebateRecordModel.php``connection='s_common'`、四态 + `statusLabel`)。
- DTO `app/game/dto/MonthlyRebateStatsQueryDTO.php`、校验 `app/game/validate/MonthlyRebateStatsValidate.php``uid/source/status/stat_range[]/orderBy(in:bet_amount,rebate_amount)/orderType/page/limit`)。
- 控制器 `app/game/controller/MonthlyRebateStatsController.php``index` 返回 list + otherData
- Logic `app/game/logic/MonthlyRebateStatsLogic.php`
- `buildQuery``uid` 精确、`source` 精确、`status` whereIn、时间范围 snap 整月(`month_start >= 月初(start)``month_start <= 月初(end)`)、排序白名单默认 `month_start desc`
- `list`:行补 `rate(=rate_snapshot)``month_start/month_end``is_current_month``status_label`,金额 `getNumberFormat`
- `statistics`:总领取/总待领取/总过期/领取率(分母 0→02 位小数)/待定(仅当筛选含本月)。
- 菜单 `db/menu-monthly-rebate-stats.sql`(挂「综合统计」父菜单,镜像 [menu-free-credits-stats.sql](backend/slot_admin/db/menu-free-credits-stats.sql)`component=game/monthlyRebateStats/index` + `sm_system_group_menu` 授权)。
backend/slot_admin_vue镜像 [freeCreditsStats/index.vue](backend/slot_admin_vue/src/views/game/freeCreditsStats/index.vue)
- `src/api/game/monthlyRebateStats.js``src/views/game/monthlyRebateStats/index.vue`:筛选(ID/渠道/状态/按日范围)、`#tableAfterButtons` 顶部总计、可排序列(有效下注额/返水金额)、统计周期列显示「本月」或 `month_start - month_end`
slot_wallet
- 确认流水类型 `69` 打码归类为 活动赠送 Y3`SOURCE_TYPE_ACTIVITY_REWARD=3`),如有类型白名单补 69。
### ext_config 标准格式type=14
```json
{
"vip_rates": [
{"vip_level": 0, "rate_percent": 0},
{"vip_level": 1, "rate_percent": 0.5},
{"vip_level": 15, "rate_percent": 2.0}
],
"banner_image": ""
}
```
### cron
- `monthlyRebateAccrue` 每天 00:05`monthlyRebateSettle` 每月 1 日 00:15`monthlyRebateExpire` 每月 1 日 00:20。
### 与周返水共用注意
- 月返水与周返水各自独立表/配置/命令/流水类型,互不影响;同一用户同期可同时拥有日/周/月三套返水记录。
- 若日/周/月三套都上,建议抽取「曾充值判断 + profit 哈希解码 + 月/周边界」公共片段,避免三处复制(可选优化,不阻塞)。
### 收尾门禁
-`app/**/*.php` 后按 `slot-backend-completion-report` Skill 跑 `verify-slot-backend.sh` + docker `php -l`,回复附「检测结果」章节(含 PHPDoc:checked
</plan>
<todos>
[
{"id": "consts", "content": "slot_lib Consts 新增 ACTIVITY_TYPE_MONTHLY_REBATE=14、TRANSACTION_TYPE_MONTHLY_REBATE=69"},
{"id": "sql-model", "content": "monthly_rebate.sql + MonthlyRebateRecordModel(month_start/last_accrued_date/vip_level/rate_snapshot/四态/findByUidAndMonth)"},
{"id": "config-model-methods", "content": "RechargeGiftConfigModel 加 TYPE_MONTHLY_REBATE 与 getMonthlyRebateActiveInfo 系列方法"},
{"id": "services", "content": "MonthlyRebateCalcService(VIP费率单乘) 与 MonthlyRebateConfigService(vip_rates/maxRate/rateForVip/canonical)"},
{"id": "logic", "content": "MonthlyRebateLogicinfo/claim(CAS+钱包回滚)/accrue(写vip/rate快照)/settle(读VIP+过期上上月)/expire"},
{"id": "controller-route", "content": "MonthlyRebateController + MonthlyRebateValidator + 路由注册"},
{"id": "commands", "content": "命令 MonthlyRebateAccrue/Settle/Expire + cron"},
{"id": "activity-entry", "content": "ActivityConfigEntity 读写 type=14 走 canonicalExtConfigForStorage"},
{"id": "admin-stats", "content": "slot_admin 每月返水统计Model(s_common)/DTO/Validate/Controller/Logic(buildQuery月snap+list+statistics)"},
{"id": "admin-vue", "content": "slot_admin_vue monthlyRebateStats api.js + index.vue(筛选/总计/排序/统计周期)"},
{"id": "admin-menu-sql", "content": "menu-monthly-rebate-stats.sql 挂综合统计父菜单 + 分组授权"},
{"id": "wallet-verify", "content": "slot_wallet 确认流水类型69 打码归 活动赠送Y3"},
{"id": "deploy-doc", "content": "编写 monthly_rebate_deploy.md"},
{"id": "verify-gate", "content": "跑 verify-slot-backend.sh + php -l 输出检测结果章节"}
]
</todos>

View File

@@ -0,0 +1,92 @@
<!-- 22f17591-d664-4371-a1b6-9e4769285ad8 -->
---
todos:
- id: "middleware"
content: "新建 app/middleware/Language.php:读 X-Lang、归一化、每请求 locale()、设 $request->language"
status: pending
- id: "register"
content: "config/middleware.php 全局组在 TraceId 前注册 Language 中间件"
status: pending
- id: "config"
content: "config/translation.php 增加 supported=['zh_CN','en'],保留默认 zh_CN"
status: pending
- id: "trans-files"
content: "新建 resource/translations/{zh_CN,en}/messages.php,含 errors(按 OtaErrorCode)+ validation + common.ok"
status: pending
- id: "exception"
content: "BusinessException message 改可选;Handler 渲染时 trans('errors.'+code);Logic 7 处抛出去掉中文只传 code"
status: pending
- id: "result-auth"
content: "Result::fail 支持空 message 回退 trans;AdminAuth/InternalTokenAuth 去掉中文消息"
status: pending
- id: "validate"
content: "3 个 validator 的 $message 改翻译 key;AdminController::validate 返回前 trans();补全 validation.* 译文"
status: pending
- id: "verify"
content: "internal/admin 带 X-Lang 验证消息随 locale 变化 + 连续请求无串台,跑收尾检测脚本"
status: pending
isProject: false
---
# OTA 接口国际化(i18n)
## 结论先行
「中间件解析 header」思路正确,但在 Webman(常驻进程)里**核心动作是 `locale($lang)`**,不是把语言塞进 `$request->language``$request->language` 只作附带标记(给 Logic/日志用,非必须)。已具备:`config/translation.php``symfony/translation`。缺:语言中间件、翻译文件、把硬编码消息接到 `trans()`
约定:自定义头 `X-Lang`(值 `zh_CN` / `en`),默认 `zh_CN`,覆盖 internal + admin。
## 数据流
```mermaid
flowchart LR
req["HTTP 请求 X-Lang: en"] --> lang["Language 中间件 locale(en) + request->language"]
lang --> auth["Auth 中间件 Result::fail(code)"]
auth --> ctrl["Controller / Validate"]
ctrl --> logic["Logic throw BusinessException(code)"]
logic --> handler["Handler trans(code) 渲染"]
handler --> resp["{code, message(已按 locale 翻译), data}"]
```
## 改动点
### 1. 语言中间件(新增)
新建 `app/middleware/Language.php`(`MiddlewareInterface`):
-`X-Lang`(可兼容 `X-Language`),归一化(`zh`/`zh-CN`/`zh_cn``zh_CN`;`en`/`en-US``en`),不在支持列表则用默认。
- **每个请求都调 `locale($lang)`**(进程级全局状态,必须每请求重置,否则串语言)。
-`$request->language = $lang`(附带)。
- 支持列表 + 默认值读 `config('translation')`(见第 5 步)。
### 2. 注册为全局中间件
[config/middleware.php](config/middleware.php) 的 `''` 组在 `TraceId` 前加入 `app\middleware\Language::class`,确保 admin/internal 鉴权失败消息也按 locale 翻译。
### 3. 翻译文件(新增)
新建 `resource/translations/zh_CN/messages.php``resource/translations/en/messages.php`,返回两段:
- `errors` => 以 `OtaErrorCode` 各常量字符串为 key 的消息(对应现 Logic / Auth 里的中文)。
- `validation` => 校验消息 key(见第 6 步)。
调用形如 `trans('errors.' . $code)``trans($validationKey)`
### 4. 消息改为 trans() 取值
- [app/exception/Handler.php](app/exception/Handler.php):渲染 `BusinessException``message = trans('errors.' . $code)`(为空回退 code)。
- [app/exception/BusinessException.php](app/exception/BusinessException.php):`message` 改为可选;Logic 抛出时只传 code,去掉硬编码中文(`FirmwareLogic` 5 处、`OtaReportLogic`/`OtaCheckLogic`/`UpgradeRecordQueryLogic` 各 1 处)。需要动态文案的保留可选 message 入参。
- [app/support/Result.php](app/support/Result.php):`fail(string $code, ?string $message = null, ...)`,`$message` 为空时取 `trans('errors.' . $code)`;成功 `message``trans('common.ok')`
- 两个 Auth 中间件(`AdminAuth``InternalTokenAuth`)`Result::fail` 去掉中文,只传 code。
### 5. 配置补充
[config/translation.php](config/translation.php) 增加 `supported => ['zh_CN','en']`,`locale` 维持 `zh_CN` 作默认。中间件据此校验/回退。
### 6. 校验消息国际化(think\Validate)
为统一到单一 i18n(trans),不引入 think\Lang 第二套:
- 3 个 validator(`FirmwareCreateValidate``FirmwareListValidate``UpgradeRecordListValidate`)的 `$message` 值改为翻译 key(如 `validation.firmware.product_key_required`)。
- [app/admin/controller/AdminController.php](app/admin/controller/AdminController.php) `validate()` 返回前对错误信息做 `trans()`(key 命中则翻译,未命中原样返回)。
- 两个 locale 的 `messages.php` 补全这些 `validation.*` key。
## 验证
- internal:`POST /internal/ota/check` 带/不带 `X-Lang: en`,断言鉴权失败、业务异常、参数错误的 message 随 locale 变化。
- admin:固件创建非法参数,`X-Lang: en` 返回英文校验消息。
- 连续两请求(en 后 zh_CN)验证无 locale 串台(常驻进程回归)。
- 收尾跑 `~/.cursor/skills/slot-backend-completion-report/scripts/report.sh` 并附检测结果。
## 不做 / 待确认
- 不替换为 Accept-Language(已选自定义头)。
- 英文译文先给准确直译,文案润色后续可调。

View File

@@ -0,0 +1,99 @@
<!-- 27a4a527-c3b0-4e37-b4ed-ba7e02f51f70 -->
---
todos:
- id: "composer"
content: "在 composer.json 增加 vcs repository 并 docker composer require quanfuxia/log:dev-main"
status: pending
- id: "logconfig"
content: "改写 config/log.php 使用 SeasLogHandler + SeasLogLineFormatter + IntrospectionProcessor"
status: pending
- id: "middleware"
content: "新增 app/middleware/TraceId.php 调用 TraceContext::init并在 config/middleware.php 注册全局中间件"
status: pending
- id: "verify"
content: "php -l 校验、请求验证日志落盘,跑收尾门禁脚本"
status: pending
isProject: false
---
# 引入并配置 quanfuxia/log
## 背景
`quanfuxia/log``Quanfuxia\Log\`)是一个 Webman/Monolog → SeasLog 的日志适配库,核心组件:
- `SeasLogHandler`Monolog 记录写入 SeasLog自动 `SeasLog::setRequestID(traceId)`BasePath 设为 `runtime_path()/logs`
- `SeasLogLineFormatter`:日志行格式化
- `Trace\TraceContext`:基于 `Webman\Context``trace_id` / `request_time` 上下文
环境已确认:`php82` 容器存在 `SeasLog` 扩展PHP 8.2.24;库要求 `php>=8.2``monolog ^2.0`(项目已具备)。仓库仅有 `main` 分支、无 tag故按 `dev-main` 引入。容器内项目路径 `/app/www/ai-device/ota`
## 1. composer 引入(在 docker php82 内执行)
在 [composer.json](composer.json) 增加 `repositories` 与依赖:
- 顶层新增:
```json
"repositories": [
{ "type": "vcs", "url": "https://git.waixingkeji.net/quanfuxia/log.git" }
]
```
- `require` 增加 `"quanfuxia/log": "dev-main"`
执行安装(遵循 dev-environment 规则,宿主机不直接跑 composer
```bash
docker exec -w /app/www/ai-device/ota php82 composer require quanfuxia/log:dev-main
```
> 项目 `minimum-stability: dev` + `prefer-stable: true``dev-main` 可正常解析。私有仓库已验证可匿名 clone若 composer 拉取需鉴权再补充凭据。
## 2. 配置 config/log.php
将 [config/log.php](config/log.php) 的 `default` channel 由 `RotatingFileHandler` 改为 `SeasLogHandler`,并加上 `IntrospectionProcessor` 注入调用源(`extra.class/function/file/line`
```php
use Monolog\Logger;
use Monolog\Processor\IntrospectionProcessor;
use Quanfuxia\Log\SeasLogHandler;
use Quanfuxia\Log\SeasLogLineFormatter;
return [
'default' => [
'handlers' => [[
'class' => SeasLogHandler::class,
'constructor' => ['level' => Logger::DEBUG, 'bubble' => true],
'formatter' => [
'class' => SeasLogLineFormatter::class,
'constructor' => [
"%message% %extra.class%%extra.callType%%extra.function% %extra.file%:%extra.line% %context%\n",
'Y-m-d H:i:s', true, true,
],
],
]],
'processors' => [[
'class' => IntrospectionProcessor::class,
'constructor' => [Logger::DEBUG, ['support\\Log'], 0],
]],
],
];
```
> [config/process.php](config/process.php) 中 `'logger' => Log::channel('default')` 无需改动,框架日志将随之写入 SeasLog。
## 3. 新增 Trace 中间件初始化 trace_id
每次 HTTP 请求开始时初始化链路 ID使同一请求内日志 trace_id 一致,并支持上游透传。
- 新增 `app/middleware/TraceId.php`(实现 `Webman\MiddlewareInterface`):从请求头(如 `X-Trace-Id`)取值,调用 `Quanfuxia\Log\Trace\TraceContext::init($headerTraceId)`,再 `return $handler($request)`
- 在 [config/middleware.php](config/middleware.php) 注册为全局中间件:
```php
return [
'' => [ app\middleware\TraceId::class ],
];
```
> CLI / 非中间件入口无需额外处理:`TraceContext::getTraceId()` 在缺失时会自动生成并写回上下文。
## 4. 验证
```bash
docker exec -w /app/www/ai-device/ota php82 php -l config/log.php
docker exec -w /app/www/ai-device/ota php82 php -l app/middleware/TraceId.php
# 启动后请求一次接口,检查日志落盘
docker exec php82 sh -lc 'ls -R /app/www/ai-device/ota/runtime/logs'
```
并按 `slot-backend-completion-report` 跑收尾门禁。
## 注意 / 待确认
- `git_status` 显示 `composer.json`/`composer.lock` 已有 `vlucas/phpdotenv` 改动,本次只追加,不回退既有改动。
- 日志格式字符串、`X-Trace-Id` 头名称如需调整可后续微调(默认按 readme 示例)。

View File

@@ -0,0 +1,47 @@
---
name: refer-earn doc update
overview: 基于浏览器实测(数字随汇率浮动、佣金计算器拆解、分享弹窗细节),更新 docs/推荐返佣需求文档.md补全「1498.87 的来源与性质」「邀请奖金解锁机制」「佣金计算器」「立即邀请分享弹窗」四块内容。
todos:
- id: invite-bonus
content: 更新 §3.3/§3.41498.87 = 1500 USDT 基准÷汇率,性质为每位好友锁定奖金上限,配置存整数 USDT
status: completed
- id: calculator
content: 新增佣金计算器章节:入口/路由、输入项、输出口径、实测样例数据表
status: completed
- id: share-modal
content: 补全立即邀请分享弹窗:社交渠道、推荐链接/二维码/推荐码+复制
status: completed
- id: usdt-fx
content: §5 补 USDT 基准币 + 汇率折算导致展示浮动§6 配置项补基准额/解锁速率/上限
status: completed
- id: open-questions
content: §7 补充邀请奖金解锁公式与上限、计算器与费率表一致性 待确认项
status: completed
isProject: false
---
# 更新推荐返佣需求文档
仅修改 [docs/推荐返佣需求文档.md](docs/推荐返佣需求文档.md) 一个文件,把本轮浏览器实测结论补进去。无代码改动。
## 关键实测结论(写入依据)
- 重载页面后数字变化:邀请奖金 `1498.87 → 1499.01`、EXP `4,996.27 → 4,996.71`。证实「整数基准 + 实时汇率」模型。
- 佣金计算器输出 `US$ ≈ USDT`,证实**基准币为 USDT**USD 为汇率折算、随汇率浮动。
- `1498.87 ≈ 1500 USDT / 实时汇率`,是**每位被邀请好友可解锁的邀请奖金上限(单人 + 上限)**,非即时白送。
- 计算器实验Lv9 / 老虎机 / 存款 0USD下注 1万→144.96、10万→1,174.86、100万→10,699.47;存款 1000 额外 +50.00=5%,确认 Lv9 存款奖金率)。
- 按 Lv9 老虎机团队 A 佣金 1%100/10k拆分剩余 ≈45/175/699 随投注增长但边际递减 → 符合「锁定邀请奖金按投注解锁且封顶」模型(精确曲线待产品确认)。
## 文档改动点
- **§3.3 / §3.4(邀请奖金)**:明确 `1498.87` = `1500 USDT 基准 ÷ 实时汇率`性质为「每位好友锁定奖金上限」由该好友投注逐步解锁落地配置应存整数基准USDT展示层做汇率折算不得硬编码 `1498.87`
- **新增 §3.x 佣金计算器**:记录入口(可领奖金卡片左侧计算器图标,路由 `/refer-earn-calc`)、输入项(我的代理级别 Lv1Lv9、朋友货币类型、朋友存款金额、朋友赌注分类、朋友下注金额、输出预期奖金 `US$ ≈ USDT`)、口径(= 存款奖金 + 投注佣金 + 解锁的邀请奖金),并附本轮实测样例数据表。
- **补全 §3.4「立即邀请」分享弹窗**:标题「分享到」,社交渠道 Facebook / WhatsApp / LINE / Messenger / Telegram / X / Email推荐链接 `https://vpgame1.vip/?c=<推荐码>`、推荐二维码、推荐代码(如 `aP53Alj`+ 复制按钮。
- **§5 业务规则**:补「金额基准币为 USDT前端按实时汇率折算为展示币种故展示值会随汇率浮动」。
- **§6 落地建议**`referral_global_config` 增加「邀请奖金基准额USDT 整数)、单人解锁速率、单人解锁上限」;明确展示层汇率折算职责。
- **§7 待确认**:把「邀请奖金单人解锁公式与上限(实测 1M 投注仅解锁约 699未达 1500 上限,曲线疑似边际递减)」「各等级/各游戏类型佣金率与计算器是否完全一致」列为重点对齐项。
## 验证
- 文档为 markdown无 PHP 改动,不触发后端校验门禁。
- 自查保留原文档结构与已有表格新增内容与实测数据一致、单位标注USD/USDT/每10k清晰。

View File

@@ -0,0 +1,78 @@
<!-- 254c9e72-64e2-4a49-bb96-cb80c68065d7 -->
---
todos:
- id: "config"
content: "新建 slot-user/config/register_bonus.php从 env 读默认开关/金额(大单位)/打码倍数,支持按 source 覆盖"
status: pending
- id: "service"
content: "新建 slot-user/app/service/wallet/RegisterBonusService.php读配置+Redis NX 幂等+slot_sdk WalletClient->register+fail-open删除旧 activity 网关"
status: pending
- id: "callers"
content: "AbstractRegisterService::grantRegisterBonusAfterNewUserRegistered 与 EventRegister::triggerRegisterBonus 切换到新服务"
status: pending
- id: "sdk-wagering"
content: "修复 slot_sdk WalletService::register() 补传 bonus_wagering"
status: pending
- id: "activity-cleanup"
content: "确认无其他调用方后,下线 slot-activity 注册赠金 innerapi 与 slot_sdk ActivityService::triggerRegisterBonus 相关代码"
status: pending
- id: "verify"
content: "注册各入口+MQ 兜底验证幂等与 wagering跑后端门禁脚本"
status: pending
isProject: false
---
# 注册赠金从活动服解耦到用户服
## 背景与现状
当前链路:`slot-user` 注册 → [`RegisterBonusGatewayService`](slot-user/app/service/activity/RegisterBonusGatewayService.php) → (slot_sdk) `ActivityClient` → [`slot-activity` `RegisterBonusLogic`](slot-activity/app/innerapi/logic/RegisterBonusLogic.php)(查活动配置 + Redis 幂等锁 + 调钱包 register
问题:注册赠金强依赖活动服;活动服不可用时新用户拿不到赠金(且 register 类型钱包调用是钱包账户创建入口,间接影响)。
目标(已确认):**完全解耦**,赠金配置放 slot-user 的 **config 文件**,由用户服直接调钱包,不再依赖 slot-activity。
```mermaid
flowchart LR
reg["slot-user 注册 / EventRegister MQ"] --> svc["新 RegisterBonusService(读 config + Redis 幂等)"]
svc -->|slot_sdk WalletClient->register| wallet["slot-wallet RegisterService 入账+建账户"]
```
## 关键修复点(必须)
- **slot_sdk 漏传 `bonus_wagering`**[`WalletService::register()`](slot_sdk/src/service/wallet/WalletService.php) 仅拼 `type/fee/bonus` + base payload`bonus_wagering` 被丢弃,导致钱包侧 [`RegisterService::resolveRegisterBonusRequiredWager`](slot-wallet/app/service/wallet/RegisterService.php) 始终按默认 1 倍。需补传。
- **幂等归属转移**:钱包 `register``biz_id` 去重,原幂等靠活动服 Redis NX 锁。解耦后由 slot-user 持有 Redis NX 锁(沿用 `biz_id = register:bonus:{uid}`),避免同步路径与 `EventRegister` MQ 兜底重复发放。
## 改动清单
### 1. slot-user新增赠金配置config 文件)
- 新建 `slot-user/config/register_bonus.php`:从 env 读默认开关/金额(大单位)/打码倍数,并支持按 `source` 覆盖;如 `enabled``default => ['amount' => env('REGISTER_BONUS_AMOUNT',0), 'wagering' => env('REGISTER_BONUS_WAGERING',1)]``sources => ['pwa_a' => [...]]`
- 金额大单位经 `slot\foundation\Tools\MoneyTool::bigUnitToSmallUnit` 转最小单位;币种取自 `UserShardModel->currency`
### 2. slot-user新增直连钱包的赠金服务替换活动网关
- 新建 `slot-user/app/service/wallet/RegisterBonusService.php`(公共能力:读配置 + 跨服务调钱包):
-`source` 解析金额/倍数金额≤0 或未启用 → 记日志跳过。
- Redis `SET NX EX` 幂等锁key 含 uid命中重复直接返回。
- 经 slot_sdk `WalletClient->register(WalletRegisterEntity{uid,source,currency,organization,biz_id,bonus,bonus_wagering})` 入账。
- fail-opencatch `Throwable``LoggerService::error`,不抛出(不阻断注册);失败时删除锁以便 MQ 兜底重试。
- 日志含 `uid/source/currency/bonus/biz_id`
- 删除 [`slot-user/app/service/activity/RegisterBonusGatewayService.php`](slot-user/app/service/activity/RegisterBonusGatewayService.php)。
### 3. slot-user切换调用方
- [`AbstractRegisterService::grantRegisterBonusAfterNewUserRegistered`](slot-user/app/service/register/AbstractRegisterService.php) 改调新 `RegisterBonusService`(影响 6 个 RegisterService 子类,无需逐个改)。
- [`EventRegister::triggerRegisterBonus`](slot-user/app/command/EventRegister.php) 同步改为新服务(保留 MQ 兜底语义)。
### 4. slot_sdk补传 bonus_wagering
- [`WalletService::register()`](slot_sdk/src/service/wallet/WalletService.php) 的 `WalletUpdateEntity` payload 增加 `'bonus_wagering' => $entity->bonus_wagering``WalletUpdateEntity`/钱包 DTO 已支持该字段)。
### 5. slot-activity下线注册赠金入口清理确认无其他调用方后执行
- 删除 `slot-activity/app/innerapi/{controller/RegisterBonusController, logic/RegisterBonusLogic, dto/RegisterBonusTriggerDto, validate/RegisterBonusValidate}.php` 及其路由。
- 删除 slot_sdk `ActivityService::triggerRegisterBonus``RegisterBonusTriggerEntity`/响应实体grep 确认仅 slot-user 旧网关使用)。
- `activity_type=7 注册赠送` 活动数据保留与否由运营决定,本次不动表结构。
## 待确认 / 决策
- **是否对每个新用户都调一次 register 以确保钱包账户必建**(即便赠金为 0当前钱包账户由 register 调用创建,建议赠金=0 时仍调用 `register(bonus=0)` 兜底建账户;若钱包账户另有创建入口则无需。实现时按现状默认「仅金额>0 才发」,此点单独标注。
-`source` 区分金额的具体取值由运营提供config 先给 `default`
## 验收
- 注册(各 RegisterService+ MQ 兜底各跑一次,确认:赠金按配置入账一次(幂等不重复)、`bonus_wagering` 生效(钱包 fund lot `required_wager` 正确)、活动服关停不影响注册与发放。
- 收尾执行 `slot-backend-completion-report` 门禁verify + `php -l`)。

View File

@@ -0,0 +1,155 @@
<!-- 82f6bca9-5c06-4eb6-bb4f-d44d3dbdfbc3 -->
---
todos:
- id: "add-compose-service"
content: "在 docker-compose.yml 新增 slotMysql 服务(镜像 8.0.33、卷 datadir_slot_mysql、端口 3310"
status: pending
- id: "start-slotmysql"
content: "docker compose up -d slotMysql 并等待 mysqladmin ping 就绪"
status: pending
- id: "dump-restore"
content: "mysqldump 全库管道导入 slotMysql--single-transaction --set-gtid-purged=OFF"
status: pending
- id: "verify-data"
content: "对比库列表并抽样校验表行数,确认复制成功"
status: pending
isProject: false
---
# 创建 slotMysql 并复制 goMysql 数据
## 现状
| 项目 | goMysql现有 |
|------|----------------|
| 镜像 | `mysql:8.0.33` |
| 数据卷 | [`docker/data/datadir_go_mysql`](/Users/ray/Documents/project/docker/data/datadir_go_mysql)(约 7.3G |
| 宿主机端口 | `3309` → 容器 `3306` |
| root 密码 | `root` |
| 库数量 | 约 70 个(全库复制) |
配置来源:[`docker/docker-compose.yml`](/Users/ray/Documents/project/docker/docker-compose.yml) 第 4153 行。
## 目标架构
```mermaid
flowchart LR
subgraph docker_net [default network]
goMysql["goMysql :3306"]
slotMysql["slotMysql :3306"]
php82[php82]
end
host3309["宿主机 :3309"] --> goMysql
host3310["宿主机 :3310"] --> slotMysql
php82 -->|"现有 .env 仍连 goMysql"| goMysql
goMysql -->|"mysqldump 全库"| slotMysql
```
两容器并行运行、数据独立;应用暂不切换。
## 步骤 1在 docker-compose 中新增 slotMysql
编辑 [`docker/docker-compose.yml`](/Users/ray/Documents/project/docker/docker-compose.yml),在 `goMysql` 服务后追加:
```yaml
slotMysql:
image: mysql:8.0.33
container_name: slotMysql
working_dir: /app
volumes:
- /Users/ray/Documents/project:/app
- ./data/datadir_slot_mysql:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
ports:
- "3310:3306"
networks:
- default
```
要点:
- **独立数据卷** `./data/datadir_slot_mysql`(首次 `up` 时自动初始化空实例)
- **宿主机端口 `3310`**`3309` 已被 goMysql 占用)
- 与 goMysql 同镜像、同密码、同网络,便于容器内互访
## 步骤 2启动 slotMysql 并等待就绪
```bash
cd /Users/ray/Documents/project/docker
docker compose up -d slotMysql
```
轮询直到可连接(约 3060 秒):
```bash
docker exec slotMysql mysqladmin -uroot -proot ping
```
## 步骤 3全库逻辑复制推荐方式
**选用逻辑导出/导入**,原因:
- goMysql **无需停机**,现有应用不受影响
- 避免直接拷贝 `datadir` 带来的 InnoDB 文件锁/UUID 冲突风险
- 两容器版本一致(`8.0.33`),兼容性有保障
在宿主机执行(管道直连,不落盘大 SQL 文件):
```bash
docker exec goMysql mysqldump -uroot -proot \
--all-databases \
--single-transaction \
--routines \
--triggers \
--events \
--set-gtid-purged=OFF \
| docker exec -i slotMysql mysql -uroot -proot
```
参数说明:
- `--single-transaction`InnoDB 一致性快照,复制期间 goMysql 可继续读写
- `--set-gtid-purged=OFF`:本地开发环境无 GTID 复制,避免导入报错
**预计耗时**7.3G 数据约 1545 分钟,视磁盘 IO 而定;期间勿重启两容器。
### 备选方案(未采用)
直接 `cp -a datadir_go_mysql → datadir_slot_mysql` 需**停止 goMysql**,且有 binlog/ibdata 一致性风险;仅适合可接受停机且追求极速的场景。本次不采用。
## 步骤 4验证数据一致性
```bash
# 库数量对比
docker exec goMysql mysql -uroot -proot -N -e "SHOW DATABASES;" | sort > /tmp/go_dbs.txt
docker exec slotMysql mysql -uroot -proot -N -e "SHOW DATABASES;" | sort > /tmp/slot_dbs.txt
diff /tmp/go_dbs.txt /tmp/slot_dbs.txt
# 抽样校验行数(示例)
docker exec goMysql mysql -uroot -proot -N -e "SELECT COUNT(*) FROM s_common.some_table"
docker exec slotMysql mysql -uroot -proot -N -e "SELECT COUNT(*) FROM s_common.some_table"
```
连通性验证:
- 容器内:`docker exec slotMysql mysql -uroot -proot -e "SELECT 1"`
- 宿主机:`mysql -h127.0.0.1 -P3310 -uroot -proot -e "SHOW DATABASES;"`(若本机有 mysql 客户端)
## 步骤 5日常使用说明
| 访问方式 | 命令/地址 |
|----------|-----------|
| 容器内php82 等) | `slotMysql:3306`,用户 `root`,密码 `root` |
| 宿主机 | `127.0.0.1:3310` |
| 启停 | `docker compose up -d slotMysql` / `docker compose stop slotMysql` |
**不改动** [`www/slot`](/Users/ray/Documents/project/www/slot) 及各服务 `.env` 中的 `DB_*_HOST = 'goMysql'`;后续若要切换,再批量改 host 并重启对应 Webman 进程。
## 风险与注意
1. **复制期间 goMysql 有新写入**`--single-transaction` 保证 InnoDB 表一致MyISAM 表(若有)可能略有偏差,开发环境通常可接受。
2. **磁盘空间**`datadir_slot_mysql` 将再占约 7G+,确保 `/Users/ray/Documents/project/docker/data` 所在磁盘有余量。
3. **复制失败重试**:若导入中断,最干净做法是 `docker compose stop slotMysql`,删除 `datadir_slot_mysql` 目录后重新 `up` 再导入。
4. **用户/权限**`--all-databases` 会同步 `mysql` 系统库中的用户与授权root 密码与 goMysql 一致。
## 涉及文件
- 修改:[`docker/docker-compose.yml`](/Users/ray/Documents/project/docker/docker-compose.yml)
- 新建(自动):`docker/data/datadir_slot_mysql/`
- 不修改:各服务 `.env``php82` 等现有配置

View File

@@ -0,0 +1,150 @@
<!-- 06741b7f-ce5d-4d77-8966-93bfe93d396a -->
---
todos:
- id: "migrate-log-calls"
content: "13 个文件LoggerService::info/error/warning → support\\Log统一 context 为 array"
status: pending
- id: "migrate-trace-timing"
content: "InnerCurlService / OutputService / EventBus改用 Context + TraceIdMiddleware::initContext"
status: pending
- id: "delete-logger-service"
content: "删除 LoggerService.php更新 README §8.1"
status: pending
- id: "fix-handler-syntax"
content: "修复 app/exception/Handler.php 末尾多余花括号"
status: pending
- id: "verify"
content: "grep 无残留引用 + 跑 report.sh + CLI/HTTP/MQ 冒烟"
status: pending
isProject: false
---
# slot_agent 废弃 LoggerService 完整迁移
## 结论
**可以不再使用 `LoggerService` 写日志**,但不能「只配好 `config/log.php` 就删类」——当前仍有 **13 个文件、约 56 处** `LoggerService::` 调用,且 3 处依赖其 trace/timing 工具方法。
你已有的新栈已覆盖旧能力:
| 能力 | LoggerService | 新配置 |
|------|---------------------|--------|
| 落盘 | 直接 `SeasLog::*` | [`config/log.php`](slot_agent/config/log.php) → `SeasLogHandler` |
| traceId | `$_SERVER['TRACE_ID']` 手动拼进 message | [`TraceIdMiddleware`](slot-foundation/src/Middleware/TraceIdMiddleware.php) → `Context::get('trace_id')` + `SeasLog::setRequestID` |
| 调用位置 | `debug_backtrace` 手动 JSON | `IntrospectionProcessor`(已排除 `support\Log` |
| 请求耗时 | `$_SERVER['REQUEST_TIME_FLOAT']`HTTP 几乎未初始化) | `Context::get('request_time')`Middleware 已写入) |
当前项目处于 **双轨并存**会导致同一次请求里日志格式、trace 来源不一致:
- 已用 `support\Log`[`AuthMiddleware`](slot_agent/app/middleware/AuthMiddleware.php)、[`RabbitMqService`](slot_agent/app/service/RabbitMqService.php)、[`Test`](slot_agent/app/command/Test.php)
- 仍用 `LoggerService`EventBus、各 Service/Logic、Exception Handler 等
```mermaid
flowchart LR
subgraph old [旧路径]
LS[LoggerService] --> SeasLogDirect[SeasLog 直连]
LS --> ServerTrace["$_SERVER TRACE_ID"]
end
subgraph new [新路径]
LogFacade["support\\Log"] --> Monolog[Monolog]
Monolog --> Handler[SeasLogHandler]
Handler --> SeasLogCtx[SeasLog + Context trace_id]
TraceMW[TraceIdMiddleware] --> Context[Context]
end
```
---
## 迁移范围(按职责)
### 1. 写日志:统一改为 `support\Log`
涉及文件(全部在 `slot_agent/app/` 下):
- [`command/EventBus.php`](slot_agent/app/command/EventBus.php)15 处)
- [`innerapi/logic/AgentLogic.php`](slot_agent/app/innerapi/logic/AgentLogic.php)
- [`service/ReferralRewardConfigService.php`](slot_agent/app/service/ReferralRewardConfigService.php)9 处)
- [`service/InnerCurlService.php`](slot_agent/app/service/InnerCurlService.php)8 处日志)
- [`service/UserReferralGatewayService.php`](slot_agent/app/service/UserReferralGatewayService.php)
- [`service/ReferralRewardService.php`](slot_agent/app/service/ReferralRewardService.php)
- [`service/activity/UserAgentRegisterService.php`](slot_agent/app/service/activity/UserAgentRegisterService.php)
- [`service/LuckyRewardInviteCallbackGatewayService.php`](slot_agent/app/service/LuckyRewardInviteCallbackGatewayService.php)
- [`service/ShareConfigService.php`](slot_agent/app/service/ShareConfigService.php)
- [`exception/Handler.php`](slot_agent/app/exception/Handler.php)
- [`innerapi/exception/Handler.php`](slot_agent/app/innerapi/exception/Handler.php)
**替换约定**(与现有 `AuthMiddleware` 对齐):
```php
// 旧
LoggerService::info(__METHOD__, $payload);
// 新 — context 必须是 array标量包一层
Log::info(__METHOD__, is_array($payload) ? $payload : ['msg' => $payload]);
```
```php
// 旧 — Throwable
LoggerService::error(__METHOD__, $exception);
// 新 — 与 AuthMiddleware 一致
Log::error($exception);
// 或需要业务前缀时:
Log::error(__METHOD__, ['msg' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()]);
```
CLI/MQ 消费若需独立 trace在 handler 入口调用一次:
```php
use Slot\Foundation\Middleware\TraceIdMiddleware;
TraceIdMiddleware::initContext(); // 替代 LoggerService::initGenerateTraceId()
```
[`EventBus::deal()`](slot_agent/app/command/EventBus.php) 第 59 行即此处。
### 2. trace / timing改用 Context不再读 `$_SERVER`
| 文件 | 旧 API | 新 API |
|------|--------|--------|
| [`InnerCurlService`](slot_agent/app/service/InnerCurlService.php) | `LoggerService::getTraceId()` | `Context::get('trace_id')`;空则 `TraceIdMiddleware::initContext()` 后再取 |
| [`OutputService`](slot_agent/app/service/OutputService.php) | `LoggerService::getRequestTime()` | `Context::get('request_time', microtime(true))``timing = microtime(true) - $start` |
| [`EventBus`](slot_agent/app/command/EventBus.php) | `initGenerateTraceId()` | `TraceIdMiddleware::initContext()` |
`TRACE_CHILD_ID` / `setChildId` / `initRequestTime` 在 slot_agent **无任何调用**,删除 `LoggerService` 时一并移除即可。
### 3. 删除与文档
- 删除 [`app/service/LoggerService.php`](slot_agent/app/service/LoggerService.php)
- 更新 [`README.md`](slot_agent/README.md) §8.1:由「统一 `LoggerService`」改为「统一 `support\Log` + `Context trace_id`
- **保留** [`AppBootStrap`](slot_agent/app/AppBootStrap.php):仍负责 SeasLog 按 worker 分目录(`cli` / `webman`),与 `SeasLogHandler` 互补
### 4. 顺带修复(改 Handler 时)
[`app/exception/Handler.php`](slot_agent/app/exception/Handler.php) 文件末尾有多余 `{\n\n}`,迁移时一并去掉,避免语法问题。
---
## 不需要改动的部分
- [`config/log.php`](slot_agent/config/log.php) — 已就绪
- [`config/middleware.php`](slot_agent/config/middleware.php) — `TraceIdMiddleware` 已在最前
- [`config/process.php`](slot_agent/config/process.php) — 已注入 `Log::channel('default')`
---
## 验证
1. 跑 completion report`SLOT_ROOT=/Users/ray/Documents/project/www/slot/slot_agent ~/.cursor/skills/slot-backend-completion-report/scripts/report.sh`
2. 手动冒烟:
- HTTP`AuthMiddleware` 已有 `Log::info`,确认 `runtime/logs/webman/` 含 trace + 调用栈
- CLI`php webman test`[`Test.php`](slot_agent/app/command/Test.php) 已有 Log 示例)
- MQ`event:bus` 消费一条消息,确认 CLI 日志有独立 trace_id
3. 确认全仓库 `slot_agent` 内无 `LoggerService` 引用
---
## 风险与注意
- **日志格式会变**:旧格式为 `trace_id|Class::method | json {"file":...}` 单行;新格式由 `SeasLogLineFormatter` + `IntrospectionProcessor` 决定。若 ELK/告警规则按旧格式解析,需同步调整。
- **跨服务 trace 传递**`InnerCurlService` 请求头 `traceId` 应改为传 `Context::get('trace_id')`,与 [`TraceIdMiddleware`](slot-foundation/src/Middleware/TraceIdMiddleware.php) 一致(不再用 `trace_id:xxx` 前缀的 uniqid 格式)。
- **OutputService timing 行为会修正**HTTP 请求将正确使用 Middleware 写入的 `request_time`,不再依赖几乎未初始化的 `REQUEST_TIME_FLOAT`

View File

@@ -0,0 +1,123 @@
---
name: Spin 响应补全字段
overview: 当前 `POST /api/lucky-reward/spin` 仅返回 `poolItemId` 与抽奖后总 `myAmountQf`,未返回本次命中的 `prizeType` 与实际入账 `prizeAmount`,与 [04 方案](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md) 及 PRD 中奖弹窗需求不符。需在 `SpinResultEntity` 补字段并在 Logic 填充。
todos:
- id: extend-spin-result-entity
content: SpinResultEntity 增加 prizeType、prizeAmount 及中文属性注释
status: cancelled
- id: fill-spin-logic-response
content: executeManualSpin 返回时填充 drawResult.prizeType 与 formatAmountDisplay(creditedQf)
status: cancelled
- id: update-spin-api-docs
content: 更新 lucky_reward_api.md及 deploy 冒烟说明)响应字段与示例
status: cancelled
- id: add-spin-response-test
content: 补充单元测覆盖 random/spin/cashout 三种 prizeType 与 prizeAmount 断言
status: cancelled
isProject: false
---
# Spin 响应补全:中奖类型与中奖金额
## 现状(你的判断是对的)
[`SpinResultEntity`](slot_console/app/entity/luckyReward/SpinResultEntity.php) 当前只有:
| 字段 | 含义 |
|------|------|
| `poolItemId` | 命中的奖池格 ID前端可对照 `records`/`status` 里的 `poolItems` 反查类型,但**不是直接返回类型** |
| `myAmountQf` | 抽奖**之后**的 My Amount 总额(大单位 float |
| `spinAvailable` / `playerStatus` / `isDuplicate` | 状态 |
[`executeManualSpin`](slot_console/app/api/logic/LuckyRewardLogic.php) 事务内已算出 `$drawResult->prizeType``$creditedQf`(随机金额封顶后的**实际入账**),但组装响应时**未写入 Entity**
```275:281:slot_console/app/api/logic/LuckyRewardLogic.php
return new SpinResultEntity([
'poolItemId' => $drawResult->poolItemId,
'myAmountQf' => LuckyRewardAmountService::formatAmountDisplay3((int) $activityPlayer->my_amount_qf),
'spinAvailable' => (int) $activityPlayer->spin_available,
'playerStatus' => (int) $activityPlayer->status,
'isDuplicate' => false,
]);
```
[`lucky_reward_api.md`](slot_console/doc/lucky_reward_api.md) §3 文档同样未描述 `prizeType` / `prizeAmount`。
与设计文档冲突点:[04 方案 §5 第 7 步](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md) 明确要求返回「**命中类型、金额**、刷新后的 my_amount/次数」PRD §3.2 也要求按类型展示不同中奖弹窗,且随机金额弹窗展示金额须与**实际入账**一致(封顶后 `credited_qf`)。
```mermaid
sequenceDiagram
participant Client
participant SpinAPI as POST_spin
participant Logic as LuckyRewardLogic
participant Draw as DrawService
Client->>SpinAPI: 手动 Spin
SpinAPI->>Logic: executeManualSpin
Logic->>Draw: draw
Draw-->>Logic: prizeType + rawPrizeAmountQf
Logic->>Logic: applySpinPrize -> creditedQf
Note over Logic: 现况prizeType/creditedQf 只写 DB 与日志
Logic-->>Client: poolItemId + myAmountQf缺本次中奖字段
```
---
## 建议补全方案
### 1. 扩展 `SpinResultEntity`
在 [`SpinResultEntity.php`](slot_console/app/entity/luckyReward/SpinResultEntity.php) 新增:
- **`prizeType`**`int`):见 [`RewardPoolItemModel::PRIZE_TYPE_*`](slot_console/app/model/common/RewardPoolItemModel.php)
- `1` 随机金额 / `2` 1x Spin / `3` Cash Out
- **`prizeAmount`**`float`**本次 Spin 实际展示/入账金额**(大单位,与 `openBox.initAmount`、`records.items[].prizeAmount` 口径一致)
赋值规则(与落库 [`spin_record.prize_amount_qf`](slot_console/app/api/logic/LuckyRewardLogic.php) 一致):
| prizeType | prizeAmount |
|-----------|-------------|
| 随机金额 (1) | `formatAmountDisplay($creditedQf)`(封顶后实际入账,非 raw 随机值) |
| 1x Spin (2) | `0` |
| Cash Out (3) | `0` |
保留现有 `poolItemId`(转盘停格动画)与 `myAmountQf`(更新后总额),不破坏兼容。
### 2. Logic 填充
[`LuckyRewardLogic::executeManualSpin`](slot_console/app/api/logic/LuckyRewardLogic.php) 返回处增加:
```php
'prizeType' => $drawResult->prizeType,
'prizeAmount' => LuckyRewardAmountService::formatAmountDisplay($creditedQf),
```
无需改 Controller仍 `$spinResultEntity->activeData()`)。
### 3. 文档
更新 [`lucky_reward_api.md`](slot_console/doc/lucky_reward_api.md) §3 响应表与 JSON 示例;[`lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 冒烟项可补一句「spin 响应含 prizeType/prizeAmount」。
可选:同步 [04 方案](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md) 示例 JSON若文档有旧字段名
### 4. 测试
- 新增或扩展 Logic 单元测mock draw 结果):断言 random 命中时 `prizeAmount == creditedQf` 展示值、`prizeType == 1`Spin/CashOut 时 `prizeAmount == 0`。
- 若有 YApi #557 spin 接口文档,一并更新字段说明。
---
## 不在本次范围
- 不改抽奖算法、封顶逻辑、Redis 锁。
- 不改 `records` 列表结构Record Tab 仍只有 `prizeAmount`,无 `prizeType`;若前端 Record 也要类型可另开需求)。
- `isDuplicate` 目前恒为 `false`(无 spin 幂等重放路径),本次不扩展。
---
## 前端使用建议(供联调)
- **停格**`poolItemId`
- **弹窗类型**`prizeType`
- **弹窗金额 / 飞金币**`prizeAmount`(仅 type=1 时 >0
- **进度条/My Amount 刷新**`myAmountQf`

View File

@@ -0,0 +1,157 @@
---
name: Spin去spin_id加锁
overview: 手动 Spin 去掉前端必填 `spin_id`,改为 Redis 用户锁防并发 + 事务内 `spin_available` 校验;`spin_id` 仅服务端写库用;连点拿不到锁立即报错。
todos:
- id: api-validator
content: spin API/Validator去掉 spin_id 入参Controller 两参调用 Logic
status: completed
- id: logic-lock
content: LuckyRewardLogicSET NX 用户锁 fail-fast + 服务端生成 spin_id + 移除客户端幂等分支
status: completed
- id: tests-docs
content: RedisKeyManagerService 锁 key + 单测/文档/YApi 更新
status: completed
isProject: false
---
# Spin 去掉前端 spin_idRedis 锁 + 次数校验)
## 产品约定(已确认)
- **防并发**Redis 用户级锁,连点第二笔 **拿不到锁立即报错**(不重试等待)。
- **防重复扣次**:事务内校验 `spin_available > 0`,成功则 `-1`;无次数则拒绝。
- **不做**客户端幂等 / 弱网重试幂等:超时后若已扣次,再次 spin 会报「无可用 Spin」→ **前端应改调 `status` / `records` 刷新**,勿无脑重试 spin。
```mermaid
sequenceDiagram
participant FE as Frontend
participant Logic as LuckyRewardLogic
participant Redis
participant DB
FE->>Logic: POST spin 无 body
Logic->>Redis: SET lock uid NX TTL 5s
alt lockFail
Redis-->>Logic: 未拿到
Logic-->>FE: BusinessException Spin处理中
else lockOk
Logic->>DB: spin_available>0 校验+抽奖+写record
Logic->>Redis: unlock
Logic-->>FE: SpinResultEntity
end
```
---
## 代码改动slot_console
### 1. API 层
**[`LuckyRewardController::spin()`](slot_console/app/api/controller/LuckyRewardController.php)**
- 移除 `LuckyRewardValidator::SCENE_SPIN` 校验及对 `spin_id` 的读取。
- 调用 `$this->logic->spin($uid, $source)`(两参)。
**[`LuckyRewardValidator`](slot_console/app/api/validator/LuckyRewardValidator.php)**
- 删除 `SCENE_SPIN` / `spin_id` 规则(或保留空 scene 备用spin 接口不再走 Validate。
### 2. Logic 核心
**[`LuckyRewardLogic::spin()`](slot_console/app/api/logic/LuckyRewardLogic.php)**
| 变更 | 说明 |
| --- | --- |
| 签名 | `spin(int $uid, string $source): SpinResultEntity` |
| 删除 | 入口 `findByUidAndSpinId` + `buildSpinResultFromRecord` 的**客户端幂等**分支 |
| 新增 | 方法开头 `acquireSpinLock($uid)` / `finally releaseSpinLock` |
| 新增 | 服务端生成 `spinId``manual:{uid}:{cycleId}:{uniqid()}`(或 `random_bytes` 短串),仅用于 `lucky_reward_spin_record.spin_id` 满足 `uk_uid_spinid` |
| 保留 | 开宝箱校验、`grantDailySpinIfNeeded``ensureUserCanSpin`、事务内二次 `spin_available` 校验、抽奖与落库逻辑 |
| 响应 | `SpinResultEntity.spinId` 仍返回(服务端生成,供 records 展示);`isDuplicate` 固定 `false`(或后续从 Entity 移除该字段需评估 FE 兼容性,建议先保留恒 false |
**Redis 锁实现**(复用现有 [`RedLock`](slot_console/app/service/RedLock.php)
```php
// RedisKeyManagerService 新增
/** Lucky Rewards 手动 Spin 用户锁前缀 */
const LUCKY_REWARD_SPIN_LOCK = 'lucky_reward:spin:lock:';
// Logic 内
$lockKey = RedisKeyManagerService::luckyRewardSpinLockKey($uid);
$lock = RedLock::getInstance('default')->lock($lockKey, 5000);
if ($lock === false) {
throw new BusinessException('Spin is in progress, please try again');
}
try {
// ... 原 spin 业务 ...
} finally {
RedLock::getInstance('default')->unlock($lock);
}
```
- TTL **5000ms**:覆盖一次抽奖+事务;`RedLock::lock` 默认 `retryCount=3` 会在内部短暂重试——若需严格「一次拿不到就失败」,在 Logic 侧用 **单次 `SET NX`**`Redis::set($key, $token, 'EX', 5, 'NX')`)替代 RedLock或给 RedLock 封装 `tryLockOnce()`。**建议**:新增 private `tryAcquireSpinLockOnce()``SET NX EX 5`,符合 fail-fast 选型。
### 3. 辅助方法
- [`RedisKeyManagerService`](slot_console/app/service/RedisKeyManagerService.php):新增 `luckyRewardSpinLockKey(int $uid): string`
- 可选private `generateManualSpinId(int $uid, int $cycleId): string` 集中生成写库 id。
---
## 不改 / 兼容
- **表结构**`lucky_reward_spin_record.spin_id` + `uk_uid_spinid` 保留;值改为服务端生成。
- **records API**:仍返回 `spinId` 字段,无 breaking change。
- **开宝箱自动首次 Spin**:仍用 `auto_first:{uid}:{cycle_id}`,不受影响。
---
## 测试
| 项 | 做法 |
| --- | --- |
| 单元测 | 新增 `LuckyRewardSpinLockUnitTest`mock Redis 或使用可注入 lock 的测试双(若难 mock至少测 `generateManualSpinId` + validator 无 spin_id |
| Logic 单测 | 更新/新增:无 `spin_id` 参数签名;`isDuplicate` 恒 false |
| 集成测 | 若有 DB spin 集成测则去掉 payload `spin_id`;并发锁集成测可选(需 Redis |
当前仓库 **无** spin 集成测,以 Logic 单测 + 手动冒烟为主。
---
## 文档
- [`04_slot_console_活动主流程方案.md`](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md) §5改为 Redis 锁 + `spin_available`,去掉「前端 spin_id 必填」。
- [`00_整体技术方案.md`](docs/requirements/lucky_rewards/00_整体技术方案.md) §3.4 / §3.6:手动 Spin 幂等说明更新。
- [`lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 冒烟项:去掉「带 spin_id 幂等」。
- **YApi** spin 接口cat 115删除 request `spin_id` 必填;补充并发锁错误文案;**FE 约定**spin 失败/超时先调 status。
---
## 前端契约(联调说明)
```text
POST /api/lucky-reward/spin
Body: {} 或空
```
- 点击 Spin 后 **UI 防抖**(禁用按钮至响应返回)。
- 请求失败/超时:**不要**立即再次 spin`status` / `records``spinAvailable``myAmount`、最新 record。
- 若返回「Spin is in progress」稍后重试或等当前请求结束。
---
## 已知边界(产品已接受)
| 场景 | 行为 |
| --- | --- |
| 连点 | 第二笔拿不到锁 → 立即报错 |
| 弱网:已成功但响应丢失 | 再次 spin → `spin_available=0` 报错;靠 status/records 恢复 UI |
| 弱网:仍有多次数且用户再点 | 会消耗**下一次** Spin非重试上一把 |
---
## 涉及文件
- [`slot_console/app/api/controller/LuckyRewardController.php`](slot_console/app/api/controller/LuckyRewardController.php)
- [`slot_console/app/api/logic/LuckyRewardLogic.php`](slot_console/app/api/logic/LuckyRewardLogic.php)
- [`slot_console/app/api/validator/LuckyRewardValidator.php`](slot_console/app/api/validator/LuckyRewardValidator.php)
- [`slot_console/app/service/RedisKeyManagerService.php`](slot_console/app/service/RedisKeyManagerService.php)
- 测试 + 需求/deploy/YApi 文档

View File

@@ -0,0 +1,165 @@
---
name: Stats init 重复分析
overview: 已用生产数据确认auto_first 以 spin_source=1、prize_type=1、prize_amount_qf=init 落库,当前 statistics 会把同一笔开宝箱金额算两遍。修复方向是在 aggregateSpinStats 排除 spin_source=AUTO_FIRST保留 init + 手动 Spin 随机入账相加。
todos:
- id: verify-auto-first-row
content: 确认 slot_console 开宝箱 auto_first 记录的 prize_type / spin_source / prize_amount_qf 落库值
status: completed
- id: exclude-auto-first-stats
content: aggregateSpinStats 排除 spin_source=AUTO_FIRST并补 LuckyRewardSpinRecordModel 常量
status: completed
- id: add-stats-test
content: 补统计用例:仅开宝箱无手动 Spin 时 total_reward_amount_qf=init 总和,且 spin_total/random_hit_count=0
status: completed
isProject: false
---
# LuckyRewardStatsLogic 统计口径分析
## 直接回答
**不是。** `$spinStats` 里**没有**完整包含 `$initAmountTotalQf`,两者是**刻意分开**再相加的:
```php
// backend/slot_admin/app/game/logic/LuckyRewardStatsLogic.php
$initAmountTotalQf = (int) (clone $playerQuery)->sum('p.init_amount_qf');
$spinStats = $this->aggregateSpinStats($playerQuery);
$prizeAmountTotalQf = (int) ($spinStats['prize_amount_total_qf'] ?? 0);
$totalRewardAmountQf = $initAmountTotalQf + $prizeAmountTotalQf;
```
`$spinStats` 返回的是 **Spin 记录维度** 的聚合,与 player 表上的 `init_amount_qf` 来源不同:
| 字段 | 数据来源 | 含义 |
|------|----------|------|
| `$initAmountTotalQf` | `lucky_reward_player.init_amount_qf` | 开宝箱命中初始金额汇总 |
| `$spinStats['prize_amount_total_qf']` | `lucky_reward_spin_record.prize_amount_qf``prize_type=1` | 随机金额类 Spin **实际入账**汇总 |
| `$spinStats['spin_total']` 等 | `lucky_reward_spin_record` 行数 | 命中次数/比率,**不是金额** |
需求文档口径([02_管理后台方案.md](docs/requirements/lucky_rewards/02_管理后台方案.md) §7.2
> **总奖励金额** = `sum(player.init_amount_qf)` + `sum(spin_record.prize_amount_qf)`(开宝箱初始 + Spin 随机入账 = 实际投放)
因此 **`$initAmountTotalQf` 不能删**`total_reward_amount_qf` 本应是「init + **手动** Spin 随机入账」,不应把 auto_first 展示记录算进 prize 部分。
---
## 生产数据已确认重复计数
用户提供的真实行:
```sql
INSERT INTO lucky_reward_spin_record
(uid, cycle_id, spin_id, spin_source, prize_type, prize_amount_qf, my_amount_after_qf)
VALUES
(1545906, 46, 'auto_first:1545906:46', 1, 1, 9603, 9603);
```
字段解读(与 DDL 一致):
| 字段 | 值 | 含义 |
|------|-----|------|
| `spin_id` | `auto_first:1545906:46` | 开宝箱自动首次 SpinRecord 展示) |
| `spin_source` | `1` | 自动首次 |
| `prize_type` | `1` | 随机金额 |
| `prize_amount_qf` | `9603` | 与 `player.init_amount_qf` 相同 |
对 uid=1545906、cycle=46 若仅开宝箱、无手动 Spin
- `$initAmountTotalQf` = **9603**(来自 player
- `$spinStats['prize_amount_total_qf']` = **9603**auto_first 被 `prize_type=1` 命中)
- `$totalRewardAmountQf` = **19206**(应为 **9603**
同时 **`spin_total` / `random_hit_count`** 也会把 auto_first 算进 Spin 次数与命中率,导致指标失真(每个参与用户天然 +1 次 Spin、+1 次 random 命中)。
---
## `spin_total` 同样算错
**是的。** `$spinStats['spin_total']``lucky_reward_spin_record` **全表 count**,没有任何 `spin_source` 过滤:
```php
$spinTotal = (int) (clone $spinQuery)->count(); // 含 auto_first
```
对你给的 uid `1545906`:只开宝箱、从未手动 Spin 时:
| 指标 | 当前错误值 | 修正后应为 |
|------|------------|------------|
| `spin_total` | **1**auto_first | **0** |
| `random_hit_count` | **1**auto_first 且 prize_type=1 | **0** |
| `random_hit_rate` | **100%** | **0%** |
需求文档 [02_管理后台方案.md](docs/requirements/lucky_rewards/02_管理后台方案.md) §7.3 明细列 **Spin** 用的是 `player.spin_used`,注释为 **「不含初始自动」**;总览 `spin_total` 应与之一致,只统计**真实消耗 Spin 次数**的记录(`spin_source` 为每日/邀请/手动),不应含开宝箱 auto_first。
连带影响的字段(同一 `$spinQuery` 未过滤):
- `spin_total` — 分母偏大
- `random_hit_count` / `random_hit_rate` — 分子、分母都含 auto_first
- `cashout_hit_count` / `cashout_hit_rate` — 若 auto_first 不会 prize_type=3通常不受影响但仍应统一排除
- `spin_prize_hit_count` / `spin_prize_hit_rate` — 同上
- `prize_amount_total_qf` — 金额重复(见上)
修复时在 `$spinQuery` 基查询一次性加 `spin_source <> AUTO_FIRST`,上述字段一并修正。
---
## 根因
[`aggregateSpinStats()`](backend/slot_admin/app/game/logic/LuckyRewardStatsLogic.php) 只按 `prize_type=1` 过滤金额/次数,**未排除 `spin_source=1`auto_first**
```php
$prizeAmountTotalQf = (int) (clone $spinQuery)
->where('sr.prize_type', LuckyRewardSpinRecordModel::PRIZE_TYPE_RANDOM)
->sum('sr.prize_amount_qf');
```
C 端开宝箱写 auto_first 时为了 Record 展示使用了 `prize_type=1` + `prize_amount_qf=init`,与 My Amount 入账无关admin 统计误将其当作「Spin 随机入账」。
需求 [04_slot_console_活动主流程方案.md](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md)`auto_first` **仅动画/Record不叠加金额**
```mermaid
flowchart TD
openBox[openBox 开宝箱]
playerInit["player.init_amount_qf = 9603"]
autoFirst["spin_record auto_first prize_amount_qf = 9603"]
statsInit["initAmountTotalQf += 9603"]
statsPrize["prize_amount_total_qf += 9603"]
doubleCount["total_reward = 19206 重复"]
openBox --> playerInit
openBox --> autoFirst
playerInit --> statsInit
autoFirst --> statsPrize
statsInit --> doubleCount
statsPrize --> doubleCount
```
---
## 修复方案(待执行)
在 [`aggregateSpinStats()`](backend/slot_admin/app/game/logic/LuckyRewardStatsLogic.php) 中,**所有** spin 记录聚合(次数与金额)统一排除 auto_first
1. [LuckyRewardSpinRecordModel](backend/slot_admin/app/game/model/common/LuckyRewardSpinRecordModel.php) 增加常量:
- `SPIN_SOURCE_AUTO_FIRST = 1`
- `SPIN_SOURCE_DAILY = 2`
- `SPIN_SOURCE_INVITE = 3`(与 DDL 注释对齐)
2. `$spinQuery` 基查询增加:`->where('sr.spin_source', '<>', SPIN_SOURCE_AUTO_FIRST)`
- 影响:`spin_total``random_hit_count``cashout_hit_count``spin_prize_hit_count``prize_amount_total_qf`
3. **保持** `$totalRewardAmountQf = $initAmountTotalQf + $prizeAmountTotalQf` 不变
4. 补测试:仅开宝箱用户 → `total_reward_amount_qf === sum(init_amount_qf)`auto_first 行存在但不计入 prize
**不改 C 端落库**auto_first 继续用于 Record 展示;仅修正 admin 统计过滤。
**不建议**删掉 `$initAmountTotalQf` 或改为只 sum spin_record。
---
## 小结
| 问题 | 答案 |
|------|------|
| `$spinStats` 是否已包含 `$initAmountTotalQf` | **否**;但 `prize_amount_total_qf` 对 auto_first **重复计入了同一份 init** |
| 两处相加是否合理? | **公式合理**;当前实现因未排除 auto_first **结果错误** |
| 生产数据是否证实? | **是**uid 1545906 示例9603 被算成 19206 |
| `spin_total` 是否也算错? | **是**;仅开宝箱用户会显示 spin_total=1、random_hit_rate=100% |

View File

@@ -0,0 +1,145 @@
---
name: Support Invite 离线补推
overview: 用户提出的「离线写 Redis + WS 连接后补推」方案可行;项目已有 `user_websocket_connect` 事件与在线 Redis Set可在 `deliverInviteeSupportInvitePopup` 与连接回调中实现,无需回退 HomeEvent。
todos:
- id: pending-service
content: 新增 LuckyRewardSupportInvitePendingServiceRedis key/TTL、enqueue、flush、可选 sent 标记
status: completed
- id: deliver-branch
content: deliverInviteeSupportInvitePopup在线即时推离线 enqueue
status: completed
- id: ws-connect-flush
content: WebsocketConnectEventService::run 连接后 flush pendingsAdd 之后)
status: completed
- id: tests
content: 集成/单测:离线 enqueue + connect flush在线直推不写 Redis
status: completed
isProject: false
---
# Support Invite 离线 Redis 补推方案
## 结论:方案可行
你的思路与现网架构**匹配**,比把 Support Invite 塞回 HomeEvent 更贴切(仍只弹一次,且针对「注册时 WS 尚未连上」的竞态)。
现网已有能力:
| 能力 | 位置 |
| --- | --- |
| WS 连接 MQ | `slot_game` gateway → `console_bus` `TYPE_USER_WEBSOCKET_CONNECT` |
| 连接处理入口 | [`EventBus::websocketConnectEvent`](slot_console/app/command/EventBus.php) → [`WebsocketConnectEventService::run`](slot_console/app/service/event/WebsocketConnectEventService.php) |
| 在线判定 Redis Set | `RedisKeyManagerService::getUserOnlineKey()`connect 时 `sAdd`、disconnect 时 `sRem` |
| 即时弹窗 | [`WsService::notifyClientPOP`](slot_console/app/service/WsService.php) → hub MQ**离线会丢** |
[`DelayTipPopService`](slot_console/app/service/DelayTipPopService.php) 是「延时 N 秒再推 tipPop」的 ZSet**不适合**本场景;本需求是「等 WS 连上再推」,应走 **connect 时 flush**,不是 cron 扫延时队列。
```mermaid
sequenceDiagram
participant Bind as invite_bind_success
participant Logic as deliverInviteeSupportInvitePopup
participant Redis as Redis_pending
participant Hub as WsService
participant WS as websocketConnectEvent
Bind->>Logic: openBox + buildPopup
alt user_online
Logic->>Hub: notifyClientPOP
else user_offline
Logic->>Redis: SET payload EX TTL
end
WS->>Redis: GET pending
alt has_pending
WS->>Hub: notifyClientPOP
WS->>Redis: DEL
end
```
---
## 推荐实现(在 Redis 方案上略作增强)
### 1. 新增 `LuckyRewardPendingPopupService`(或 Logic 内 private + 小 Service
职责单一:**被邀请人 Support Invite 的 pending 投递**。
- **Redis Key**`lucky_reward:support_invite_popup:{uid}:{cycle_id}`(幂等,同一轮次只存一条)
- **Value**`json_encode` 后的 popList 单项(与现 `buildSupportInvitePopup` 结构一致)
- **TTL**:建议 **3060 分钟**(覆盖注册加载 + WS 握手;过短会丢弹,过长无必要)
- **写入**`SET key value EX ttl NX`NX 防止 bind 重试覆盖/重复)
### 2. 改 [`deliverInviteeSupportInvitePopup`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)
顺序不变:**先** `ensureInviteeAutoOpenBox`**再** `buildSupportInvitePopup`;推送逻辑改为:
```php
if ($this->isUserOnline($inviteeUid)) {
WsService::notifyClientPOP($inviteeUid, [$supportInvitePopup]);
return;
}
$this->pendingPopupService->enqueueSupportInvite($inviteeUid, $cycleId, $supportInvitePopup);
```
**在线判定**`Redis::sIsMember(RedisKeyManagerService::getUserOnlineKey(), $inviteeUid)`(与现网 disconnect 维护的 Set 一致)。
> 注意:存在 **竞态**bind 比 `user_websocket_connect` 早几十~几百 ms。可选增强推荐**在线则即时推 + 仍 SET NX pending**connect flush 时 **GETDEL**,若已推过则 payload 相同、客户端需幂等忽略重复 type。更简单做法**仅离线写 Redis**;若偶发丢弹可接受则不做双写。
### 3. WS 连接时 flush
在 [`WebsocketConnectEventService::run($uid)`](slot_console/app/service/event/WebsocketConnectEventService.php) 末尾(或 `EventBus::websocketConnectEvent` 调 Logic 一行):
1. 查当前 active `cycle_id`(与 `buildSupportInvitePopup` 同源)
2. `GETDEL lucky_reward:support_invite_popup:{uid}:{cycle_id}`
3. 有值 → `json_decode``WsService::notifyClientPOP($uid, [$popup])`
**只弹一次**:发送成功后 key 已 DEL重连不会重复除非 bind 再次 success 且 NX 允许新 key——同一 cycle 不会)。
### 4. 可选DB 兜底(比纯 Redis 更稳)
若担心 TTL 内仍未连 WSconnect 时除读 Redis 外,可 **fallback**
- `helper` 存在 + `box_opened_at > 0` + Redis 无 key + 从未发送标记
→ 再 `buildSupportInvitePopup` 推一次
发送标记可用 Redis `lucky_reward:support_invite_sent:{uid}:{cycle_id}` SET NX永久或 7d TTL。**与「只弹一次」产品一致**,且 bind 时 openBox 已落库,**不依赖 Redis 里缓存 payload**。
建议:**Redis 存 payload 为主connect 时 GETDELTTL 过期则 fallback 从 DB 重建一次**(实现成本低、容错更好)。
---
## 不建议的做法
- **不要**再挂 HomeEvent与「只弹一次、注册时触发」冲突且会每次回大厅重复弹
- **不要**复用 `user_pending_popup` 表(项目已废弃,见 deploy 文档)
- **不要**只用 `DelayTipPopService` 固定延时 N 秒N 难估,且 WS 未连上仍会丢)
---
## 改动文件(实施范围)
| 文件 | 改动 |
| --- | --- |
| 新建 `app/service/luckyReward/LuckyRewardSupportInvitePendingService.php` | enqueue / flush / isUserOnline 封装 |
| [`LuckyRewardInviteLogic.php`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) | `deliverInviteeSupportInvitePopup` 分支在线/离线 |
| [`WebsocketConnectEventService.php`](slot_console/app/service/event/WebsocketConnectEventService.php) | connect 时 flush pending |
| [`RedisKeyManagerService.php`](slot_console/app/service/RedisKeyManagerService.php) | 新增 key 常量 + 中文注释 |
| 单测/集成测 | mock Redis 或集成测:离线 enqueue → connect flush |
**不在本次范围**除非你要求YApi/05 文档、邀请人 Claim Now、helper 未落库排查。
---
## 风险与对策
| 风险 | 对策 |
| --- | --- |
| bind 早于 connect误判离线 | 可接受则只写 Redis要严格则 connect 必 flush + DB fallback |
| hub 已连但 console 在线 Set 未更新 | connect 事件顺序flush 放在 `websocketConnectEvent` **sAdd 之后** |
| 重复弹 | key 含 cycle_id + GETDEL + 客户端按 type 去重 |
| TTL 过期未连 WS | fallback 从 DB rebuildhelper + opened box |
---
## 结论
**可行,且是正确补洞方向**;实现上建议:**离线 Redis pending + WS connect flush**,并加 **DB fallback / sent 标记** 防止 TTL 丢弹。在线判定复用现有 `USER_ONLINE_SET`,接入点放在已存在的 `WebsocketConnectEventService`

View File

@@ -0,0 +1,92 @@
<!-- 5511b223-7953-4aa5-bd6e-94f0d6c56b21 -->
---
todos:
- id: "dep"
content: "在 php82 容器执行 composer require symfony/lock:7.4.9"
status: pending
- id: "factory"
content: "新增 app/support/OtaLockFactory.php 封装 symfony LockFactory + RedisStore用 support\\Redis::connection()->client()"
status: pending
- id: "refactor"
content: "重构 OtaCheckLogic 锁方法acquire(false) 重试+SERVICE_BUSYrelease(),删除手写 SET/Lua 与 support\\Redis 依赖"
status: pending
- id: "verify"
content: "运行 phpunit + php -l + 完成门禁,确认全绿"
status: pending
isProject: false
---
# 用 symfony/lock 7.4.9 替换 OTA 分布式锁
## 目标与范围
- 仅替换 [app/logic/OtaCheckLogic.php](app/logic/OtaCheckLogic.php) 中的锁实现(`withDeviceFirmwareLock` / `acquireLock` / `releaseLock`)。
- 业务流程(先查后建/复用、§7.5 幂等)、错误码 `SERVICE_BUSY`、TTL/重试参数语义保持不变。
- 单测/集成测试结构不变(仍依赖 docker `redis`,跳过守卫不变)。
## 为什么可行
- `php82` = 8.2.24,满足 symfony/lock 7.4PHP ≥ 8.2)。
- symfony `RedisStore` 接受原生 `\Redis`,可由 `support\Redis::connection()->client()` 取得(见 `vendor/illuminate/redis/Connections/Connection.php:81``client()`)。
- symfony `Lock` 自带唯一 token + 所有者校验的 `release()`,可删除手写 Lua 释放脚本。
```mermaid
flowchart LR
Logic[OtaCheckLogic] -->|create resource| Factory[OtaLockFactory]
Factory -->|RedisStore| RawRedis["support Redis connection client (\\Redis)"]
Logic -->|"acquire(false) 重试 / release()"| LockObj[Symfony Lock]
```
## 改动点
### 1. 依赖
-`php82` 容器内执行dev-environment 规则,禁止宿主机 php/composer
`docker exec -w /app/www/ai-device/ota php82 composer require symfony/lock:7.4.9`
- 结果会更新 [composer.json](composer.json) / `composer.lock` / `vendor`
### 2. 新增 `app/support/OtaLockFactory.php`
- 职责:封装 symfony 锁与 phpredis 客户端的装配,返回可用的 `LockInterface`
- 每次调用基于「当前」连接构建 `RedisStore`(不缓存客户端,规避 webman 连接池跨请求换连接导致的陈旧句柄):
```php
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Lock\Store\RedisStore;
use support\Redis;
final class OtaLockFactory
{
/** 基于当前 redis 连接创建一个带 TTL 的命名分布式锁 */
public static function create(string $resource, float $ttlSeconds): LockInterface
{
$store = new RedisStore(Redis::connection()->client());
return (new LockFactory($store))->createLock($resource, $ttlSeconds);
}
}
```
### 3. 重构 [app/logic/OtaCheckLogic.php](app/logic/OtaCheckLogic.php)
- 删除 `use support\Redis;`;新增 `use Symfony\Component\Lock\LockInterface;``use app\support\OtaLockFactory;`
- 保留常量 `LOCK_KEY_PREFIX` / `LOCK_TTL_SECONDS` / `LOCK_MAX_RETRY` / `LOCK_RETRY_INTERVAL_US`
- `withDeviceFirmwareLock`
```php
$lock = OtaLockFactory::create(self::LOCK_KEY_PREFIX . $deviceId . ':' . $firmwareId, (float) self::LOCK_TTL_SECONDS);
$this->acquireOrFail($lock);
try {
return $criticalSection();
} finally {
$this->releaseQuietly($lock);
}
```
- `acquireOrFail(LockInterface $lock)`:循环 `LOCK_MAX_RETRY` 次调用 `$lock->acquire(false)`,成功 return否则 `usleep(LOCK_RETRY_INTERVAL_US)`;用尽后 `Log::warning` + `throw new BusinessException(OtaErrorCode::SERVICE_BUSY)`
- `releaseQuietly(LockInterface $lock)``try { $lock->release(); } catch (Throwable) { Log::warning(...) }`释放失败不影响主流程TTL 兜底)。
- 删除手写 token 生成与 Lua 释放脚本(`acquireLock`/`releaseLock` 旧实现)。
## 验证
- `docker exec -w /app/www/ai-device/ota php82 ./vendor/bin/phpunit`(含 `OtaCheckLogicTest` 真连 redis 验证加锁/幂等)。
- 对改动文件容器内 `php -l`
- 运行完成门禁 `~/.cursor/skills/slot-backend-completion-report/scripts/report.sh`
## 备注 / 取舍
- 可选:将 [composer.json](composer.json) 的 `"php": ">=8.1"` 提升为 `>=8.2` 以与 symfony/lock 对齐(非必需,运行时已是 8.2)。
- 备选方案:不新增 `OtaLockFactory`,把装配内联为 `OtaCheckLogic` 私有方法;本方案选独立 support 类以隔离基础设施、便于复用与替换 Store。
- 阻塞策略:沿用 `acquire(false)` 有界重试而非 `acquire(true)` 无限阻塞,避免阻塞 webman worker并保留 `SERVICE_BUSY` 行为。

View File

@@ -0,0 +1,230 @@
<!-- 9333b12a-cba7-4c83-9a56-b9ca81467dd0 -->
---
todos:
- id: "db-tenant-code"
content: "新增 tenant_code 字段、唯一索引,更新 saimulti.sql 与存量回填脚本"
status: pending
- id: "server-generate-resolve"
content: "SystemOrganizationLogic 实现码生成、add 自动写入、appInfo code 分支LoginController 接收 tenant_code"
status: pending
- id: "tenant-vue-code-mode"
content: "tenant-vue siteStore/App.vue/http/.env/types 从 app_id 模式切换为 tenant_code 模式"
status: pending
- id: "admin-vue-display"
content: "admin-vue 机构列表与编辑弹窗展示 tenant_code只读及可选登录链接"
status: pending
- id: "docs-verify"
content: "更新 README跑 verify 脚本与手动登录联调"
status: pending
isProject: false
---
# tenant_code 租户登录改造方案
## 现状
当前租户端通过 [`tenant-vue/.env`](tenant-vue/.env) 的 `VITE_APP_MODE` 区分两种模式:
| 模式 | 环境值 | 识别方式 | 入口示例 |
|------|--------|----------|----------|
| app_id | `appid` | URL `?app_id=1` | 可猜测自增 id |
| domain | `domain` | `location.host` | 管理端配置域名 |
核心链路:
```mermaid
sequenceDiagram
participant Browser
participant TenantVue
participant Server
participant DB
Browser->>TenantVue: ?app_id=1 或域名访问
TenantVue->>Server: GET /saimulti/appInfo
Server->>DB: 按 id 或 domain 查 sm_system_organization
Server-->>TenantVue: 返回 id/title/logo...
TenantVue->>Server: 后续请求 Header App-Id=机构id
```
关键文件:
- 前端站点识别:[`tenant-vue/src/store/modules/site.ts`](tenant-vue/src/store/modules/site.ts)、[`tenant-vue/src/App.vue`](tenant-vue/src/App.vue)、[`tenant-vue/src/utils/http/index.ts`](tenant-vue/src/utils/http/index.ts)
- 后端入口:[`server/plugin/saimulti/app/controller/LoginController.php`](server/plugin/saimulti/app/controller/LoginController.php) → [`SystemOrganizationLogic::appInfo()`](server/plugin/saimulti/app/logic/system/SystemOrganizationLogic.php)
- 租户隔离:全站仍依赖 `App-Id` 请求头([`TenantController`](server/plugin/saimulti/basic/TenantController.php)、[`TenantModel`](server/plugin/saimulti/basic/TenantModel.php)**内部继续使用数字机构 id不改为 tenant_code**
## 目标架构
`appid` 模式替换为 `code` 模式domain 模式不动):
```mermaid
sequenceDiagram
participant Browser
participant TenantVue
participant Server
participant DB
Browser->>TenantVue: /auth/login?tenant_code=A3K9M2
TenantVue->>Server: GET /saimulti/appInfo?tenant_code=A3K9M2&mode=code
Server->>DB: WHERE tenant_code=A3K9M2
Server-->>TenantVue: id, title, logo, tenant_code...
Note over TenantVue: 持久化 tenant_code + 解析后的 org id
TenantVue->>Server: POST /tenant/login, Header App-Id=1
```
**安全收益**:对外 URL 只暴露 6 位随机码(大写+数字,排除 0/O、1/I/L不再暴露可枚举的自增 id。
**tenant_code 获取方式**:与现有 app_id 一致,从浏览器 URL 查询参数自动读取([`getUrlQueryValue`](tenant-vue/src/store/modules/site.ts) 已支持 hash 路由),**登录页无需新增输入框**(避免与验证码字段 `code` 混淆)。
---
## 1. 数据库变更
在 [`sm_system_organization`](db/saimulti.sql) 增加字段:
```sql
ALTER TABLE `sm_system_organization`
ADD COLUMN `tenant_code` varchar(6) NOT NULL COMMENT '租户访问码6位随机' AFTER `domain`,
ADD UNIQUE INDEX `uk_tenant_code` (`tenant_code`);
```
同步更新 [`db/saimulti.sql`](db/saimulti.sql) 建表语句与 seed 数据。
**存量机构回填**:新增独立迁移脚本(如 `db/migrate_tenant_code.sql` 或由一次性 PHP 命令生成),为已有记录生成不重复 6 位码;规则与新建一致。
---
## 2. Server 后端
### 2.1 Model
[`SystemOrganization.php`](server/plugin/saimulti/app/model/system/SystemOrganization.php) 补充类 PHPDoc表说明 + `@property string $tenant_code 租户访问码`)。
可选:新增 `findEnabledByTenantCode(string $tenantCode)` 查询方法。
### 2.2 Logic — 核心改动
[`SystemOrganizationLogic.php`](server/plugin/saimulti/app/logic/system/SystemOrganizationLogic.php)
- **`generateUniqueTenantCode()`**private
- 字符集:`ABCDEFGHJKLMNPQRSTUVWXYZ23456789`32 字符)
- 循环生成 6 位 + 查重,直到唯一
- **`add($data)`** 重写/扩展:保存前若未传 `tenant_code`,自动调用生成器写入
- **`appInfo($identifier, $mode)`** 扩展分支:
- `mode === 'domain'` → 现有逻辑不变
- `mode === 'code'``where('tenant_code', $identifier)` 查询
- 移除或废弃 `mode !== 'domain'` 时按自增 id 查询的路径(原 appid 模式)
- **`appInfo` 返回字段**增加 `tenant_code`(供前端展示/持久化)
### 2.3 Controller
[`LoginController::appInfo()`](server/plugin/saimulti/app/controller/LoginController.php)
- 读取 `tenant_code` 查询参数code 模式)
- `mode=code` 时传入 `appInfo($tenantCode, 'code')`
- domain 模式保持 `appid=host` + `mode=domain`
**不改动** `App-Id` 头解析逻辑 — 租户 API 仍接收机构数字 id。
---
## 3. tenant-vue 租户端
### 3.1 环境配置
[`tenant-vue/.env`](tenant-vue/.env)
```env
# 模式1: code 通过 URL ?tenant_code= 区分租户
# 模式2: domain 通过域名区分
VITE_APP_MODE = code
```
### 3.2 siteStore 重构
[`tenant-vue/src/store/modules/site.ts`](tenant-vue/src/store/modules/site.ts)
- 常量 `TENANT_CODE_QUERY_KEY = 'tenant_code'`
- `SiteInfoParams` 改为 `{ tenantCode: string; mode: string }`(替代 `appid`
- `loadSiteInfo``/saimulti/appInfo``tenant_code` + `mode`
- 解析成功后:`info.id` 用于 `App-Id` 头;`tenant_code` 持久化到 localStorage刷新后无需 URL 参数也能识别租户)
- domain 模式分支逻辑保持不变
### 3.3 路由监听
[`tenant-vue/src/App.vue`](tenant-vue/src/App.vue)
- `route.query.app_id``route.query.tenant_code`
- 相应函数重命名(如 `getRouteTenantCode`
### 3.4 HTTP 拦截器
[`tenant-vue/src/utils/http/index.ts`](tenant-vue/src/utils/http/index.ts)
- `appMode === 'code'`:优先 `siteStore.info.id` 作为 `App-Id`;未加载时用已持久化的 org id
- 移除 `appid` 模式分支
### 3.5 类型定义
[`tenant-vue/src/types/api/api.d.ts`](tenant-vue/src/types/api/api.d.ts)`siteInfoResponse` 增加 `tenant_code?: string`
---
## 4. admin-vue 总后台
### 4.1 机构列表
[`admin-vue/src/views/admin/panel/organization/index.vue`](admin-vue/src/views/admin/panel/organization/index.vue) 增加列:
- `tenant_code` — 标签「租户码」
- 可选:展示租户登录链接模板 `租户端地址?tenant_code=xxx`(方便复制发给客户)
### 4.2 编辑弹窗
[`admin-vue/src/views/admin/panel/organization/modules/edit-dialog.vue`](admin-vue/src/views/admin/panel/organization/modules/edit-dialog.vue)
- **新增**时:不展示 tenant_code后端自动生成
- **编辑**时:只读展示 `tenant_code`(不可修改,保证链接稳定)
- 不在表单提交中包含 tenant_code防篡改
---
## 5. 文档
更新 [`README.md`](README.md) 租户前端配置章节:
- 模式 1`code` + `?tenant_code=A3K9M2`
- 模式 2`domain`(不变)
- 删除 app_id 相关说明
---
## 6. 兼容与测试要点
| 场景 | 预期 |
|------|------|
| 新机构创建 | 自动生成唯一 6 位 tenant_code |
| `?tenant_code=xxx` 访问 | 加载站点信息,登录成功 |
| 刷新页面(无 URL 参数) | localStorage 中 tenant_code + org id 仍可识别 |
| 错误/不存在 tenant_code | appInfo 报错「未找到该应用」 |
| domain 模式部署 | 行为与改造前一致 |
| 旧 `?app_id=1` 链接 | **不再支持**(按你的替换需求) |
手动验证路径:
1. 总后台新建机构 → 列表出现 tenant_code
2. 租户端 `http://localhost:16888/?tenant_code=XXXXXX` → Logo/标题正确
3. admin/admin 登录 → 租户 API 正常(菜单、用户信息)
4. domain 模式 `.env` 切换后仍可用
---
## 改动范围摘要
| 层 | 文件 | 动作 |
|----|------|------|
| DB | `db/saimulti.sql` + 迁移脚本 | 加字段、唯一索引、存量回填 |
| Server | `SystemOrganizationLogic.php` | 生成码、appInfo code 分支、add 钩子 |
| Server | `LoginController.php` | 接收 tenant_code 参数 |
| Server | `SystemOrganization.php` | PHPDoc |
| tenant-vue | `site.ts`, `App.vue`, `http/index.ts`, `.env`, `api.d.ts` | appid → code |
| admin-vue | `organization/index.vue`, `edit-dialog.vue` | 展示 tenant_code |
| Docs | `README.md` | 更新模式说明 |
**刻意不改**`App-Id` 请求头机制、TenantModel 全局 scope、登录接口参数验证码 `code` 保持不变)。

View File

@@ -0,0 +1,136 @@
---
name: toBalance 清零分析
overview: 产品要求 To Balance 后客户端仍展示领取金额。推荐**保留 my_amount_qf 清零**(进度已兑现),在 status 接口对已提取用户用 cashout_record 回填 myAmountDisplay并禁止已提取用户继续 Spin 污染状态。
todos:
- id: build-state-withdrawn-display
content: buildStateEntityplayerStatus=已提取时myAmountDisplay 取自 lucky_reward_cashout_record.amount_qf大单位
status: completed
- id: block-spin-after-withdrawn
content: executeManualSpinstatus=已提取时拒绝 Spin防 status/my_amount 被改回可提取)
status: completed
- id: keep-zero-my-amount
content: toBalance 事务内保留 my_amount_qf=0 + status=已提取(不改删除清零逻辑)
status: completed
- id: sync-docs-yapi
content: 更新 lucky_reward_api.md、04 需求 §7、YApi
status: completed
isProject: false
---
# To Balance 后展示领取金额 — 方案(迭代)
## 产品诉求(新增)
客户端 To Balance **成功之后**,仍要在活动页展示**领取时的金额**(含刷新 status、再次进入活动不能只靠 toBalance 响应本地缓存)。
当前问题:`toBalance``my_amount_qf = 0` 后,`POST /api/lucky-reward/status``myAmountDisplay` 变为 `0.00`,客户端无法继续展示 $10.00 等已领取金额。
---
## 推荐方案:库内清零 + status 展示回填(推荐)
**不改为「不清零 my_amount_qf」**,而是区分「活动进度」与「展示金额」:
| 层 | 行为 |
| --- | --- |
| DB `my_amount_qf` | **继续清零** — 表示本轮可 Spin 累积的进度已兑现,避免尾差/Spin 叠加 |
| DB `status` | **已提取(3)** — 客户端据此隐藏 To Balance 按钮 |
| status 响应 `myAmountDisplay` | **已提取时**从 [`LuckyRewardCashoutRecordModel::findSuccessByUidAndCycle`](slot_console/app/model/common/LuckyRewardCashoutRecordModel.php) 读 `amount_qf`,经 `formatAmountDisplay()` 返回 |
改动点:[`LuckyRewardLogic::buildStateEntity()`](slot_console/app/api/logic/LuckyRewardLogic.php)(约 788806 行)
```php
// 伪代码
if ($hasOpenedBox && (int)$activityPlayer->status === STATUS_WITHDRAWN) {
$cashout = LuckyRewardCashoutRecordModel::findSuccessByUidAndCycle($uid, $cycleId);
$myAmountQf = $cashout !== null ? (int)$cashout->amount_qf : 0;
} else {
$myAmountQf = $hasOpenedBox ? (int)$activityPlayer->my_amount_qf : 0;
}
```
展示值为**实际入账金额**`floor(my_amount/10)*10` 后的值),与 toBalance 响应 `amountDisplay` 一致,语义正确。
```mermaid
flowchart TD
toBalance[toBalance 成功] --> zero["my_amount_qf=0\nstatus=已提取"]
zero --> cashoutRow[cashout_record 保留 amount_qf]
cashoutRow --> statusPoll[客户端调 status]
statusPoll --> display["myAmountDisplay=提取金额\nplayerStatus=3"]
```
---
## 备选方案:取消清零(不推荐单独使用)
删除 `my_amount_qf = 0` 一行status 直接读库内 `my_amount_qf` 即可展示。
**缺点**(见原分析):
- 尾差残留(转入 floor 后库内仍 > 转入额)
- 提取后若还有 Spin[`executeManualSpin`](slot_console/app/api/logic/LuckyRewardLogic.php) 会改 `my_amount_qf` / 把 `status` 改回可提取(2)
- 与需求文档 §7「my_amount 本笔归零」不一致
若走此方案,**必须**同步加 Spin 拦截,否则状态机会脏。
---
## 必须配套:已提取用户禁止 Spin
无论是否清零,[`executeManualSpin()`](slot_console/app/api/logic/LuckyRewardLogic.php) 当前**不校验** `STATUS_WITHDRAWN`。提取后若 `spin_available > 0`(邀请 Spin 等),仍可能:
- 增加 `my_amount_qf`
-`status` 从 3 改回 2
建议在 Spin 入口增加:
```php
if ((int)$activityPlayer->status === LuckyRewardPlayerModel::STATUS_WITHDRAWN) {
throw new BusinessException('Already withdrawn this cycle');
}
```
资金安全仍由 `cashout_record` 幂等保证;此拦截主要为**状态一致 + 展示正确**。
---
## 客户端约定(无需新字段)
沿用现有 [`LuckyRewardStateEntity`](slot_console/app/entity/luckyReward/LuckyRewardStateEntity.php)
- `playerStatus === 3`(已提取)→ 隐藏 To Balance / 展示「已领取」态
- `myAmountDisplay` → 仍展示进度条/金额数字(提取后由服务端回填为领取金额)
- toBalance 当场成功仍可用响应 `amountDisplay`;之后以 status 为准
**不新增** `withdrawnAmountDisplay` 字段,除非客户端希望区分「当前可提进度」与「历史已提」——当前产品只需展示领取金额,复用 `myAmountDisplay` 即可。
---
## 需求文档调整
[`04_slot_console_活动主流程方案.md`](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md) §7 第 6 步建议改为:
> 成功:写 cashout_record`player.status=已提取`、**`my_amount_qf` 归零(进度清空)****status 接口对已提取用户 `myAmountDisplay` 取 cashout_record.amount_qf 展示**。
---
## 实施范围(待你确认后执行)
| 文件 | 改动 |
| --- | --- |
| [`LuckyRewardLogic.php`](slot_console/app/api/logic/LuckyRewardLogic.php) | `buildStateEntity` 已提取回填;`executeManualSpin` 拦截已提取 |
| 集成测 | 新增/扩展toBalance 后 status 的 `myAmountDisplay` 等于提取额 |
| [`lucky_reward_api.md`](slot_console/doc/lucky_reward_api.md) + YApi #554/#561 | status 字段说明:已提取时 myAmountDisplay 含义 |
| 需求 §7 | 与实现对齐 |
**不改动**`toBalance``my_amount_qf = 0`(保留)。
---
## 原分析问题答复(更新结论)
| 问题 | 更新结论 |
| --- | --- |
| 必须清零吗? | **库内建议继续清零**;展示不清零,改由 status 回填 |
| 不清零唯一目的「展示金额」? | **否**;用 cashout_record 回填更干净 |
| 重复打款? | 仍靠 cashout_record与是否清零无关 |

View File

@@ -0,0 +1,320 @@
<!-- 8500b436-6684-4cb3-a26f-8d927dd70f9b -->
---
todos:
- id: "define-constants"
content: "在 slot-foundation 新增 WalletEventMQ 常量exchange + routingKey"
status: pending
- id: "add-publisher"
content: "在 slot-wallet 新增 WalletBetSuccessMqPublisher封装 {type, uid, data, ts} 载荷组装"
status: pending
- id: "extend-wallet-dto"
content: "slot-wallet / slot-pwa DTO 与 Validate 增加 provider_code、game_code 透传字段"
status: pending
- id: "hook-bet-success"
content: "在 WalletBetWinLogic::bet() commit 后调用 publisher幂等命中跳过"
status: pending
- id: "pwa-pass-game-context"
content: "slot-pwa CashLogic 调 wallet 时透传 provider_code如 pop与 game_code"
status: pending
- id: "consumer-bind"
content: "各消费服务自建 queue 并 bind topic 模式wallet.bet.success / wallet.bet.#"
status: pending
isProject: false
---
# wallet.bet.success 消息体设计方案
## 背景与定位
当前 `slot-wallet` 下注成功后已有两类 MQ但都不适合作为**通用钱包事件总线**
| 现有通道 | 载荷 | 局限 |
|---|---|---|
| `slot_console` / `console_bus` | `{ uid, type:'bet', data:{ source, amount } }` | 仅统计,缺 biz_id / round_id / 资金拆分 |
| `slot_activity` / `trial_reward_bus` | `{ type, uid, data, ts }` | 活动专用,且目前由 **slot-pwa** 在钱包 API 返回后投递,非 wallet 权威源 |
| `slot_hub` | WebSocket 钱包刷新 | 面向客户端,非业务事件 |
`slot-foundation` 文档/测试中的示例 `{"uid":1001,"bet_amount":500}` 过于简陋,无法支撑多服务幂等与金额语义区分。
**新事件定位**wallet 事务提交后的**权威下注成功事件**,供 activity / console / 统计 / 返水等各自按 Topic 模式订阅(如 `wallet.bet.#``wallet.#`)。
```mermaid
sequenceDiagram
participant Caller as 调用方_PWA或游戏网关
participant Wallet as slot_wallet
participant DB as wallet_log
participant Exchange as slot.wallet.event.exchange
participant Activity as slot_activity
participant Stats as 统计服务
Caller->>Wallet: bet(biz_id, fee, round_id, ...)
Wallet->>DB: commit 写入 biz_type=bet
Wallet->>Exchange: publish wallet.bet.success
Exchange-->>Activity: 各自 queue 绑定
Exchange-->>Stats: 各自 queue 绑定
```
---
## 推荐信封结构
沿用 [`TrialRewardMqPublisher`](slot-wallet/app/service/mq/TrialRewardMqPublisher.php) 的约定,便于消费方统一解析:
```json
{
"type": "wallet.bet.success",
"uid": 12345,
"ts": 1718092800,
"data": { }
}
```
- `type`:与 routingKey 一致,便于日志/死信/转发时脱离 routing 元数据也能识别
- `uid`:放信封层,消费方可快速过滤
- `ts`事件产生时间Unix 秒),非 DB `created_at`
- `data`:业务载荷(见下)
---
## 推荐 `data` 字段(通用可扩展)
### 1. 幂等与追溯(必填)
| 字段 | 来源 | 说明 |
|---|---|---|
| `biz_id` | `WalletUpdateRequestDTO->biz_id` | 业务幂等键,消费方应用 `uid + biz_id` 去重 |
| `ledger_id` | `wallet_log.id` | wallet 侧唯一流水号,需查账时可直接定位 |
| `round_id` | request | 关联同局 win |
| `trace_id` | request可空 | 链路追踪 |
### 2. 渠道上下文(必填)
| 字段 | 来源 |
|---|---|
| `currency` | request |
| `source` | request |
| `organization` | request |
### 3. 金额语义(必填,三者不可混用)
下注存在三种路径([`WalletBetWinLogic::bet()`](slot-wallet/app/api/logic/WalletBetWinLogic.php)),金额字段必须区分:
| 字段 | 含义 | 计算规则 |
|---|---|---|
| `bet_amount` | 名义下注额 | 恒等于 request `fee`(最小货币单位,*1000 |
| `wallet_deduct_amount` | 实际扣款额 | real/trial = `fee`FS 代付 = `0` |
| `valid_bet_amount` | 计入打码/有效投注额 | real = `betResult.withdraw + betResult.deposit`trial = `0`FS 代付 = `fee`(全额计入,与 [`TrialValidBetNotifyService`](slot-wallet/app/service/trial/TrialValidBetNotifyService.php) 一致) |
> 消费方按业务选用:`bet_amount` 做流水统计;`valid_bet_amount` 做活动/返水;`wallet_deduct_amount` 做资金变动核对。
### 4. 下注分类(必填)
| 字段 | 取值 | 判定 |
|---|---|---|
| `bet_mode` | `trial` / `real_money` / `free_spin` | 对应三条执行分支 |
辅助布尔字段(便于过滤,与 `bet_mode` 冗余但实用):
- `is_fs_paid_bet`0/1
- `fs_account_id`FS 路径时 > 0否则 0
### 5. 资金拆分摘要real_money 路径建议带trial/FS 可简化)
```json
"deduction": {
"bonus": 0,
"deposit": 3000,
"withdraw": 2000,
"hit_side": "deposit"
}
```
来源:[`BetService::execute()`](slot-wallet/app/service/wallet/BetService.php) 返回的 `betResult`。供返水、RTP、资金归因等消费方使用。
**不建议**在 MQ 中带完整 `fund_detail` / `remark` JSON体积大、含 lot_no 等内部细节);需要时可凭 `ledger_id` 回查 `wallet_log`
### 6. 游戏身份(多上游平台场景,建议必填)
slot-pwa 已有完整游戏映射链(见下),但 **slot-wallet 不查 g_game 表**,因此游戏身份必须由调用方(通常是 slot-pwa在下注请求中透传wallet 原样写入 MQ。
```mermaid
flowchart LR
subgraph pwa [slot_pwa]
ProviderCode["provider_code 如 pop"]
ExternalCode["vendor_game_id 即 external_game_code"]
GameCode["game_code 本平台编码"]
end
subgraph mapping [g_game_platform_mapping]
MapRow["platform_id + external_game_code"]
end
subgraph game [g_game]
GameRow["game_code 全局唯一"]
end
ProviderCode --> MapRow
ExternalCode --> MapRow
MapRow --> GameRow
GameRow --> GameCode
```
| 字段 | 对应 slot-pwa 概念 | 说明 |
|---|---|---|
| `provider_code` | `GPlatformModel.code` / `GameRoundModel.provider_code` | 上游平台编码,如 `pop`;多平台并存时**必填** |
| `game_code` | `GGameModel.game_code` / `PopTransferCallbackContext::gameCode()` | 本平台全局唯一游戏编码;消费方可直接关联 `g_game` |
| `vendor_game_id` | `GGamePlatformMappingModel.external_game_code` | 上游原始游戏 IDPOP 回调 `gameid`);与 `provider_code` 组合可唯一定位 mapping |
| `game_category` | `WalletTrialGameContextResolver::resolveGameCategory()` | 如 `SLOTS`;默认 `SLOTS` |
**唯一定位规则**(与 [`PopGameResolveService`](slot-pwa/app/service/game/PopGameResolveService.php) 一致):
- 主键语义:`provider_code` + `vendor_game_id``g_game_platform_mapping``g_game`
- 消费方若只需本平台游戏:读 `game_code` 即可
- 消费方若需区分上游来源:用 `provider_code` + `vendor_game_id`
- 三者齐全时消费方可交叉校验,避免 mapping 变更导致歧义
当前 gap[`CashLogic::invokeWalletBetOrWin()`](slot-pwa/app/pop/logic/CashLogic.php) 已解析出 `boundGame``providerCode()`,但调 wallet 时**仅传了** `vendor_game_id` / `game_category`**未传** `provider_code` / `game_code`——落地时需补齐。
wallet 层**不持久化**游戏字段到 `wallet_log`,必须在 commit 后从 request 即时写入 MQ。
---
## 完整示例
### 真实资金下注
```json
{
"type": "wallet.bet.success",
"uid": 12345,
"ts": 1718092800,
"data": {
"biz_id": "pg_tx_20240611_001",
"ledger_id": 987654321,
"currency": "USD",
"round_id": "round_abc123",
"source": "myslot",
"organization": 1001,
"trace_id": "trace_xyz",
"bet_amount": 5000,
"wallet_deduct_amount": 5000,
"valid_bet_amount": 5000,
"bet_mode": "real_money",
"is_fs_paid_bet": 0,
"fs_account_id": 0,
"provider_code": "pop",
"game_code": "pop_sweet_bonanza",
"game_category": "SLOTS",
"vendor_game_id": "pg_soft_001",
"deduction": {
"bonus": 0,
"deposit": 3000,
"withdraw": 2000,
"hit_side": "deposit"
}
}
}
```
### FS 代付下注
```json
{
"type": "wallet.bet.success",
"uid": 12345,
"ts": 1718092800,
"data": {
"biz_id": "pg_tx_fs_001",
"ledger_id": 987654322,
"currency": "USD",
"round_id": "round_fs_001",
"source": "myslot",
"organization": 1001,
"trace_id": "",
"bet_amount": 2000,
"wallet_deduct_amount": 0,
"valid_bet_amount": 2000,
"bet_mode": "free_spin",
"is_fs_paid_bet": 1,
"fs_account_id": 5566,
"provider_code": "pop",
"game_code": "pop_sweet_bonanza",
"game_category": "SLOTS",
"vendor_game_id": "pg_soft_001",
"deduction": {
"bonus": 0,
"deposit": 0,
"withdraw": 0,
"hit_side": ""
}
}
}
```
### 试玩期下注
```json
{
"type": "wallet.bet.success",
"uid": 12345,
"ts": 1718092800,
"data": {
"biz_id": "trial_bet_001",
"ledger_id": 987654323,
"currency": "USD",
"round_id": "round_trial_001",
"source": "myslot",
"organization": 1001,
"trace_id": "",
"bet_amount": 1000,
"wallet_deduct_amount": 1000,
"valid_bet_amount": 0,
"bet_mode": "trial",
"is_fs_paid_bet": 0,
"fs_account_id": 0,
"provider_code": "pop",
"game_code": "pop_trial_slots",
"game_category": "SLOTS",
"vendor_game_id": "pg_trial_001",
"deduction": {
"bonus": 1000,
"deposit": 0,
"withdraw": 0,
"hit_side": "bonus"
}
}
}
```
---
## 关键行为约定
1. **仅首次成功投递**:幂等命中(`findByBizIdAndType` 已有记录)时**不**发 MQ避免重复消费。
2. **投递时机**`commit()` 之后,与现有 `sendConsoleBus('bet')` 同级([`WalletBetWinLogic` L106-108](slot-wallet/app/api/logic/WalletBetWinLogic.php))。
3. **失败策略**MQ 发送失败只记 warning 日志,**不回滚**已提交的钱包事务(与 `TrialRewardMqPublisher` 一致)。
4. **消费方幂等**:建议以 `uid + biz_id``ledger_id` 做唯一约束/去重。
5. **与 trial_reward_bus 关系**:短期可并存;长期 activity 可改为订阅 `wallet.bet.success` 并按 `bet_mode` / `valid_bet_amount` 自行路由,逐步去掉 PWA 侧重复投递。
---
## 若落地实现(后续步骤)
1. **slot-foundation**:新增 [`WalletEventMQ`](slot-foundation/src/Constants/MQ/) 常量类(`EXCHANGE = slot.wallet.event.exchange``ROUTING_KEY_BET_SUCCESS = wallet.bet.success`)。
2. **slot-wallet**
- `WalletUpdateRequestDTO` / Validate 增加 `provider_code``game_code`(字符串,可空但游戏下注场景应由调用方传入)
- 新增 `WalletBetSuccessMqPublisher`(或通用 `WalletEventMqPublisher`
-`WalletBetWinLogic::bet()` commit 后组装上述 `data` 并 publish
- 抽取 `resolveBetMode()` / `resolveValidBetAmount()` 私有方法,避免金额语义散落
3. **slot-pwa**(游戏上下文来源):
- `WalletWinOrBetRequestDTO` 增加 `provider_code``game_code`
- [`CashLogic::invokeWalletBetOrWin()`](slot-pwa/app/pop/logic/CashLogic.php) 从 `transferContext->providerCode()``boundGame->game_code` 透传
- [`WalletService::appendTrialGameContext()`](slot-pwa/app/service/WalletService.php) 非空时写入请求体
- 后续新上游平台(非 pop沿用同一字段平台 code 取自各自 `providerCode()` 实现
4. **消费方**:各服务自建 queue + bind`wallet.bet.success``wallet.bet.#`),按 `provider_code` / `game_code` 过滤统计。
---
## 设计原则小结
- **信封统一**`{ type, uid, data, ts }`,与 activity 事件一致
- **金额三分**`bet_amount` / `wallet_deduct_amount` / `valid_bet_amount`,避免 FS、trial、real 混用
- **自洽但不臃肿**:含消费方 80% 场景所需字段;深度明细靠 `ledger_id` 回查
- **游戏三元组**`provider_code` + `vendor_game_id` + `game_code`,对齐 slot-pwa 映射,支持多上游平台
- **权威源在 wallet**:从 PWA 侧活动通知逐步收敛到 wallet 发出的事件;游戏身份由 PWA 解析后透传

View File

@@ -0,0 +1,106 @@
<!-- 2b9f6c44-867e-43e5-b054-01a0ea21c12a -->
---
todos:
- id: "scaffold"
content: "创建 webman-log 目录与 composer.json、.gitignore、phpunit.xml.dist"
status: pending
- id: "src"
content: "复制 SeasLogHandler / SeasLogLineFormatter / TraceContext 到 src 并改为 Quanfuxia\\Log 命名空间"
status: pending
- id: "tests"
content: "复制 testsbootstrap、config/app、config/log、Log 测试)并改命名空间引用"
status: pending
- id: "readme"
content: "编写新库 readme.md用途、安装、log.php 接入示例、ext-seaslog 要求)"
status: pending
- id: "verify"
content: "容器内 composer install 并运行 phpunit 验证"
status: pending
isProject: false
---
# webman-log 独立库拆分方案
## 目标与决策
- 位置:同级目录 `/Users/ray/Documents/project/www/ray/webman-log`
- 包名 `quanfuxia/log`,命名空间 `Quanfuxia\Log\`
- 完全独立:自带一份 trace 上下文,不依赖 `slot/foundation`
- 原库 `slot-foundation/src/Log` 及其引用保持不动(仅复制)
## 来源文件(复制并改命名空间)
- [src/Log/SeasLogHandler.php](/Users/ray/Documents/project/www/ray/slot-foundation/src/Log/SeasLogHandler.php) → `webman-log/src/SeasLogHandler.php`,命名空间改为 `Quanfuxia\Log``use slot\foundation\Trace\TraceContext` 改为 `use Quanfuxia\Log\Trace\TraceContext`
- [src/Log/SeasLogLineFormatter.php](/Users/ray/Documents/project/www/ray/slot-foundation/src/Log/SeasLogLineFormatter.php) → `webman-log/src/SeasLogLineFormatter.php`,命名空间改为 `Quanfuxia\Log`
- [src/Trace/TraceContext.php](/Users/ray/Documents/project/www/ray/slot-foundation/src/Trace/TraceContext.php) → `webman-log/src/Trace/TraceContext.php`,命名空间改为 `Quanfuxia\Log\Trace`(自带,保证独立)
## 新建库目录结构
```text
webman-log/
composer.json
.gitignore
phpunit.xml.dist
readme.md
src/
SeasLogHandler.php # Quanfuxia\Log
SeasLogLineFormatter.php # Quanfuxia\Log
Trace/TraceContext.php # Quanfuxia\Log\Trace
tests/
bootstrap.php
config/
app.php
log.php
Log/
SeasLogLineFormatterTest.php
```
## composer.json 要点
```json
{
"name": "quanfuxia/log",
"type": "library",
"autoload": { "psr-4": { "Quanfuxia\\Log\\": "src/" } },
"autoload-dev": { "psr-4": { "Tests\\": "tests/" } },
"require": {
"php": ">=8.2",
"monolog/monolog": "^2.0",
"workerman/webman-framework": "^2.1"
},
"suggest": { "ext-seaslog": "写入 SeasLog 需要该扩展" },
"require-dev": { "phpunit/phpunit": "^11.5" }
}
```
说明:保留 `workerman/webman-framework`,因为 `TraceContext``Webman\Context``SeasLogHandler``runtime_path()` / `request()` 辅助函数。
## 依赖关系
```mermaid
graph LR
Monolog[Monolog Logger] --> Handler[SeasLogHandler]
Handler --> Formatter[SeasLogLineFormatter]
Handler --> Trace[TraceContext]
Handler --> SeasLog[ext-seaslog]
Trace --> Ctx[Webman Context]
```
## 测试与配置
- 复制并改命名空间:`tests/Log/SeasLogLineFormatterTest.php``use Quanfuxia\Log\...`
- 复制 `tests/bootstrap.php``tests/config/app.php`
- 复制 `tests/config/log.php` 并把 handler/formatter 类引用改为 `Quanfuxia\Log\` 命名空间
- `phpunit.xml.dist` 与原库一致testsuite 名改为 `quanfuxia-log`
- `.gitignore` 复用原库内容vendor、runtime、.phpunit.cache 等)
## readme.md
新库 readme 说明用途Monolog→SeasLog 适配、自动注入 trace_id、安装、`config/log.php` 接入示例、对 `ext-seaslog` 的要求。
## 验证
拆分后在容器内运行:
```bash
docker exec php82 sh -lc 'cd /app/www/ray/webman-log && composer install && ./vendor/bin/phpunit'
```

View File

@@ -0,0 +1,98 @@
<!-- 4a3bab11-4dc6-415d-869a-958278641c6b -->
---
todos:
- id: "disable-webman-log"
content: "在 config/plugin/webman/log/app.php 将 enable 设为 false或接 WEBMAN_LOG_ENABLE 环境变量)"
status: pending
- id: "restart-webman"
content: "docker exec 内执行 php webman restart 使配置生效"
status: pending
- id: "verify-logs"
content: "验证 SeasLog/LoggerService 仍写入 runtime/logs/{worker}/,且 webman.log 不再出现 [Redis] 请求块"
status: pending
isProject: false
---
# 关闭 webman/log middleware 对业务日志的影响
## 结论(直接回答)
**不会影响你本身的业务日志。**
`config/plugin/webman/log/middleware.php` 注册的是插件自带的 `Webman\Log\Middleware`,与业务代码里的 `LoggerService``LogMiddleware` 是两套独立机制。
---
## slot_pwa 里实际有三套日志
```mermaid
flowchart LR
subgraph business [业务日志_不受影响]
LoggerService --> SeasLog
SeasLog --> runtime_logs_worker["runtime/logs/{worker}/"]
end
subgraph monolog [Monolog_不受影响]
SupportLog["support\\Log / Log::debug"] --> config_log["config/log.php"]
config_log --> webman_log_file["runtime/logs/webman.log"]
config_log --> log_log_file["runtime/logs/log.log"]
end
subgraph plugin [webman/log插件_关闭后停止]
WebmanLogMW["Webman\\Log\\Middleware"] --> SupportLogDefault["Log::channel default"]
WebmanLogMW --> auto["自动记录 IP/URL/POST/SQL/Redis"]
end
```
| 日志来源 | 配置/入口 | 写入位置 | 关 webman/log 后 |
|---------|-----------|----------|------------------|
| **LoggerService**(主力) | [app/service/LoggerService.php](slot_pwa/app/service/LoggerService.php) + [app/AppBootStrap.php](slot_pwa/app/AppBootStrap.php) 初始化 SeasLog | `runtime/logs/{worker_name}/` | **正常** |
| **LogMiddleware**traceId | [config/middleware.php](slot_pwa/config/middleware.php) 的 `api`/`gasea` 路由 | 只初始化 traceId业务 log 大多已注释 | **正常** |
| **support\Log / Monolog** | [config/log.php](slot_pwa/config/log.php) | `webman.log` / `log.log` | **正常**(你主动 `Log::info()` 仍会写) |
| **webman/log 插件** | [config/plugin/webman/log/middleware.php](slot_pwa/config/plugin/webman/log/middleware.php) | 同上 `default` 通道 → `webman.log` | **停止**自动请求汇总 |
你看到的 `[Redis] Redis::hincrby('prometheus:...')` 属于最后一行:**插件在每个请求结束时自动拼接 Redis/SQL**,不是 `LoggerService` 打的。
---
## 关闭后会失去什么
仅失去 **webman/log 自动请求日志**,典型内容:
- 请求行:`IP METHOD URL [xxms] [webman/log]`
- `[POST]` 请求体
- `[SQL]` / `[Redis]` 本请求内所有命令(含 Prometheus 的 `hincrby`
- 经插件捕获的异常堆栈(写入同一请求日志块)
官方说明:插件**不替代** webman 内核日志;未捕获异常仍可能由框架异常处理单独记录。
## 关闭后会失去的一个「副作用」能力
`Webman\Log\Middleware` 还会在请求结束检测 **未提交的数据库事务**`rollBack` + 抛 `RuntimeException`。关掉插件后这条开发期保护也会消失(与业务 `LoggerService` 无关,但排障时需注意)。
---
## 推荐关闭方式(不要直接删 middleware.php
Webman 加载插件配置时,若同目录 [config/plugin/webman/log/app.php](slot_pwa/config/plugin/webman/log/app.php) 中 `enable => false`,会**跳过** `middleware.php` 的加载(见 `Config::loadFromDir` 逻辑)。
**推荐**:改 `app.php`,而不是删/清空 `middleware.php`
```php
'enable' => false,
```
或按环境控制(与现有 `DEBUG` 类似):
```php
'enable' => filter_var(getenv('WEBMAN_LOG_ENABLE'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false,
```
改完后需 **restart webman** 生效。
---
## 验证清单(关闭后自测)
1. 触发一条业务接口,确认 `runtime/logs/{worker}/` 下 SeasLog 仍有 `LoggerService` 输出
2. 确认 `runtime/logs/webman.log` 不再出现 `[Redis]` / `[webman/log]` 请求块
3. 故意打一条 `LoggerService::error()``Log::error()`,确认仍写入对应文件
4. 异常接口:确认业务异常处理与 SeasLog 错误日志仍正常

View File

@@ -0,0 +1,108 @@
<!-- 215d598c-9837-4e65-a3e9-850d78cd5f00 -->
## 周返水Weekly Cashback实现方案
### 已定决策(来自本轮确认)
- 二、三:按评审意见修订需求文档、计费/配置与每日返水解耦。
- 四:方案 B —— 周有效投注每日落库,规避 `user:profit:Ymd` 的 7 天 TTL。
- 五.1VIP 费率存活动配置 `ext_config.vip_rates`type=13不放 VIP 表。
- 五.2VIP 取「周末最后一刻」(结算下周一读当前 VIP 即可)。
- 五.3:结算上周的同时把「上上周」未领取的置过期。
- 五.4VIP0 不进页面,不处理。
- 五.5/6/7倒计时对齐周界四周记录入库返水 `floor` 取整到厘。
### 计费模型(与每日返水的关键差异)
- 每日返水 = 下注累进分段(`tiers`);周返水 = `周有效投注 × rate(vip%)` 单乘,按 `floor` 取整。
- 统计周:周一 00:00:00 ~ 周日 23:59:59**服务器时区**(统一口径,修订文档里"美国时间"表述)。
- 周有效投注 = 当周 7 天 `rebate_bet` 之和(仅充值用户累加,沿用 `slot_pwa` 现有口径pwa 无需改动)。
### 数据流
```mermaid
flowchart TD
pwa["slot_pwa incBet 仅充值用户累加 rebate_bet"] --> redis["redis user:profit:Ymd TTL7天"]
accrue["weeklyRebateAccrue 每天00:05 处理昨日"] --> redis
accrue --> rec["weekly_rebate_record 当周Pending bet_amount累加"]
settle["weeklyRebateSettle 周一00:15"] --> rec
settle --> vip["读当前VIP rate=vip_rates level"]
settle --> expirePrev["上上周 Claimable -> Expired"]
claim["C端 claim 上周"] --> wallet["WalletService gift 类型68 打码Y3"]
```
### 落库方案 B幂等
- 新表 `weekly_rebate_record` 增加 `last_accrued_date`date
- `weeklyRebateAccrue`(每天)处理**昨日**key 仅 1 天,必在 TTL 内):遍历昨日 `user:profit:` 哈希,充值用户且 `rebate_bet>0` → 定位昨日所属周的记录(无则建 Pending→ 若 `last_accrued_date < 昨日``bet_amount += rebate_bet` 且更新 `last_accrued_date`(重跑不重复累加)。
- C 端「This Week」展示 = `record.bet_amount`(昨日及之前)+ 今日 redis 实时 `rebate_bet``rebate = floor(weekBet * rate /100)`(镜像每日返水 `syncTodayPending` 思路)。
### 结算/过期(周一)
- `weeklyRebateSettle`:对上周 `week_start` 的 Pending 记录,读当前 VIP → `rate=vip_rates[level]``rebate=floor(bet*rate/100)``rebate>0``Claimable`,写 `vip_level`/`rate_snapshot`/`claimable_at=本周一`/`expire_at=下周一`;同一次把「上上周」`Claimable 且 expire_at<=now``Expired`
- `weeklyRebateExpire`:兜底,`status=Claimable AND expire_at<=now -> Expired`(镜像 `expireDueRecords`)。
- 顺序accrue 先于 settle。
### 复用 vs 新建
- 复用骨架:领取短事务 CAS + 钱包入账失败回滚 + 结算结构化日志(镜像 [DailyRebateLogic](slot_console/app/api/logic/DailyRebateLogic.php)`RechargedUidSetService``UserProfitEntity`、四态 + `statusLabel`、Controller/Validator 形态。
- 新建VIP 费率,不复用 tiers 累进):`WeeklyRebateCalcService::calcRebateLi(betLi, ratePercent)``WeeklyRebateConfigService`(解析 `vip_rates``maxRate``rateForVip``canonicalExtConfigForStorage`)。
### 文件清单
slot_lib
- [Consts.php](slot_lib/src/common/const/Consts.php) 新增 `ACTIVITY_TYPE_WEEKLY_REBATE=13``TRANSACTION_TYPE_WEEKLY_REBATE=68`
slot_console
- 模型 `app/model/common/WeeklyRebateRecordModel.php`(四态 + `findByUidAndWeek`)。
- `RechargeGiftConfigModel``TYPE_WEEKLY_REBATE=13``getWeeklyRebateActiveInfo/...ByExactSource`(镜像每日返水方法)。
- 服务 `app/service/WeeklyRebateCalcService.php``app/service/WeeklyRebateConfigService.php`
- Logic `app/api/logic/WeeklyRebateLogic.php`info/claim/accrue/settle/expire
- Controller `app/api/controller/WeeklyRebateController.php`、Validator `app/api/validator/WeeklyRebateValidator.php`
- 命令 `app/command/WeeklyRebateAccrue.php``WeeklyRebateSettle.php``WeeklyRebateExpire.php`
- 路由:在 api 路由注册 weekly-rebate info/claim与每日返水同处
- SQL `db/weekly_rebate.sql`(含 `last_accrued_date`、唯一键 `uniq_uid_week`)。
- 活动配置入口 [ActivityConfigEntity.php](slot_console/app/entity/activity/ActivityConfigEntity.php) 读写处对 `TYPE_WEEKLY_REBATE``WeeklyRebateConfigService::canonicalExtConfigForStorage`
- 部署文档 `doc/weekly_rebate_deploy.md`(镜像 daily_rebate_deploy
backend/slot_admin+ vue
- 字典 `activity_type` 增「周返水」value=13菜单「周返水统计」活动 type=13 编辑页 VIP 费率16 档)配置 UI周返水统计页。
slot_wallet
- 确认 `TRANSACTION_TYPE_WEEKLY_REBATE=68` 打码归类为 活动赠送 Y3`SOURCE_TYPE_ACTIVITY_REWARD=3`),与每日返水一致;如有类型白名单需补 68。
### 需求文档修订(周返水.md
- 领取按钮「昨天返水金额」→「上一周返水金额」。
- 规则文案「refreshes daily」改为「本周累计实时刷新、每周一结算」。
- 时区统一为服务器时区(删「美国时间」歧义)。
- `No Btes``No Bets`
### ext_config 标准格式type=13
```json
{
"vip_rates": [
{"vip_level": 0, "rate_percent": 0},
{"vip_level": 1, "rate_percent": 0.5},
{"vip_level": 15, "rate_percent": 2.0}
],
"banner_image": ""
}
```
### cron
- `weeklyRebateAccrue` 每天 00:05`weeklyRebateSettle` 每周一 00:15`weeklyRebateExpire` 每周一 00:20兜底
### 收尾门禁
-`app/**/*.php` 后按 `slot-backend-completion-report` Skill 跑 `verify-slot-backend.sh` + docker `php -l`,回复附「检测结果」章节。
</plan>
<todos>
[
{"id": "doc-fix", "content": "修订 周返水.md 笔误(昨天->上周、daily->weekly、时区统一、No Bets"},
{"id": "consts", "content": "slot_lib Consts 新增 ACTIVITY_TYPE_WEEKLY_REBATE=13、TRANSACTION_TYPE_WEEKLY_REBATE=68"},
{"id": "sql-model", "content": "建 weekly_rebate.sql 与 WeeklyRebateRecordModel含 last_accrued_date、四态、findByUidAndWeek"},
{"id": "config-model-methods", "content": "RechargeGiftConfigModel 加 TYPE_WEEKLY_REBATE 与 getWeeklyRebateActiveInfo 系列方法"},
{"id": "services", "content": "WeeklyRebateCalcService(VIP费率单乘) 与 WeeklyRebateConfigService(解析 vip_rates/maxRate/rateForVip/canonical)"},
{"id": "logic", "content": "WeeklyRebateLogicinfo/claim(短事务CAS+钱包回滚)/accrue/settle(读VIP+过期上上周)/expire"},
{"id": "controller-route", "content": "WeeklyRebateController + WeeklyRebateValidator + 路由注册"},
{"id": "commands", "content": "命令 WeeklyRebateAccrue/Settle/Expire + cron 配置"},
{"id": "activity-entry", "content": "ActivityConfigEntity 读写 type=13 走 canonicalExtConfigForStorage"},
{"id": "admin", "content": "slot_admin 字典/菜单/type=13 VIP费率配置页/周返水统计页"},
{"id": "wallet-verify", "content": "slot_wallet 确认流水类型68 打码归 活动赠送Y3"},
{"id": "deploy-doc", "content": "编写 weekly_rebate_deploy.md 部署文档"},
{"id": "verify-gate", "content": "跑 verify-slot-backend.sh + php -l输出检测结果章节"}
]
</todos>
</invoke>

View File

@@ -0,0 +1,68 @@
<!-- 215d598c-9837-4e65-a3e9-850d78cd5f00 -->
## 每周返水统计(后台)
镜像现有 Free Credits 统计页([FreeCreditsStatsController.php](backend/slot_admin/app/game/controller/FreeCreditsStatsController.php) / [FreeCreditsStatsLogic.php](backend/slot_admin/app/game/logic/FreeCreditsStatsLogic.php) / [freeCreditsStats/index.vue](backend/slot_admin_vue/src/views/game/freeCreditsStats/index.vue) / [menu-free-credits-stats.sql](backend/slot_admin/db/menu-free-credits-stats.sql)),同请求返回 `data/total/otherData(总计)`
### 依赖
- 依赖「周返水核心」计划已建表 `s_common.weekly_rebate_record`(字段:`uid, source, week_start, bet_amount(厘), rebate_amount(厘), status(1待定/2待领/3已领/4过期), vip_level, rate_snapshot, last_accrued_date, claimable_at, expire_at, claimed_at`)。
- 小调整(核心计划侧):`weeklyRebateAccrue` 累加当周 Pending 行时,同时把当前 `vip_level``rate_snapshot` 写入该行,使后台对所有状态(含待定)都能直接读行内费率,无需查实时 VIP / 共享 Redis。
### 数据流
```mermaid
flowchart LR
vue["每周返水统计 index.vue sa-table"] -->|"GET /game/weeklyRebateStats/index"| ctrl["WeeklyRebateStatsController"]
ctrl --> dto["WeeklyRebateStatsQueryDTO + Validate"]
dto --> logic["WeeklyRebateStatsLogic list + statistics"]
logic --> model["WeeklyRebateRecordModel connection s_common"]
logic -->|"data/total"| vue
logic -->|"otherData 总计"| vue
```
### 后端文件backend/slot_admin
- 模型 `app/game/model/common/WeeklyRebateRecordModel.php``connection='s_common'``table='weekly_rebate_record'`,四态常量 + `statusLabel`(镜像 [FreeCreditsPlayerModel.php](backend/slot_admin/app/game/model/common/FreeCreditsPlayerModel.php))。
- DTO `app/game/dto/WeeklyRebateStatsQueryDTO.php`(镜像 [FreeCreditsStatsQueryDTO.php](backend/slot_admin/app/game/dto/FreeCreditsStatsQueryDTO.php),归一化 page/limit
- 校验 `app/game/validate/WeeklyRebateStatsValidate.php``uid/source/status/stat_range[]/orderBy(in:bet_amount,rebate_amount)/orderType/page/limit`(镜像 [FreeCreditsStatsValidate.php](backend/slot_admin/app/game/validate/FreeCreditsStatsValidate.php))。
- 控制器 `app/game/controller/WeeklyRebateStatsController.php``index()` 返回 `list + otherData=statistics`(路由自动 `/game/weeklyRebateStats/index`)。
- Logic `app/game/logic/WeeklyRebateStatsLogic.php`
- `buildQuery($params)``uid` 精确;`source` 精确;`status` 单/多选 `whereIn`;按日范围 snap 整周 → `week_start >= 周一(start)``week_start <= 周一(end)`;排序白名单 `bet_amount`/`rebate_amount`,默认 `week_start desc`
- `list()`:分页取行,逐行补 `rate(=rate_snapshot)``week_start/week_end(week_start+6)``is_current_week``status_label`,金额 `getNumberFormat` 转美元字符串。
- `statistics()`(顶部总计,对筛选集合聚合):
- 总领取 `SUM(rebate_amount) WHERE status=已领`
- 总待领取 `SUM(rebate_amount) WHERE status=待领取`
- 总过期 `SUM(rebate_amount) WHERE status=过期`
- 领取率 `总领取/(总领取+总待领取+总过期)`(分母 0 → 0保留 2 位百分比
- 待定 `SUM(rebate_amount) WHERE status=待定`,仅当筛选范围包含本周时计算,否则 0
### 前端backend/slot_admin_vue
- `src/api/game/weeklyRebateStats.js``getPageList``/game/weeklyRebateStats/index`
- `src/views/game/weeklyRebateStats/index.vue``sa-table`(镜像 freeCreditsStats
- 搜索区用户ID(input)、渠道(`commonStore.allSourcesOptionsNoAll` 可搜)、状态(四种 select)、统计周期(`a-range-picker` mode=date 不带时分)。
- `#tableAfterButtons` 顶部总计:总领取 / 总待领取 / 总过期 / 领取率% / 待定。
-用户ID、渠道号、有效下注额(sortable)、返水率、返水金额(sortable)、状态(tag)、统计周期(`本周``week_start - week_end`)。
- `stats = crudRef.getTableOtherData()`;金额已由后端格式化,前端直接展示。
### 菜单 SQLbackend/slot_admin/db/menu-weekly-rebate-stats.sql
- 镜像 [menu-free-credits-stats.sql](backend/slot_admin/db/menu-free-credits-stats.sql):挂在「综合统计」父菜单下(部署时确认其 `sm_system_menu.id`,缺失则建),`code/route/component = game/weeklyRebateStats/index`,并补 `sm_system_group_menu` 授权。
### 字段口径与说明
- 仅统计充值用户(`weekly_rebate_record` 本就只对充值用户落库)。
- 返水率取行内 `rate_snapshot`:历史行为结算时快照,待定行为 accrue 时写入的当前 VIP 费率(每周按最新 VIP
- 待定行 `bet_amount` 为已 accrue 到昨日的累计(后台读库口径,不含当日实时增量)。
- 金额单位厘 → `getNumberFormat` 转美元展示。
### 收尾门禁
-`app/**/*.php` 后按 `slot-backend-completion-report` Skill 跑 `verify-slot-backend.sh` + docker `php -l`,回复附「检测结果」章节(含 PHPDoc:checked
</plan>
<todos>
[
{"id": "stats-model", "content": "slot_admin WeeklyRebateRecordModel(connection s_common) + 四态/statusLabel"},
{"id": "stats-dto-validate", "content": "WeeklyRebateStatsQueryDTO + Validate(uid/source/status/stat_range/orderBy白名单)"},
{"id": "stats-controller", "content": "WeeklyRebateStatsController index 返回 list + otherData"},
{"id": "stats-logic", "content": "WeeklyRebateStatsLogicbuildQuery(周snap/排序) + list(行补week区间/rate/状态) + statistics(五项总计+领取率+待定本周判断)"},
{"id": "stats-vue", "content": "weeklyRebateStats api.js + index.vue(筛选/顶部总计/可排序列/统计周期展示)"},
{"id": "stats-menu-sql", "content": "menu-weekly-rebate-stats.sql 挂综合统计父菜单 + 分组授权"},
{"id": "accrue-rate-snapshot", "content": "核心侧调整accrue 对 Pending 行写入当前 vip_level/rate_snapshot"},
{"id": "stats-verify", "content": "跑 verify + php -l 输出检测结果章节"}
]
</todos>

View File

@@ -0,0 +1,111 @@
---
name: 充值后下注返水
overview: 在下注发生时用现有 `user:recharged` 集合判断是否已充值,仅充值用户额外累计 `rebate_bet`;每日返水改用 `rebate_bet`,不影响 VIP 输钱返利等仍使用全量 `bet`
todos:
- id: pwa-rebate-bet
content: pwa UserProfitService 增加 rebate_bet并在 incBet 时用 user:recharged 集合判断后累计
status: completed
- id: console-use-rebate-bet
content: console UserProfitEntity + DailyRebateLogic 结算/同步改用 rebate_bet
status: completed
- id: deploy-doc-test
content: 更新 daily_rebate_deploy.md 发布顺序与冒烟用例;跑 verify + 相关测试
status: completed
isProject: false
---
# 充值后的下注才计入每日返水
## 背景与缺口
当前实现([`DailyRebateLogic`](file:///Users/ray/Documents/project/www/slot/slot_console/app/api/logic/DailyRebateLogic.php))仅在结算/同步时用 `userHasDeposit()` 过滤,下注额来自共享 Redis 日哈希([`slot_pwa` `UserProfitService::incBet`](file:///Users/ray/Documents/project/www/slot/slot_pwa/app/service/user/UserProfitService.php)**全天 `bet` 无差别累计**。
因此「同一天先下注、后首充」会把首充前下注也算进返水——与产品「充值后的下注才算」不符。
**产品已确认口径**
- 开启计时:普通充值 + 签到购(与现网 `RechargedUidSetService::add` 一致)
- 历史:仅上线日起按新规则;不回溯历史结算日
**约束**:同一 Redis 日盈利哈希还被 [`LoseReturnDeposit`](file:///Users/ray/Documents/project/www/slot/slot_console/app/command/LoseReturnDeposit.php)VIP 输钱返利)使用,**不能**改 `bet` 语义或阻止未充值用户累计 `bet`
```mermaid
flowchart LR
subgraph pwa [slot_pwa]
Bet[WalletService bet]
IncBet[UserProfitService.incBet]
Bet --> IncBet
IncBet --> betField["bet 全量"]
IncBet --> CheckSet["SISMEMBER user:recharged"]
CheckSet --> rebateBetField["充值用户才累加 rebate_bet"]
end
subgraph wallet [slot_wallet]
Recharge[recharge / rechargeSign]
Recharge --> SetUid[SADD user:recharged]
end
subgraph console [slot_console]
Settle[dailyRebateSettle]
Settle --> UseRebateBet["读 rebate_bet 算档"]
end
rebateBetField --> Settle
SetUid --> CheckSet
```
---
## 方案:新增 `rebate_bet`,下注时用集合判断
### 1. slot_pwa — 下注时累计 `rebate_bet`
扩展 [`UserProfitService`](file:///Users/ray/Documents/project/www/slot/slot_pwa/app/service/user/UserProfitService.php)
- 序列化结构:`bet``win`、**`rebate_bet`**(默认 0反序列化兼容旧数据
- 新建或复用一个轻量 `RechargedUidSetService`(读 share Redis `SISMEMBER user:recharged`
- `incBet` 逻辑:
- `bet` 仍始终 `+= fee`(供输钱返利等)
-`SISMEMBER user:recharged uid = 1`,则 `rebate_bet += fee`
- 否则不累加 `rebate_bet`
**性能**:每次下注 1 次 `SISMEMBER`;如下注高频,可对「已充值」状态做短 TTL 本地/Redis 缓存可选非必须。Redis 异常时按未充值处理,宁可少算不可多算。
### 2. slot_console — 返水只读 `rebate_bet`
| 文件 | 改动 |
|------|------|
| [`UserProfitEntity`](file:///Users/ray/Documents/project/www/slot/slot_console/app/entity/command/UserProfitEntity.php) | 增加 `public int $rebate_bet = 0` |
| [`DailyRebateLogic`](file:///Users/ray/Documents/project/www/slot/slot_console/app/api/logic/DailyRebateLogic.php) | `settleOneUserFromProfitHash``readTodayBetFromRedis``syncTodayPending` 使用 **`rebate_bet`** 作为有效下注(无字段或旧日为 0**禁止** fallback 到 `bet`,避免误发) |
| 结算日志 | `samples` 中 bet 字段可改为 `rebate_bet` 或同时打 `bet`/`rebate_bet` 便于对账 |
保留现有 `userHasDeposit()` 校验(双保险:未在集合内仍 skip
### 3. 部署与验收(更新 [`daily_rebate_deploy.md`](file:///Users/ray/Documents/project/www/slot/slot_console/doc/daily_rebate_deploy.md)
**发布顺序**:确认 `center`/`wallet` 已有 `user:recharged` 机制并完成回填 → 发布 `slot_pwa` → 发布 `slot_console``slot_pwa` 必须早于次日 `dailyRebateSettle` cron
**冒烟用例**
1. 未充值用户下注 → `rebate_bet=0` → 结算 skip / 无可领
2. 同日:先下注 100 → 再首充 → 再下注 200 → 仅 `rebate_bet=200` → 返水按 200 档位
3. 已充值老用户(已在 `user:recharged` 集合)→ 上线后下注直接累计 `rebate_bet`
4. VIP 输钱返利:仍读 `bet`,行为不变
---
## 不改动的部分
- `user:recharged` SET 语义不变
- `center` 不新增共享 Redis key
- `wallet` 充值成功后写集合的逻辑不变
- 领取/活动页 `userHasDeposit` 门槛不变
- 不改动 `slot_sdk`(无跨服务 HTTP
- 不做历史日 `rebate_bet` 回填
---
## 风险与说明
| 项 | 说明 |
|----|------|
| 上线前已在 set 的老用户 | 上线后发生的下注会直接累计 `rebate_bet`,符合“已充值用户后续下注算返水” |
| 首充与下注并发 | 以下注时 `SISMEMBER user:recharged` 的结果为准;集合写入前的下注不计入,写入后的下注计入 |
| Redis 异常 | pwa 判断集合失败应记 error 且 **不累加** `rebate_bet`(宁可少算不可多算) |

View File

@@ -0,0 +1,236 @@
---
name: 全局活动轮次
overview: Lucky Rewards 活动配置与轮次均改为全平台唯一:`lucky_reward_config``lucky_reward_tier_config``lucky_reward_cycle` 移除 `source`;转盘奖项已迁至 `reward_pool_item`(无 sourcelegacy `lucky_reward_prize_config` 确认删除C 端仍用 `lucky_reward_player.source` 记录用户注册渠道。
todos:
- id: ddl-migration
content: 新增 lucky_reward_drop_source.sqlconfig/tier/cycle 删 source确认 legacy prize_config 已 DROP同步 lucky_reward.sql 与需求文档
status: completed
- id: config-model-service
content: LuckyRewardConfigModel 改为 findEnabled() 单例ConfigService requireEnabledConfig/resolveActiveCycle/createNextCycle 去 source 参数
status: completed
- id: cycle-model-rollover
content: LuckyRewardCycleModel 全局 findActive/maxCycleNoCycleRolloverService 去 sourceTierConfig 去 source
status: completed
- id: console-callers
content: Logic/Service 配置查询改 findEnabled();轮次查询改 findActive()player 写入仍保留 resolvedSource
status: completed
- id: admin-crud
content: slot_admin Config/Tier Logic/Validate/Controller 去 source 字段;主配置改为单例校验
status: completed
- id: tests-verify
content: 更新集成测试 seed全局 config+cycle补跨渠道同 config/cycle 用例phpunit + verify-slot-backend.sh
status: completed
isProject: false
---
# Lucky Rewards 配置与轮次全局化(不区分渠道)
## 目标与边界
| 维度 | 变更后 |
| --- | --- |
| `lucky_reward_config` | **全平台唯一**主配置,**移除 `source` 列**(表内仅保留一行或业务层强制单例) |
| `lucky_reward_tier_config` | **移除 `source` 列**,仅通过 `config_id` 关联主配置 |
| `lucky_reward_prize_config` | **已废弃**;奖项 SSOT 为 **`reward_pool` + `reward_pool_item`**`pool_code=lucky_reward`**本身无 `source`**)。若环境仍残留 legacy 表,执行 DROP**无需**对其 ALTER 删列 |
| `lucky_reward_cycle` | **全平台唯一**进行中轮次,**移除 `source` 列** |
| `lucky_reward_player.source` 等业务表 | **保留**,表示**用户注册/归属渠道**,供后台统计筛选,与活动配置无关 |
| wheel 短码 `biz_id=cycle_id` | **不变**,全渠道共用同一 `cycle_id` |
```mermaid
flowchart TB
subgraph before [现状]
ConfigA[config source=A]
ConfigB[config source=B]
ConfigA --> CycleA[cycle source=A]
ConfigB --> CycleB[cycle source=B]
end
subgraph after [改造后]
GlobalConfig[单一 lucky_reward_config]
GlobalCycle[单一 active cycle]
PlayerA[player source=渠道A]
PlayerB[player source=渠道B]
GlobalConfig --> GlobalCycle
GlobalCycle --> PlayerA
GlobalCycle --> PlayerB
end
```
与 [`00_整体技术方案.md`](docs/requirements/lucky_rewards/00_整体技术方案.md) 一致cycle 表本无 `source`;配置亦改为全局单套参数。
---
## 1. DDL 与数据迁移
新增 [`backend/slot_admin/db/lucky_reward_drop_source.sql`](backend/slot_admin/db/lucky_reward_drop_source.sql)(合并原 cycle 脚本,一次迁移三表):
### 1.1 `lucky_reward_config`
1. **合并多行配置**(若存在按渠道多行)
- 保留 **`source='default'``status=1` 的行**;若无 default 启用行则保留 `id` 最小且 `status=1` 的行
- 将其余行的 `lucky_reward_tier_config.config_id` **重指向**保留行
- 删除其余 config 行
2. **改表**
- `DROP INDEX idx_source`
- `DROP COLUMN source`
### 1.2 `lucky_reward_tier_config`
- `DROP COLUMN source`(已通过 `config_id` 关联列冗余admin Tier Logic/Validate 同步去 source 字段)
### 1.3 `lucky_reward_prize_config`legacy
> 现状:转盘奖项已迁移至 [`reward_pool.sql`](backend/slot_admin/db/reward_pool.sql) 的 `reward_pool_item`console 通过 [`LuckyRewardConfigService::listLuckyRewardPoolItems()`](slot_console/app/service/luckyReward/LuckyRewardConfigService.php) 读 `pool_code=lucky_reward`**无渠道维度**。
迁移步骤(写入 `lucky_reward_drop_source.sql` 末尾或独立段落):
1.**`lucky_reward_prize_config` 表仍存在** 且尚未迁移:先跑 [`reward_pool_migrate_lucky_reward_prize.sql`](backend/slot_admin/db/reward_pool_migrate_lucky_reward_prize.sql)(迁移脚本内 `@config_id` 改为取合并后的**唯一** config 行,不再 `WHERE source='default'`
2. 验证 `reward_pool_item` 数据完整后,执行 [`reward_pool_drop_legacy_prize_config.sql`](backend/slot_admin/db/reward_pool_drop_legacy_prize_config.sql)`DROP TABLE IF EXISTS lucky_reward_prize_config`
3. **无 PHP Model/Logic 改动**(已无 `LuckyRewardPrizeConfig*` 代码路径;后台菜单已指向 `RewardPoolItemController`
文档同步:[`04_slot_console_活动主流程方案.md`](docs/requirements/lucky_rewards/04_slot_console_活动主流程方案.md) 中将 `lucky_reward_prize_config` 表述改为 `reward_pool_item`
### 1.4 `lucky_reward_cycle`
1. 合并重复 `status=1`:保留 `id` 最大一行,其余改 `STATUS_ENDED=2`(不合并 player 行)
2. `DROP INDEX idx_source_status``DROP COLUMN source``ADD KEY idx_status (status)`
### 1.5 同步基线 DDL
- [`backend/slot_admin/db/lucky_reward.sql`](backend/slot_admin/db/lucky_reward.sql) — config / tier / cycle 去掉 `source`**不包含**已废弃的 prize_config 建表
- [`docs/requirements/lucky_rewards/02_管理后台方案.md`](docs/requirements/lucky_rewards/02_管理后台方案.md) §2.1 / §2.3 / §2.4(去掉「用 source 区分渠道」§2.2 已说明 prize 在 reward_pool
---
## 2. Model 层
### 2.1 [`LuckyRewardConfigModel`](slot_console/app/model/common/LuckyRewardConfigModel.php)console + admin 同步)
- 删除 `@property string $source`
- 删除 `findEnabledBySourceWithFallback(string $source)`
- 新增 `findEnabled(): ?self``status=STATUS_ENABLED``order id asc`,取唯一启用配置
- admin Model 去掉 search 按 source 的 scope若有
### 2.2 [`LuckyRewardTierConfigModel`](slot_console/app/model/common/LuckyRewardTierConfigModel.php)
- 删除 `@property string $source`
- `listEnabledByConfigId(int $configId)` 不变
### 2.3 [`LuckyRewardCycleModel`](slot_console/app/model/common/LuckyRewardCycleModel.php)
- 删除 `source``findActiveBySource` / `maxCycleNo(string $source)`
- 新增 `findActive(): ?self``maxCycleNo(): int`
---
## 3. Service 层slot_console
### 3.1 [`LuckyRewardConfigService`](slot_console/app/service/luckyReward/LuckyRewardConfigService.php)
| 方法 | 改造 |
| --- | --- |
| `requireEnabledConfig()` | 无参;内部 `findEnabled()`,未开启抛 `BusinessException` |
| `resolveActiveCycle(LuckyRewardConfigModel $activityConfig)` | 去掉 `$source`;查 `findActive()`;创建下一轮调 `createNextCycle($activityConfig, ...)` |
| `createNextCycle(LuckyRewardConfigModel $activityConfig, ?int $baseTimestamp = null)` | 去掉 `$source``cycle_days` 直接取自传入的**唯一** `$activityConfig`;不写 cycle.source事务 + `FOR UPDATE` 防并发双 active |
### 3.2 [`LuckyRewardCycleRolloverService`](slot_console/app/service/luckyReward/LuckyRewardCycleRolloverService.php)
- `rolloverExpiredCycle`:去掉 `$expiredCycle->source`
- 开启下一轮:`findActive()` 为空且 `findEnabled()` 非空时 `createNextCycle($activityConfig, $nowTimestamp)`
---
## 4. Logic / 其它调用点slot_console
**配置读取**:所有 `findEnabledBySourceWithFallback($resolvedSource)` / `requireEnabledConfig($source)` 改为无参全局读取。
**轮次读取**:所有 `findActiveBySource(...)` 改为 `findActive()`
**仍保留 `resolveSource($uid, $source)` 的场景**(仅写业务行渠道归属,**不**用于查配置):
- `lucky_reward_player.source`
- `lucky_reward_spin_grant.source`
- `lucky_reward_helper.source`
- `lucky_reward_spin_record.source`
- 日志 / MQ 回调 `channel_code` 字段
| 文件 | 改动要点 |
| --- | --- |
| [`LuckyRewardLogic.php`](slot_console/app/api/logic/LuckyRewardLogic.php) | enter/spin/openBox/toBalance配置无参轮次 `findActive()`player 写入仍用 `$resolvedSource` |
| [`LuckyRewardInviteLogic.php`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) | invite_bind、弹窗、claim配置/轮次全局helper/player 仍写用户渠道 |
| [`LuckyRewardSupportInvitePendingService.php`](slot_console/app/service/luckyReward/LuckyRewardSupportInvitePendingService.php) | flush 时查全局 config + active cycle |
| [`ShareService.php`](slot_console/app/service/ShareService.php) | `resolveOrCreateWheelShareRow``requireEnabledConfig()` + `resolveActiveCycle($config)` |
Controller 仍向 Logic 传 `$request->userEntity->source`(供 player 归属Logic 内部不再用它查 config。
---
## 5. 管理后台slot_admin
| 文件 | 改动 |
| --- | --- |
| [`LuckyRewardConfigLogic`](backend/slot_admin/app/game/logic/LuckyRewardConfigLogic.php) | 去掉 `source` 写入与 `ensureSourceUnique`;新增 **单例校验**(全表仅允许 1 行update 除外) |
| [`LuckyRewardConfigValidate`](backend/slot_admin/app/game/validate/LuckyRewardConfigValidate.php) | save/update scene 移除 `source` |
| [`LuckyRewardConfigController`](backend/slot_admin/app/game/controller/LuckyRewardConfigController.php) | index 去掉 source 筛选options 返回 `id,status`(无 source |
| [`LuckyRewardTierConfigLogic`](backend/slot_admin/app/game/logic/LuckyRewardTierConfigLogic.php) | 去掉 `source` 写入与列表 `config_source` 展示 |
| [`LuckyRewardTierConfigValidate`](backend/slot_admin/app/game/validate/LuckyRewardTierConfigValidate.php) | 移除 `source` |
| Model PHPDoc | Config / Tier / Cycle 三表同步 |
[`LuckyRewardStatsLogic`](backend/slot_admin/app/game/logic/LuckyRewardStatsLogic.php)**不变** — 统计仍可按 `lucky_reward_player.source` 筛用户渠道。
**前端**(若 [`slot_admin_vue`](backend/slot_admin_vue) 有 Lucky Reward 配置页渠道字段):移除主配置/分层表单中的「渠道」输入与列表列(本计划标注为 admin 联调项,改 PHP 后前端需同步)。
---
## 6. 测试
[`LuckyRewardDbTestCase::seedEnabledActivity`](slot_console/tests/Integration/LuckyRewardDbTestCase.php)
- 不再按 `TEST_SOURCE` 创建独立 config改为 **更新全局唯一 config 为 ENABLED**(或 insert 仅当表空)
- cycle seed 不写 `source`;先 `findActive()` 结束旧 active
- player / helper 测试行仍可写 `source => TEST_SOURCE` 模拟用户渠道
更新所有集成测试中的 `findEnabledBySourceWithFallback` / `findActiveBySource` / config 按 source 查询。
**新增用例**:两渠道用户(不同 `player.source`)进入活动,得到相同 `config` 参数与 `cycle_id`
---
## 7. 部署顺序
1. 执行 `lucky_reward_drop_source.sql`(合并 config + 删列)
2. **同批发布** slot_console + slot_admin删列后旧代码会 SQL 报错)
3. slot_admin_vue 去渠道字段(可与后端同批或紧随其后)
---
## 8. 风险与验收
| 风险 | 处理 |
| --- | --- |
| 线上多渠道各有 config / active cycle | 迁移脚本合并为单行 config + 单行 active cycle |
| 非 default 渠道 config 有差异化参数 | 迁移保留 default 启用行;运营需事先确认 default 参数为 SSOT |
| 并发创建双 active cycle | `createNextCycle` 事务 + 行锁 |
| 后台误建第二条 config | Logic 单例校验拦截 |
**验收清单**
- 全渠道用户 `enter` 读到同一套 target_amount / cycle_days / tier
- 全渠道同一 `cycle_id`;轮转后仅一条新 active
- 后台主配置 CRUD 无渠道字段,不可新增第二条
- 统计页仍可按 **玩家 source** 筛选
- `phpunit` Lucky Rewards 集成测 + `verify-slot-backend.sh` PASS
---
## 涉及文件汇总
**DDL**`lucky_reward_drop_source.sql``lucky_reward.sql``reward_pool_migrate_lucky_reward_prize.sql`(改 config 选取逻辑)、`reward_pool_drop_legacy_prize_config.sql`、需求文档
**slot_console**`LuckyRewardConfigModel``LuckyRewardTierConfigModel``LuckyRewardCycleModel``LuckyRewardConfigService``LuckyRewardCycleRolloverService``LuckyRewardLogic``LuckyRewardInviteLogic``LuckyRewardSupportInvitePendingService``ShareService`、集成测试
**slot_admin**`LuckyRewardConfigModel``LuckyRewardTierConfigModel``LuckyRewardCycleModel``LuckyRewardConfigLogic``LuckyRewardTierConfigLogic`、对应 Validate/Controller
**无需改动(已无 source**`reward_pool` / `reward_pool_item``RewardPoolItemLogic`(转盘奖项 CRUD
**保留 source 不改**`lucky_reward_player` 及 spin/helper/record/grant 业务表;`LuckyRewardStatsLogic` 玩家渠道筛选

View File

@@ -0,0 +1,137 @@
---
name: 渠道编号自动生成
overview: 在 slot-admin 后端创建渠道时自动生成唯一 6 位字母数字编号编辑时禁止修改slot-admin-vue 前端对应隐藏创建输入、编辑只读展示,并移除前端校验。
todos:
- id: backend-add-generate
content: GameServerLogic实现 add() + generateUniqueSource(),合并原 save() 逻辑edit() unset source
status: completed
- id: backend-validate
content: GameServerValidatesave/update 场景移除 source 校验
status: completed
- id: frontend-edit-form
content: edit.vue新增隐藏编号、编辑只读、移除校验、提交时不传 source
status: completed
- id: verify
content: Docker 内手工验证创建/编辑,跑 verify-slot-backend.sh
status: completed
isProject: false
---
# 渠道编号系统自动生成方案
## 背景与范围
渠道管理对应模块:
| 层级 | 路径 |
|------|------|
| 前端列表/表单 | [`slot-admin-vue/src/views/game/source/index.vue`](slot-admin-vue/src/views/game/source/index.vue)、[`edit.vue`](slot-admin-vue/src/views/game/source/edit.vue) |
| API | `POST /game/game-server/save``PUT /game/game-server/update` |
| 后端 | [`GameServerController`](slot-admin/app/game/controller/GameServerController.php) → [`GameServerLogic`](slot-admin/app/game/logic/GameServerLogic.php) → [`GameServerModel`](slot-admin/app/model/GameServerModel.php) |
| 校验 | [`GameServerValidate`](slot-admin/app/game/validate/GameServerValidate.php) |
当前行为:创建/编辑时前端手动填写 `source`(编号),后端 `save`/`update` 场景均校验 `source` 必填。
**额外发现(需一并修复)**[`GameServerLogic::save()`](slot-admin/app/game/logic/GameServerLogic.php) 含 `secret_key` 生成、`extend_data` 格式化、Redis 同步等逻辑,但 [`BaseController::save()`](slot-admin/plugin/saimulti/basic/BaseController.php) 实际调用的是 `logic->add()`,导致创建时这些逻辑**未执行**。本次应改为在 `add()` 中统一处理(参照 [`GGameLogic::add()`](slot-admin/app/game/logic/GGameLogic.php) 模式)。
```mermaid
sequenceDiagram
participant Vue as slot-admin-vue
participant Ctrl as GameServerController
participant Logic as GameServerLogic
participant DB as game_server
Vue->>Ctrl: POST save不含 source
Ctrl->>Logic: add(data)
Logic->>Logic: generateUniqueSource()
Logic->>Logic: prepareCreateData()
Logic->>DB: insert
Logic->>Logic: sync(redis)
Ctrl-->>Vue: success
Vue->>Ctrl: PUT updatesource 只读或不传)
Ctrl->>Logic: edit(id, data)
Logic->>Logic: unset source
Logic->>DB: update
Logic->>Logic: sync(redis)
```
---
## 编号规则(已确认)
- **格式**6 位 **大写字母 + 数字** 混合(如 `A3K9X2`
- **字符集**`A-Z` + `0-9`(统一大写,与现有 `sync()``strtoupper($source)` 行为一致)
- **唯一性**:生成后查库 [`GameServerModel::getBySource()`](slot-admin/app/model/GameServerModel.php),冲突则重试(最多 20 次),失败抛 `ApiException`
- **存量数据**:已有渠道编号不变,仅新建渠道走自动生成
---
## 后端改动slot-admin
### 1. [`GameServerLogic.php`](slot-admin/app/game/logic/GameServerLogic.php)
**新增 `add()`**(替代当前未接入的 `save()`
- 调用 `generateUniqueSource()` 写入 `$data['source']`,忽略前端传入值
- 复用现有 `save()` 内创建前处理:`secret_key``format(extend_data)``dot_type`/`fb_status`/`fb_pix`
- `parent::add($data)``sync($data['source'])`
- 删除或内联原 `save()` 方法,避免双入口
**新增私有方法**(均需中文 PHPDoc
- `generateUniqueSource(): string` — 生成唯一 6 位编号
- `prepareCreateData(array $data): array` — 从原 `save()` 提取的创建前数据整理(可选,保持方法 ≤50 行)
**修改 `edit()`**
- 在更新前 `unset($data['source'])`,防止通过 API 篡改编号
- 其余逻辑保持不变
### 2. [`GameServerValidate.php`](slot-admin/app/game/validate/GameServerValidate.php)
- `save` 场景:**移除** `source`(后端生成,不要求前端传)
- `update` 场景:**移除** `source`(不可编辑)
- 可保留 `source` 规则定义供其他场景复用,但不再出现在 save/update scene
### 3. [`GameServerModel.php`](slot-admin/app/model/GameServerModel.php)(可选小改)
- 新增 `existsBySource(string $source): bool`,供 Logic 查重,语义更清晰(非必须,可直接用 `getBySource`
---
## 前端改动slot-admin-vue
### [`edit.vue`](slot-admin-vue/src/views/game/source/edit.vue)
**模板**(约 L19-23
- **新增模式**:不展示编号输入框;可加一行提示文案「渠道编号将在创建后自动生成」
- **编辑模式**:展示 `source``disabled` 只读输入框
**校验规则**(约 L306-311
- 移除 `source``required` 规则
**提交**(约 L344-357
- 新增/编辑提交前均 `delete data.source`,避免误传
列表页 [`index.vue`](slot-admin-vue/src/views/game/source/index.vue) 已有「编号」列,创建成功后刷新即可看到生成结果,无需改动。
---
## 安全与兼容
- 后端 `edit()` 强制 `unset source` 为最终防线,不依赖前端
- 新建渠道若前端仍传 `source`,后端忽略并覆盖为系统生成值
- 不影响 [`refreshFb`](slot-admin/app/game/controller/GameServerController.php) 等按 `source` 查询的现有功能
---
## 验证步骤
1. Docker 内创建渠道:不传编号,保存成功,列表出现 6 位字母数字编号
2. 编辑渠道:编号字段只读,修改名称等其他字段保存成功,编号不变
3. 尝试通过 API 直接 PUT 修改 `source`,确认后端不更新该字段
4. 执行 `SLOT_ROOT=/Users/ray/Documents/project/www/ray ~/.cursor/hooks/verify-slot-backend.sh`

View File

@@ -0,0 +1,167 @@
---
name: 移除 pending popup 表
overview: 移除 Lucky Rewards 转盘邀请人 Claim Now 弹窗对 `user_pending_popup` 的依赖,改为在 HomeEvent 中根据 `lucky_reward_player.pending_spin_count > 0` 动态构建弹窗;未领取前每次回大厅重复展示,直至 `claim-inviter-spin` 清零。
todos:
- id: build-inviter-popup
content: LuckyRewardInviteLogic 新增 buildInviterClaimNowPopup(),删除 notifyInviterInviteSuccess/enqueue
status: completed
- id: home-event-simplify
content: HomeEvent 改用 buildInviterClaimNowPopup移除 PendingPopupService
status: completed
- id: remove-pending-popup-infra
content: 删除 PendingPopupService/Model/DTO/Entity 及 deploy DDL 引用
status: completed
- id: update-tests-docs
content: 更新集成测、需求文档与 lucky_reward_deploy 冒烟说明
status: completed
isProject: false
---
# 移除 user_pending_popup改用 pending_spin_count 驱动转盘弹窗
## 背景与结论
当前邀请人「Claim Now」弹窗存在**双源**
```mermaid
sequenceDiagram
participant InviteBind as invite_bind
participant Player as lucky_reward_player
participant Grant as lucky_reward_spin_grant
participant Popup as user_pending_popup
participant Home as HomeEvent
InviteBind->>Grant: 写 invite_inviter grant
InviteBind->>Player: pending_spin_count += N
InviteBind->>Popup: enqueue lr_invite:{cycle}:{invitee}
Home->>Popup: fetchPending + consume
Home->>Player: resolvePendingSpinCount 注入 payload
```
- [`LuckyRewardInviteLogic::notifyInviterInviteSuccess()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 入队 `user_pending_popup`
- [`HomeEvent::appendLuckyRewardHomePopups()`](slot_console/app/command/event/HomeEvent.php) 再读 `pending_spin_count` 注入 payload
**全仓库检索结果**`PendingPopupService` / `user_pending_popup` **仅被 Lucky Rewards 使用**,无其它业务消费者。可以按你的要求移除该表及相关代码,改以 player 表为唯一触发源。
你已确认弹窗行为:**`pending_spin_count > 0` 时每次回大厅都弹,直到 `claim-inviter-spin` 领完**比旧「consume 后不再弹」更符合待领语义)。
---
## 目标行为
| 场景 | 是否弹 Claim Now | 数据来源 |
| --- | --- | --- |
| `pending_spin_count > 0` | 是,每次 HomeEvent flush | [`resolvePendingSpinCount()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) |
| 领取后 `pending_spin_count = 0` | 否 | claim 流程已有扣减 |
| `inviter_spin_reward = 0` | 否(无待领 Spin | 与 grant 逻辑一致 |
| 多次邀请、多笔待领 | **一条**弹窗,`pending_spin_count` 为累计值;被邀请人信息取**最早未领** grant | [`findUnclaimedInviterGrant()`](slot_console/app/model/common/LuckyRewardSpinGrantModel.php) + 解析 `biz_id` `invite_inviter:{cycle_id}:{invitee_uid}` |
弹窗 payload 保持与现网客户端兼容(`type: lucky_reward_invite_success`
```json
{
"type": "lucky_reward_invite_success",
"data": {
"invitee_uid": 200001,
"invitee_nickname": "Alice",
"invitee_avatar": "3",
"spin_reward": 1,
"cycle_id": 34,
"pending_spin_count": 2,
"title": "LUCKY YOU!",
"content": "You've received 1 Free Spin",
"button_text": "Claim Now",
"priority": 50
}
}
```
- `spin_reward`:当前最早未领 grant 的 `spin_count`(通常 1
- `pending_spin_count`player 累计待领总数(已有 [`resolvePendingSpinCount()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)
Support Invite被邀请人弹窗**不变**,仍走 [`buildSupportInvitePopup()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) + `ensureInviteeAutoOpenBox()`
---
## 代码改动
### 1. 新增邀请人弹窗构建方法
在 [`LuckyRewardInviteLogic`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 增加 public 方法,例如 `buildInviterClaimNowPopup(int $uid, string $source): array|false`
- 活动关闭 / 无有效轮次 → `false`
- `resolvePendingSpinCount($uid, $source) <= 0``false`
-`findUnclaimedInviterGrant($uid, $cycleId)`;若 grant 为空但 count>0脏数据→ 打 error 日志并 `false`
- 从 grant `biz_id` 解析 `invitee_uid``fetchUserProfile()` 取昵称/头像
- 返回与现网一致的 `type` + `data` 结构
### 2. 简化 HomeEvent
[`HomeEvent::appendLuckyRewardHomePopups()`](slot_console/app/command/event/HomeEvent.php)
- 删除 `PendingPopupService` 引用及 `fetchPending` / `consume` 循环
- 在 Support Invite 之后调用 `buildInviterClaimNowPopup()`,有则 `$luckyRewardPopups[]` 追加
- `pending_spin_count` 已在 popup data 内组装,无需二次注入
### 3. 删除 invite_bind 入队逻辑
[`LuckyRewardInviteLogic`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)
- 删除 `notifyInviterInviteSuccess()` 及对 `PendingPopupService::enqueue` 的调用(`handleInviteBind` 第 108 行)
- 移除 `PendingPopupService` / `PendingPopupEnqueueDTO` 依赖
- `InviteBindProcessContextDTO::$popupBizId` 若仅用于 popup可一并删除保留 `inviterBizId` 供 grant 幂等)
### 4. 移除 pending popup 基础设施(无其它引用)
删除 slot_console 内:
- [`app/service/PendingPopupService.php`](slot_console/app/service/PendingPopupService.php)
- [`app/model/common/UserPendingPopupModel.php`](slot_console/app/model/common/UserPendingPopupModel.php)
- [`app/dto/pendingPopup/PendingPopupEnqueueDTO.php`](slot_console/app/dto/pendingPopup/PendingPopupEnqueueDTO.php)
- [`app/entity/pendingPopup/*`](slot_console/app/entity/pendingPopup/)
DDL / 部署文档:
- [`backend/slot_admin/db/user_pending_popup.sql`](backend/slot_admin/db/user_pending_popup.sql) 标记废弃或删除
- 可选新增 `backend/slot_admin/db/user_pending_popup_drop.sql``DROP TABLE IF EXISTS user_pending_popup`)供已部署环境执行
- 更新 [`slot_console/doc/lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 部署步骤(去掉第 2 步建表)
### 5. 测试
更新 [`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php)
- 删除对 `UserPendingPopupModel` 的断言(约 6178、9699 行)
- 新增用例:`buildInviterClaimNowPopup` 在 bind 后返回非 false且含 `pending_spin_count``claimInviterSpin` 后返回 false
更新 [`LuckyRewardDbTestCase`](slot_console/tests/Integration/LuckyRewardDbTestCase.php)
- 去掉 `user_pending_popup` 表存在性检查与 cleanup
可选:新增单元测覆盖 `buildInviterClaimNowPopup` 的 grant biz_id 解析mock 较少时可放集成测)。
### 6. 文档
- [`docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §5Claim Now 改为 `pending_spin_count > 0` + `buildInviterClaimNowPopup`
- [`docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md`](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md):标注 Lucky Rewards 已不再使用通用表;若整表无其它用途则机制废弃
- [`lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md) 冒烟:邀请人回大厅见 Claim Now可重复至领取
---
## 行为差异说明(验收时注意)
| 项 | 旧user_pending_popup | 新pending_spin_count |
| --- | --- | --- |
| 未点 Claim 再次回大厅 | 不再弹(已 consume | **继续弹**(你已确认) |
| 多笔邀请 | 可能多条 popup 队列 | **一条**count 累计 |
| inviter_spin_reward=0 | 仍入队通知 | **不弹**count 为 0 |
---
## 验收清单
1. invite_bind success → `pending_spin_count` 增加,**不写** `user_pending_popup`
2. 邀请人 HomeEvent → popList 含 `lucky_reward_invite_success``pending_spin_count` 正确
3. 未 claim 前多次回大厅 → 弹窗仍出现
4. `POST claim-inviter-spin` 后 → `pending_spin_count=0`,弹窗不再出现
5. 被邀请人 Support Invite + auto openBox 不受影响
6. `RUN_DB_TESTS=1` 集成测通过verify + php -l PASS

View File

@@ -0,0 +1,140 @@
---
name: 移除被邀请人Spin配置
overview: 去掉错误的「被邀请人 invite_bind 发 Spin / invitee_spin_reward」能力保留 PRD 4.3 Support Invite在轮次有效期内按 helper 关系为被邀请人自动开宝箱一次(复用现有 openBox 自动 Spin过期轮次不建 helper、不开箱、不弹窗。
todos:
- id: remove-invitee-spin-grant
content: 删除 grantInviteeSpin/claim-invitee-spin/ProcessContext invitee 字段及 Controller 路由
status: completed
- id: support-invite-auto-openbox
content: 实现 ensureInviteeAutoOpenBox + 重构 buildSupportInvitePopupHomeEvent 接入
status: completed
- id: admin-remove-invitee-config
content: Admin/API/Model 去掉 invitee_spin_reward 配置项
status: completed
- id: docs-tests-invitee-removal
content: 更新 05/API 文档;调整集成测并跑 verify
status: completed
isProject: false
---
# 移除被邀请人 Spin 配置,改为 helper + 自动开宝箱
## 背景澄清
- **错误理解**`invitee_spin_reward` + `invite_bind` 给被邀请人预发 Spingrant_type=3 / `claim-invitee-spin`)。
- **产品本意**:被邀请人 Spin 来自**开宝箱**既有流程([`LuckyRewardLogic::openBox`](slot_console/app/api/logic/LuckyRewardLogic.php) 内 `createOpenBoxAutoFirstSpinRecord` + `grantDailySpinIfNeeded`**不**单独配置「被邀请人 Spin 次数」。
- **Support InvitePRD 4.3)保留**:有效期内按 **helper 关系**处理;**自动开宝箱一次**;轮次过期则**无 helper、不自动开箱、不弹 Support Invite**(与已有 `skipped_expired_cycle` 一致)。
```mermaid
sequenceDiagram
participant User as slot_user_register
participant Logic as LuckyRewardInviteLogic
participant Home as HomeEvent
participant Box as LuckyRewardLogic_openBox
User->>Logic: invite_bind wheel有效短码
alt cycle有效
Logic->>Logic: helper+邀请人pending_spin
Note over Logic: 不再 grantInviteeSpin
else cycle过期
Logic-->>User: skipped_expired_cycle
end
User->>Home: 被邀请人回大厅
alt helper存在且cycle有效且未开箱
Home->>Logic: ensureInviteeAutoOpenBox
Logic->>Box: openBox一次
Home->>User: SupportInvite弹窗my_amount
else 过期或无helper
Home-->>User: 无SupportInvite
end
```
---
## 1. 删除「被邀请人发 Spin」链路
### slot_console Logic / API
| 删除/停用 | 文件 |
|-----------|------|
| `grantInviteeSpinForHelper()` 及事务内调用 | [`LuckyRewardInviteLogic.php`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) |
| `claimInviteeSpin()` / `claimPendingSpinByGrantType(... INVITEE)` | 同上 |
| `POST claim-invitee-spin` | [`LuckyRewardController.php`](slot_console/app/api/logic/LuckyRewardController.php) + 路由 |
| `InviteBindProcessContextDTO``inviteeSpinReward``inviteeBizId` | [`InviteBindProcessContextDTO.php`](slot_console/app/dto/luckyReward/InviteBindProcessContextDTO.php) |
保留 `LuckyRewardSpinGrantModel::GRANT_TYPE_INVITEE` / 历史 grant 只读兼容(不在新流程写入)。
### 配置与后台
| 项 | 处理 |
|----|------|
| [`lucky_reward_config.invitee_spin_reward`](backend/slot_admin/db/lucky_reward.sql) | **停止读写**;可选后续 DDL 删列(本次可留列默认 0避免强迁移 |
| Admin 列表/编辑「被邀请人Spin」 | [`backend/slot_admin_vue/.../luckyReward/config/*.vue`](backend/slot_admin_vue/src/views/game/luckyReward/config/) 移除字段 |
| slot_console 保存配置 API | 若 DTO/Validator 含该字段,一并移除 |
| [`LuckyRewardConfigModel`](slot_console/app/model/common/LuckyRewardConfigModel.php) `@property` | 标注废弃或删除 |
### 文档
- 更新 [`05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md):删除被邀请人 grant/claim 描述;改为「被邀请人 Spin = 开宝箱流程」。
- 更新 [`lucky_reward_api.md`](slot_console/doc/lucky_reward_api.md):移除 `claim-invitee-spin`
- 在 PRD 侧注记:`invitee_spin_reward` 配置项作废(可选改 [`转盘活动-功能需求文档.md`](docs/requirements/转盘活动-功能需求文档.md) 配置表一行)。
---
## 2. Support Invite + 自动开宝箱(有效期内)
### 新增编排(`LuckyRewardInviteLogic`
**`ensureInviteeAutoOpenBox(int $uid, string $source): void`**
1. 解析 active cycle`resolveActiveCycle`);无进行中轮次 → return。
2. `LuckyRewardHelperModel::findByInviteeAndCycle($uid, $cycleId)` 无记录 → return无 helper 不开箱)。
3. `LuckyRewardPlayerModel``box_opened_at > 0` → return幂等
4. 调用 [`LuckyRewardLogic::openBox($uid, $source)`](slot_console/app/api/logic/LuckyRewardLogic.php)(吞「已开箱」类 BusinessException打 info 日志)。
**重构 `buildSupportInvitePopup()`**
- **删除**对 `findUnclaimedInviteeGrant` / `pending_spin_count` 的依赖。
- **条件**helper 存在 + active cycle 有效(`end_at > now`+ 已开箱(可先调 `ensureInviteeAutoOpenBox` 再读 player
- **payload**:邀请人头像/昵称、`my_amount_qf``target_amount_qf`(去掉 spin 待领字段)。
### HomeEvent 接入
[`HomeEvent::appendLuckyRewardHomePopups`](slot_console/app/command/event/HomeEvent.php) 顺序调整为:
```php
$inviteLogic->ensureInviteeAutoOpenBox($uid, $source);
$supportInvitePop = $inviteLogic->buildSupportInvitePopup($uid, $source);
// 再 merge pendingPopup...
```
过期 wheel 短码:`invite_bind``skipped_expired_cycle`**无 helper** → 上述两步自然 no-op。
---
## 3. 邀请人侧不变
- 邀请人仍:`pending_spin_count` + Claim Now 弹窗 + `claim-inviter-spin`
- wheel 分享 cycle 绑定方案**不改动**。
---
## 4. 测试
| 用例 | 预期 |
|------|------|
| invite_bind 成功 | 仅 inviter grant/helper**无** invitee grantinvitee `spin_available` 仍为 0 |
| invitee HomeEventhelper + 有效 cycle | 自动 `openBox` 一次;`spin_available` 来自 daily/openBox 逻辑Support Invite 有 `my_amount_qf` |
| 过期短码 invite_bind | `skipped_expired_cycle`;无 helperHomeEvent 无开箱、无 Support Invite |
| 删除 claim-invitee-spin 相关集成测 | 改为 auto openBox + Support Invite 断言 |
更新 [`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php)、[`LuckyRewardDbTestCase`](slot_console/tests/Integration/LuckyRewardDbTestCase.php)(去掉 `invitee_spin_reward` seed
---
## 5. 不在本次范围
- 修改开宝箱 / 每日 Spin 核心算法(仅**复用** `openBox`)。
- 删除 DB 列 `invitee_spin_reward`(可后续单独 migration
- 清理历史 `grant_type=3` 数据。

View File

@@ -0,0 +1,119 @@
---
name: 精简 Spin 响应
overview: 调整 `POST /api/lucky-reward/spin``SpinResultEntity`:去掉 spinId/prizeType/prizeAmountQf/myAmountDisplay新增 poolItemIdmyAmountQf 改为大单位 float3 位小数向下取整)。
todos:
- id: amount-format-3dp
content: LuckyRewardAmountService 新增 formatAmountDisplay3 + 单测
status: completed
- id: spin-result-entity
content: 精简 SpinResultEntity 字段poolItemId + myAmountQf float
status: completed
- id: logic-return
content: executeManualSpin 返回新结构
status: completed
- id: docs-yapi
content: 更新 lucky_reward_api.md §3 与 YApi spin 接口
status: completed
isProject: false
---
# 手动 Spin 响应精简方案
## 现状
- 路径:`POST /api/lucky-reward/spin`**无请求 Body**JWT 鉴权)
- 返回 [`SpinResultEntity`](slot_console/app/entity/luckyReward/SpinResultEntity.php) 由 [`LuckyRewardLogic::executeManualSpin()`](slot_console/app/api/logic/LuckyRewardLogic.php) 组装
- 抽奖结果 [`DrawResultEntity`](slot_console/app/entity/luckyReward/DrawResultEntity.php) 已含 `poolItemId`(与活动详情 `poolItems[].id` 同源,即 `reward_pool_item.id`
## 目标响应 `data`
| 字段 | 类型 | 说明 |
|------|------|------|
| poolItemId | int | 命中的奖池项 ID客户端对照 `poolItems` 定位格子/本地图) |
| myAmountQf | float | 抽奖后 My Amount**大单位、3 位小数、向下取整**(字段名沿用,语义变更) |
| spinAvailable | int | 剩余 Spin 次数 |
| playerStatus | int | 玩家状态 |
| isDuplicate | bool | 幂等重复(当前手动 Spin 仍固定 `false` |
**删除:** `spinId``prizeType``prizeAmountQf``myAmountDisplay`
示例:
```json
{
"poolItemId": 3,
"myAmountQf": 9.570,
"spinAvailable": 0,
"playerStatus": 1,
"isDuplicate": false
}
```
## 实现步骤
### 1. 金额格式化3 位小数)
在 [`LuckyRewardAmountService`](slot_console/app/service/luckyReward/LuckyRewardAmountService.php) 新增专用方法,例如 `formatAmountDisplay3(int $amountQf): float`
- 规则:`floor($amountQf) / 1000`,再 `number_format(..., 3, '.', '')` 转 float
- 与现有 2 位 `formatAmountDisplay()` 并存,避免影响 status/open-box/records 等接口
在 [`LuckyRewardAmountServiceTest`](slot_console/tests/Unit/LuckyRewardAmountServiceTest.php) 补充用例(如 `9570 → 9.570``9576 → 9.576`)。
### 2. 更新 Entity
修改 [`SpinResultEntity`](slot_console/app/entity/luckyReward/SpinResultEntity.php)
- 删除:`spinId``prizeType``prizeAmountQf``myAmountDisplay`
- 新增:`poolItemId`int
- 修改:`myAmountQf` 类型 `int → float`PHPDoc 注明「大单位 3 位小数展示值」
### 3. 更新 Logic 组装
[`LuckyRewardLogic::executeManualSpin()`](slot_console/app/api/logic/LuckyRewardLogic.php) 返回处改为:
```php
return new SpinResultEntity([
'poolItemId' => $drawResult->poolItemId,
'myAmountQf' => LuckyRewardAmountService::formatAmountDisplay3((int) $activityPlayer->my_amount_qf),
'spinAvailable' => (int) $activityPlayer->spin_available,
'playerStatus' => (int) $activityPlayer->status,
'isDuplicate' => false,
]);
```
- 服务端仍生成 `manualSpinId` 写库/日志,**仅不再返回给客户端**
- `prize_type``prize_amount_qf` 仍写入 `lucky_reward_spin_record`Record Tab 不受影响
### 4. 文档与 YApi
- 更新 [`slot_console/doc/lucky_reward_api.md`](slot_console/doc/lucky_reward_api.md) §3 字段表与示例
- 同步 YApi 手动 Spin 接口project 14cat_115 内 spin 对应 ID#553561 同组)
### 5. 自检
-`verify-slot-backend.sh` + docker `php -l`
-`LuckyRewardAmountServiceTest`、现有 `LuckyRewardDrawServiceTest`(确认 `poolItemId` 链路未断)
## 数据流(变更后)
```mermaid
sequenceDiagram
participant Client
participant SpinAPI as POST_spin
participant Logic as LuckyRewardLogic
participant Draw as DrawService
participant DB as spin_record
Client->>SpinAPI: JWT, no body
SpinAPI->>Logic: executeManualSpin
Logic->>Draw: draw(poolItems)
Draw-->>Logic: poolItemId, prizeType
Logic->>DB: spin_id, prize_type, prize_amount_qf
Logic-->>Client: poolItemId, myAmountQf(3dp), spinAvailable, playerStatus
```
## 影响范围
- **Breaking change**:依赖旧 Spin 响应字段的前端需改为用 `poolItemId` 对照 `poolItems` 展示命中格My Amount 读 `myAmountQf`float 3 位)
- **无改动**请求体仍为空Controller/Validator 无需改;后台奖池项 CRUD 不变

View File

@@ -0,0 +1,178 @@
---
name: 转盘与Agent分享归因
overview: 实现「转盘分享双计agent + 转盘、agent 分享仅计 agent」wheel 与 user_agent 各一条 share_url 短码MQ 的 share_origin 直接来自 invite_code 查表console 仅 share_origin=wheel 时发转盘助力。
todos:
- id: console-origin
content: "slot_console: wheel 独立落库 origin=wheelLogic 仅 wheel 计助力invite-link/createShareUrl 走 wheel 短码"
status: completed
- id: user-mq
content: "slot_user: shouldNotifyAgentByInviteOrigin 含 wheelMQ share_origin 来自 share_url.origin"
status: completed
- id: agent-filter
content: "slot_agent建议: console 回调粗筛 share_origin=wheel"
status: completed
- id: tests-docs
content: 单测/集成测 + 需求文档/YApi/deploy 对齐(撤销 wheel→user_agent 映射说明)
status: completed
isProject: false
---
# 转盘分享 vs Agent 分享单向归因方案share_origin 双短码)
## 产品规则SSOT
| 分享入口 | share_url.origin | Agent 邀请 | Lucky Rewards 助力 |
| --- | --- | --- | --- |
| 转盘分享(`from=wheel` / invite-link | `wheel` | 算 | 算 |
| Agent 分享(`from=user_agent` | `user_agent` | 算 | **不算** |
## 方案选型(已确认)
**方案 A两条短码**`wheel``user_agent``share_url` 各存一行,同一邀请人可有 **两个** `short_code`
- MQ `share_origin` 由注册时 `invite_code``share_url.origin` 得到,**无需** `landing_scene`、**无需** FE 注册透传额外字段。
- 撤销当前 [`ShareService::resolvePersistOrigin()`](slot_console/app/service/ShareService.php) 把 `wheel → user_agent` 的映射。
```mermaid
sequenceDiagram
participant Inviter
participant Console as slot_console
participant User as slot_user
participant Agent as slot_agent
alt WheelShare
Inviter->>Console: createShareUrl from=wheel
Console->>Console: share_url origin=wheel 短码W
Note over Inviter: 分享短码W
User->>User: register invite_code=W
User->>Agent: MQ share_origin=wheel
Agent->>Console: callback share_origin=wheel
Console->>Console: success发Spin
else AgentShare
Inviter->>Console: createShareUrl from=user_agent
Console->>Console: share_url origin=user_agent 短码A
User->>User: register invite_code=A
User->>Agent: MQ share_origin=user_agent
Agent->>Console: callback share_origin=user_agent
Console->>Console: skipped_not_wheel
Note over Agent: agent关系照常
end
```
---
## 为何之前不能「只改 MQ 不改落库」
当前实现把 `from=wheel` **映射成** `user_agent` 落库(复用一条短码)。此时代码查表得到的 `origin` 永远是 `user_agent`MQ 无法出现 `share_origin=wheel`,除非 FE 在注册时强行覆盖 —— 那与 `landing_scene` 同类,且语义与 DB 不一致。
**双短码**后:`invite_code` 本身即归因,链路最简。
---
## 实现步骤
### 1. slot_consolewheel 独立短码 + 助力判定
**[`ShareService`](slot_console/app/service/ShareService.php)**
- **删除或停用** `resolvePersistOrigin()` 对 wheel 的 `user_agent` 映射;`SHARE_FROM_WHEEL` 直接作为 `createUrl()``$from` / `ShareUrlModel.origin`
- `isAgentShareFrom()` 保持 `user_agent` + `wheel`agent 文案接口仍适用)。
- 更新/替换 [`ShareServiceWheelFromTest`](slot_console/tests/Unit/ShareServiceWheelFromTest.php):断言 wheel 创建后 `origin=wheel`,且与 `user_agent` 为**不同** `short_code`(同一 uid 两行)。
**[`GiftController::createShareUrl()`](slot_console/app/api/controller/GiftController.php)**
- `from=wheel``createUrl(ShareService::SHARE_FROM_WHEEL)`,不再经 `resolvePersistOrigin`
**[`LuckyRewardInviteLogic::buildInviteLink()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)**
- 同上,直接 `createUrl(SHARE_FROM_WHEEL)`
- PHPDoc 更新:不再写「落库复用 user_agent 短码」。
**[`LuckyRewardInviteLogic::handleInviteBind()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php)**
- 将现有「必须 `share_origin=user_agent`」改为 **必须 `share_origin=wheel`**
```php
if ($callbackDto->shareOrigin !== ShareService::SHARE_FROM_WHEEL) {
return $this->buildInviteBindResult(
InviteBindResultEntity::STATUS_SKIPPED_NOT_WHEEL,
'Invite code origin is not wheel'
);
}
```
**[`InviteBindResultEntity`](slot_console/app/entity/luckyReward/InviteBindResultEntity.php)**
- 新增 `STATUS_SKIPPED_NOT_WHEEL = 'skipped_not_wheel'`(保留旧 `skipped_not_user_agent` 常量亦可,新逻辑用新 status
- **不需要** `landing_scene` / `skipped_no_landing`(除非后续另有用途)。
**[`InviteBindCallbackDTO`](slot_console/app/dto/luckyReward/InviteBindCallbackDTO.php)**
- 已有 `shareOrigin`,无需新增 `landingScene`agent/SDK 侧 landing_scene 字段可留空,不读)。
### 2. slot_user发 MQ + agent 资格
**[`AbstractRegisterService::shouldNotifyAgentByInviteOrigin()`](slot_user/app/service/register/AbstractRegisterService.php)**
```php
return in_array($origin, ['user_agent', 'wheel'], true);
```
**[`notifyAgentInviteBind()`](slot_user/app/service/register/AbstractRegisterService.php)**
- `share_origin` 继续写 `$this->invite_share_origin`(来自 `share_url.origin`wheel 注册自然为 `wheel`
- **无需**新增 `landing_scene` 属性或 MQ 字段(与 agent 侧已有 `landing_scene` 字段兼容即可,留空)。
**[`resolveInviteUidByInviteCode()`](slot_user/app/service/register/AbstractRegisterService.php)** — 已读 `shareRow->origin`,双短码下无需改逻辑。
### 3. slot_agentconsole 回调粗筛(建议)
[`LuckyRewardInviteCallbackGatewayService::canNotifyInviteBind()`](slot_agent/app/service/LuckyRewardInviteCallbackGatewayService.php) 增加:
-`share_origin === 'wheel'` 时 HTTP 调 consoleagent 绑定、奖励、关系同步**不受影响**,仍处理全部 invite_bind MQ
- `user_agent` 绑定不再打 console减少无效请求。
### 4. 前端 / 产品说明
- 转盘页 Copy Link / 社媒分享:使用 **invite-link****create-share-url `from=wheel`** 返回的 `code`wheel 短码)。
- Agent 中心分享:继续使用 **`from=user_agent`** 返回的 `code`(另一条短码)。
- **不要混用**:用 agent 短码进转盘页,只计 agent、不计转盘 —— 符合产品规则。
### 5. 测试
| 仓库 | 用例 |
| --- | --- |
| slot_console | `ShareServiceWheelFromTest`:同 uid 存在 wheel + user_agent 两行、短码不同 |
| slot_console | `LuckyRewardInviteLogicUnitTest``share_origin=user_agent``skipped_not_wheel``wheel` + 新注册 → success |
| slot_console | `LuckyRewardInviteBindIntegrationTest``buildValidInviteBindPayload()``share_origin``wheel` |
| slot_user | `shouldNotifyAgentByInviteOrigin`wheel / user_agent 为 true其它为 false |
### 6. 文档与 YApi
- 更新 [`05_slot_console_邀请助力与弹窗方案.md`](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §2有效助力 = **新注册** + **`share_origin=wheel`**(双短码,非 landing_scene
- 更新 [`00_整体技术方案.md`](docs/requirements/lucky_rewards/00_整体技术方案.md) 归因段落。
- [`lucky_reward_deploy.md`](slot_console/doc/lucky_reward_deploy.md)、YApi **81** / invite-link说明 wheel 与 user_agent **不同 code**;撤销「复用 user_agent 短码」描述。
- innerapi 回调文档:`skipped_not_wheel``landing_scene` 标注为可选/未使用。
---
## 判定优先级console 更新后)
1. invalid_params
2. skipped_self_invite
3. skipped_old_user
4. **skipped_not_wheel**(原 skipped_not_user_agent 逻辑替换)
5. activity_closed
6. already_processed
7. success
---
## 风险与边界
- **历史已发出的 wheel 链接**:若当时用的是映射后的 `user_agent` 短码,升级后只计 agent、不计转盘新 wheel 链接需走 invite-link / `from=wheel` 拿新短码。可在发版说明中写清。
- **同一用户两条码**:运营/客服需知 wheel 与 agent 链接不可互换。
- **手工绑码**`share_url.origin` 决定 MQ `share_origin`;绑 agent 码不计转盘。
- **slot_sdk / agent** `landing_scene` 字段保留兼容,本期不参与判定。
---
## 涉及仓库
- **必改**`slot_console``slot_user`
- **建议改**`slot_agent`HTTP 粗筛 `share_origin=wheel`
- **不改**`slot_sdk`(已有 share_origin 转发)
- **FE**:使用正确短码即可,无 register 额外字段

View File

@@ -0,0 +1,172 @@
---
name: 转盘分享周期绑定
overview: 推荐在 `share_url` 增加通用 `biz_type` + `biz_id`(转盘绑定 `lucky_reward_cycle.id`),按当前轮次复用/新建短码;过期校验以 `lucky_reward_cycle.end_at` 为真源invite_bind 侧对过期轮次返回 skipped 而不影响注册。
todos:
- id: ddl-share-url-biz
content: share_url 增加 biz_type/biz_id + 唯一键;同步 slot_console/slot_user Model PHPDoc
status: completed
- id: share-service-wheel-reuse
content: ShareService wheel 分支:按 active cycle_id 复用或新建短码
status: completed
- id: invite-bind-expired-check
content: LuckyRewardInviteLogic invite_bind 校验 share 绑定 cycle 未过期且匹配 active cycle返回 skipped_expired_cycle
status: completed
- id: docs-tests
content: 更新 05 文档;单测/集成测覆盖同轮复用、跨轮新建、过期跳过
status: completed
isProject: false
---
# 转盘分享链接与活动轮次绑定方案
## 结论(直接回答你的二选一)
**推荐:`biz_type` + `biz_id`(转盘 `biz_id = cycle_id`),不推荐单独加 `expire_at` 作为唯一方案。**
| 方案 | 优点 | 缺点 |
|------|------|------|
| **仅 `expire_at`** | 查询简单(`expire_at > now` | 与 `lucky_reward_cycle.end_at` **双份真源**,易漂移;`user_agent`/`red_packet` 等 origin 语义不同,全局 `expire_at` 难统一 |
| **`biz_type` + `biz_id`(推荐)** | 与业务轮次一一对应;**有效期以 `lucky_reward_cycle.end_at` 为准**;同轮次内复用、新轮次新建;可扩展其它活动 | 需改 `ShareService` 查询与唯一键invite_bind 需多一步校验 |
可选:**可冗余 `expire_at = cycle.end_at` 仅作索引加速**,但判定仍应 join/查 `lucky_reward_cycle`,不以 `share_url.expire_at` 为 SSOT。
---
## 现状问题
[`ShareService::createUrl`](slot_console/app/service/ShareService.php) 通过 [`ShareUrlModel::isPlayerCreated($uid, $from)`](slot_console/app/model/ShareUrlModel.php) 按 `(creator_id, origin)` **永久复用**一条记录:
```php
$model = ShareUrlModel::isPlayerCreated($this->userEntity->uid, $from);
if ($model === false) { /* 新建 */ }
```
[`LuckyRewardInviteLogic::buildInviteLink`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 每次调 `createUrl(SHARE_FROM_WHEEL)`**新 cycle 开始后仍返回旧短码**。
注册侧 [`slot_user` AbstractRegisterService](slot_user/app/service/register/AbstractRegisterService.php) 只校验 `short_code` 存在,**不校验轮次**console `handleInviteBind` 直接用**当前 active cycle** 发奖,导致**旧链接可能计入新轮次**(与「每轮转盘有有效期」不符)。
你已确认过期策略:**注册/agent 关系照常Lucky Rewards 不计助力**。
---
## 推荐数据模型
在 [`s_common.share_url`](slot_user/app/model/ShareUrlModel.php) 增加:
```sql
ALTER TABLE share_url
ADD COLUMN biz_type varchar(32) NOT NULL DEFAULT '' COMMENT '业务类型wheel填lucky_reward_cycle',
ADD COLUMN biz_id bigint NOT NULL DEFAULT 0 COMMENT '业务IDwheel填lucky_reward_cycle.id';
-- wheel同一用户同一轮次唯一其它 origin 保持 biz 为空
ADD UNIQUE KEY uk_creator_origin_biz (creator_id, creator_type, origin, biz_type, biz_id);
```
语义约定:
| origin | biz_type | biz_id | 行为 |
|--------|----------|--------|------|
| `user_agent` / `red_packet` / `user_self` | `''` | `0` | 现网永久短码,不变 |
| `wheel` | `lucky_reward_cycle` | `cycle.id` | **每轮一条**,同轮复用 |
`code` 加密 JSON 可冗余写入 `cycle_id` 便于排查,但**复用查询走 DB 列**,不走解密。
---
## 核心流程
```mermaid
sequenceDiagram
participant Client as ActivityPage
participant Console as ShareService
participant Cycle as lucky_reward_cycle
participant Share as share_url
participant User as slot_user_register
participant Logic as LuckyRewardInviteLogic
Client->>Console: invite-link / createShareUrl from=wheel
Console->>Cycle: resolveActiveCycle
Console->>Share: find uid+wheel+biz(cycle_id)
alt 当前轮次已有短码
Share-->>Console: 复用 short_code
else 新轮次或无记录
Console->>Share: insert 新 short_code + biz_id
end
Console-->>Client: code + land_url
User->>Share: invite_code 查 short_code
User->>Logic: invite_bind share_origin=wheel
Logic->>Share: invite_code -> biz_id(cycle_id)
Logic->>Cycle: 校验 cycle 仍进行中且 end_at>now
alt cycle 已结束或不匹配 active
Logic-->>User: skipped_expired_cycle
else
Logic-->>User: 正常助力流程
end
```
---
## 实现要点(按服务)
### 1. slot_console — 分享创建
改动 [`ShareService::createUrl`](slot_console/app/service/ShareService.php)
- **`from !== wheel`**:保持 `isPlayerCreated(uid, from)`biz 为空)。
- **`from === wheel`**
1. `LuckyRewardConfigService::requireEnabledConfig` + `resolveActiveCycle`
2. `ShareUrlModel::findByPlayerBiz($uid, 'wheel', 'lucky_reward_cycle', $cycleId)`
3. 命中则复用;否则新建并写入 `biz_type/biz_id`
4. (可选)冗余 `expire_at = cycle.end_at` 仅索引
同步改 [`GiftController::createShareUrl`](slot_console/app/api/controller/GiftController.php) 与 [`LuckyRewardInviteLogic::buildInviteLink`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 路径(均走 ShareService一处改即可
[`ShareUrlModel`](slot_console/app/model/ShareUrlModel.php) + [`slot_user/ShareUrlModel`](slot_user/app/model/ShareUrlModel.php) 补 `@property` 与新查询方法。
### 2. slot_console — invite_bind 过期校验
在 [`LuckyRewardInviteLogic::handleInviteBind`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 有效助力判定链中(`skipped_not_wheel` 之后)增加:
1.`invite_code``share_url`console 可读 `share_url` 或经 slot_user innerapi优先 console 直读同库 `s_common.share_url`
2.`origin=wheel``biz_type=lucky_reward_cycle`
-`lucky_reward_cycle` by `biz_id`
-`status=已结束``end_at <= now()` → 返回新 status **`skipped_expired_cycle`**(注册/agent 不受影响,仅不发 Spin
-`biz_id != 当前 active cycle.id` → 同上(旧轮短码不计新轮助力)
在 [`InviteBindResultEntity`](slot_console/app/entity/luckyReward/InviteBindResultEntity.php) 增加常量 + 文档表更新([05 文档](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §3 判定表)。
### 3. slot_user — 无需阻断注册
按你的选择:**不在注册阶段 reject invite_code**。`AbstractRegisterService` 可不改,或仅补日志(`share_url.biz_id` + cycle 状态)便于排障。
### 4. 文档
更新 [05_slot_console_邀请助力与弹窗方案.md](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §2.1
- wheel 短码 **按 cycle 复用/新建**,非永久一条
- 过期短码:注册 OKLucky Rewards `skipped_expired_cycle`
---
## 测试
- **Unit**`ShareService` wheel 分支 — mock cycle`findByPlayerBiz` 命中复用 / 新 cycle 新建
- **Integration**:同一 uid 同 cycle 两次 `invite-link` 返回相同 `code`;模拟新 cycle 返回不同 `code`
- **Integration**:旧 cycle 短码 + invite_bind → `skipped_expired_cycle`,无 helper/grant
---
## 为何不选「只加 expire_at」
1. **真源重复**cycle 结束时间已在 [`lucky_reward_cycle.end_at`](backend/slot_admin/db/lucky_reward.sql);单独 `expire_at` 需与轮转任务同步,易不一致。
2. **无法表达「属于哪一轮」**:仅有 `expire_at` 难以区分「同用户第 N 轮 vs 第 N+1 轮」历史短码;`biz_id=cycle_id` 可精确归因与审计。
3. **影响面**`expire_at` 若加在全局 `share_url`,需约定 `user_agent` 等为 0/NULL`biz_id` 对非 wheel 恒为 0更清晰。
---
## 不在本次范围
- 修改 `user_agent` 分享逻辑
- 前端 Copy Link 缓存策略(后端保证同 cycle 幂等即可)
- 删除历史 cycle 的 `share_url` 行(可保留作审计;过期靠 invite_bind 拦截)

View File

@@ -0,0 +1,179 @@
---
name: 邀请回调改MQ
overview: 将 agent → console 的 Lucky Rewards 邀请助力从 HTTP innerapi 改为经 `console_bus` MQ 投递;删除 innerapi 与 slot_sdk 对应方法console EventBus 消费后复用现有 `LuckyRewardInviteLogic::handleInviteBind()`
todos:
- id: agent-mq-producer
content: "slot_agent: Gateway 改发 console_bus MQ + MQBusEntity 常量"
status: completed
- id: console-consumer
content: "slot_console: EventBus 消费 TYPE_LUCKY_REWARD_INVITE_BIND + 删 innerapi Controller"
status: completed
- id: sdk-cleanup
content: "slot_sdk: 删除 luckyRewardInviteBindCallback 及 Entity"
status: completed
- id: tests-docs-mq
content: 单测 + 需求/deploy 文档更新
status: completed
isProject: false
---
# Agent 邀请回调改走 console_bus MQ
## 目标
- **删除**`POST /innerapi/lucky-reward/invite-bind-callback`、slot_sdk `luckyRewardInviteBindCallback`
- **新增**agent 发 MQ → console `event:bus` 消费 → 发 Spin / helper
- **复用**[`LuckyRewardInviteLogic::handleInviteBind()`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 业务不变;仍仅 `share_origin=wheel` 计转盘助力
```mermaid
sequenceDiagram
participant User as slot_user
participant AgentBus as agent_bus
participant Agent as slot_agent
participant ConsoleBus as console_bus
participant Console as slot_console
User->>AgentBus: TYPE_INVITE_BIND
Agent->>AgentBus: 建关系/绑码奖励
Agent->>ConsoleBus: TYPE_LUCKY_REWARD_INVITE_BIND
Console->>Console: handleInviteBind
```
对照现网邮件:[`EventBus::notifyRewardEmail()`](slot_agent/app/command/EventBus.php) 已用 `EXCHANGE_CONSOLE` + `QUEUE_CONSOLE_BUS`
---
## 1. MQ 契约
**Exchange / Queue**(与现网一致):
- Exchange: `slot_console``MQKeyManagerService::EXCHANGE_CONSOLE`
- Queue: `console_bus``MQKeyManagerService::QUEUE_CONSOLE_BUS`
**新事件类型**agent、console 两侧常量字符串一致):
```php
const TYPE_LUCKY_REWARD_INVITE_BIND = 'lucky_reward_invite_bind';
```
**消息体**(与现 HTTP body 同形,便于 DTO 复用):
```json
{
"uid": 2001,
"type": "lucky_reward_invite_bind",
"data": {
"event_id": "invite_bind:2001",
"inviter_uid": 100,
"invitee_uid": 2001,
"invite_code": "ABC123",
"channel_code": "default",
"bind_time": 1710000000,
"share_origin": "wheel",
"is_new_register": 1,
"landing_scene": "",
"landing_token": ""
}
}
```
- `uid` = **被邀请人** `invitee_uid`(对齐其它 console_bus 消息)
- `event_id` 仍用 `invite_bind:{invitee_uid}` 幂等
---
## 2. slot_agent生产者
**重构** [`LuckyRewardInviteCallbackGatewayService`](slot_agent/app/service/LuckyRewardInviteCallbackGatewayService.php)
| 变更 | 说明 |
| --- | --- |
| 删除 | `ConsoleClient`、slot_sdk Entity、`consoleApiHost`、HTTP 重试 |
| 保留 | `isEnabled` 开关、`share_origin=wheel` 粗筛、参数校验 |
| 新增 | `RabbitMqService::getInstance(EXCHANGE_CONSOLE, QUEUE_CONSOLE_BUS)->sendMessageByBusEntity(...)` |
[`MQBusEntity`](slot_agent/app/entity/mq/MQBusEntity.php) 增加 `TYPE_LUCKY_REWARD_INVITE_BIND`
[`LuckyRewardInviteCallbackResultEntity`](slot_agent/app/entity/lucky_reward/LuckyRewardInviteCallbackResultEntity.php)
- `dispatched=true` 表示 **MQ 发送成功**
- `reason``mq_failed` 替代 `http_failed`;去掉 `console_api_host_empty`
**触发点不变**
- [`EventBus::inviteBindEvent()`](slot_agent/app/command/EventBus.php)(新建关系)
- [`AgentLogic::bindInviteCode()`](slot_agent/app/innerapi/logic/AgentLogic.php)(手工绑码补偿)
**配置**[`LuckyRewardInviteCallbackConfigService`](slot_agent/app/service/LuckyRewardInviteCallbackConfigService.php) 可移除 `timeout`/`retrySleep`HTTP 专用);保留 `lucky_reward_callback_enabled`
---
## 3. slot_console消费者
**[`MQBusEntity`](slot_console/app/entity/mq/MQBusEntity.php)**:增加 `TYPE_LUCKY_REWARD_INVITE_BIND`
**[`EventBus::deal()`](slot_console/app/command/EventBus.php)**:新增 `case`,调用 private `luckyRewardInviteBindEvent(int $uid, array $data)`
```php
$callbackDto = InviteBindCallbackDTO::fromRequest($busEntity->data);
$result = (new LuckyRewardInviteLogic())->handleInviteBind($callbackDto);
LoggerService::info('lucky_reward_invite_bind', $result->activeData());
```
**[`InviteBindCallbackDTO`](slot_console/app/dto/luckyReward/InviteBindCallbackDTO.php)**`fromRequest()` 已可读 MQ `data` 数组无需改签名PHPDoc 注明 HTTP/MQ 共用。
**ack 策略**(对齐业务语义,非 5xx 不重试):
- `handleInviteBind` 正常返回(含 `skipped_*``already_processed`)→ **ack**
- 未捕获 `Throwable`DB 异常等)→ **log + ack**(与多数 console_bus 分支一致;避免无限 requeue。若需失败重试可后续单独加 dead-letter本期不扩 scope。
**删除** [`app/innerapi/controller/LuckyRewardController.php`](slot_console/app/innerapi/controller/LuckyRewardController.php)(仅此一个 action
---
## 4. slot_sdk清理
删除或不再使用:
- [`ConsoleService::luckyRewardInviteBindCallback()`](slot_sdk/src/service/console/ConsoleService.php)
- [`LuckyRewardInviteBindCallbackRequestEntity`](slot_sdk/src/service/console/entity/LuckyRewardInviteBindCallbackRequestEntity.php)
- [`LuckyRewardInviteBindCallbackResultEntity`](slot_sdk/src/service/console/entity/LuckyRewardInviteBindCallbackResultEntity.php)
保留 `freeCreditsStatistics/list`admin 仍用)。
agent `composer.json` 若仅为该回调依赖 console SDK 路径无需改依赖agent 仍可能间接用 slot_sdk 其它能力)。
---
## 5. 测试
| 仓库 | 用例 |
| --- | --- |
| slot_console | 新增 `EventBusLuckyRewardInviteBindTest`mock AMQPMessage`type=lucky_reward_invite_bind`,断言调用 Logic / ack参考 [`EventBusFreeCreditInitTest`](slot_console/tests/Unit/EventBusFreeCreditInitTest.php) |
| slot_console | 现有 [`LuckyRewardInviteBindIntegrationTest`](slot_console/tests/Integration/LuckyRewardInviteBindIntegrationTest.php) 继续直调 Logic不受影响 |
| slot_agent | 单测 Gatewaywheel 发 MQ、user_agent skip、disabled 不发(可 mock RabbitMqService 或测 payload 组装 private 方法) |
---
## 6. 文档
- [01_slot_agent邀请回调对接方案.md](docs/requirements/lucky_rewards/01_slot_agent邀请回调对接方案.md)HTTP 改 MQ 时序图、删除 §6.1 innerapi
- [05](docs/requirements/lucky_rewards/05_slot_console_邀请助力与弹窗方案.md) §3接收方式改为 console_bus
- [00](docs/requirements/lucky_rewards/00_整体技术方案.md) §3.5 时序图Agent→Console 改为 MQ
- [lucky_reward_deploy.md](slot_console/doc/lucky_reward_deploy.md):去掉 `consoleApiHost`agent 调 console与 innerapi 冒烟项;补充 console `event:bus` 需运行
---
## 7. 部署注意
- **无需** agent 配置 `consoleApiHost`(仅此回调)
- **必须** slot_console `php webman event:bus` 消费 `console_bus`(与邮件、注册等共用进程)
- 发版顺序建议:**console 先上消费** → **agent 再切 MQ 生产**,避免短暂消息无人消费(旧 agent HTTP + 新 console 无 innerapi 窗口)
---
## 涉及文件摘要
**改**`slot_agent` Gateway + MQBusEntity + Config`slot_console` EventBus + MQBusEntity
**删**`slot_console/app/innerapi/controller/LuckyRewardController.php`slot_sdk 3 个 invite callback 文件
**不动**`LuckyRewardInviteLogic` 核心判定、C 端 `/api/*`

View File

@@ -0,0 +1,30 @@
{
"name": "cli-for-agent",
"displayName": "CLI for Agents",
"version": "1.0.0",
"description": "Patterns for designing CLIs that coding agents can run reliably: non-interactive flags, layered help with examples, pipelines, actionable errors, idempotency, and dry-run.",
"author": {
"name": "Cursor",
"email": "plugins@cursor.com"
},
"homepage": "https://github.com/cursor/plugins/tree/main/cli-for-agent",
"repository": "https://github.com/cursor/plugins",
"license": "MIT",
"keywords": [
"cli",
"command-line",
"agents",
"automation",
"terminal",
"flags",
"help"
],
"category": "developer-tools",
"tags": [
"cli",
"agents",
"automation",
"developer-tools"
],
"skills": "./skills/"
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Cursor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,11 @@
# CLI for Agents
Cursor plugin with a single skill that encodes patterns for **CLIs meant to be driven by coding agents**: non-interactive flags first, layered `--help` with examples, stdin and pipelines, fast actionable errors, idempotency, `--dry-run`, and predictable command structure.
## What it includes
- `cli-for-agents`: design and review guidance for agent-friendly command-line tools
## When to use it
Use when you are building or refactoring a CLI, writing subcommand help, or reviewing whether an existing tool will block agents (interactive prompts, missing examples, ambiguous errors).

View File

@@ -0,0 +1,87 @@
---
name: cli-for-agents
description: >-
Designs or reviews CLIs so coding agents can run them reliably: non-interactive
flags, layered --help with examples, stdin/pipelines, fast actionable errors,
idempotency, dry-run, and predictable structure. Use when building a CLI,
adding commands, writing --help, or when the user mentions agents, terminals,
or automation-friendly CLIs.
---
# CLI for agents
Human-oriented CLIs often block agents: interactive prompts, huge upfront docs, and help text without copy-pasteable examples. Prefer patterns that work headlessly and compose in pipelines.
## Non-interactive first
- Every input should be expressible as a flag or flag value. Do not require arrow keys, menus, or timed prompts.
- If flags are missing, **then** fall back to interactive mode—not the other way around.
**Bad:** `mycli deploy``? Which environment? (use arrow keys)`
**Good:** `mycli deploy --env staging`
## Discoverability without dumping context
- Agents discover subcommands incrementally: `mycli`, then `mycli deploy --help`. Do not print the entire manual on every run.
- Let each subcommand own its documentation so unused commands stay out of context.
## `--help` that works
- Every subcommand has `--help`.
- Every `--help` includes **Examples** with real invocations. Examples do more than prose for pattern-matching.
```text
Options:
--env Target environment (staging, production)
--tag Image tag (default: latest)
--force Skip confirmation
Examples:
mycli deploy --env staging
mycli deploy --env production --tag v1.2.3
mycli deploy --env staging --force
```
## stdin, flags, and pipelines
- Accept stdin where it makes sense (e.g. `cat config.json | mycli config import --stdin`).
- Avoid odd positional ordering and avoid falling back to interactive prompts for missing values.
- Support chaining: `mycli deploy --env staging --tag $(mycli build --output tag-only)`.
## Fail fast with actionable errors
- On missing required flags: exit immediately with a clear message and a **correct example invocation**, not a hang.
```text
Error: No image tag specified.
mycli deploy --env staging --tag <image-tag>
Available tags: mycli build list --output tags
```
## Idempotency
- Agents retry often. The same successful command run twice should be safe (no-op or explicit "already done"), not duplicate side effects.
## Destructive actions
- Add `--dry-run` (or equivalent) so agents can preview plans before committing.
- Offer `--yes` / `--force` to skip confirmations while keeping the safe default for humans.
## Predictable structure
- Use a consistent pattern everywhere, e.g. `resource` + `verb`: if `mycli service list` exists, `mycli deploy list` and `mycli config list` should follow the same shape.
## Success output
- On success, return machine-useful data: IDs, URLs, durations. Plain text is fine; avoid relying on decorative output alone.
```text
deployed v1.2.3 to staging
url: https://staging.myapp.com
deploy_id: dep_abc123
duration: 34s
```
## When reviewing an existing CLI
- Check: non-interactive path, layered help, examples on `--help`, stdin/pipeline story, error messages with invocations, idempotency, dry-run, confirmation bypass flags, consistent command structure, structured success output.

Submodule plugins/cache/cursor-public/figma/a742f0a700a7772ff5ed85f7c9fc1dad5afa9fcc deleted from a742f0a700

Submodule plugins/cache/cursor-public/figma/bea8bea5f676ab2bf76fa822b82f50b66653c098 added at bea8bea5f6

View File

@@ -1,16 +0,0 @@
The cursor-backend-control MCP calls Cursor backend APIs through the current user's authenticated Cursor session.
Automation tools:
- list_automations lists minimal, non-author-text automation rows visible to the current user. Its query matches only fields returned by the tool, such as IDs and trigger/action types.
- get_automation fetches one automation by ID with stored author text redacted and workflow values returned only as a redacted shape. Use it only after the user selected or provided the exact automation ID.
- create_automation creates an automation from a reviewed CreateAutomationRequest-shaped payload.
- update_automation updates an automation from a reviewed UpdateAutomationRequest-shaped payload.
- build_automation_prefill_url builds a cursor.com Automations prefill URL from a reviewed workflow JSON. Returns the URL string for the caller to open via open_resource or surface to the user.
Rules:
- Only call create_automation or update_automation after the user has reviewed the automation draft or requested the exact change.
- Do not invent an automation ID. If the user did not provide an ID, resolve it with list_automations, ask the user to choose from the returned IDs, and only then call get_automation when needed.
- These tools are unavailable in UNSPECIFIED and NO_STORAGE privacy modes because automations require reconciled storage eligibility.
- list_automations and get_automation require a fresh read confirmation before reading automation metadata; responses are redacted.
- create_automation and update_automation show a final confirmation modal before saving.
- build_automation_prefill_url is read-only and side-effect free; it does not call the backend, but still requires storage-eligible privacy mode because prefill serializes the draft outside the no-storage boundary.

View File

@@ -1,4 +0,0 @@
{
"serverIdentifier": "cursor-backend-control",
"serverName": "cursor-backend-control"
}

View File

@@ -1,4 +1,4 @@
{
"serverIdentifier": "plugin-figma-figma",
"serverName": "plugin-figma-figma"
"serverName": "figma"
}

View File

@@ -1,6 +1,6 @@
{
"name": "mcp_auth",
"description": "Authenticate this MCP server so its tools can be used. Call this tool through your MCP tool-calling interface when the server needs authentication.",
"description": "Authenticate this MCP server so the user can access all of its tools. When STATUS.md indicates this server needs authentication, you must call this tool soon through your MCP tool-calling interface.",
"arguments": {
"type": "object",
"properties": {},

View File

@@ -0,0 +1,10 @@
{"role":"user","message":{"content":[{"type":"text","text":"<timestamp>Tuesday, Jun 2, 2026, 8:17 PM (UTC+8)</timestamp>\n<user_query>\n把这个项目提交到 https://git.waixingkeji.net/ai-device/admin.git\n</user_query>"}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"まず現在のディレクトリの状態を確認します。\n\n The user wants to commit this project to a git repository, but the workspace isn't initialized as one yet, so I need to check what we're working with first."},{"type":"tool_use","name":"Shell","input":{"command":"git status 2>&1 | head -5; echo \"---\"; ls -la","description":"Check git status and list files"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":" The directory listing didn't come through, so I'm running it again to see the file structure."},{"type":"tool_use","name":"Shell","input":{"command":"ls -la","description":"List files in workspace"}}]}}
{"role":"assistant","message":{"content":[{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ai-device/admin/.gitignore"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"Git を初期化してリモートに接続し、コミット・プッシュします。"},{"type":"tool_use","name":"Shell","input":{"command":"git init && git remote add origin https://git.waixingkeji.net/ai-device/admin.git && git add -A && git status --short | head -20","description":"Init repo, add remote, stage files"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":" The vendor directory was properly excluded by gitignore, so I'm ready to commit and push these changes."},{"type":"tool_use","name":"Shell","input":{"command":"git commit -m \"init: ai-device admin project\" 2>&1 | tail -5","description":"Create initial commit"}}]}}
{"role":"assistant","message":{"content":[{"type":"tool_use","name":"Shell","input":{"command":"git branch -M main && git push -u origin main 2>&1 | tail -15","description":"Push to remote main branch","timeout":120000}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"完了しました。\n\nプロジェクトを `https://git.waixingkeji.net/ai-device/admin.git` に提交しました。\n\n- Git リポジトリを初期化し、リモート `origin` を追加\n- `.gitignore` に従い `vendor`、`runtime`、`.env` などを除外して全ファイルをステージ\n- 初回コミットを作成\n- `main` ブランチを作成し、リモートにプッシュ完了(`main -> main` 新規ブランチ)\n\nリモートの `main` ブランチにトラッキング設定済みなので、以降は `git push` だけで反映できます。"}]}}
{"role":"user","message":{"content":[{"type":"text","text":"<timestamp>Tuesday, Jun 2, 2026, 8:17 PM (UTC+8)</timestamp>\n<user_query>\n用中文\n</user_query>"}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"已完成。\n\n项目已成功提交到 `https://git.waixingkeji.net/ai-device/admin.git`\n\n- 初始化了 Git 仓库并添加远程 `origin`\n- 按 `.gitignore` 规则排除了 `vendor`、`runtime`、`.env` 等文件,暂存其余全部文件\n- 创建了首次提交\n- 创建 `main` 分支并推送到远程(新建分支 `main -> main`\n\n`main` 分支已设置好远程跟踪,之后只需 `git push` 即可推送更新。"}]}}

View File

@@ -0,0 +1,8 @@
{"role":"user","message":{"content":[{"type":"text","text":"<timestamp>Tuesday, Jun 2, 2026, 6:32 PM (UTC+8)</timestamp>\n<user_query>\n把这个项目推送到 https://git.waixingkeji.net/ai-device/device.git \n</user_query>"}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":" The user wants to push this project to a git repository, but the workspace isn't currently a git repo, so I need to check what's going on first."},{"type":"tool_use","name":"Shell","input":{"command":"git status 2>&1; echo \"---\"; ls -la","description":"检查 git 状态和目录内容"}}]}}
{"role":"assistant","message":{"content":[{"type":"tool_use","name":"Shell","input":{"command":"ls -la","description":"列出目录内容"}}]}}
{"role":"assistant","message":{"content":[{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ai-device/device/.gitignore"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"`.gitignore` 已正确忽略 `.env`、`vendor` 等。开始初始化并推送。\n\n Now I'm setting up version control—initializing the repository, adding the remote, and pushing the initial commit after checking what the default branch name is."},{"type":"tool_use","name":"Shell","input":{"command":"git init && git add -A && git status","description":"初始化仓库并暂存文件"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"All staged correctly (no `.env`/`vendor`/`runtime`). Now commit and push."},{"type":"tool_use","name":"Shell","input":{"command":"git commit -m \"$(cat <<'EOF'\ninit: AI device OTA service (webman)\nEOF\n)\" && git remote add origin https://git.waixingkeji.net/ai-device/device.git && git remote -v","description":"提交并添加远程仓库"}}]}}
{"role":"assistant","message":{"content":[{"type":"tool_use","name":"Shell","input":{"command":"git push -u origin main 2>&1","description":"推送到远程仓库","timeout":120000}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"推送完成。\n\n- 初始化 git 仓库,分支 `main`\n- 暂存 73 个文件并提交(`.env`、`vendor`、`runtime`、`.idea` 已按 `.gitignore` 排除,未上传)\n- 关联远程 `origin` → `https://git.waixingkeji.net/ai-device/device.git`\n- `git push -u origin main` 成功,本地 `main` 已跟踪远程\n\n提示本次提交使用了自动推断的提交者身份 `ray <ray@raydeMac-mini-2.local>`。如需修正,可执行 `git config user.name` / `git config user.email` 后再提交后续改动。"}]}}

View File

@@ -0,0 +1,26 @@
---
pid: 41277
cwd: "/Users/ray/Documents/project/docker"
command: "cd /Users/ray/Documents/project/www/english/collin-web && npm run dev 2>&1"
started_at: 2026-06-27T09:34:30.029Z
running_for_ms: 86397573
---
> collin-web@0.1.0 dev
> vite
VITE v7.3.6 ready in 428 ms
➜ Local: http://localhost:5173/
➜ Network: http://192.168.1.7:5173/
➜ Network: http://198.18.0.1:5173/
17:34:54 [vite] (client) ✨ new dependencies optimized: element-plus/es, element-plus/es/components/base/style/css, element-plus/es/components/container/style/css, element-plus/es/components/main/style/css, element-plus/es/components/aside/style/css, element-plus/es/components/menu/style/css, element-plus/es/components/menu-item/style/css
17:34:54 [vite] (client) ✨ optimized dependencies changed. reloading
17:35:34 [vite] (client) page reload src/main.ts
---
exit_code: unknown
elapsed_ms: 86400575
ended_at: 2026-06-28T09:34:30.604Z
---

View File

@@ -1,725 +0,0 @@
Vendors A-Z (G)
# Vendor Name begins with 'g'
| 1 | [G Gaming](https://www.igamingsuppliers.com/vendor/g-gaming/) Gibraltar, Gibraltar G Gaming is an iGaming company which develops slot games, scratchcards, video lotteries and more for the online real money games market. Categories: Other, Mobile Gaming, Lottery Software, Other, Other |
| --- | --- |
| 2 | [G Lighting](https://www.casinovendors.com/vendor/g-lighting/) St. Louis, Missouri Category: Systems |
| 3 | [G&D Consulting](https://www.igamingsuppliers.com/vendor/g-d-consulting/) Montes de Oca, San José, Costa Rica We are a leading law firm in Costa Rica with strong influence in Latin America. Our expertise expands especially in incorporation services, licensing and compliance for industries such as online gaming, cryptocurrency projects, DeFi, Web3, family offices, asset management, a... Category: Licensing and Regulation |
| 4 | [G&D Currency Technology](https://www.casinovendors.com/vendor/g-d-currency-technology/) Sterling, Virginia Billions of people place their trust in the value and authenticity of their banknotes. WIth our unique skills, we create innovative and secure foundations for monetary transactions. From forgery-proof currency design to the highly efficient processing of banknotes, all the w... Category: Currency Management Services |
| 5 | [G&G Closed Circuit Events LLC](https://www.casinovendors.com/vendor/g-g-closed-circuit-events-llc/) Campbell, California G&G Closed Circuit Events is the leader in providing boxing and Bellator events to commercial establishments like bars, restaurants, nightclubs and casinos. We have been serving the entire United States with quality Pay-per-view programming since 2009 through partnerships wi... Category: Pay-per-view |
| 6 | [G&K Services](https://www.casinovendors.com/vendor/g-k-services/) Hopkins, Minnesota Category: Supplies, Uniforms |
| 7 | [G.E.T. Enterprises](https://www.casinovendors.com/vendor/g-e-t-enterprises/) Houston, Texas Manufacturer of melamine dinnerware, plastic drinkware, hardwood and chrome tray stands for the casino food and beverage industry. Private labeling and custom logos are available upon request. Category: Equipment, Dinnerware |
| 8 | [G.H.I. Solutions, Inc. - Gaming Hospitality Information Solutions](https://www.casinovendors.com/vendor/g-h-i-solutions-inc-gaming-hospitality-information-solutions/) Las Vegas, Nevada G.H.I. Solutions is a company where our passion for technology and business process improvement translates into a more profitable business for you. We are a team of leading experts in the gaming and hospitality industries, and with decades of combined experience, we know ... Categories: Consulting, Computer Systems, Database Marketing, Consulting, Consulting |
| 9 | [G.Partners](https://www.igamingaffiliateprograms.com/affiliate-program/g-partners/) Category: Affiliate Programs |
| 10 | [G2 Database Marketing](https://www.casinovendors.com/vendor/g2-database-marketing/) Abita Springs, Louisiana With nearly 25 years in the casino industry and over 30 years of marketing management and analysis experience, we have the in-depth, hands on experience and record for success that will help you meet your bottom line objectives. Category: Database Marketing, Consulting |
| 11 | [Gable](https://www.casinovendors.com/vendor/gable/) Baltimore, Maryland As a leader in a new era of visual communications, Gable stands at the intersection of technology and craftsmanship, integrating digital displays, audiovisual, signage, and lighting into the most complex environments. We have the people, technology and experience to develop,... Category: Large Screen |
| 12 | [Gabsys](https://www.igamingsuppliers.com/vendor/gabsys/) Gabsys is a company that provides betting, gambling products and solutions along with industry best practice with new approaches tailored to meet your business needs. Categories: Sportsbook Software, Platform Providers, Gambling Operations |
| 13 | [Gaelco](https://www.casinovendors.com/vendor/gaelco/) Barcelona, Spain Gaelco is one of the most important video game developers and publishers in the world. Our recognised professional experience allows us to produce ever more entertaining and exciting games, providing players with unforgettable thrills and emotion. The secret of our success ... Category: Other |
| 14 | [Gafcon, Inc.](https://www.casinovendors.com/vendor/gafcon-inc/) San Diego, California Gafcon, Inc. offers a full range of Gaming and Hospitality Preconstruction and Construction related Professional Services, including Program Management, Construction Management, Reconstruction Services and Legal Support. Category: Management Services, General Contracting |
| 15 | [Gaff Tapes](https://www.casinovendors.com/vendor/gaff-tapes/) San Antonio, Texas We sell Adhesive products such as gaffers tape and spike tape used in Casino concerts and exhibitions. For over 20 years, Gaff Tapes has been catering to Las Vegas casinos such as the LVH, Caesars, and many more. We sell our products for 40% less than our competitors, no sal... Category: Other |
| 16 | [GAFFG - Gaming Affiliates Guide](https://www.igamingsuppliers.com/vendor/gaffg-gaming-affiliates-guide/) Gaffg.com is a portal for webmasters and affiliates in the online gambling industry. Of course any content that is relevant for online marketing will be present and any useful information about the online gaming business as a whole. This site aims to be the market place for ... Category: Other |
| 17 | [Gage Corporation, International](https://www.casinovendors.com/vendor/gage-corporation-international/) Sparta, Wisconsin The Gage Corporation, International serves architects and designers around the globe with distinctive metal architectural products. Gage is recognized worldwide as a premier supplier of specialty metal architectural products. Category: Metal |
| 18 | [Gaging.com](https://www.casinovendors.com/vendor/gaging-com/) Las Vegas, Nevada We are based in Las Vegas and specialize in product knowledge and after-sales service and training. We carry a wide range of industrial products and have over twenty-five years of measurement experience. Download our free Dice Micrometer instructions for Fowler & VIS micro... Category: Tools |
| 19 | [Galantz SRL](https://www.casinovendors.com/vendor/galantz-srl/) Buenos Aires, Capital federal, Argentina The Company is a very competitive provider of cash handling equipment with an excellent after sale service. Category: Counterfeit Detectors |
| 20 | [Galaxia Electronics Co., Ltd.](https://www.casinovendors.com/vendor/galaxia-electronics-co-ltd/) Seoul, South Korea Galaxia Electronics is the sister company of the Hyosung Group and we are the leading company of LED Display and LED Media Facade manufactuere in Korea. Category: LED Systems |
| 21 | [Galaxion LLC](https://www.casinovendors.com/vendor/galaxion-llc/) Odessa, Ukraine Galaxion is a Ukrainian company engaged in the field of gaming business: operation, sales, distributing, manufacturing and servicing of gaming equipment and components. Category: Amusement Equipment, Casino Software |
| 22 | [Galaxsys LLC](https://www.igamingsuppliers.com/vendor/galaxsys-llc/) Yerevan, Armenia Galaxsys offers a wide range of fast and skill games in the iGaming industry. Our game portfolio has been developed to allow our partners to increase their overall offering, improve both player acquisition and retention, and generate profitable growth. Category: Skill Games Software |
| 23 | [Galaxy 88 Ltd](https://www.casinovendors.com/vendor/galaxy-88-ltd/) London, United Kingdom Category: |
| 24 | [Galaxy Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/galaxy-affiliates/) London, England, United Kingdom Category: Affiliate Programs |
| 25 | [Galaxy Control Systems](https://www.casinovendors.com/vendor/galaxy-control-systems/) Walkesville, Maryland Category: Other, Other |
| 26 | [Galaxy Entertainment Group](https://www.casinovendors.com/vendor/galaxy-entertainment-group/) Central, Hong Kong Galaxy Entertainment Group (“GEG” or the “Group”) is one of the worlds leading resorts, hospitality and gaming companies. GEG is listed on the Hong Kong Stock Exchange and is a constituent of the Hang Seng Index. GEG is one of the three original concessionaires in Macau... Category: Other |
| 27 | [Galaxy Event Productions](https://www.casinovendors.com/vendor/galaxy-event-productions/) Sunrise, Florida Galaxy Event Production specializes in award winning, turnkey casino shows and entertainment. We are a full production company that will enhance your casino events! We specialize in grand openings and casino reopening's. We add new high energy to poker tournaments. Be sure ... Category: Theatrical Company, Promotions |
| 28 | [Galaxy Gaming](https://www.casinovendors.com/vendor/galaxy-gaming/) Las Vegas, Nevada "Delivering the finest gaming products and experiences in the galaxy" with table games such as the World's most popular side bet,"Lucky Ladies", 21+3, High Card Flush, World Poker Tour Heads Up Hold'em, Emperor's Challenge Pai Gow Poker and more. Also, offering players a ch... Category: New Game Manufacturer, Table Game Manufacturer |
| 29 | [Galaxy Plaza Ltd.](https://www.casinovendors.com/vendor/galaxy-plaza-ltd/) Vratsa, Vraca, Bulgaria Galaxy Plaza Ltd. is a Bulgarian private company, established in 1996 and specialized in design, production, delivery and installation of the fully furnishing for houses, stores, hotels, bars, coffee-houses, restaurants and offices. We have also a sheet metal processin... Category: Furnishings |
| 30 | [Galaxy Sign Source LLC](https://www.casinovendors.com/vendor/galaxy-sign-source-llc/) Chapel Hill, North Carolina Galaxy Sign Source is a newly formed company under the leadership of a management team who share over 100 years of combined expertise in sign sales, design and fabrication. Our research and manufacturing facility is located in China and this enables us to offer significant ... Category: Neon |
| 31 | [Galaxy4games](https://www.igamingsuppliers.com/vendor/galaxy4games/) Tallinn, Estonia Galaxy4Games team is based on high-skilled game industry professionals. Our experience spans match3, match2, farm, hidden objects, physics puzzles, and bingo projects along with different metagame mixes. Our main rules are fast development to test CPI, each stage optimiza... Categories: Software Development, Mobile Gaming, Mobile Gaming |
| 32 | [GalaxyText](https://www.casinovendors.com/vendor/galaxytext/) Dorvai, Quebec, Canada Offering SMS text message marketing along with mobile apps and mobile websites for casinos of all sizes. Category: E-messaging Systems |
| 33 | [Galera Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/galera-affiliates/) Category: Affiliate Programs |
| 34 | [Galewind Software Corp.](https://www.igamingsuppliers.com/vendor/galewind-software-corp/) Vancouver, British Columbia, Canada Our Adobe Flash application provides the ease of use of a non-download Casino with the rich graphics and fluid animation of a download product. Our offerings include the Practice Casino (shown here), a Bonus and/or Rebate Casino, and a full-featured Tournament Casino. All o... Category: Casino Software |
| 35 | [Gallagher Briody-Butler](https://www.casinovendors.com/vendor/gallagher-briody-butler/) Princeton, New Jersey Category: Other |
| 36 | [Gallant Background Checks](https://www.casinovendors.com/vendor/gallant-background-checks/) Owasso, Oklahoma Nation Wide background and drug testing services.Certified Business T.E.R.O Tribal Employment Rights Office through Cherokee Nation, Osage, Creek Tribes. We give tribal discounts as a way to give back to the tribes and to help the Indian Community. Our company has Integrity ... Category: Employee Screening, Security and Fraud |
| 37 | [Gallery Digital Signage](https://www.casinovendors.com/vendor/gallery-digital-signage/) Fairfield, New Jersey Gallery™ Digital Signage Solutions provides a unique combination of multimedia technology that will inform and effectively engage your audience. The Gallery™ Digital Signage software offering varies from single use to multiple use options showcased through a wide range of ki... Category: Monitors |
| 38 | [Gallery Street](https://www.casinovendors.com/vendor/gallery-street/) Roswell, Georgia Gallery Street is an e-commerce site that features an online fine art gallery and the capability to purchase museum quality giclee prints and innovative decor accessories based on art in the gallery. Gallery Street is the only online company that gives visitors access to an ... Category: Art, Wallcoverings |
| 39 | [Galls LLC](https://www.casinovendors.com/vendor/galls-llc/) Lexington, Kentucky Galls is your reliable source for quality, in-stock public safety equipment and uniforms. Like you, we're quick, efficient and effective. We understand that the demanding needs of your profession drive your purchasing decisions, so we demand the quality gear you require to d... Category: Uniforms |
| 40 | [Galston Associates](https://www.casinovendors.com/vendor/galston-associates/) Trimdon Village, England, United Kingdom Category: Other |
| 41 | [Gamanza Group](https://www.igamingsuppliers.com/vendor/gamanza-group/) OPERATORS & GAME DESIGNERS: TAKE CONTROL OF YOUR GAMES & EXCELERATE YOUR BUSINESS! We develop a state of the art DIY- & AGGREGATION GAMING PLATFORM. It contains: a great DYI Toolkit, which gives YOU the outstanding tools to design and easy assemble your own games. Surely ... Category: Platform Providers, Casino Software |
| 42 | [Gamatron](https://www.igamingsuppliers.com/vendor/gamatron/) Category: Casino Software |
| 43 | [Gambatria](https://www.casinovendors.com/vendor/gambatria/) Las Vegas, Nevada Gambatria (formerly known as Compu-Flyers) has more than 20 years of gaming analysis experience. The company was founded by Lenny Frome, considered for many years to be the premier analyst in the industry. The company is now run by his son Elliot, who has more than 15 year... Category: Game Design |
| 44 | [Gambee d.o.o. - Superior Gaming Experience](https://www.casinovendors.com/vendor/gambee-d-o-o-superior-gaming-experience/) Sezana, Slovenia Gambee is dedicated to providing cutting-edge solutions in the area of electronic and automated casino games. Our current focus lies in the design, production and support for advanced electronic table games and slot machines. Our solutions are successfully installed and used... Category: Table Games |
| 45 | [GamBetNews](https://www.casinovendors.com/vendor/gambetnews/) Cork, Munster, Ireland GamBet News, formerly Coin Op News Europe, is one of the oldest trade publications in the world for the gaming, betting, casino, bingo and lottery businesses. With unparalleled experience in the industry, GamBet News continues the tradition of providing the very best in up t... Category: Gaming Information, Business Publications |
| 46 | [Gamble Beast](https://www.igamingsuppliers.com/vendor/gamble-beast/) Gamble Beast is a market-leading provider of technology solutions to the sports betting and gaming industry supporting both the online and the land-based operations. We have combined together a strong and knowledgeable group of professionals with proven industry expertise... Categories: Platform Providers, Gambling Operations, Sportsbook Software |
| 47 | [Gamble Zen Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gamble-zen-partners/) Category: Affiliate Programs |
| 48 | [GambleFi Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gamblefi-affiliates/) Category: Affiliate Programs |
| 49 | [GambleID, LLC.](https://www.igamingsuppliers.com/vendor/gambleid-llc/) Houston, Texas GambleID (TSEVO) is a leading provider of Payment & Player Compliance solutions focused on online gaming. Our turn-key solution for daily fantasy sports, social gaming, regulated online poker, casino, and sports book operators features all of the payment management, cust... Categories: Software, Geolocation Services, Consulting |
| 50 | [GambleOn](https://www.igamingaffiliateprograms.com/affiliate-program/gambleon/) Category: Affiliate Programs |
| 51 | [Gamblers Anonymous International Service Office](https://www.casinovendors.com/vendor/gamblers-anonymous-international-service-office/) Gamblers Anonymous is a fellowship of men and women who share their experience, strength and hope with each other that they may solve their common problem and help others to recover from a gambling problem. Category: Other |
| 52 | [Gambler's Book Club](https://www.casinovendors.com/vendor/gambler-s-book-club/) Las Vegas, Nevada Since 1964, the world leading resource, largest and oldest bookshop specializing in books, computer software, and videos on gambling, casino management, employee training and all aspects of sports handicapping. Wholesale 70 titles, retails over 2,200. Open Monday-Saturday 9... Categories: Videos, Other, Books |
| 53 | [Gamblers General Store, Inc.](https://www.casinovendors.com/vendor/gamblers-general-store-inc/) Las Vegas, Nevada 6,000 items for the home gambler. A full line of chips, casino value, roulette, tournament, promotion in a variety of colors, weights and sizes. A new line of Casino and homestyle roulette wheels: 32 in., 30 in., and 19 in. Award wheels, dice, cards, custom poker chips, ta... Category: Home Gaming Products, Poker Chips |
| 54 | [GamblersPick](https://www.casinovendors.com/vendor/gamblerspick/) Or Yehuda, Israel GamblersPick.com is a community-driven online casinos portal that provides comprehensive information about all aspects of online gambling at online casinos. From industry news to casino and bonus reviews, as well as tips, tricks, and advice to enhance your chances of winning... Categories: Consumer Portals, Directories, Internet |
| 55 | [GambleStakes Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gamblestakes-affiliates/) Category: Affiliate Programs |
| 56 | [Gamblify ApS](https://www.igamingsuppliers.com/vendor/gamblify-aps/) Copenhagen, Denmark Gamblify ApS is a privately owned, independent company that produces hardware and software solutions for the gambling industry. The current product portfolio consists of a slot-machine platform, a betting terminal solution and an online casino. Category: Software Development, Casino Software |
| 57 | [Gambling Affiliation](https://www.financeaffiliateprograms.com/affiliate-program/gambling-affiliation/) Sliema, Malta Gambling-Affiliation.com, also known as Net Business Ltd, was created in 2006 by two french entrepreneurs. It offers its affiliates and brands an independent platform where both parties find a unique place to send and receive traffic dedicated to the iGaming industry. The fi... Category: Affiliate Programs |
| 58 | [Gambling Consulting](https://www.igamingsuppliers.com/vendor/gambling-consulting/) Boulogne, Île-de-France, France Gambling Consulting is specialized in E.U Gambling Markets. Experienced in all Marketing means to reach your targeted audience and increase your customer database at the lowest cost. Our pledge is to promote the highest professionalism and ethical standard. Category: Consulting |
| 59 | [Gambling Craft](https://www.igamingaffiliateprograms.com/affiliate-program/gambling-craft/) Gambling Craft is a reliable affiliate program with in house developed casino brands, affiliate platform and games currently in development. The team consists of iGaming experts with 10 years of experience in the industry. There are more than 300 employees that work with one... Category: Affiliate Programs |
| 60 | [Gambling Insider](https://www.casinovendors.com/vendor/gambling-insider/) London, England, United Kingdom Gambling Insider is the free premier event-driven B2B magazine for the gaming industry, delivering first-class industry knowledge, market analysis and trends, and in-depth interviews with those in the know. Members include top-level CEOs, COOs, directors, business owners and... Category: Magazines |
| 61 | [Gambling Invest](https://www.casinovendors.com/vendor/gambling-invest/) Providence, Grand' Anse (Mahé), Seychelles GamblingInvest.com is a domain names marketplace completely dedicated to gambling-related domains. From betting domains to casino and sportsbook names, from igaming domains to poker domains, at GamblingInvest.com companies and individuals within the gambling industry can ... Categories: Other, Other, Other, Other, Domain Registration |
| 62 | [Gambling Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gambling-partners/) Category: Affiliate Programs |
| 63 | [Gambling Soft](https://www.igamingsuppliers.com/vendor/gambling-soft/) Tyumen, Tyumen, Russia Gambling Soft is a relatively young casino software company from Russia. We tried to create a unique and competitive product at a low price, and we succeeded! We offer complete solutions for the iGaming business: slots, games with live dealers, casino sites, turnkey casin... Categories: Casino Software, Casino Software, Affiliate Program Software, Software |
| 64 | [Gambling Therapy](https://www.casinovendors.com/vendor/gambling-therapy/) Gambling Therapy is a Global Online Helproom for anybody affected by problem gambling. It is available in 28 different languages and mirrors all those languages that are offered by the gambling operators. Gambling Therapy offers forums, live advice, help and support, e-mail ... Category: Problem Gambling Treatment, Problem Gambling |
| 65 | [Gambling Turkey](https://www.igamingsuppliers.com/vendor/gambling-turkey/) Sliema, Malta, Malta Gambling Turkey, the ultimate iGaming digital marketing agency, helps businesses reach their full potential in the Turkish market with superpower of inside knowledge and tailor-made digital marketing services, including SEO, Link building, Web & Graphic design, Copywriting, ... Categories: Social Media, Consulting, Consulting, Translation Services, Website Content, Services |
| 66 | [Gambling Wages](https://www.igamingaffiliateprograms.com/affiliate-program/gambling-wages/)*Highest Revenue Sharing in the Industry for the Lifetime of Your Players *Access to Your Own Account Manager with Complete Tracking and Reporting *Fresh Content! *On-Time Payments! *Cutting Edge Marketing Technology and Effective Tools to Maximize Returns *2-Tier ... Category: Affiliate Programs |
| 67 | [GamblingDomains.io](https://www.igamingsuppliers.com/vendor/gamblingdomains-io/) GamblingDomains.io is the premier marketplace for gambling domains. We cover all the main gambling verticals including casino, bingo, sportsbetting, poker and lottery. Our domains include some that are well over 10 years old as well as ones that have an existing backlink pro... Category: Other, Domain Registration |
| 68 | [GamblingProfesional](https://www.igamingsuppliers.com/vendor/gamblingprofesional/) Montevideo, Montevideo, Uruguay GamblingProfesional is an independent Spanish speaking community, link between affiliates, affiliate programs, agencies and professionals involved in the online gambling and financial products market. Its administrators are not owners, nor do they have direct dependence bond... Category: Business Portals |
| 69 | [Gamblo Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gamblo-affiliates/) Category: Affiliate Programs |
| 70 | [Gamdom Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gamdom-affiliates/) Category: Affiliate Programs |
| 71 | [Game Box Builders](https://www.casinovendors.com/vendor/game-box-builders/) Greensboro, North Carolina Our company is owned and operated by leaders in the gaming industry. Game Box Builders is staffed by experienced engineers, designers, and cabinetry experts. Our facilities are equipped with state-of-the-art manufacturing technologies to meet the personalized demands of our ... Categories: Electronic Games, New Game Manufacturer, Bases-Cabinets-Stands (Wood) |
| 72 | [Game Design Automation Pty Ltd](https://www.casinovendors.com/vendor/game-design-automation-pty-ltd/), New South Wales, Australia Tools for the design of advanced slot machine mathematics and development of game prototypes. Categories: Game Design, Design, Other |
| 73 | [Game Guys LLC](https://www.casinovendors.com/vendor/game-guys-llc/) New Orleans, Louisiana Poker Productions offers a complete line of quality casino games for rent. Our friendly, knowledgeable and patient dealers will entertain and teach you guest how to play. Our prices are affordable and our customer service is second to none. We have been serving our customers... Category: Casino Party Rental |
| 74 | [Game Interaction Group BV](https://www.igamingsuppliers.com/vendor/game-interaction-group-bv/) AMESTERDAM, Netherlands Game Interaction Group, provides gaming operators with a complete and modular gaming platform in order to meet all customers requirements, no matter how big or small these might be. Thanks to 15 years experience in the i-gaming industry, we understand that lowering opera... Category: Other, Platform Providers |
| 75 | [Game Media Works (GMW)](https://www.igamingsuppliers.com/vendor/game-media-works-gmw/) Category: Casino Software, Gambling Operations |
| 76 | [Game Media Works](https://www.igamingsuppliers.com/vendor/game-media-works/) Larnaca, Cyprus Category: Platform Providers |
| 77 | [Game Show America](https://www.casinovendors.com/vendor/game-show-america/) Sun Prairie, Wisconsin Game Show America offers a number of exciting interactive floor promotions to draw traffic to your casino. We work with you and your promotions and marketing team to provide the best promotions possible to increase player loyalty. Each one of our game promotions are thorough... Category: Promotions |
| 78 | [Game Show Gurus](https://www.casinovendors.com/vendor/game-show-gurus/) Hoffman Estates, Illinois Game Shows are Winners With Your Guests, Which Means a Jackpot for Your Casino. Casinos can use our game shows for many things: •Entertainment Stages •Player Development •Floor Promotions •Traffic Building •Private Events/Banquets. We are very easy to work with and cost effe... Categories: Multi-media Productions, Stage Equipment, Production, Promotions |
| 79 | [Game Shows Alive](https://www.casinovendors.com/vendor/game-shows-alive/) Coral Springs, Florida Game Shows Alive can emulate, create and produce TV style game shows for use at any type of event. We offer full production anywhere in the United States. Category: Production |
| 80 | [Game Stands, LLC](https://www.casinovendors.com/vendor/game-stands-llc/) El Cajon, California Game Stands has a proven track record with over 24 years of experience. Integrity along with a solutions based focus gives Games Stands a unique opportunity to add value to our customers' business. Categories: Electronic Games, Accessories, Parts |
| 81 | [Game Time Amusement and Billiards](https://www.casinovendors.com/vendor/game-time-amusement-and-billiards/) Tempe, Arizona We have over 50 years experience in the Amusement and Gaming industry. We wholesale slot and video lottery machines worldwide as well as provide consulting in different applications. Category: Consulting, Amusement Equipment |
| 82 | [Game World Event Services, LLC.](https://www.casinovendors.com/vendor/game-world-event-services-llc/) St Charles, Missouri Game World Event Services specializes in corporate parties and trade shows. We carry a full line of professional grade casino equipment as well as simulators, video games, pool tables, inflatables, carnival and arcade activities. All of the equipment we offer is owned and op... Category: Amusement Equipment |
| 83 | [Game360](https://www.igamingsuppliers.com/vendor/game360/) Rome, Italy Game360, part of SG Digital, has developed a comprehensive, self made and proprietary platform which supports multichannel gaming by providing interfaces over web, mobile, tablet and other devices like smart tvs. This platform includes content management, customer relatio... Category: Platform Providers, Gambling Operations |
| 84 | [Game-Ace](https://www.igamingsuppliers.com/vendor/game-ace/) Kharkiv, Ukraine Game-Ace Creative Studio is a game development division of Program-Ace, headquartered in Eastern Ukraine. We are a talented and creative team of designers, artists, producers, programmers, and managers who are focused on crafting addictive games that amaze and excite players... Category: Casino Software |
| 85 | [Gameacon](https://www.casinovendors.com/vendor/gameacon/), New Jersey At its core, every casino has its theme and the demographics to which it caters. But today's, and the future's customers of the casino industry have grown up in a very technical world. They believe in different philosophies and look for an overall immersive experience to en... Category: Other, Conferences |
| 86 | [GameAnalytics Ltd](https://www.casinovendors.com/vendor/gameanalytics-ltd/) Edinburgh, Scotland, United Kingdom GamesAnalytics believes there is a new doctrine in games: Player Relationship Management. Founded in 2010, we bring together extensive expertise from both the games and data mining industries to offer cross-platform predictive analytics technology solutions. Headquartered in... Category: Other |
| 87 | [GameArt](https://www.igamingsuppliers.com/vendor/gameart/) Ta' Xbiex, Malta GameArt is an independent online casino software provider and developer, providing innovative games and cutting-edge solutions dedicated to online and landbased gaming operators. The company was founded in 2013 by a group of serial entrepreneurs who have had successful exper... Categories: Gambling Operations, Software Development, Casino Software, Mobile Gaming, Other |
| 88 | [GameBridge Services Limited](https://www.igamingsuppliers.com/vendor/gamebridge-services-limited/) Douglas, Isle of Man GameBridge provides everything you need to launch and grow your iGaming business - player management, bonuses, payments, CRM, risk & compliance, analytics, gamification, native apps, and much more - all in one platform. Ready for real-money casinos, sweepstakes, crypto gamin... Category: Gambling Operations, Platform Providers |
| 89 | [Gameburger Studios](https://www.igamingsuppliers.com/vendor/gameburger-studios/) Gameburger Studios is a game development studio launched in 2019 which is dedicated to producing premium games with all the trimmings. The company supplies their online games exclusively to Microgaming. Category: Casino Software |
| 90 | [GameCo](https://www.casinovendors.com/vendor/gameco/) New York, New York GameCo LLC is a pioneering company uniting the experience of playing video games with the excitement of gambling by creating the worlds first Video Game Gambling Machines (VGM™). Video Game Gambling combines the fun and interactivity of video games with the thrill and an... Category: Slot Machines |
| 91 | [GameColony.com Affiliate Program](https://www.igamingaffiliateprograms.com/affiliate-program/gamecolony-com-affiliate-program/) Category: Affiliate Programs |
| 92 | [Gamecraft](https://www.casinovendors.com/vendor/gamecraft/) Rydalmere, New South Wales, Australia Gamecraft develop progressive jackpot link strategies to increase gaming machine performance and revenue. Our main effort is to create value by achieving a sustained increase in turnover to gaming machine operations. Category: Other, Progressive Jackpot Equipment |
| 93 | [GamedayMath](https://www.igamingsuppliers.com/vendor/gamedaymath/) Orlando, Florida GamedayMath is a bettors guide to getting an edge against the sportsbooks. With us, there is unlimited earning potential with our affiliate program. There's no ceiling on how much you can earn, offering you the freedom to maximize your income. The more effort and skill you ... Category: Sportsbook Software |
| 94 | [Gamefish Global](https://www.igamingsuppliers.com/vendor/gamefish-global/) Sydney, New South Wales, Australia Gamefish Global is a premium casino game development and distribution provider. Category: Casino Software, Casino Software |
| 95 | [Gamegram Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gamegram-affiliates/) Category: Affiliate Programs |
| 96 | [GameGrow Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gamegrow-partners/) Category: Affiliate Programs |
| 97 | [GameHouse](https://www.igamingsuppliers.com/vendor/gamehouse/) At GameHouse, we believe its good to game. Thats why we are dedicated to a single mission: to enrich lives through games and experiences that people love to play and share. As the largest developer, publisher, and distributor of casual games with millions of players around... Categories: Software Development, Casino Software, Mobile Gaming, Other |
| 98 | [Gameiom Technologies Limited](https://www.igamingsuppliers.com/vendor/gameiom-technologies-limited/) Douglas, Isle of Man GAMEIOM has two main objectives: firstly, to provide an aggregation platform that allows game developers a quick and viable route to market; and secondly, to provide content, including proprietary products, that excites and engages players from all over the globe. We are ... Category: Platform Providers, Casino Software |
| 99 | [GameOn Consultants Limited](https://www.igamingsuppliers.com/vendor/gameon-consultants-limited/) Onchan, Isle of Man GameOn Consultants offers a wide range of services from advice and assistance with implementation of products and licensing, sourcing and managing white label solutions; developing product set up requirements, devising bonus and loyalty strategies, fraud and risk analysis an... Categories: Licensing and Regulation, Consulting, Security and Fraud, Consulting |
| 100 | [GameOn Marketing Limited](https://www.igamingsuppliers.com/vendor/gameon-marketing-limited/) Isle of Man, United Kingdom Categories: Other, Search Engine Optimization, Trade Shows and Conferences |
| 101 | [GameOn Marketing](https://www.igamingaffiliateprograms.com/affiliate-program/gameon-marketing/) Onchan, Isle of Man GameOn Affiliates, a division of GameOn International Limited, provides gaming clients with tailored affiliate management services and excellent customer value. We specialise in taking the extra step by focusing directly on the player acquisition journey, from affiliate recr... Categories: Affiliate Programs, Consulting, Consulting |
| 102 | [GamePlan Consultants Pty. Ltd.](https://www.casinovendors.com/vendor/gameplan-consultants-pty-ltd/) Burleigh Heads, Queensland, Australia Our entire focus in training and consulting is based on the CRM philosophy. We believe that CRM starts with the right people, and the way in which the casino treats its own people. Internal marketing is thus a major thrust of our organization wherein we blend marketing and H... Category: Consulting |
| 103 | [Gameplay Interactive](https://www.igamingsuppliers.com/vendor/gameplay-interactive/) Gameplay Interactive provide the most engaging and gaming experience for your players consists of many online gaming product including the industry leader in Live Dealers Casino, 3D Slot and Games, Lottery (Keno and iLotto), Sportsbetting, P2P games such as Poker Mahjong pro... Categories: Casino Software, Poker Software, Live Dealer, Sportsbook Software, Gambling Operations |
| 104 | [Gameplay Media GmbH](https://www.igamingsuppliers.com/vendor/gameplay-media-gmbh/) Frankfurt, Germany GamePlay Media GmbH is a media buying & planning agency for the entertainment sector. The range of services includes all aspects of online marketing like social media, SEM, SEO, real-time bidding (RTB) and display, affiliates and newsletter marketing. Category: Social Media |
| 105 | [Gamer Casino Seating](https://www.casinovendors.com/vendor/gamer-casino-seating/) Parkmore Sandton, Gauteng, South Africa Gamer Entertainment Products is a South African based company, specializing in the manufacturer of customized casino slot and table seating. Gamer Entertainment is is a vibrant, young and innovative manufacturer of casino table and slot seating whose creative designs emphasi... Categories: Bases-Cabinets-Stands (Wood), Bases-Cabinets-Stands (Metal), Other |
| 106 | [Gameroom Gallery](https://www.casinovendors.com/vendor/gameroom-gallery/) Ridgeland, Mississippi We are Central Mississippi's oldest and largest pool table and Gaming supplier. We offer a full array of casino supplies, game seating, barstools, combination game tables, billiard table lights, wall art, pool cues, air hockey, foosball tables, restaurant seating and amuseme... Categories: Casino, Furnishings, Furnishings |
| 107 | [Gameroomdepot](https://www.casinovendors.com/vendor/gameroomdepot/) anjou, Quebec, Canada Categories: Equipment, Blackjack Tables, Equipment, Equipment, Other, Chips, Manufacturer |
| 108 | [Games Global Limited](https://www.igamingsuppliers.com/vendor/games-global-limited/) Douglas, Isle of Man Games Global is a supplier of unique and innovative iGaming content. Bringing together some of online gaming's biggest and brightest stars, the Games Global portfolio is home to thousands of titles from 50+ studio partners. Category: Casino Software |
| 109 | [Games Marketing Services](https://www.casinovendors.com/vendor/games-marketing-services/) Paris, France In the advisory field, Games Marketing Services approach is market and customer orientated. In-depth analysis and understanding of customer objectives allow suitable solutions in terms of means, structure and deadlines. The proximity that defines each of GMS missions result... Category: Multi-media Productions |
| 110 | [Games Valley](https://www.igamingsuppliers.com/vendor/games-valley/) Cluj Napoca, Romania Games Valley delivers a modern, technology-led approach to game aggregation, designed to meet the needs of todays iGaming operators. Our team brings decades of hands-on industry knowledge, which has shaped a resilient and scalable infrastructure built for high performance. ... Category: Other |
| 111 | [Games Warehouse](https://www.casinovendors.com/vendor/games-warehouse/) Pride Park, England, United Kingdom Games Warehouse has grown to become the leading supplier of pay-to-play video entertainment terminals in the UK. The Company has developed an ever-expanding portfolio of gaming and skill/entertainment products targeted at its core UK customer base and beyond. We are co... Categories: Game Design, Casino Software, Mobile Gaming |
| 112 | [GameScale Europe Limited](https://www.igamingsuppliers.com/vendor/gamescale-europe-limited/) St. Paul's Bay, Malta GameScale provides a unique gaming platform designed for running a successful online gaming business. Our mission is to provide you with the best technology, which is custom, suited to your present and future needs. We can build exclusive software to specification or help yo... Categories: Live Dealer, Casino Software, Sportsbook Software, Racebook Software |
| 113 | [GAMESERVICE S.C.](https://www.casinovendors.com/vendor/gameservice-s-c/) Krosno, Poland Gameservice company is one of the members of Gameservice Group, with headquarters in Haczów, Poland. It is engaged in the manufacture of highly advanced gaming machines. In its designs, the company uses exclusively components from renowned and world-wide acknowledged comp... Category: Slot Machines |
| 114 | [GamesGuru Pvt. Ltd.](https://www.igamingsuppliers.com/vendor/gamesguru-pvt-ltd/) New Delhi, Delhi, India Established in 2016, Games Guru is India's driving diversion development organization, giving Casino Game Development and Casino art production services to the worldwide Casino games industry with master's games engineers, design and creation directors working in our workpla... Categories: Casino Software, Poker Software, Bingo Software, Betting Exchange Software, Skill Games Software, Consulting |
| 115 | [Gamesman Limited](https://www.casinovendors.com/vendor/gamesman-limited/) West Sussex, United Kingdom Illuminated push-buttons & reel mechanisms. Category: Parts |
| 116 | [GameSpring Co. Ltd.](https://www.casinovendors.com/vendor/gamespring-co-ltd/) Seoul, South Korea Casino / Poker game development specialist. Texas Holdem, Badugi, Omaha, High-Low resizing, multitable, replay and even straddle and more features. Online baccarat, blackjack, roulette, taisai, caribbean poker, casino war, slotmachine and World unique squeeze baccarat Se... Categories: Poker Software, Casino Software, Multi-player Games |
| 117 | [GamesScorekeeper](https://www.igamingsuppliers.com/vendor/gamesscorekeeper/) Aarhus, Århus, Denmark Today GameScorekeeper delivers esports data and content solutions to some of the leading players in the esports market. Our clients range from betting operators to media companies and fantasy leagues. With extensive coverage of the three biggest esports, CS: GO, League of... Category: Other, Gambling Operations |
| 118 | [Gamesys Limited](https://www.igamingsuppliers.com/vendor/gamesys-limited/) London, England, United Kingdom Gamesys develops proprietary multi-platform gaming software consisting of Instant Win, Bingo and Casino Games along with quality promotional and account management tools such as software and design, system security, hosting and maintenance, game development, reporting and Eb... Category: Bingo Software, Casino Software |
| 119 | [Gamevy Limited](https://www.igamingsuppliers.com/vendor/gamevy-limited/) London, England, United Kingdom Gamevy is an award-winning, licensed supplier and operator producing a high- quality, select range of real-money games. The company believes in combining skill, chance and life-changing jackpots for the ultimate in fun. Categories: Casino Software, Skill Games Software, Lottery Software, Mobile Gaming |
| 120 | [Gamewise](https://www.igamingsuppliers.com/vendor/gamewise/) Miami, Florida Gamewise is a turnkey digital gambling, sportsbook, and gaming infrastructure solution. Category: Gambling Operations |
| 121 | [Gaminator](https://www.igamingsuppliers.com/vendor/gaminator/) San Francisco, California Gaminator Casino is a renowned iGaming provider that offers investors a full range of solutions for launching and supporting gaming start-ups. Having started as a small enterprise, the company has achieved stunning success and gained recognition in several markets at once: t... Category: Casino Software |
| 122 | [Gaming & Entertainment Touch Technology](https://www.casinovendors.com/vendor/gaming-entertainment-touch-technology/) Las Vegas, Nevada We stock over 45,000 Touch Sensors in our Inventory and we Guarantee to have the lowest prices on Touch Sensors. Our Casino Air products, SmartPower Systems, and Ceronix Monitors are 3 more great ways we offer to save you time and money. Please visit us at www.get-t.net and ... Categories: Touchscreens, LCD, Monitors, Surge Suppression, Power Sources, Air Filtration Systems |
| 123 | [Gaming & Leisure](https://www.casinovendors.com/vendor/gaming-leisure/) Las Vegas, Nevada Gaming & Leisure® (G&L) is dedicated to the betterment of the gaming and hospitality industry in all that we do. G&L platforms and offerings provide 360° insight into every industry aspect and reaches owners, operators and the business partners who serve them domestically an... Categories: Other, Magazines, Consulting, Other |
| 124 | [Gaming & Resort Development, Inc.](https://www.casinovendors.com/vendor/gaming-resort-development-inc/) Laguna Woods, California The company has a 25 year history of providing comprehensive development & operational consulting, including highly regarded feasibility study services, for casino & resort projects worldwide, and for Tribal Communities in the U.S. & Canada. Categories: Development: Indian Gaming, Market Research and Development, Consulting, Feasibility Studies, Consulting, Consulting |
| 125 | [Gaming Analytics, Inc.](https://www.casinovendors.com/vendor/gaming-analytics-inc/) Berkeley, California Gaming Analytics offers software solutions that help casino operators make strategic improvements to the casino floor. GA saves time with AI doing the hard work for you. Category: Software Development |
| 126 | [Gaming Arts, LLC](https://www.casinovendors.com/vendor/gaming-arts-llc/) Las Vegas, Nevada Gaming Arts, a leader in "Life Changing" gaming products, is dedicated to bringing innovation and excitement to the Gaming industry. The Gaming Arts management team includes leaders in the field with many decades of experience to the younger tech savvy, providing a managemen... Category: Other |
| 127 | [Gaming Associates](https://www.casinovendors.com/vendor/gaming-associates/) Bella Vista, New South Wales, Australia Gaming Associates provide payment card industry (PCI), regulatory compliance, corporate governance and compliance, enterprise risk management to casinos, lottery operators, regulators, bet exchanges, bookmakers... Gaming is our business. PCI certification and implementation.... Categories: Consulting, Consulting, Consulting, Other, Consulting |
| 128 | [Gaming Books International](https://www.casinovendors.com/vendor/gaming-books-international/) Las Vegas, Nevada Have been selling these books since 1985 and they continue to be in demand because they are easy to understand and are priced right at $3.50 Retail. These are humorous and informative books on Las Vegas games. Category: Gaming Information |
| 129 | [Gaming Capital Group](https://www.casinovendors.com/vendor/gaming-capital-group/) Newcastle, Oklahoma Gaming is a highly challenging environment for traditional lenders. Often, new projects must struggle to find the right financing mix to get their project off the ground. Gaming equipment manufacturers and distributors often need growth capital based on their equipment ass... Categories: Leasing, Other, Financing |
| 130 | [Gaming Cards LTD](https://www.casinovendors.com/vendor/gaming-cards-ltd/) Santa Ana, California Category: Playing Cards |
| 131 | [Gaming Consultants International](https://www.casinovendors.com/vendor/gaming-consultants-international/) Dingley, Victoria, Australia Internationally recognised gaming consultants with extensive experience in slot machines, slot systems, performance analysis and improvement, technical standards, government relations and overall casino/gaming project management. Category: Consulting |
| 132 | [Gaming Corps](https://www.igamingsuppliers.com/vendor/gaming-corps/), Sweden Gaming Corps is a Swedish video game and interactive entertainment company with offices and development resources in Stockholm, Austin and Malta. Category: Casino Software, Casino Software |
| 133 | [Gaming Entertainment](https://www.igamingsuppliers.com/vendor/gaming-entertainment/) Sofia, Sofija-Grad, Bulgaria As a company we are constantly striving to evolve, with a team of seasoned rockstars in the iGaming industry, we make sure to stay one step ahead of the curve. We are constantly monitoring the ever changing landscape of the scene and quickly adapt our operations and vision t... Category: Platform Providers, Gambling Operations |
| 134 | [Gaming Equipment Manufacturing (GEM)](https://www.casinovendors.com/vendor/gaming-equipment-manufacturing-gem/) Khimki, Moskva, Russia Gaming tables, chairs, wheels, accessories. Categories: Table Game Manufacturer, Slot Stools, Equipment, Chips, CCTV Systems |
| 135 | [Gaming Floor](https://www.casinovendors.com/vendor/gaming-floor/) London, England, United Kingdom Gaming floor is a leading worldwide resource for casino trade and industry news. Content includes daily headline newslinks and press releases. Product and suppliers, stock prices, operator web site listings by coutry & continent, conference and exhibition dates, casino emplo... Categories: Gaming Information, Internet, Education |
| 136 | [Gaming Gifts](https://www.casinovendors.com/vendor/gaming-gifts/) Las Vegas, Nevada GAMING GIFTS - Supplier and manufacturer of Exquisite Casino Gaming Gifts & Awards. The sculpted, polished beauty of our crystal pieces make them unique, one-of-a-kind gifts for your all your Special Events & Tournaments. These popular designs of the Royal Flush, Blackjack, ... Categories: Gift Merchandise, Imprinted Products, Promotions |
| 137 | [Gaming in EU](https://www.igamingsuppliers.com/vendor/gaming-in-eu/) Gemert, Netherlands Gaming in EU organizes organizes the annual Gaming in Spain, Gaming in Germany and Gaming in Holland conferences. The conferences offer knowledge and networking to everyone who is professionally involved in the gaming industry: from business executives to independent consult... Categories: Trade Shows and Conferences, Trade Shows and Conferences, Trade Shows and Conferences, Business Publications, Business Publications, Business Publications |
| 138 | [Gaming in Holland](https://www.casinovendors.com/vendor/gaming-in-holland/) Gaming in Holland is the leading platform for Gaming and Lotteries in the Netherlands. With weekly local News updates and the Yearly Conference, we reach all industry decision makers in this space. Category: Gaming Information |
| 139 | [Gaming Informatics LLC](https://www.casinovendors.com/vendor/gaming-informatics-llc/) Madison, Wisconsin Auditing and Compliance software for casino operations and regularly bodies (Tribal Commissions, State, Federal) Categories: Indian Gaming, Auditing, Accounting: Slots |
| 140 | [Gaming Innovation Group Limited](https://www.igamingsuppliers.com/vendor/gaming-innovation-group-limited/) St. Julians, Malta At GiG, we pride ourselves in what we do. More than 700 GiGsters from 35 different countries are going all in to make a whole industry open and connected, like never before. We do great stuff and never settle for anything ordinary. We are game changers, because what else is ... Categories: Platform Providers, Sportsbook Software, Other |
| 141 | [Gaming Intelligence](https://www.casinovendors.com/vendor/gaming-intelligence/) London, England, United Kingdom Category: Gaming Information |
| 142 | [Gaming Laboratories International, LLC (GLI)](https://www.casinovendors.com/vendor/gaming-laboratories-international-llc-gli/) Lakewood, New Jersey Compliance is the heart of what Gaming Laboratories International (GLI®) does for suppliers, regulators, and operators worldwide. In 707 jurisdictions, companies turn to GLI for help with their compliance challenges in the areas of land-based gaming, iGaming, lottery, and cy... Categories: On-site Inspections, Training, General, Test and Measurement Equipment, Consulting, Auditing |
| 143 | [Gaming Licensing](https://www.igamingsuppliers.com/vendor/gaming-licensing/) Willemstad, Curaçao Licensing of all iGaming Products — online casinos, sports betting, poker, lotteries, and bingo. Quick and cost effective licensing solution for your igaming business. Category: Licensing and Regulation, Consulting |
| 144 | [Gaming Mail](https://www.igamingsuppliers.com/vendor/gaming-mail-1/) Basingstoke, England, United Kingdom We provide engaging offline gaming brand experiences that deliver. We manage the process for direct mail campaigns from end to end. From the strategic acquisition of printed goods to promoting your brand or product in the most efficient and cost-effective way possible Category: Direct Marketing |
| 145 | [Gaming Mail](https://www.igamingsuppliers.com/vendor/gaming-mail/) Basingstoke, England, United Kingdom Category: Direct Marketing |
| 146 | [Gaming Media Group Inc](https://www.casinovendors.com/vendor/gaming-media-group-inc/) Louisville, Kentucky Gaming Media Group is the publisher of Southern & Midwest Gaming and Destinations, a bi-monthly print and digital magazine widely regarded as the premier resource for casino and travel news throughout the Midwest and South. Every issue delivers expert insights, valuable tips... Category: Magazines |
| 147 | [Gaming Point Partner](https://www.igamingaffiliateprograms.com/affiliate-program/gaming-point-partner/) Category: Affiliate Programs |
| 148 | [Gaming Realms](https://www.igamingsuppliers.com/vendor/gaming-realms/) London, England, United Kingdom Gaming Realms creates and develops interactive next-generation online gaming applications, focused on delivery via mobile, tablet and desktop computers. Its principle businesses are BingoGodz, a multi-platform real money social bingo game; Bejig, an award-winning designer an... Categories: Gambling Operations, Casino Software, Mobile Gaming |
| 149 | [Gaming Recruiters, LLC](https://www.casinovendors.com/vendor/gaming-recruiters-llc/) Saint Louis, Missouri Recruiting services exclusively for the gaming industry since the 90's. Our expertise is identifying difficult to find candidates that fit specific needs and qualifications. We recruit all gaming disciplines including Finance, Marketing, IT, F&B, HR, Cage, Compliance, COO,... Categories: Recruitment, Consulting, Consulting, Staffing Services |
| 150 | [Gaming Signs](https://www.casinovendors.com/vendor/gaming-signs/) Buenos Aires, Buenos Aires, Argentina We are a leading manufacturer of indoor and outdoor signage for entertainment areas with unique design and use of materials at just 2/3 of price of other major companies. The Art Department combines their skill and technical experience with the knowledge of the players p... Categories: Exterior, Interior, LED Systems, LED, Slot Meters, LED Systems, LED, LED |
| 151 | [Gaming Solutions LLC](https://www.casinovendors.com/vendor/gaming-solutions-llc/) Albuquerque, New Mexico Gaming Solutions, LLC has been operating in New Mexico and Arizona for three (3) years. Founded by Lauralyn McCarthy, President of New Mexico Gaming, LLC, we offer over 50 years of gaming and high tech expertise. Our industry contacts and partnerships make Gaming Solutions a... Categories: Parts, Slot Systems, LED Systems, Kiosks, Control Room, Design, Progressive Meters, Videowalls |
| 152 | [Gaming Supplies LLC](https://www.casinovendors.com/vendor/gaming-supplies-llc/) Batumi, Georgia Gaming Supplies LLC sells casino equipment from Batumi, Georgia. Our warehouse holds over 80 casino product types, casino spare parts. We manufacture casino products, such as roulette balltrack leveler, card shredder, baccarat playing cards, baccarat and roulette displays. Category: Equipment |
| 153 | [Gaming Supply Company](https://www.casinovendors.com/vendor/gaming-supply-company/) Manassas Park, Virginia The company has been in business for over 12 years, selling quality products. They are a Deutsche Wurlitzer Distributor. They have many items priced from $9.60 to $8000.000. They offer warranties and service items. Very friendly family owned business. Category: Other |
| 154 | [Gaming Support USA](https://www.casinovendors.com/vendor/gaming-support-usa/) Las Vegas, Nevada Gaming Support is a premier supplier of products and services to the global gaming industry with offices in Nevada, The Netherlands and Belgium. Founded in 2000, the company delivers tried and tested, industry-leading solutions that grow gaming revenues and cut costs for ca... Categories: Bonus Systems, Digital, Controllers, Video, Accessories, Interior |
| 155 | [Gaming Technologies](https://www.casinovendors.com/vendor/gaming-technologies/) Vraca, Vraca, Bulgaria Gaming Technologies is a Bulgarian company, dedicated in manufacturing of gaming machines for casinos and arcades. Categories: New Game Manufacturer, Slot Systems, Equipment, Progressive Jackpot Equipment |
| 156 | [Gaming Technology Solutions - GTS](https://www.igamingsuppliers.com/vendor/gaming-technology-solutions-gts/) Ipswich, England, United Kingdom Gaming Technology Solutions (GTS), a Playtech company, is a leading global supplier of end-to-end soft gaming solutions for delivery to IP enabled devices and iTV boxes. GTS has become the market leader in the end-to-end delivery of on-line soft gaming solutions. Building on... Category: Mobile Gaming, Casino Software |
| 157 | [Gaming Tickets, Inc.](https://www.casinovendors.com/vendor/gaming-tickets-inc/) Columbus, North Carolina IGT approved supplier of cashless slot machine tickets - Gaming Tickets, Inc. provides thermal gaming tickets for use in your 'ticket-in/ticket-out' slot machines (i.e., FutureLogic, Ithaca, and Nanoptix Printers). GTI tickets are 65mm x 156mm and/or 62mm x 120mm. We feature... Categories: TITO Tickets, Tickets, Player Tracking Systems, Ticket Printing, Tickets, Printers, Distributors, Player Tracking Cards, Promotional Tickets, Manufacturing, Bungie Coils and String Cords, Players Club Merchandise, Novelty Supplies, Receipt Paper Rolls, Tickets, Ticket Printing, In-room Access |
| 158 | [Gaming Today](https://www.casinovendors.com/vendor/gaming-today/) Las Vegas, Nevada GamingToday has had its finger on the pulse of the gaming industry for nearly 40 years. Its motto, News You Can Bet On, applies to both sides of the table news for casino customers as well as casino executives. Its specialty printing offers tight turn around, accuracy and ... Category: Gaming Information, Other |
| 159 | [Gaming USA Corp.](https://www.casinovendors.com/vendor/gaming-usa-corp/) Paramus, New Jersey The Gaming Industry Weekly Report is about to begin its 16th year of publication and is the oldest gaming stock and gaming information newsletter. The Gaming Industry Daily Report is in its 12th year and was the first daily report focusing on the gaming industry. We soon ... Category: Newsletters |
| 160 | [Gaming1 Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gaming1-affiliates/) Category: Affiliate Programs |
| 161 | [Gaming1](https://www.igamingsuppliers.com/vendor/gaming1/) Brussels, Belgium Gaming1 is an online full service provider specialised in development of platforms and online casino games adapted to local markets. Based in Brussels, Gaming1 is an ultra-dynamic and innovative company resulting from the partnership between one of the most prestigious we... Categories: Casino Software, Bingo Software, Live Dealer, Mobile Gaming |
| 162 | [GamingCables.com](https://www.casinovendors.com/vendor/gamingcables-com/) Las Vegas, Nevada GamingCables.Com was founded in 2010 by Wayne J Shafer, we are located in Las Vegas, Nevada. We offer production services of LED assemblies, wire harnesses and cable assemblies for gaming companies. Parent company KNEXTEC LLC visit knextec.com Categories: Cable Assembly, Wire Harnesses, Electro-mechanical Assembly, Manufacturing, LED, Manufacturer, Connectors, Cable Assembly, LED |
| 163 | [GamingLicense.com](https://www.igamingsuppliers.com/vendor/gaminglicense-com/) Nicosia, Cyprus Our team provides expert iGaming license support to clients globally, navigating complex applications and ensuring seamless iGaming compliance with all international regulatory standards. With over 60 years of combined industry expertise, our journey began with 25 years o... Category: Licensing and Regulation |
| 164 | [Gamingmatic](https://www.casinovendors.com/vendor/gamingmatic/) Professional Gaming Terminal Manufacturer Category: Video Lottery Terminals |
| 165 | [GamingSoft](https://www.igamingsuppliers.com/vendor/gamingsoft/) Makati City, National Capital Region, Philippines GamingSoft is a vendor neutral casino software supplier to various eGaming operators of different sizes across Australia, Eastern Europe and Asia Pacific Countries. We provide casino products like live casino software, slots & games, sportsbooks software, poker, keno, financ... Categories: Gambling Operations, Casino Software, Sportsbook Software, Live Dealer |
| 166 | [Gamingtec](https://www.igamingsuppliers.com/vendor/gamingtec/) London, England, United Kingdom Gamingtec is an independent software platform provider. We offer complex turnkey solutions to B2B iGaming partners. Category: Gambling Operations |
| 167 | [Gamix Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gamix-partners/) Category: Affiliate Programs |
| 168 | [GammaStack](https://www.igamingsuppliers.com/vendor/gammastack/) Wilmington, Delaware GammaStack is the leading provider of fantasy sports and sports betting software. Extending its services in the field of eSports, its has become top rated company for eSports Software Platform development. The company also supplies customized software solutions and whitelabl... Category: Sportsbook Software |
| 169 | [GammaTek](https://www.casinovendors.com/vendor/gammatek/) Glendale, Arizona GammaTek's Baccarat displays are designed to appeal to Asian customers, using a column "run-based" method for displaying Baccarat results. GammaTek's Roulette displays are designed for remote casino sites where reliability is key. Our LED displays don't have a tricky ele... Category: Table Top Systems |
| 170 | [Gamomat Development GmbH](https://www.casinovendors.com/vendor/gamomat-development-gmbh/) Berlin, Berlin, Germany We are a German specialist gaming content design company with many years of experience across a range of key global markets. Profound knowledge, innovation and passion are reflected in our games - we develop products for the international markets and we are proud to include ... Category: Casino Software, Game Design |
| 171 | [Gamshy](https://www.igamingsuppliers.com/vendor/gamshy/) Rome, Italy Category: Casino Software |
| 172 | [Gamtec International Ltd](https://www.casinovendors.com/vendor/gamtec-international-ltd/) Denham, England, United Kingdom Gamtec Ltd. was established in 1986 with the purpose of bringing new technology and innovative concepts to the casino market. Our patented casino cash recorder set a new benchmark in MIS. This was further enhanced when Grips of Austria purchased the rights and produced the... Categories: Chips, Synthetic Gaming Layouts, Equipment, Accessories, Blackjack Tables, Equipment |
| 173 | [Gamucci Ltd.](https://www.casinovendors.com/vendor/gamucci-ltd/) Soho, England, United Kingdom Category: Specialty Items |
| 174 | [Gamzix](https://www.igamingsuppliers.com/vendor/gamzix/) Birkirkara, Malta Gamzix is a Maltese game provider that delivers vibrant slot games and scalable solutions. The providers signature Hold the Spin mechanic has become a player favorite, known for keeping the thrill going round after round. Category: Casino Software |
| 175 | [GAN - GameAccount Network](https://www.igamingsuppliers.com/vendor/gan-gameaccount-network/) London, England, United Kingdom GameAccount Network is the leading network of skill-based games where players compete against each other, not the house. For several years weve been looking beyond poker to identify and supply the worlds leading operators with a suite of games which appeal to and excite ga... Categories: Skill Games Software, Casino Software, Platform Providers, Gambling Operations |
| 176 | [Ganapati PLC](https://www.igamingsuppliers.com/vendor/ganapati-plc/) London, England, United Kingdom Bringing a new edge to iGaming, Ganapati is an established multinational company with a reputation for compelling and immersive content uniquely borne out of both Europe and Asia. Effectively implementing strategic sport sponsorship and brand opportunities, Ganapati consider... Category: Casino Software, Mobile Gaming |
| 177 | [Gander Group](https://www.casinovendors.com/vendor/gander-group/) Costa Mesa, California An Inc. 5000 company, Gander Group partners with internationally recognized brands and hundreds of casinos across America to provide trend-forward product development and merchandising solutions. Category: Promotions, Market Research and Development |
| 178 | [Ganlot, inc.](https://www.casinovendors.com/vendor/ganlot-inc/) New Taipei City, Taiwan Ganlot's range of industrial gaming boards includes specific function which is specifically designed for gaming application such as casino slot games, EGM, Roulette, VLT and AWP. Our core value is to offer the widest and flexible selection of industrial grades products inclu... Categories: Manufacturing, Circuit Board Assembly, Consulting |
| 179 | [Ganz Security / CBC Americas Corp.](https://www.casinovendors.com/vendor/ganz-security-cbc-americas-corp/) Cary, North Carolina Ganz Security by CBC is a global leader in the design, development and manufacture of world-class, trend setting security solutions. The Ganz brand offers integrated solutions across multiple market segments and includes an extensive selection of products including IP and an... Category: CCTV Systems |
| 180 | [GAO Engineering Inc.](https://www.casinovendors.com/vendor/gao-engineering-inc/) Toronto, Ontario, Canada GAO Engineering Inc. is a single stop resource for quality, market-proven products including GAO ICE's, Flash Programmers, Universal Programmers, Emulators, DSP and Microprocessor Evaluation Boards, Embedded Linux Boards, FPGA+Linux Boards, ARM IDE's, Software Development Ki... Category: Software Development |
| 181 | [GaoXin Modern Intelligent System Co., Ltd](https://www.casinovendors.com/vendor/gaoxin-modern-intelligent-system-co-ltd/) Shenzhen, China Established in 1993, Gaoxin Modern Intelligent System Co., Ltd (GXMIS for short) is one of the world's leading turnkey solution provider of automated fare collection systems for public transport including bus, bus rapid transit, light rail, commuter rail, heavy rail, ferry a... Category: Access Control, Kiosks |
| 182 | [GAR Products](https://www.casinovendors.com/vendor/gar-products/) Lakewood, New Jersey GAR Products® is a family owned and operated corporation specializing in quality seating, table tops, and table bases for all levels of the hospitality and design industries. Founded in 1956 by Morris H. Garfunkle (Mr. GAR), GAR Products®, now entering its third generation o... Categories: Restaurant, Bases, Casino |
| 183 | [Garavelli Enterprises, Inc.](https://www.casinovendors.com/vendor/garavelli-enterprises-inc/) Memphis, Tennessee Garavelli Enterprises, Inc. is a woman owned, small business, manufacturer and supplier. Airport Seating Alliance is a division that supplies high quality public seating and custom power charging solutions to international and regional airports, transportation centers, gove... Category: Benches |
| 184 | [Gardenia Software Systems, Inc.](https://www.casinovendors.com/vendor/gardenia-software-systems-inc/) Milford, Ohio Gardenia Software Systems was founded in June, 1989 for the purpose of developing and licensing PC-based software solutions to help streamline cash and document processing operations for enterprises handling large sums of cash and other media types in the gaming, banking, an... Category: Cash Processing, Consulting |
| 185 | [Garfinkel Publications](https://www.casinovendors.com/vendor/garfinkel-publications/) Vancouver, British Columbia, Canada Over 20 years experience of working with Native art and artists. We offer an extensive variety of different products, and maintain quality and affordable pricing. We can provide custom services, name drops, and work with our images or your logo. Category: Wearables |
| 186 | [GarJen Corp](https://www.casinovendors.com/vendor/garjen-corp/) Bonney Lake, Washington At GarJen Corp we are in the business of developing promotional products that are designed to create a positive product experience, create a positive word of mouth buzz and designed to keep your casino and bingo hall name in front of your players every day. Over 30 years of... Category: Promotional Items |
| 187 | [Garland Writing Instruments](https://www.casinovendors.com/vendor/garland-writing-instruments/) Coventry, Rhode Island Garland celebrates 80 years of manufacturing quality writing instruments. Our USA-Made Photo Logo Writing Instruments are highly recognizable by Garland's patented flared top design, which can showcase any full-color logo or image. Garland's complete product line includes ... Categories: Specialties, Promotional Items, Promotions, Promotions, Lapel Pins, Incentives and Awards, Recruitment, Training, General, Seminars: Employee Relations, Gift Merchandise, Souvenirs |
| 188 | [Garment Machinery Company](https://www.casinovendors.com/vendor/garment-machinery-company/) Needham, Massachusetts We are New England's Oldest Commercial Laundry Equipment Distributor, since 1939. We sell, install, and service most brands. We are always eager to earn the business. Category: Laundry Equipment |
| 189 | [Garner Holt Productions, Inc.](https://www.casinovendors.com/vendor/garner-holt-productions-inc/) San Bernardino, California Garner Holt Productions is known for outstanding design and manufacture of animatronic figures, museum quality static animals, animated props, show action equipment, sets and scenery, and also Creative Design. Clients include Mohegan Sun, Caesars, McDonalds, and Disney park... Category: Animation and Animatronics |
| 190 | [Garrett Leather Corp.](https://www.casinovendors.com/vendor/garrett-leather-corp/) Buffalo, New York Garrett Leather is a wholesale distributor of Italian upholstery leather. Over 500 colors are available for immediate shipment. Most orders ship within 24 hours of purchase. Designers may also order custom leather area rugs, made from Garrett's leather, steerhide, wovens, b... Category: Fabrics, Other |
| 191 | [Garrett Metal Detectors](https://www.casinovendors.com/vendor/garrett-metal-detectors/) Garland, Texas Garrett Metal Detectors offers you the best products and training that you need to run an effective security checkpoint. From airports and prisons to public venues and nightclubs, our hand-held, walk-through and ground search metal detection products meet the most stringent ... Category: Monitoring |
| 192 | [Garrison Flood Control Systems, LLC.](https://www.casinovendors.com/vendor/garrison-flood-control-systems-llc/) New York, New York Garrison™ Flood Control is a New York-based manufacturer and distributor of a complete line of flood control products that help prevent, mitigate and combat flood damage using a series of economical flood control products. Garrison products prevent, contain, divert, and re-r... Category: Engineering |
| 193 | [Garron Lottery Products, Inc.](https://www.casinovendors.com/vendor/garron-lottery-products-inc/) Baltimore, Maryland Category: Drawing Equipment |
| 194 | [Garuda Promo & Branding Solutions](https://www.casinovendors.com/vendor/garuda-promo-branding-solutions/) Los Angeles, California Garuda Promo and Branding Solutions are led by a team of skilled professionals with years of experience in promotional items, advertising specialties. Together with a sourcing platform of over 3500 vendor partners, we have manufacturing capabilities that cover any custom pro... Categories: Promotional Items, Coin Melting, Exhibit Supplies, Specialty Items, Personal Protection Equipment, Personal Protection Equipment |
| 195 | [Gary Green Gaming](https://www.casinovendors.com/vendor/gary-green-gaming/) Boca Raton, Florida Well-known casino industry luminary; star of the television series "CASINO INSIDER"; author of several books on the industry. One of the industry's most publicized and successful track records of development, finance, and management using our copyrighted and patented oper... Categories: Consulting, Consulting, Continuity Programs, Other |
| 196 | [Gary Panks Associates](https://www.casinovendors.com/vendor/gary-panks-associates/) Scottsdale, Arizona Category: Architecture, Landscape |
| 197 | [Gary Platt Manufacturing, LLC](https://www.casinovendors.com/vendor/gary-platt-manufacturing-llc/) Reno, Nevada Every Gary Platt chair is hand-crafted to perfect the player gaming experience through Unsurpassed Comfort. With over 40 years in delivering state-of-the-art ergonomically sculpted seating, the new generation of X2-Tended play seating continues to push the bounds of excellen... Categories: Casino, Benches, Other, Furniture Manufacturer, Casino, Slot Stools |
| 198 | [Gary Taylor Creative Group](https://www.casinovendors.com/vendor/gary-taylor-creative-group/) Los Angeles, California Why the Gary Taylor Creative Group? We offer 15 years of unparalleled service along with award winning work that builds brands and drives sales. We have valuable casino and event marketing experience working with The Venetian resort in Las Vegas. Our clients success is what... Category: Full Service Agency |
| 199 | [GasanMamo Insurance](https://www.igamingsuppliers.com/vendor/gasanmamo-insurance/) Gzira, Malta Category: Other |
| 200 | [Gaspar's Fine Architectural](https://www.casinovendors.com/vendor/gaspar-s-fine-architectural/) North Hollywood, California Gaspar's Fine Architectural Metal Works is a manufacturing company with an old world craftsman heritage and a vision for the future. We specialize in architectural exterior and interior elements, as well as unique furniture parts, fabricated by hand in copper, brass, and she... Category: Interior Design |
| 201 | [Gasser Chair Company, Inc.](https://www.casinovendors.com/vendor/gasser-chair-company-inc/) Youngstown, Ohio A Million Ways to Dazzle. Most chairs are designed to fill a space. Gasser chairs are designed to elevate it. For more than 70 years weve been designing, building and perfecting the art of commercial seating, using only the highest quality materials. When you buy a Gasser ... Categories: Casino, Slot Stools, Restaurant |
| 202 | [Gassis Energy](https://www.casinovendors.com/vendor/gassis-energy/) Atlantic City, New Jersey From 1970 until today, our family business has grown into a recognized and well respected company that has served New Jersey with pride and respect. We have constructed homes and also have built and managed major projects in New Jersey, Pennsylvania and New York. We provide ... Category: General Contracting |
| 203 | [GastonRed Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gastonred-affiliates/), Malta Category: Affiliate Programs |
| 204 | [Gate To Wire Solutions, Inc.](https://www.casinovendors.com/vendor/gate-to-wire-solutions-inc/) Toronto, Ontario, Canada Gate To Wire Solutions, Inc. (G2W) is a comprehensive service provider and advisory organization to horse racing and pari-mutuel wagering interests in Latin America, comprised of seasoned industry executives whose combined experience is being re-focused on the Latin American... Categories: Wagering, Simulcast Systems, Consulting |
| 205 | [Gates Capital Management](https://www.casinovendors.com/vendor/gates-capital-management/) New York, New York Category: Consulting |
| 206 | [Gateway Digital](https://www.igamingsuppliers.com/vendor/gateway-digital/) Zoetermeer, Netherlands - Experience of working with one of the top 3 iGaming companies - Registered vendor in the New Jersey Division of Gaming Enforcement - Enterprise - Excellent price-to-quality ratio of game development - Innovation and adaptation of latest technologies - Team of QA engine... Category: Software Development |
| 207 | [Gateway FS Construction Services](https://www.casinovendors.com/vendor/gateway-fs-construction-services/) Red Bud, Illinois Gateway FS Construction Services is a leader in the southern Illinois counties of Monroe, Randolph, Clinton, Washington, Perry and St. Clair providing construction service to customers for over 40 years in the areas of Grain Drying and Aeration Systems including Sukup, Shivv... Category: General Contracting |
| 208 | [Gaudium](https://www.casinovendors.com/vendor/gaudium/) Olomouc, Czech Republic Recruitment agency Category: Recruitment |
| 209 | [Gayle Force Enterprises](https://www.casinovendors.com/vendor/gayle-force-enterprises/) Westlake Village, California Gayle Force is one of the leading talent buyers in the competitive casino entertainment market. The service we provide is so much more than a typical talent-buyer for a casino role, including assistance with marketing, venue management and ticketing. We provide our clients w... Category: Talent Buying, Production |
| 210 | [GBE Technologies (gbet)](https://www.igamingsuppliers.com/vendor/gbe-technologies-gbet/) Dublin, Ireland GBE Technologies was established in 1999 with a goal to develop a global exchange platform for the trading of sports bets. Gbet has built its technology around a networked Broker-Exchange model, and it licences its broker software platform to gaming operators globally. Th... Category: Gambling Operations, Betting Exchange Software |
| 211 | [GBGroup](https://www.igamingsuppliers.com/vendor/gbgroup/) Chester, England, United Kingdom GBGroup combines individual identity data with technology to provide our clients with the Identity Intelligence they need to make good business decisions based on trust. Category: Security and Fraud |
| 212 | [GBL LED Lighting Inc](https://www.casinovendors.com/vendor/gbl-led-lighting-inc/) Vancouver, British Columbia, Canada With over 10 years designing & manufacturing quality LED bulbs for the Gaming and Casino market, we can bring a vibrant atmosphere to your Space. Long OEM and Private Label history! Category: LED |
| 213 | [GBL](https://www.igamingsuppliers.com/vendor/gbl/) Kitchener, Ontario, Canada Since 2014, we've helped the iGaming industry capitalize on the rapidly growing digital currency market. We recognized the need to help operators improve their payment efficiency and also lower the overall time and cost of processing a transaction through the use of Bitcoin.... Category: Software, Platform Providers |
| 214 | [GBS Linens](https://www.casinovendors.com/vendor/gbs-linens/) Anaheim, California We have been in business for over 20 years providing table linens and laundry services to the Special Events and Food Industry. As a manufacturer, we offer a quick turnaround on purchases and we boast one of the largest rental inventories in our industry. Our linens are de... Category: Table Linens |
| 215 | [GC Gaming Curacao](https://www.casinovendors.com/vendor/gc-gaming-curacao/) Willemstad, Colorado Curacao has long been recognized as one of the preferred locations for eGaming operators to base their operations. This success has been due to a combination of factors, such as a progressive legislative system, political stability, first rate telecommunications facilities a... Categories: Mobile Gaming, Compliance, Hosting, Business Brokers, Tokens |
| 216 | [GCM Partner](https://www.financeaffiliateprograms.com/affiliate-program/gcm-partner/) Category: Affiliate Programs |
| 217 | [GD'Tronics](https://www.casinovendors.com/vendor/gd-tronics/) Keratsini - Piraeus, Greece We design and market professional monitors for non-stop operation ranging from open frame to multimedia monitors. Applications of our monitors include information kiosks, public information displays, gaming & gabling machines. Category: Monitors, Open Frame |
| 218 | [GE Interlogix, Kalatel Division](https://www.casinovendors.com/vendor/ge-interlogix-kalatel-division/) Corvallis, Oregon Meeting your security needs - As the need to protect people and property continues to increase, GE Interlogix keeps pace with innovations in security technology. Because we are part of GE, we have the resources of one of the largest companies in America behind us. We put t... Categories: Digital Video Recorders, Multiplexers, CCTV Systems, High-speed Domes, Pan and Tilt Devices, Digital Video Management Systems, Video Multiplexers |
| 219 | [Gear for Sports](https://www.casinovendors.com/vendor/gear-for-sports/) Lenexa, Kansas Gear For Sports is a leading national manufacturer of customized sportswear apparel. Graphics are designed with the individual client's needs in mind. The company provides low minimums and fast turnarounds. Categories: Luggage, Logoed, Promotional Products, Apparel, Logoed |
| 220 | [Geding Information Inc](https://www.casinovendors.com/vendor/geding-information-inc/) Dongguan, Guangdong, China Company established in October, 1982 started with business of setting up security surveillance system and CCTV system engineering projects. In 1994 for expansion, company started running agency business, importing and selling the reed switches and electronic components and p... Categories: Position Sensors, Position Sensors, Position Sensors, Position Sensors |
| 221 | [Geeks of Technology](https://www.casinovendors.com/vendor/geeks-of-technology/) Hollywood, Florida Well-rounded, Florida-based technology expert integrator, providing the gaming industry with Design and Installation services for AudioVisual Systems, Lighting and Climate Controls, Motorized Windows Treatments, Touch Panel Controls, Automation and IT Services. Categories: Controls, Design, Audio Systems, Integration Services, Networking, Communication Systems, Networking Equipment |
| 222 | [Gefim Sas](https://www.casinovendors.com/vendor/gefim-sas/) Misinto, Michigan GEFIM offers electronice machines entirely made by painted steel, chrome or gold plated provided with the most important mechanical security that is very reliable. We have 10 years experience in planning and construction of game machines. Besides, each machine, thanks to its... Category: Bases-Cabinets-Stands (Metal) |
| 223 | [Gehl's Guernsay Farms Incorporated](https://www.casinovendors.com/vendor/gehl-s-guernsay-farms-incorporated/) Germantown, Wisconsin Gehls Guernsey Farms offers a full ine of cheese sauces, chili sauce, hassle-free dispensers for sauce and tortilla chips. Puddings and Main Street Cafe Iced Lattes are also offered. Category: Other |
| 224 | [Geiger Automatenbau GmbH](https://www.casinovendors.com/vendor/geiger-automatenbau-gmbh/) Sonthofen, Germany Geiger is one of the leading supplier for spare parts and accessories in Europe with more than 30 years experience in our branch. We offer you a wide range of items, but we are also concentrated on the token market. We are one of the worlds leading companies for high securit... Category: Tokens |
| 225 | [Gemified](https://www.igamingaffiliateprograms.com/affiliate-program/gemified/) Bnei Brak, Israel Gemified is more than a Publisher network - we're a performance engine tailored for the sweepstakes iGaming space. Founded by marketers and engineers who've scaled Publisher empires, we're here to bring a new level of intelligence to user acquisition. Category: Affiliate Programs |
| 226 | [Gemini 2000 Ltd](https://www.casinovendors.com/vendor/gemini-2000-ltd/) Poole, England, United Kingdom Since 1997, Gemini 2000 has had the opportunity to pioneer the NFC technology market and provide bookmakers with top-of-the-range products for numerous smart card applications. Over the years we have become established as a leading UK-based manufacturer, developing innovativ... Category: Smart Card Systems |
| 227 | [Gemini Gaming LLC of Nevada](https://www.casinovendors.com/vendor/gemini-gaming-llc-of-nevada/) Las Vegas, Nevada Backed by a group of used slot machine parts warehouses, Gemini Gaming offers a large variety of quality, used, and tested slot machine parts for business or personal use. We accept large or small orders and are experts at finding those hard to locate items. Category: Parts, TITO Tickets |
| 228 | [Gemini Technologies](https://www.casinovendors.com/vendor/gemini-technologies/) Tecumseh, Michigan Category: Janitorial Equipment and Supplies |
| 229 | [GemPartner](https://www.igamingaffiliateprograms.com/affiliate-program/gempartner/) Category: Affiliate Programs |
| 230 | [GemSlots Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gemslots-partners/) Category: Affiliate Programs |
| 231 | [Gemsys Money Handling Systems Inc.](https://www.casinovendors.com/vendor/gemsys-money-handling-systems-inc/) Mississauga, Ontario, Canada Gemsys Money Handling Systems Inc. supports a highly comprehensive product line of coin, currency, token, and ticket equipment and systems. We are committed to a leadership role in providing all clients with the best equipment backed by quality after sales service and suppor... Categories: Currency Handling Equipment, Coin Handling Equipment, Counterfeit Detectors, Chip Handling, Coin Dispensing, Scales, Cash Storage Equipment, Coin Wrapping, Accessories, Banking and Cashier Supplies, Bill Validator Cleaning Cards, Bill Validators, Cash Processing, Cash Processing, Consulting, Coin Bags, Coin Redemption, Self-service, Hard Count, Plastic Bags, Soft Count, Supplies, Other, Specialty Items |
| 232 | [Genera Networks](https://www.casinovendors.com/vendor/genera-networks/) Stockholm, Stockholms, Sweden Genera Networks is an independent and neutral gaming solution provider with no direct or indirect connection to cross-border operators. We aggregate the most successful products, technology and content, all to fit your specific needs. Categories: Electronic Systems, Other, Slot Machines, Bingo Software, Casino Software, Poker Software, Racebook Software |
| 233 | [General Bank Supply, Inc.](https://www.casinovendors.com/vendor/general-bank-supply-inc/) Troy, Michigan General Bank Supply has been serving its customers for over 60 Years! We offer personalized customer service providing quality products and a commitment to customer satisfaction. Category: Banking and Cashier Supplies |
| 234 | [General Coatings Corporation](https://www.casinovendors.com/vendor/general-coatings-corporation/) Orange, California General Coatings Corporation is a family owned painting company with offices in San Diego & Orange County specializing in customer service. Category: Other |
| 235 | [General Link (GLIC)](https://www.casinovendors.com/vendor/general-link-glic/) City of Industry, California General Link was funded in 2004 and supplies LED lighting, LED displays, LED boards. We have a showroom and warehouse in Los Angeles, which offers full technical supports to our customers in America, south America and North America. Our products are assembled in China. Th... Category: LED Systems |
| 236 | [General Roof Management](https://www.casinovendors.com/vendor/general-roof-management/) Sacramento, California General Roof Management is an independent roof consulting firm serving clients throughout Nevada and California. We have 25 years experience in our industry. From leak investigation on a single building to full roof management programs on an entire building inventory, we of... Category: Consulting |
| 237 | [General Seating Solutions](https://www.casinovendors.com/vendor/general-seating-solutions/) South Windsor, Connecticut General Seating Solutions (GSS) is a world-class manufacturer of restaurant booths, banquettes, benches, chairs and sofas for the foodservice and hospitality industries. Category: Restaurant, Benches |
| 238 | [General Security Services Corp.](https://www.casinovendors.com/vendor/general-security-services-corp/) Minneapolis, Minnesota Category: Other, Other |
| 239 | [General Touch Co., Ltd.](https://www.casinovendors.com/vendor/general-touch-co-ltd/) Chengdu City, Sichuan, China General Touch has been a leading touch solutions provider in the global marketplace for more than 20 years. By putting the customers interest first, GT consistently offers exceptional customer experience and satisfaction through its wide variety of touch technologies and so... Categories: Monitors, Open Frame, Monitors, Open Frame, Monitors, Touchscreens, Touchscreens, Touchscreens, Touchscreens, Touchscreens |
| 240 | [General Vending Services, Limited (GVS)](https://www.casinovendors.com/vendor/general-vending-services-limited-gvs/) Horley, England, United Kingdom General Vending Services is a specialist supplier of tea and coffee vending machines, food and snack vending machines, table top vending machines and water coolers. GVS has been providing total vending support for its clients since the 1920s. GVS provides unsurpassed custo... Category: Vending Machines, Dispensers |
| 241 | [GenerationWeb](https://www.igamingsuppliers.com/vendor/generationweb/) Categories: Sportsbook Software, Racebook Software, Mobile Gaming |
| 242 | [Generator Source, LLC](https://www.casinovendors.com/vendor/generator-source-llc/) Brighton, Colorado Generator Source, formerly Diesel Service & Supply, has been buying, servicing, and selling new, surplus, and used industrial diesel engines and electric power generators for over 30 years. You will always get a competitive price for your equipment, but you'll also be deali... Category: Materials |
| 243 | [Genesis Air](https://www.casinovendors.com/vendor/genesis-air/) Lubbock, Texas Genesis Air is the manufacturer of indoor air quality systems. Using G.A.P. technology, we can help reduce your overall operating costs. G.A.P. is dedicated to the removal of smoke, bacteria, particulate matter and the disinfection of your indoor air. Any of our systems can ... Category: Air Filtration Systems |
| 244 | [Genesis Associates](https://www.casinovendors.com/vendor/genesis-associates/) Santa Ana, California Genesis Associates has been providing complete design services to many of the largest casino companies in the world such as the Mandalay Resort Group, MGM Grand, Penn National Gaming, and has been used as a source to forecast the future trends of casino design. Over the past... Categories: Design, Design, Native American, Interior Design, Interior |
| 245 | [Genesis Games Limited](https://www.casinovendors.com/vendor/genesis-games-limited/) Chesham, England, United Kingdom Genesis is a company at the cutting edge of technology, providing broadband, techno-efficient e-solutions for all coin operated entertainment machines requirements. Our extensive knowledge base with 50 years experience between our partners gives us the ability to understand... Categories: Slot Machines, Equipment, Software |
| 246 | [Genesis Gaming Solutions, Inc.](https://www.casinovendors.com/vendor/genesis-gaming-solutions-inc/) Spring, Texas Genesis Gaming Solutions, Inc develops software and hardware for casion management and player tracking systems. Category: Software |
| 247 | [Genesis Gaming, Inc. (GGI)](https://www.igamingsuppliers.com/vendor/genesis-gaming-inc-ggi/) Henderson, Nevada Genesis Gaming, Inc. is based in Las Vegas, Nevada and is a content development company with extensive and diversified gaming experience. Our team has been a key supplier of third party content to the most prominent manufacturers in the gaming industry. We are experienced in... Category: Casino Software |
| 248 | [Genesis Recycling Ltd.](https://www.casinovendors.com/vendor/genesis-recycling-ltd/) Aldergrove, British Columbia, Canada We at Genesis Recycling provide electronic recycling to the gaming industry. We have a very high level of security for the safe demanufacturing of all gaming equipment. We recycle all materials in an environmentally sound manor. We are certified under ISO 9001 and 14001. We ... Category: Parts |
| 249 | [Genesys One Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/genesys-one-affiliates/) Genesys Affiliates offers your players HD quality games along with an incentive program for your VIP players. You will benefit from flexible and highly competitive commission deals tailored to the market and customer segment which you are promoting; customized acquisition ca... Category: Affiliate Programs |
| 250 | [Genetec Inc.](https://www.casinovendors.com/vendor/genetec-inc/) Saint Laurent, Quebec, Canada Genetec is a pioneer in the physical security and public safety industry and a global provider of world-class IP video surveillance, access control and license plate recognition (LPR) solutions to markets such as transportation, education, retail, gaming, government and more... Category: Other |
| 251 | [Genieee](https://www.casinovendors.com/vendor/genieee/) Pune, Mahārāshtra, India One of the Top HTML5 Game Development Company in India. Being the top game development company in India, Genieee provides best HTML5 game development services. With our creative and fun oriented game development experience we are able build more than 1000+ html5 games for mu... Category: Mobile Gaming, New Game Manufacturer |
| 252 | [Genii Limited](https://www.igamingsuppliers.com/vendor/genii-limited/) San Gwann, Malta Genii is a gaming technology provider focused on building the next generation online gaming platform. The company is steered by a team of entrepreneurs that have led the field, both in the business of gaming and technological innovation, since the 1990s. Genii is founded ... Categories: Gambling Operations, Casino Software, Mobile Gaming |
| 253 | [GenioBet Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/geniobet-affiliates/) Category: Affiliate Programs |
| 254 | [Genius Sports](https://www.igamingsuppliers.com/vendor/genius-sports/) London, England, United Kingdom Founded in 2001, Genius Sports is one of the worlds largest sports technology companies. Category: Sportsbook Software |
| 255 | [Genlot Game Technology co.,Ltd](https://www.casinovendors.com/vendor/genlot-game-technology-co-ltd/) Shenzhen, China Since 2000, Genlot has established itself as a leading provider of compelling solutions to the global gaming industry. With a proven product portfolio encompassing all key gaming verticals, Genlot specializes in the development and deployment of leading-edge bespoke gaming s... Category: Other |
| 256 | [GennaGroup S.R.L.](https://www.casinovendors.com/vendor/gennagroup-s-r-l/) San Mango Piemonte, Campania, Italy The GennaGroup is founded in 2002 as satellite company of the GennaGiochi to improve the functions of import-export and distribution of spare parts for the assembly and the aid to the customers. Despite the recent such a constitution company makes use of the professionalism ... Categories: Amusement Equipment, Coin Dispensing, Parts, Magnetic Counters, Parts, Power Sources, Other, Components, Manufacturing, LED, Lamps and Lamp Shades, Coin Dispensing, Monitoring, Locks, Spotlight Lamps, LED Systems, Other |
| 257 | [GenPrime, Inc.](https://www.casinovendors.com/vendor/genprime-inc/) Spokane, Washington Determine in 5 minutes if an unknown powder is a credible threat or a harmless hoax. The Prime Alert Biodetection/Threat Verification System is the only first response tool that combines a broad Microbe Screen with Ricin and Botulinum Toxin Screens to provide the most compre... Category: Other |
| 258 | [Gentec Technologies Ltd.](https://www.casinovendors.com/vendor/gentec-technologies-ltd/) Calgary, Alberta, Canada Category: Consulting |
| 259 | [Gentex Corporation](https://www.casinovendors.com/vendor/gentex-corporation/) Zeeland, Michigan Category: Alarms |
| 260 | [Genwac, Inc. (WATEC)](https://www.casinovendors.com/vendor/genwac-inc-watec/) Orangeburg, New York Category: Other |
| 261 | [GeoComply Ltd](https://www.igamingsuppliers.com/vendor/geocomply-ltd/) Henderson, Nevada GeoComply offers regulators and operators a reliable, secure and user-friendly solution for the Geolocation of online users. Focusing on the regulated iGaming and broadcasting industries, GeoComply works closely with its customers to harness cutting edge technology to serve ... Category: Geolocation Services |
| 262 | [Geoffrey Parker Games Ltd](https://www.casinovendors.com/vendor/geoffrey-parker-games-ltd/) Saffron Walden, England, United Kingdom Regarded as the finest maker of traditional board games, including luxury World Championship backgammon, chess, bridge, home casino games and licensed parlour games such as Monopoly, Trivial Pursuit, Scrabble and Cluedo. Fine games tables in beautiful marquetry inlaid woods,... Category: Promotional Items |
| 263 | [Georgia Carpet Industries](https://www.casinovendors.com/vendor/georgia-carpet-industries/) Dalton, Georgia As a rising leader in the Hospitality Flooring Industry, Georgia Carpet Industries knows that color and design make the room. By offering the latest styles and patterns and a complete line of Flooring for the Hospitality Industry your entire property will look beautiful. Our... Category: Carpets, Flooring |
| 264 | [Georgia Case Company](https://www.casinovendors.com/vendor/georgia-case-company/) Tucker, Georgia We are an original equipment manufacturer offering our services directly to the gaming industry. We sell at a wholesale level direct to end users, and provide a low cost, no risk solution to industry requirements. Categories: Packaging Material, Scenery and Set Design, Other, Services |
| 265 | [Georgia Expo Manufacturing Corporation](https://www.casinovendors.com/vendor/georgia-expo-manufacturing-corporation/) Norcross, Georgia Georgia Expo is your one stop shop for all your casino floor needs! We're the largest manufacturer of Pipe & Drape in the United States! In addition we provide Exhibit Products to turn any event into something extraordinary. Adjustable Height Expo Tables, Table skirting, cro... Categories: Exhibits, Exhibit Supplies, Exhibits |
| 266 | [Georgia Pacific Professional](https://www.casinovendors.com/vendor/georgia-pacific-professional/) Atlanta, Georgia Category: Janitorial Equipment and Supplies |
| 267 | [Georgia Stage, LLC](https://www.casinovendors.com/vendor/georgia-stage-llc/) Duluth, Georgia Georgia Stage, LLC is a leader in Theatrical Curtains and Fabrics, Pipe & Drape, Track and Rigging. We are committed to providing our customers with the highest quality products and services and to keeping the hand crafted look and feel we have come to be known for since 199... Category: Stage Equipment, Display Systems |
| 268 | [Georgia Steel Entertainment](https://www.casinovendors.com/vendor/georgia-steel-entertainment/) Toronto, Ontario, Canada Georgia Steel Entertainment provides Vintage Music shows Featuring Georgia Steel a popular musical entertainer in the Toronto area. Her mother Ivy Steel an acclaimed Jazz vocalist supported her start in the Jazz classics. Georgia's compelling vocal performances are mesmeriz... Category: Music Production |
| 269 | [GeoVision](https://www.casinovendors.com/vendor/geovision/) Irvine, California GeoVision is the leading provider of digital surveillance with specialization in video enhancement analytics and integrable solutions including NVR, IP Camera, CMS, Access Control and Loss Prevention. With more than 9 million GeoVision channels sold to over 100 countries, we... Category: CCTV Systems |
| 270 | [Germisept](https://www.casinovendors.com/vendor/germisept/) Newport Beach, California Germisept is a family-owned brand founded on the pursuit of passion and innovation. Our mission is deeply rooted in quality, providing amazing value to our customers and community. We have grown and continue to evolve through constant leading-edge products, thus enabling our... Category: Hand Sanitizer |
| 271 | [Germstar/Soaptronic](https://www.casinovendors.com/vendor/germstar-soaptronic/) Lake Forest, California Category: Hygiene Products |
| 272 | [Geron Associates](https://www.casinovendors.com/vendor/geron-associates/) Markham, Ontario, Canada Category: Exhibits |
| 273 | [GES Holiday Retail (formerly Becker Group)](https://www.casinovendors.com/vendor/ges-holiday-retail-formerly-becker-group/) Baltimore, Maryland For over half a century, Becker Group (now GES) has produced award-winning, cost effective display and exhibit solutions for casinos, hotels, resorts, shopping centers and commercial properties, transforming every type of commercial property into stunning destinations. Categories: Holiday, Christmas, Other, Multi-media Productions, Interior |
| 274 | [GESI Hospitality](https://www.casinovendors.com/vendor/gesi-hospitality/) Astoria, New York Category: Locks |
| 275 | [Get Green Recycling Corp](https://www.casinovendors.com/vendor/get-green-recycling-corp/) Aurora, Illinois Every Casino has different metal ingredients for their gaming tokens, prices vary upon the precious metals contained in the weighted tokens, a sample token given to us will determine the recovery value you will receive. Get Green Recycling is your simple, secure solution... Category: Coin Melting, Coin Melting |
| 276 | [Get Maine Lobster](https://www.casinovendors.com/vendor/get-maine-lobster/) Portland, Maine At Get Maine Lobster, we create the modern culinary adventures that bring the allure of the ocean right to your door. We know that the freshest seafood deserves to be much more than a meal...it should be an experience. From meaty, deep-water Maine lobsters to sweet diver sca... Category: Seafood |
| 277 | [Get Noticed Advertising](https://www.casinovendors.com/vendor/get-noticed-advertising/) Boulder City, Nevada Get Noticed has been in business since 1995 and has proven to be one of the top companies in the advertising and promotion industry here in Las Vegas. With attention to detail and excellent customer service Get Noticed will always get the job done right. Category: Specialties |
| 278 | [Get The Picture, LLC](https://www.casinovendors.com/vendor/get-the-picture-llc/) Lincoln, Rhode Island We work with several Fortune 500 companies, hospitals, and educational institutions and have earned their business and trust. As the area's only award winning certified picture framer, we have the expertise to get it done right. Category: Art, Moldings |
| 279 | [GeWeTe GmbH & Co. KG](https://www.casinovendors.com/vendor/gewete-gmbh-co-kg/) Mechernich, Germany For every need, the perfect solution with this claim GeWeTe cash handling technology near Cologne (Germany), develops for over 18 years compelling solutions for high-quality money changing systems. GeWeTe covers the entire spectrum: from mini-changer WGS 102 to the high-en... Category: Cash Handling Equipment |
| 280 | [GFInteriors](https://www.casinovendors.com/vendor/gfinteriors/) City of Industry, California We manufacture our own product and our prices do not reflect our high standard of design and make but are very competitive.We have tables with semiprecious stones and marble in neo baroque and contemporary style. Category: Furnishings |
| 281 | [GFM Holdings Limited](https://www.casinovendors.com/vendor/gfm-holdings-limited/) Colchester, England, United Kingdom GFM: Promotional Marketing, Online Games and Marketing Services. Categories: Other, Promotions, Promotions |
| 282 | [GG.bet Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gg-bet-affiliates/) Willemstad, Curaçao GG.BET was developed by eSports enthusiasts and former professionals. Our goal is to create an intuitive and convenient platform for betting on all major eSports events in the world. On GG.BET you can always quickly and easily place a bet on your favorite team. Our cash o... Category: Affiliate Programs |
| 283 | [GGPartners](https://www.igamingaffiliateprograms.com/affiliate-program/ggpartners/) Category: Affiliate Programs |
| 284 | [GGR Partners](https://www.igamingaffiliateprograms.com/affiliate-program/ggr-partners/) Category: Affiliate Programs |
| 285 | [GGRSOFT](https://www.igamingsuppliers.com/vendor/ggrsoft/) Vilnius, Lithuania Decades of experience have given us safe to say PhDs in iGaming. We know the pain, and we know the gain. The challenges and opportunities within the industry excite us. As a forward-thinking iGaming company, were equipped to navigate the complexities and deliver abnorma... Categories: Licensing and Regulation, Consulting, Platform Providers, Gambling Operations |
| 286 | [GHA Technologies](https://www.casinovendors.com/vendor/gha-technologies/) Huntington Beach, California GHA Technologies, Inc. provides computer reselling and systems integration services. It sells various Internet, bandwidth, security, VoIP, wireless, video, and identification technologies specializing in customizing file servers, computers, and laptops, as well as mission-cr... Category: Computer Systems |
| 287 | [Ghirardelli Chocolate Company](https://www.casinovendors.com/vendor/ghirardelli-chocolate-company/) San Leandro, California Celebrating 160 years, Ghirardelli Chocolate continues to hand-select the world's finest cocoa beans and uses only the purest ingredients for our award-winning chocolate. We specialize in beautifully packaged gifts, ideal for VIPs, frequent guests, arrival gifts, promo annou... Category: Chocolate |
| 288 | [Ghost Beads, LLC](https://www.casinovendors.com/vendor/ghost-beads-llc/) Las Vegas, Nevada Category: Jewelry |
| 289 | [GHY Stone](https://www.casinovendors.com/vendor/ghy-stone/) Beijing, Beijing, China When you open this web we guess you are looking for something with special designs and reasonable prices for your home. So you are in right place. GHY basically are a manufacturer and 80% of products showed here can be made to order by ourselves. And we have strong combinati... Category: Materials |
| 290 | [GI Games Co PTE Limited](https://www.casinovendors.com/vendor/gi-games-co-pte-limited/), Singapore GI GAMES CO is a company that specializes in creating state-of-the-art lottery software solutions that redefine the gaming experience. Category: Other |
| 291 | [GI Tech Gaming Co India Private Limited](https://www.igamingsuppliers.com/vendor/gi-tech-gaming-co-india-private-limited/) Chennai, Tamil Nādu, India Thirty Seven years and Counting. That is how long GI Tech Gaming has been working in India and International Market in the lottery business. With a good sense for trends and strategy, GI has the technological edge, young and vibrant team of entreprenuers and professionals wi... Categories: Lottery Software, Sportsbook Software, Mobile Gaming |
| 292 | [Giacona Container Corporation, Inc.](https://www.casinovendors.com/vendor/giacona-container-corporation-inc/) New Orleans, Louisiana Categories: Other, Specialties, Specialties, Gift Merchandise, Souvenirs, Cruise Ship Concesssionaire, Promotions, Promotional Items |
| 293 | [Giant Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/giant-affiliates/) Nicosia, Cyprus THE HIGHEST CONVERTING LOTTO PARTNER PROGRAM Our goal is to continue to lead the iGaming industry as the highest converting lotto affiliate platform. Our sales funnels and telesales team will convert your quality lotto traffic easily. Giant Affiliates is the affiliate... Category: Affiliate Programs |
| 294 | [Giant Bows](https://www.casinovendors.com/vendor/giant-bows/) Norwalk, Connecticut Manufactures giant display bows up to 24 feet wide. Styles: 2-Loops, 4-Loops, 6-Loops, 10-Loops and 16-Loops. Matching giant ribbons up to 5 feet wide. Gift wrap buildings & cars. Weatherproof. Category: Other |
| 295 | [Gibson Graphics Group, Inc.](https://www.casinovendors.com/vendor/gibson-graphics-group-inc/) York, Pennsylvania Gibson Graphics is a full service marketing communications firm with in house print, mail, and fulfillment capabilities. We specialize in direct marketing campaigns, whether large format posters or banners for an in house event or direct mail advertising to your high roller... Categories: Large Format, Billboards, Mailing Services, Printers, Manufacturers |
| 296 | [GIC Management Corporation](https://www.casinovendors.com/vendor/gic-management-corporation/) Pompano Beach, Florida GIC has extensive experience in lotteries and gaming around the world. Our associations with suppliers and vendors allow us to offer the best solutions for all gaming promoters. We have provided services to "Blue Chip" companies and promoters in the business including the fo... Category: Other |
| 297 | [Giesecke & Devrient](https://www.casinovendors.com/vendor/giesecke-devrient/) Dulles, Virginia Giesecke & Devrient (G&D) is an internationally operating technology group with over 156 years of experience and over thirty subsidiaries worldwide. The organization is a leading supplier of currency processing automation systems, vault management software, banknotes and sec... Categories: Currency Handling Equipment, Cash Processing, Consulting, Cash Handling Equipment, Smart Card Systems, Plastic Cards |
| 298 | [Gift Baskets by Kim](https://www.casinovendors.com/vendor/gift-baskets-by-kim/) Los Angeles, California Gift Baskets by Kim offers a distinctive collection of beautiful gift baskets for all your gift giving needs. We offer a number of theme gift baskets from Housewarming Gifts to Wedding gifts and Bridal Gifts. From Newborn baby gift baskets, gift baskets for her and gift bas... Category: Gift Merchandise |
| 299 | [Gift Wonders](https://www.casinovendors.com/vendor/gift-wonders/) Ningbo, Zhejiang, China With an experience of poker chips set, dice, texas hold'em production since year of 1999, we have become one of the largest manufacture in these items. Our production capability is around half million pcs of chips/day quality guranteed. kindly contact us at the info displaye... Category: Poker Chips |
| 300 | [Gift Works Plus](https://www.casinovendors.com/vendor/gift-works-plus/) Waukesha, Wisconsin If you are looking for something truly special, unique and personal, GiftWorksPlus is the perfect place to find it! With our ever-increasing selection of wooden picture frames and new product lines, we are ready to help you find that perfect gift. Whether you're looking f... Category: Other |
| 301 | [Gigaboard Polska](https://www.casinovendors.com/vendor/gigaboard-polska/) Warszawa, Poland We specialize in large-format advertising media, such as superbacklight, and advertising in the prestigious shopping centres. Our company helps the Client find the perfect solution while planning outdoor campaigns. Our experience in this field enables us to offer good advice... Category: Full Service Agency |
| 302 | [Gigadat](https://www.igamingsuppliers.com/vendor/gigadat/) Winnipeg, Manitoba, Canada Gigadat is a team comprised of Canadian payment experts who understand e-merchant needs and requirements, as well as their industry specifics to create a reliable, convenient and secure payments ecosystem, designed to support consumers, e-merchants and financial institutions... Category: Mobile Gaming |
| 303 | [GigaMedia Limited](https://www.casinovendors.com/vendor/gigamedia-limited/) Taipei, Taipei, Taiwan GigaMedia is a diversified provider of online entertainment and broadband services, with headquarters in Taipei, Taiwan. The company develops software for online entertainment services, including the global online gaming market. GigaMedia also operates a major Taiwanese broa... Categories: Software, Other, Software Development |
| 304 | [Gigantic Game Show Give Away](https://www.casinovendors.com/vendor/gigantic-game-show-give-away/) Hoffman Estates, Illinois Gigantic Game Show Give Away™ is a fast moving audience participation show using mostly risk reward games designed to create incremental sales at retail, highlight sponsors, create excitement, and give away valuable prizes. Designed in part, in the style of TV game shows tha... Categories: Theatrical Company, Agency, Production, Promotional Games |
| 305 | [Gilbane Building Company](https://www.casinovendors.com/vendor/gilbane-building-company/) Philadelphia, Pennsylvania Stability...Strength...Experience. Gilbane Building Company has been in the construction business since 1873 and manages over $3 billion of construction annually for our clients. With 28 offices serving owners from coast-to-coast, Gilbane marries the strength of a large na... Category: Consulting |
| 306 | [Gilderfluke & Co., Inc.](https://www.casinovendors.com/vendor/gilderfluke-co-inc/) Burbank, California We manufacture and design show control systems for robotic animation, dynamic fountains, motion platforms, lighting and special effects, modular audio systems, clock/carillons and much more for theme parks, museums, themed restaurants, churches, and airports (to name a few).... Category: Digital Audio Repeater Systems, Animation and Animatronics |
| 307 | [Gills Printing and Color Graphics](https://www.casinovendors.com/vendor/gills-printing-and-color-graphics/) Las Vegas, Nevada Gills has provided forms and color printing and mail services to the casino and hotel industry for 39 years. Category: Other |
| 308 | [Gillware, Inc.](https://www.casinovendors.com/vendor/gillware-inc/) Madison, Wisconsin Gillware Incorporated is located in Madison, Wisconsin, specializing in data recovery from troubled hard drives and reliable remote storage solutions for individuals and corporations alike. Founded in 2004 by Brian and Tyler Gill, Gillware's original mission was to be the be... Category: Data Retrieval Systems, Other |
| 309 | [Gimme Credit LLC](https://www.casinovendors.com/vendor/gimme-credit-llc/) New York, New York Category: Consulting |
| 310 | [Gimoka Coffee UK](https://www.casinovendors.com/vendor/gimoka-coffee-uk/) London, England, United Kingdom Gimoka Coffee UK is the UK distributor of the Italian coffee roaster Gruppo Gimoka. Our mission is to deliver genuine and high quality Italian espresso, roasted according to the traditional coffee artisan practice, directly to you. Lavazza and Nespresso compatible capsules: ... Category: Coffee |
| 311 | [Giocaonline Srl](https://www.igamingsuppliers.com/vendor/giocaonline-srl/) Milan, Italy Category: Casino Software, Casino Software |
| 312 | [Giochi Telematici Affiliazione](https://www.igamingaffiliateprograms.com/affiliate-program/giochi-telematici-affiliazione/) Category: Affiliate Programs |
| 313 | [Gioco News](https://www.igamingsuppliers.com/vendor/gioco-news/) Terni, Umbria, Italy Gioconews is a gaming network with a monthly review with an international delivery because the magazine is in Italian and in English language. It also has an online daily paper (www.gioconews.it) and two other specific online daily news dedicated to the Poker and Casino worl... Category: Consumer Publications |
| 314 | [Gioielli Italy](https://www.casinovendors.com/vendor/gioielli-italy/) Stockton, California Category: Other |
| 315 | [Girard Emilia Custom WoodCarvers, Inc.](https://www.casinovendors.com/vendor/girard-emilia-custom-woodcarvers-inc/) New York, New York Category: Furniture |
| 316 | [Girard's Foodservice Salad Dressings](https://www.casinovendors.com/vendor/girard-s-foodservice-salad-dressings/) City of Industry, California Girard's Foodservice Dressings distributes upscale dressings, sauces and mayonnaise. They manufacture over 100 varieties of dressings and sauces. Category: Other |
| 317 | [Girls Night Out the Show](https://www.casinovendors.com/vendor/girls-night-out-the-show/) Las Vegas, Nevada Girls Night Out the Show® Heats Up the Stages across the USA and brings down the house Seven Nights a Week! Along With Having The BEST GIRLS NIGHT EVER... Here's a few more details about what you can look forward to at GNO The Show: 90 sexy minutes of getting extremely ... Category: Production, Agency |
| 318 | [Girvin, Inc.](https://www.casinovendors.com/vendor/girvin-inc/) Seattle, Washington Our ability to distinctly articulate your brand is our point of difference. Girvin approaches each project from the client's point of view and puts business results at the forefront of our thinking. This approach insures delivery of results that are on strategy, time and bud... Category: Environmental Graphic Design |
| 319 | [GIS - Gambling Integrity Services](https://www.casinovendors.com/vendor/gis-gambling-integrity-services/) Winchester, England, United Kingdom Gambling Integrity Services is a consultancy firm advising governments, regulators and operators in the latest policy and processes for consumer protection, regulation and responsible gambling. We are a member of GiGA, IMGL and our consultants are internationally known and ... Category: Compliance |
| 320 | [Gist Specialties Inc](https://www.casinovendors.com/vendor/gist-specialties-inc/) North Las Vegas, Nevada Young single parent father with talent and vision along with his awesome team of skilled craftsman is ready to design and/or fabricate for your needs. Specializing in architectural themeing and fabrication in high end decor, Gist manufactures in GRG, GFRC, FRP, and almost a... Categories: Fabrication, Theming, Fabrication, Sculpture, Theming, Facility Design, Fabricators |
| 321 | [GISTRA, S.L.](https://www.casinovendors.com/vendor/gistra-s-l/) We are the leading cash management company in Spain. Our cashiers are the best sellers in the Spanish market and we are able to manage the direct payment of all slots machines, jackpots, roulettes and bets installed in casinos Category: ATM Products and Services |
| 322 | [Gitchi Gaming, Inc.](https://www.casinovendors.com/vendor/gitchi-gaming-inc/) Prescott, Wisconsin Gitchi Gaming, Inc. is a complete supplier for slots, table games, cage, vault, bingo & hospitality, specializing in Furniture, Fixtures and Equipment Packages. Categories: Equipment, Supplies, Slot Stools, Storage Systems, Bases-Cabinets-Stands (Wood), Slot Stools, Casino, Equipment, Slot Stools, Tables, Carts, Chips, Interior, Furnishings, Equipment, Change Banks, Change Banks, Equipment, Bases-Cabinets-Stands (Wood) |
| 323 | [Give&Take Profit](https://www.igamingaffiliateprograms.com/affiliate-program/give-take-profit/) Category: Affiliate Programs |
| 324 | [GKMT IT](https://www.igamingsuppliers.com/vendor/gkmt-it/) Jaipur, Rājāsthan, India GKMT IT is an IT-based firm communicating top-notch Website & App Development Company in Jaipur, Graphics & UI/UX Designing, and Digital Marketing indoor your budget cost and pronounced by the dream of creating the fittest for the world with the tardiest technology. Our comp... Category: Software Development |
| 325 | [Gladiator Lighting](https://www.casinovendors.com/vendor/gladiator-lighting/) Aurora, Colorado Our team at Gladiator Lighting have over 20+ years of experience in the lighting industry. Our strong relationships with lighting manufacturers allows us to bring you high quality light bulbs and fixtures at extremely affordable prices. We believe by utilizing the Internet, ... Category: Supplies |
| 326 | [Glamour Flooring](https://www.casinovendors.com/vendor/glamour-flooring/) Katy, Texas Glamour Flooring is your one stop shop for all your home remodeling needs. "Simply the best at what we do." That's what we pride our business upon. Providing our customers with outstanding customer service and professional expert help. Our sales staff and designing team will... Category: Flooring |
| 327 | [Glaro Products](https://www.casinovendors.com/vendor/glaro-products/) Matthews, North Carolina We at www.Glaro-Products.com Sell Glaro Hospitality products exclusively. Everything is manufactured under one roof, so anything you purchase will coordinate perfectly with everything else we sell. No longer is there a need to agonize over what products will look good togeth... Category: Furniture, Metal Products |
| 328 | [Glaro, Inc.](https://www.casinovendors.com/vendor/glaro-inc/) Hauppauge, New York Since 1945, Manufactures of Distinctive metal products for hotels, institutions and public places. As a rule every order is shipped within 1 to 3 days. Bellman carts, Sign frames, key drop boxes, planters, crowd control barriers, waste and smoking receptacles, clothes rack... Categories: Receptacles, Fabrication, Metal, Crowd Control, Doormen |
| 329 | [Glasdon, Inc.](https://www.casinovendors.com/vendor/glasdon-inc/) Sandston, Virginia Glasdon, Inc. supply a wide range of waste management products including trash cans, recycling containers and ash receptacles. We pride ourselves on offering products of the highest quality and value, in a choice of styles, colors and options that complement a variety of app... Categories: Waste Management, Barriers and Germ Guards, Barriers and Germ Guards, Facility Cleaning and Disinfection Services, Facility Cleaning and Disinfection Services |
| 330 | [Glass Creations Unlimited, Inc.](https://www.casinovendors.com/vendor/glass-creations-unlimited-inc/) Dallas, Texas A complete glass design studio that designs and manufacturers metal, wood, lighting, and more to accent projects. We are one of the most reputable companies for glass signage and architectural glass. Glass Creations is known for providing fascinating designs for hotels, re... Categories: Illuminated, Glass Art, Amenities, Indoor, Interior, Design |
| 331 | [Glass Surface Systems, Inc.](https://www.casinovendors.com/vendor/glass-surface-systems-inc/) Barberton, Ohio Glass Surface Systems Inc. has produced SHATTERPROOF lighting for all types of industries for 30 years. Our coating provides glass containment, non-yellowing shatterproofing for all your industrial, commercial, and institutional requirements. H.I.D. metal halide, high pressu... Category: Other |
| 332 | [Glasslight](https://www.casinovendors.com/vendor/glasslight/) Santa Cruz, California Glasslight works in all facets of architectural carved glass. From exquisite brilliant cut mandalas in starfire glass to sandblasted multiples in clear or mirror. Whether contemporary hotel design, victorian to deco restoration or sculptural glass, we can help you develop a ... Category: Glass Art |
| 333 | [Glassometry Studios](https://www.casinovendors.com/vendor/glassometry-studios/) Hood River, Oregon Glassometry studios owner Laurel Marie Hagner has her degree in sculpture. She has been pushing boundaries with metal and glass for over 16 years. Her sculptural metal work is fantastical and executed with the highest quality. With custom sculptural pieces made for compan... Categories: Glass Art, Fabrication, Metal |
| 334 | [GLC Abogados](https://www.igamingsuppliers.com/vendor/glc-abogados/) Los Yoses, San José, Costa Rica Category: Consulting |
| 335 | [Gleiss Lutz](https://www.igamingsuppliers.com/vendor/gleiss-lutz/) Berlin, Berlin, Germany For many years, we have been following the development of e-business with all its many and varied facets. Our work has concerned fundamental matters like the registration, securing and defence of domains worldwide (including WIPO proceedings), the establishment of joint plat... Category: Compliance |
| 336 | [Glendale Awning Company](https://www.casinovendors.com/vendor/glendale-awning-company/) Middle Village, New York Glendale Awning Company, a division of PHK GROUP, INC is a company that manages all awnings, canopies, signs, banners, channel letters, aluminum awning, lexan awning products and service in NYC Tri-State area. We are one of the oldest awning manufacturer in NYC. Buy direct f... Category: Other |
| 337 | [Glenn Green Galleries](https://www.casinovendors.com/vendor/glenn-green-galleries/) Tesuque, New Mexico An art treasure located in the lovely historical village of Tesuque - just six minutes from Santa Fes Plaza. Glenn, Sandy and their daughter Kerry Green hope the that the public will enjoy the works they show online and that they will personally visit their varied & expansi... Category: Art |
| 338 | [Glenn Rieder LLC](https://www.casinovendors.com/vendor/glenn-rieder-llc/) West Allis, Wisconsin Glenn Rieder LLC ("GR") manufactures and installs complete interiors for casinos, including architectural millwork, decorative glass, ornamental metal, cast materials, faux finishes, booth and banquette seating, solid surfaces and stone tops. Categories: Interior, Millwork, Moldings |
| 339 | [GLI Europe B.V.](https://www.casinovendors.com/vendor/gli-europe-b-v/) Hillegom, Zuid-Holland, Netherlands For more than 20 years, Gaming Laboratories International has been the world leader in independent testing for the gaming industry. With 13 testing laboratories spread across Africa, Asia, Australia, Europe, South America and the United States, GLI is recognized in more than... Category: Software Testing and Certification, Testing |
| 340 | [Glitnor Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/glitnor-affiliates/) Category: Affiliate Programs |
| 341 | [Global Access Unlimited](https://www.casinovendors.com/vendor/global-access-unlimited/) Largo, Florida We are Woman Owned Small Business celebrating 11 years of electronics distribution. Although our core competency is the supply of commercial through military board level components, we pride ourselves in our ability to provide our customers with anything utilized in the ma... Category: Parts |
| 342 | [Global Architectural Models](https://www.casinovendors.com/vendor/global-architectural-models/) Las Vegas, Nevada Scale models for any project. Category: Supplies |
| 343 | [Global Art, Inc.](https://www.casinovendors.com/vendor/global-art-inc/) Kentwood, Michigan Global Art has serviced the retail industry in picture framing and signage frames for 30 years. We maintain all our deadlines while still creating quality products for the industry. We can customize products & services for the industry by adding a uniqueness to framing or ... Category: Interior Design, Furnishings |
| 344 | [Global Awards, Inc.](https://www.casinovendors.com/vendor/global-awards-inc/) Las Vegas, Nevada Global Awards is a creative - full service engraving company offering quality service, craftsmanship & customer satisfaction. We specialize in name badges, slot machine & interior ADA approved signage, plaques & awards promotional gift items. Our master engravers are highly ... Categories: Plaques, Engraving, Engraved Signs Manufacturer, Indoor, Signage, Incentives and Awards, Plastics |
| 345 | [Global Beerco USA](https://www.casinovendors.com/vendor/global-beerco-usa/) Davis, California Global Beerco USA is committed to applying todays advanced communication technology to deliver the highest standards of customer support and continuous education to each HouseBrew operator. HouseBrew owners attend a two-day comprehensive training course at the University of ... Category: Bar Equipment |
| 346 | [Global Bet Guide](https://www.casinovendors.com/vendor/global-bet-guide/) London, England, United Kingdom GlobalBetGuide is an independent iGaming portal focused on Nigeria & South Africa, with coverage also extending to Australia and New Zealand. We publish expert-edited reviews of sportsbooks, casinos, and live dealer platforms, along with in-depth guides on local payment meth... Category: |
| 347 | [Global Betting & Gaming Consultants - GBGC](https://www.igamingsuppliers.com/vendor/global-betting-gaming-consultants-gbgc/) Castletown, Isle of Man GBGC has on its team several specialist consultants who can provide economic research, 'know how' in all areas of gambling, market research, statistical data, software solutions, payment solutions, electronic point of sale, information display systems, online technology and ... Categories: Consulting, Consulting, Consulting, Consulting, Consulting |
| 348 | [Global Billiards Manufacturing](https://www.casinovendors.com/vendor/global-billiards-manufacturing/) Carson, California The success of Los Angeles based Global Billiard Manufacturing can be attributed to a similar force: blending the Old World values of craftsmanship with an understanding of evolving business trends and customer needs. Founded more than three decades ago by a young immigrant ... Category: Amusement Equipment |
| 349 | [Global Drilling Fluids & Chemicals Limited](https://www.casinovendors.com/vendor/global-drilling-fluids-chemicals-limited/) Faridabad, Haryāna, India Manufacturers and suppliers of drilling fluids, oil drilling fluids and chemicals exporters from India. The Companys product range covers drilling fluids for oil and Gas Wells, Mud Chemicals, Workover and Completion Fluids, Production Chemicals, Well Stimulation Chemicals a... Category: Other |
| 350 | [Global Equipment Co., Inc.](https://www.casinovendors.com/vendor/global-equipment-co-inc/) Buford, Georgia Leading distributor of industrial products for over 50 years. Category: Other, Other |
| 351 | [Global Fabric Group](https://www.casinovendors.com/vendor/global-fabric-group/) Easley, South Carolina Global Fabric Group is a wholesaler of finished products for the hospitality and healthcare industries. Category: Linens |
| 352 | [Global Game](https://www.casinovendors.com/vendor/global-game/) Panchiao City, Taipei, Taiwan Category: New Game Manufacturer |
| 353 | [Global Games & Gaming (G3) Magazine](https://www.casinovendors.com/vendor/global-games-gaming-g3-magazine/) Manchester, United Kingdom G3 is a global media channel supplying news, market research, expert opinions and data to the international gaming community. G3 encompasses a monthly print and digital magazine, G3Newswire.com daily gaming news service, podcasts and support Apps for both magazine and news d... Category: Magazines, Business Publications |
| 354 | [Global Gaming Business](https://www.casinovendors.com/vendor/global-gaming-business/) Boulder City, Nevada GGB is a leading gaming trade publication focusing on the worldwide gaming industry. GGB is the exclusive official publication of the American Gaming Association, AGEM, and the official G2E magazine. Publications include Tribal Government Gaming, Casino Style, Progressive P... Categories: Magazines, Business Publications, Consulting |
| 355 | [Global Gaming Expo (G2E)](https://www.casinovendors.com/vendor/global-gaming-expo-g2e/) Norwalk, Connecticut At G2E, youll find the industrys leading suppliers of the latest technologies and new products, four days of hard-hitting strategies and essential education, and unparalleled networking that are indispensable for predicting upcoming opportunities and unforeseen challenges.... Categories: Shows, Conferences, Trade Shows and Conferences |
| 356 | [Global Gaming Initiatives](https://www.casinovendors.com/vendor/global-gaming-initiatives/) Las Vegas, Nevada With 20 years of hands on experience, Global Gaming Initiatives has the greatest insight as to what the end user wishes to see in a casino and gaming product. From his entry into gaming management in 1987, Mr. Meyer held operational and internal audit positions with such ent... Categories: Game Design, Design, Assessment, Brokerage, Other |
| 357 | [Global Industry Products Corp](https://www.casinovendors.com/vendor/global-industry-products-corp/) Las Vegas, Nevada Global Industry Products began developing relationships with the casino industry in Las Vegas. We have committed ourselves in providing our customers with the highest quality products, lowest pricing, and excellence in customer service. Today we are even more committed ... Categories: Other, Disposable Tableware, Paper Products |
| 358 | [Global Intelligence Network, LLC](https://www.casinovendors.com/vendor/global-intelligence-network-llc/) Las Vegas, Nevada Global conducts confidential and discreet investigations for due diligence in regulatory compliance, key employee backgrounds and market entry reports. Global manages both domestic and international investigations with an extensive network of assets. In the last three years... Categories: Investigations, Indian Gaming, Fulfillment Services |
| 359 | [Global Lighting & Signs](https://www.casinovendors.com/vendor/global-lighting-signs/) San Diego, California Global Lighting & Signs is an electrical and sign contractor that installs indoor and outdoor signage in Casinos. Category: Illuminated |
| 360 | [Global Link Language Services, Inc.](https://www.casinovendors.com/vendor/global-link-language-services-inc/) Boston, Massachusetts Global Link Language Services, founded in 1996, has emerged as an industry leader. Our premise is simple yet effective: we provide superior services and experience, extensive linguistic resources and competitive rates. Most importantly, we not only meet the expectations of o... Category: Translation Services |
| 361 | [Global Mfg. LLC](https://www.casinovendors.com/vendor/global-mfg-llc/) Newark, New Jersey We are the lowest cost, highest quality producer in our Field. We own our own factories in Mexico and have very quick turn around. We ship from Laredo Texas and Newark New Jersey. We do our embroidery in Mexico which makes us very competitive in specializng what we make. Category: Apparel Manufacturer |
| 362 | [Global Mfg. Solutions](https://www.casinovendors.com/vendor/global-mfg-solutions/) Franklin, Ohio Global Mfg. Solutions strives to assist every customer in accomplishing their decorating goals. Customer satisfaction is paramount to our existence as a leading provider of foam shapes. Exceeding customer expectations is our primary goal. We can accept most cad shapes or ... Category: Theming |
| 363 | [Global Monitor](https://www.casinovendors.com/vendor/global-monitor/) Guadalajara, Mexico Global Monitor is more than 14 years experience in industrial monitors for gaming machines, we integrate the best solutions in monitors with and without touch screen for our customers, and we are certifie by companies like 3M in US to integrate their touch screens with the b... Category: Other |
| 364 | [Global One Technologies](https://www.casinovendors.com/vendor/global-one-technologies/) Oceanside, California Global One Technologies is a design, engineering and systems integration firm, which transforms the way our customers live and do business by providing the best and most appropriate Audio Video and Technology solutions available to meet their functional, budgetary and implem... Category: Control Room |
| 365 | [Global Payment Technologies, Inc.](https://www.casinovendors.com/vendor/global-payment-technologies-inc/) Bohemia, New York Global Payment Technologies is a designer and manufacturer of currency validators supporting over 75 valid country-databases in the gaming, vending, banking and retail industries. GPTs validators are unmatched in quality and performance, as is their unsurpassed commitment ... Category: Bill Validators |
| 366 | [Global Power Products](https://www.casinovendors.com/vendor/global-power-products/) Simi Valley, California Global Power Products specializes in many diverse industries from Gaming to Medical. We have a wide selection of standard power supplies. We also do modified and custom designs. Our lead-times are within 6-8 weeks. All our products are backed by a minimum 2 year warranty. Category: Power Sources |
| 367 | [Global Promotional Sourcing](https://www.casinovendors.com/vendor/global-promotional-sourcing/) Las Vegas, Nevada Global Promotional Sourcing (GPS) is the ONLY all-in-one provider of loyalty solutions for the gaming industry. Founded in 2001, weve grown into a trusted $200M+ marketing partner for top casino groups, delivering innovative, data-driven strategies that enhance guest engage... Category: Promotional Items |
| 368 | [Global Recruiters Network](https://www.casinovendors.com/vendor/global-recruiters-network/) Chicago, Illinois Global Recruiters Network, Inc.(GRN) is an expanding network dedicated to connecting high-quality companies with high-quality talent to advance in both business and career goals. Each of our offices specialize in a variety of disciplines, industries, and geographies, giving ... Category: Recruitment |
| 369 | [Global Refractory Installers and Suppliers](https://www.casinovendors.com/vendor/global-refractory-installers-and-suppliers/) Manistee, Michigan Global Refractory is comprised of project managers and service technicians. They have come together to bring their many years of designing, building, installing and servicing the air pollution control, aluminum melting and steel processing industries. Category: Air Filtration Systems |
| 370 | [Global Resource, Inc.](https://www.casinovendors.com/vendor/global-resource-inc/) Houston, Texas We carry all major brands of telephone equipment priced at 40-60% below retail. We offer the strongest warranty in the industry-- 3 year advanced replacement on all telephone and system parts. Some of the name brands we carry include: Nortel, Meridian, Teledex, Telematrix... Categories: Telecommunications Systems, Other, Communication Systems, In-room Messaging, Communications, In-house |
| 371 | [Global Safe Corporation](https://www.casinovendors.com/vendor/global-safe-corporation/) Boca Raton, Florida Global Safe Corporation is a leading manufacturer of electronic hotel safes. They have installed their hotel room safes in hospital patient rooms, university dormitories, United States military bases and embassies around the world. Categories: Safes, Safes, Safes, Safes, Safes |
| 372 | [Global Scenic Services, Inc.](https://www.casinovendors.com/vendor/global-scenic-services-inc/) Bridgeport, Connecticut Global Scenic Services is your partner in every aspect of your production. We operate from a 40,000 sq ft fabrication facility equipped to handle all of your fabrication needs including automation. We are prepared to tackle projects from the smallest show to the most lav... Category: Production |
| 373 | [Global Security Products, Inc.](https://www.casinovendors.com/vendor/global-security-products-inc/) Miami, Florida Paradyme/Global Security Products, Inc. is an experienced systems integration provider. Our in-house design and consulting team takes projects from conception to implementation and operation. Our experienced team has designed and installed systems for National Palaces, Presi... Category: CCTV Systems |
| 374 | [Global Security Solutions](https://www.casinovendors.com/vendor/global-security-solutions/) Tulsa, Oklahoma Our expertise and strengths are rooted in our firm understanding that each security project needs to be tailor-made to each clients needs, specifications, and environment. We in building working partnerships, where the client is able to maximize the benefits of the services... Category: CCTV Systems |
| 375 | [Global Security Technologies (GST)](https://www.casinovendors.com/vendor/global-security-technologies-gst/) Odessa, Odes'ka Oblast', Ukraine Let us express to you our respect and introduce GST-Group (www.gst-group.com) - manufacturer and distributor of advanced high-grade security seals for preventing unauthorized access and fraud. Security seals for game machines, cash boxes, meters (electric, gas, water), calib... Category: Plastics |
| 376 | [Global Semisolutions](https://www.casinovendors.com/vendor/global-semisolutions/) Clearwater, Florida Global Semisolutions brings industry expertise to your electronic component needs. Our specialized sales team gives you the diversity in product knowledge that you need- the market expertise and technical skills of a specialist and the global supply chain services of a large... Category: Components |
| 377 | [Global Shakeup](https://www.casinovendors.com/vendor/global-shakeup/) North Hollywood, California Snowdomes, and snow globes designed to your specifications. Our focus is exclusively on these items and we are the best in the business. All-inclusive pricing (no surprise setup or extra charges) and on-time delivery takes the worry out of ordering these prized collectibles.... Categories: Wholesale, Souvenirs, Gift Merchandise |
| 378 | [Global Storm Partners](https://www.igamingaffiliateprograms.com/affiliate-program/global-storm-partners/) Category: Affiliate Programs |
| 379 | [Global Supply Network](https://www.casinovendors.com/vendor/global-supply-network/) Boulder, Colorado Global Supply Network is a manufacturer of Thermal & 2-ply Rolls, Printer ribbons,toner cartridge, InkJet cartridge, copier toners> We also have a full line of Thermal & Direct labels. We have Manufactured in the United States for over 25 years experience in the markets. O... Categories: Toner Cartridges, ATM Products and Services, Other, Bar Equipment, Paper, Other, Change Banks, Other, Supplies, Banking, Other |
| 380 | [Global Tote](https://www.igamingsuppliers.com/vendor/global-tote/) Broadmeadow, New South Wales, Australia The Global Tote is set to change Race books around the world. With the worlds first Business to Business only tote system its giving wagering operators globally the opportunity to provide a RaceBook to their clients like never before.Guaranteed returns, More content, No lo... Category: Gambling Operations, Sportsbook Software |
| 381 | [Global Trends U.S.A.](https://www.casinovendors.com/vendor/global-trends-u-s-a/) Canoga Park, California We are a mid-size embroidery and digitizing company offering our clients the highest quality production to be found anywhere. We have digitized over 250,000 individual logos since 1995, so we know what to do and how to do it precisely and perfectly. We have worked with man... Category: Embroidery |
| 382 | [Global Verification Network](https://www.casinovendors.com/vendor/global-verification-network/) Palatine, Illinois How do you know who you're hiring? Redridge Verification can help you answer this question. They offer accurate information, with a quick turnaround rate. Please visit their website today. Category: Employee Screening |
| 383 | [GlobalBet](https://www.casinovendors.com/vendor/globalbet/) Ruggell, Ruggell, Liechtenstein GlobalBet is a prominent B2B provider, serving as a trusted partner to the world's largest lottery operators across the globe. With a strong presence in five countries, GlobalBet offers comprehensive gaming solutions tailored to the unique requirements of the lottery industr... Categories: Other, Gambling Operations, Sportsbook Software, Racebook Software |
| 384 | [Globaldev Group](https://www.casinovendors.com/vendor/globaldev-group/) Belmont, California Globaldev Group helps companies advance their value by providing a complete set of software development solutions and leveraging our global talent pool. Category: Web Site Development |
| 385 | [Globalization Partners International](https://www.casinovendors.com/vendor/globalization-partners-international/) McLean, Virginia Globalization Partners International provides an array of globalization services that help companies communicate with the world. Our core service offerings enable firms to design, develop, and deploy multilingual documentation, software and Web sites for worldwide use. GP... Category: Translation Services, Translation Services |
| 386 | [GlobalProjectors.com](https://www.casinovendors.com/vendor/globalprojectors-com/) Guangzhou, Guangdong, China Globalprojectors.com is located in HongKong,China. Our company is established in 1997. Our store is to provide all the customers of us with the manufacturer wholesales price in Projection equipment and accessories without any aftersales commision. Our higly efficient logist... Category: Projectors |
| 387 | [Globant](https://www.igamingsuppliers.com/vendor/globant/) Capital Federal, Argentina We want to challenge the status quo and become the best company developing solutions that combine the best of engineering, innovation and design. Our goal is to be the leader in the creation of innovative software products that appeal to global audiences. We are a new-bre... Category: Software Development, Other |
| 388 | [GLOBAST Sh.a.](https://www.casinovendors.com/vendor/globast-sh-a/) Tirana, Tiranë, Albania Great offers for used electro-mechanical roulettes, slots and a complete Bingo Hall Equipment. Contact us for more details... Categories: Equipment, Slot Machines, Refurbished, Bingo Hall Management Systems |
| 389 | [Globe Party, Inc.](https://www.casinovendors.com/vendor/globe-party-inc/) Panorama City, California Globe Party, Inc is one of the USA leading entertainment companies. Our passion for innovative, fresh and creative entertainment ensures that we deliver distinctive experience to our clients in an easy, stress free way. Globe Party works with a diverse range of high qua... Category: Agency |
| 390 | [Globe Ticket](https://www.casinovendors.com/vendor/globe-ticket/) Carol Stream, Illinois The nation's oldest ticket printer (1868). As the manufacturer of tickets for the original thermal ticket printers, we have the most experience in the nation with this product. In addition we also produce thermal tickets for event admission, and movie theaters nationwide in... Categories: TITO Tickets, Tickets, Supplies |
| 391 | [Globo Technologies](https://www.igamingsuppliers.com/vendor/globo-technologies/) Moscow, Russia Globo Technologies was founded in 2001. Originally, its founders had set out to create a one-of-a-kind online casino, but were unable to find a unique software vendor that met their standards of quality. This prompted the start of their own software development company. Glob... Category: Casino Software, Poker Software |
| 392 | [GLORY (U.S.A.) Inc.](https://www.casinovendors.com/vendor/glory-u-s-a-inc/) West Caldwell, New Jersey GLORY is the world leader in the design and manufacture of cash management solutions that consist of casino kiosks with ATM functionality, bill breaking and ticket redemption; cash dispensers, cash recyclers and currency sorters and integration with many of the top cash acce... Categories: Kiosks, Cash Processing, Currency Handling Equipment, Currency Handling Equipment, Coin Wrapping, Change Banks |
| 393 | [Glory Global Solutions Limited](https://www.casinovendors.com/vendor/glory-global-solutions-limited/) Las Vegas, Nevada At Glory Global Solutions, innovation is at the heart of what we do. We bring real innovation to our customers, through technology, process and our people. Through our innovation, we fundamentally change the way cash moves across operations, how staff work, how customers are... Category: Currency Management Services |
| 394 | [Glory Partners](https://www.igamingaffiliateprograms.com/affiliate-program/glory-partners/) Category: Affiliate Programs |
| 395 | [Gloss Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gloss-partners/) Category: Affiliate Programs |
| 396 | [Glove Connection](https://www.casinovendors.com/vendor/glove-connection/) Henderson, Nevada The Glove Connection is a local company located in Henderson Nevada. We have been in business since 2001. We are a "Full Service Safety Supply House." We provide disposable Latex and Nitrile gloves to casinos. We also provide several items to Engineering and Horticulture dep... Category: Other, Other |
| 397 | [Glownight Games](https://www.igamingsuppliers.com/vendor/glownight-games/) New Hyde Park, New York Glownight Games is a prominent in 2D and 3D Game development, iOS & Android mobile game development company building games with great design & high-performance to provide a great user experience. Glownight Games is an aggregation of the world-class mobile game developers who... Category: Mobile Gaming |
| 398 | [Glu Mobile Inc.](https://www.igamingsuppliers.com/vendor/glu-mobile-inc/) San Francisco, California Glu Mobile is a leading global developer and publisher of freemium games for smartphone and tablet devices. Glu's unique technology platform enables its titles to be accessible to a broad audience of consumers all over the world - supporting iOS, Android, Palm, Windows Phon... Category: Mobile Gaming |
| 399 | [Glux Gtek (Shenzhen) Inc](https://www.casinovendors.com/vendor/glux-gtek-shenzhen-inc/) Shenzhen, China Glux Gtek is China's No.1 in LED curtain products, supply LED display to 2008 Olympics. With 17 years manufacturing & 15 years rental business experiences, we have customers from over 60 countries worldwide;our references include 2008 Beijing Olympics Games, CCTV (China Cen... Categories: LED Systems, LED, Videowalls, LED Systems |
| 400 | [GM Monarch West, LLC](https://www.casinovendors.com/vendor/gm-monarch-west-llc/) Las Vegas, Nevada Our staff has extensive experience in manufacturing custom millwork interiors for the Gaming and Hospitality Industry. We offer a commitment to customer service and pride ourselves on completing all projects on schedule to the customer's satisfaction. We offer Value Engineer... Category: Theming |
| 401 | [GM Telecom Supply, Inc.](https://www.casinovendors.com/vendor/gm-telecom-supply-inc/) Tampa, Florida Fiber Optic Manufacturing house. Lead time same day or next day delivery on all products from single to multi strand fiber assemblies example LC,SC,FC,D4,MU,BICONIC,SMA,DIN,MTRJ etc. Category: Fiber Optics Products |
| 402 | [GMD Industries, Inc.](https://www.casinovendors.com/vendor/gmd-industries-inc/) College Point, New York In the 33 years in existence, GMD Industries has provide decorative glass products to the gaming and high end retail markets. Our extensive knowledge when it comes to providing solutions allows us to manufacture products that others struggle with, such as oversize pieces of ... Category: Glass Art |
| 403 | [GMF Hospitality Inc](https://www.casinovendors.com/vendor/gmf-hospitality-inc/) Tenafly, New Jersey GMF Hospitality is a leading supply of upholstery products to a number of casino properties in Atlantic City, Las Vegas and throughout the US Category: Upholstery |
| 404 | [GMP Design Associates](https://www.casinovendors.com/vendor/gmp-design-associates/) Staffordshire, England, United Kingdom Established since 1990, award winning leisure designers GMP are currently one of the leading design consultancies in the late night entertainment market. Our highly creative and professional team are experienced in producing value for money interiors that are dynamic, stylis... Category: Interior |
| 405 | [GMR Transciption](https://www.casinovendors.com/vendor/gmr-transciption/) Tustin, California GMR Transcription provides state-of-the-art, affordable and accurate transcription services in the United States. With several million minutes of audio recorded and thousands of happy clients from an ever-growing list, GMR is your trusted source for transcription services at... Category: Translation Services |
| 406 | [GMW - Golden Metal Works](https://www.casinovendors.com/vendor/gmw-golden-metal-works/) Aligarh, India Established in 1975, Golden Metal Works has earned an enviable reputation as Manufacturer and Exporters of Quality Builders Hardwares in Brass, Aluminium & Iron as well. It has a very good standing with its customers all across the world. Presently, the company exports its B... Category: Other |
| 407 | [GN Exhibits Plus](https://www.casinovendors.com/vendor/gn-exhibits-plus/) Hauppauge, New York Over 25 years of experience with trade show exhibits and complete convention services. We provide special custom props, prototypes, and integrated industrial design services. Imagine it, design it, build it from concept to completion we do it all. www.gnexhibitsplus.com Category: Exhibit Supplies, Trade Shows and Conferences |
| 408 | [GnG Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gng-affiliates/) Category: Affiliate Programs |
| 409 | [GNISEC](https://www.casinovendors.com/vendor/gnisec/) Sherman, Texas GNISEC is a national security company providing system installation and service of security camera systems, alarm systems, access control, integration and networking. We offer the latest in digital video recording technology. Stop by our booth for a demonstration and a pre... Category: Alarms |
| 410 | [Go Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/go-affiliates/) Category: Affiliate Programs |
| 411 | [Go Barefoot](https://www.casinovendors.com/vendor/go-barefoot/) Gardena, California Go Barefoot has been designing and producing clothing for almost 50 years. Go Barefoot manufacturers island and beach lifestyle clothing. Category: Other |
| 412 | [GO Business](https://www.igamingsuppliers.com/vendor/go-business/) GO is the leading provider of ICT services in Malta, operating the primary IP link to Europe with capacity in excess of 2.5Gbps and immediate plans for a secondary link. GO also operates a number of state-of-the-art data centres that are managed round the clock by an excelle... Category: Hosting |
| 413 | [Go Green Lighting USA](https://www.casinovendors.com/vendor/go-green-lighting-usa/) Margate, Florida We are providers, designers and manufaturers of LED lightign products. We also do installation and services of our products. We have a wide range of products and we can design and customize to any customer's need. Category: LED |
| 414 | [GO plc](https://www.casinovendors.com/vendor/go-plc/) Marsa, Malta GO plc (formerly Maltacom) has become Maltas first and only quadruple play operator, a truly converged telecommunications operator with a huge range of services. And to help you find exactly the right service for you, weve grouped them together into three areas GO Busine... Categories: Communication Systems, Hosting, Hosting |
| 415 | [Go Win Casino Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/go-win-casino-affiliates/) Category: Affiliate Programs |
| 416 | [Go2Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/go2affiliates/) Category: Affiliate Programs |
| 417 | [Goat Gaming Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/goat-gaming-affiliates/) Category: Affiliate Programs |
| 418 | [GodBunny Partners](https://www.igamingaffiliateprograms.com/affiliate-program/godbunny-partners/) Category: Affiliate Programs |
| 419 | [Godiva Chocolatier, Inc.](https://www.casinovendors.com/vendor/godiva-chocolatier-inc/) New York, New York Category: Chocolate |
| 420 | [Goff Public, Inc.](https://www.casinovendors.com/vendor/goff-public-inc/) Saint Paul, Minnesota Goff Public is an independent communications agency based in Minnesota offering public relations and government relations services. We are skilled, experienced problem solvers who tell our clients stories, advocate for their interests and protect their reputations while se... Category: Public Relations and Publicity |
| 421 | [GoFrugal Technologies](https://www.casinovendors.com/vendor/gofrugal-technologies/) Chennai, Tamil Nādu, India GoFrugal is a leading retail business management software company India specializing in retail, distribution and supply chain management solutions. We offer end to end solutions from store automation to multi-channel retailing suitable for volume, value and service to the re... Category: Systems |
| 422 | [GOG Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gog-affiliates/) Category: Affiliate Programs |
| 423 | [Gogame Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gogame-partners/) Category: Affiliate Programs |
| 424 | [GOJO Industries Inc.](https://www.casinovendors.com/vendor/gojo-industries-inc/) Akron, Ohio GOJO Industries, Inc. has a portfolio of products that includes industry leading formulas under the GOJO® and PURELL® brand names. GOJO is known for state-of-the-art dispensing technology, engineered with attention to design and durability. In partnership with our distributo... Category: Hygiene Products, Supplies |
| 425 | [Gold Club d.o.o.](https://www.casinovendors.com/vendor/gold-club-d-o-o/) Sezana, Sežana, Slovenia Gold Club D.O.O. developes automated roulettes. The Gold Club Roulette for 5,6,8 and 10 players is a completely automated, computer controlled gambling machine. Its classical design and esthetical perfection, combined with cutting edge technology, sets new standards to one's... Category: Equipment |
| 426 | [Gold Coast Flood Restorations](https://www.casinovendors.com/vendor/gold-coast-flood-restorations/) El Cajon, California At Gold Coast Flood Restorations, we believe every customer deserves our fullest attention. That your problems are ours. And that we are obligated to do everything within our power to makes those problems disappear. Gold Coast is a Christian-based, family owned and operat... Categories: Claims, Other, Consulting, Other |
| 427 | [Gold Crown Gaming](https://www.casinovendors.com/vendor/gold-crown-gaming/) Miami, Florida Gold Crown Gaming Categories: Slot Machines, Refurbished, Supplies, Equipment, Manufacturer, Furnishings, Reconditioned, Shuffling Machines, Blackjack Tables, Chip Handling, Equipment, Bill Validators, Chip Handling, Chips, Electronic Systems, Slot Stools, Accessories, Blackjack Tables, Blackjack Tables, Chips, Multi-player Games, Chips, Reconditioned, Poker Network, Equipment, Slot Stools, Coin Hoppers, Electronic Games, Gaming Products, Shuffling Machines, Pai Gow, Shuffling Machines, Tables, Accessories, Accessories, Equipment, Video Devices (used), Equipment, Reconditioned, Equipment, Gaming Products, Collection Systems, Chip Handling, Poker Chips, Chips, Used, Coin and Chip Storage, Furnishings, Slot Machines, Refurbished |
| 428 | [Gold Deluxe Ltd](https://www.igamingsuppliers.com/vendor/gold-deluxe-ltd/) Gold Deluxe was established in 2011 July; with over 100 employees in Philippines. It specializes in online casino platform for Baccarat and other casino games. Gold Deluxe has led the online gaming industry by providing innovative & cutting edge casino solutions to leading g... Category: Live Dealer, Mobile Gaming |
| 429 | [Gold Fusion](https://www.casinovendors.com/vendor/gold-fusion/) Conyers, Georgia The GOLD FUSION team is comprised of dedicated professionals who work synergistically to provide you, the customer, with the most feature-packed system on the market today. Programmers, Gamers, Artists, Technicians, Engineers, Customer Support, Account Representatives and In... Category: Software |
| 430 | [Gold Link S.R.L](https://www.casinovendors.com/vendor/gold-link-s-r-l/) Buenos Aires, Capital federal, Argentina Categories: Electronic Systems, Equipment, Slot Machines, Systems |
| 431 | [Goldbet Partners](https://www.igamingaffiliateprograms.com/affiliate-program/goldbet-partners/) Category: Affiliate Programs |
| 432 | [Golden Euro Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/golden-euro-affiliates/) Category: Affiliate Programs |
| 433 | [Golden Games](https://www.casinovendors.com/vendor/golden-games/) Pfäffiko, Switzerland Category: Slot Machines |
| 434 | [Golden Gorilla Media Limited](https://www.igamingsuppliers.com/vendor/golden-gorilla-media-limited/) Newcastle upon tyne, England, United Kingdom Digital Growth Specialists We are digital marketing and media publishers that get brands discovered online. Category: Search Engine Optimization, Website Content |
| 435 | [Golden Hero Limited](https://www.igamingsuppliers.com/vendor/golden-hero-limited/) Category: Casino Software, Casino Software |
| 436 | [Golden Limo Worldwide](https://www.casinovendors.com/vendor/golden-limo-worldwide/) San Jose, California SFO Golden Limo consistently provides on-time, prompt and professional chauffeured limo service to meet the challenging transportation needs of San Jose business and leisure travelers. With our team of professional chauffeurs, fleet of latest sedans, vans, limo-buses and var... Category: Limousines |
| 437 | [Golden Matrix Group](https://www.igamingsuppliers.com/vendor/golden-matrix-group/) Golden Matrix Group is a leading provider of turnkey and white label gaming platforms, Esports technology and gaming content. Categories: Gambling Operations, Platform Providers, Other |
| 438 | [Golden Palace Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/golden-palace-affiliates/) GoldenPalaceAffiliates.com represents world-renown brands that have withstood the test of time. GoldenPalace.com was established in 1997, virtually since the advent of online gaming itself. We hold operators to the highest possible standards to ensure that players receive th... Category: Affiliate Programs |
| 439 | [Golden Race](https://www.igamingsuppliers.com/vendor/golden-race/) Birguma Naxxar, Malta Golden Race is the “one stop partner” for virtual sportsbetting and number games. We fulfill all special needs regarding different clients, countries and habits. By constantly improving existing products and developing innovative new games, we build up “one stop clients” tha... Category: Gambling Operations, Other |
| 440 | [Golden Rock Studios](https://www.igamingsuppliers.com/vendor/golden-rock-studios/) Gibraltar, Gibraltar Golden Rock Studios is a game developer of online slots and table games. Category: Casino Software |
| 441 | [Golden Royal Technology Developer Co.,Ltd.](https://www.casinovendors.com/vendor/golden-royal-technology-developer-co-ltd/) Yongkang, Tainan, Taiwan Our company has been engaged in developing and manufacturing various software and hardware for electronic gaming such as electronic baccarat. We have a specialized team that offers the most specialized, conscientious service, the latest development of machinery, and permanen... Category: Electronic Games |
| 442 | [Golden Sunshine Entertainment Products Limited](https://www.casinovendors.com/vendor/golden-sunshine-entertainment-products-limited/) Guangzhou, China Category: Playing Cards |
| 443 | [Golden View Localization](https://www.casinovendors.com/vendor/golden-view-localization/) Shenzhen, Guangdong, China One-stop shop translation & localization solutions into East Asia and South East Asian languages with 13 years excellence. Category: Translation Services |
| 444 | [Golden Waffles](https://www.casinovendors.com/vendor/golden-waffles/) South Bend, Indiana For over 80 years Golden Waffles has been America's Favorite waffle. They are the world's largest supplier of waffle irons and waffle mix for the best hotels, universities, restaurants and theme parks. If you've eaten a waffle at a hotel, most likely it was a Carbon's Golde... Category: Equipment, Other |
| 445 | [Golden Whale Productions GmbH](https://www.casinovendors.com/vendor/golden-whale-productions-gmbh/) Vienna, Austria Data-driven services in platform-building, games-design, player-analytics and much more Golden Whale Productions provides know-how and products that let you utilize the power of your data for informed decisions. Solutions for player behaviour and classification, retention ... Category: |
| 446 | [Goldenbet Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/goldenbet-affiliates/) Category: Affiliate Programs |
| 447 | [Golden-Race A.B. Group](https://www.igamingsuppliers.com/vendor/golden-race-a-b-group/) Birguma Naxxar, Malta Golden Race is a young and dynamic holding company that was born at the beginning of 2006 in the field of sports betting and with the successful launch of dogs racings with over 8,000 licenses sold. Because of the success of its first product, the company decided to invest a... Category: Racebook Software, Live Dealer |
| 448 | [Golden-Race.ru](https://www.igamingsuppliers.com/vendor/golden-race-ru/) Netishin, Ukraine Category: Racebook Software |
| 449 | [Goldfinger Monitors](https://www.casinovendors.com/vendor/goldfinger-monitors/) John's Island, South Carolina Goldfinger is the fastest growing monitor company in the United States designing and manufacturing non-touch and touch screen monitors with touch-screen capable on-screen menus boasting state-of-the-art technology and durability. We offer a full line of monitors that are bui... Category: Monitors, Card Readers |
| 450 | [Goldfire Studios](https://www.igamingsuppliers.com/vendor/goldfire-studios/) Oklahoma City, Oklahoma GoldFire Studios is pioneering the next generation of social gaming by bringing real-time multiplayer games to your tablets and computers with cutting edge web technologies. Our vision is to enable the same engaging gameplay and meaningful social experiences across all devic... Category: Other |
| 451 | [Goldray Industries Ltd.](https://www.casinovendors.com/vendor/goldray-industries-ltd/) Calgary, Alberta, Canada Goldray is a leading manufacturer and innovator for decorative glass. We have one of the most complete and modern manufacturing facilities for fabricated decorative glass in North America. Our reliance on outsourcing is very minimal, this gives us an advantage in controlli... Category: Glass Art, Exhibits |
| 452 | [Goldrush Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/goldrush-affiliates/) Category: Affiliate Programs |
| 453 | [Goldstein-Schwartz Inc.](https://www.casinovendors.com/vendor/goldstein-schwartz-inc/) Maryland Heights, Missouri We have worked with Naval Engineers designing Flexible Utility Systems for many new projects and have supplied numerous Casino Riverboats in Missouri, Illinois, Iowa, Mississippi, Indiana and Louisiana with various styles of Hose and Fittings for their Utility Systems handli... Category: Other |
| 454 | [Golf Resources Group](https://www.casinovendors.com/vendor/golf-resources-group/) Plano, Texas D.A. Weibring/GRI was formed in October, 1987 for the purpose of consulting on agronomic issues with golf course architects, owners, and operators. The formation of the company was achieved with the combined efforts of PGA Tour Professional D.A. Weibring and Dallas real est... Categories: Artificial Grass Surfaces, Other, Consulting |
| 455 | [Gollehon Books](https://www.casinovendors.com/vendor/gollehon-books/) Grand Rapids, Michigan Gollehon Books are among the top sellers in national bookstore chains and are perfectly suited for casino promotions, awards, give-aways, prizes and tournament gifts. Write, call, email, or fax for a free catalog! Category: Books |
| 456 | [Golpas Partners](https://www.igamingaffiliateprograms.com/affiliate-program/golpas-partners/) Category: Affiliate Programs |
| 457 | [Gomeeki](https://www.igamingsuppliers.com/vendor/gomeeki/) Lavender Bay, New South Wales, Australia Gomeeki, the mobile commerce company is committed in providing clients with high-quality Mobile application development services. Gomeekis operation is headquartered in Sydney Australia, with an additional service delivery & support team located in Bangkok, Thailand. ... Category: Mobile Gaming |
| 458 | [GOMO Mobile Technology Co., Ltd.](https://www.igamingsuppliers.com/vendor/gomo-mobile-technology-co-ltd/) Guangzhou, Guangdong, China GOMO Mobile Technology Co., Ltd. (hereinafter referred to as “GOMO”) was founded in 2003 with its headquarter located in Guangzhou. Riding on the opportunities in the era of Mobile Internet, GOMO has developed into the world leading mobile application developer and mobile ad... Category: Mobile Gaming |
| 459 | [Gondola Adventures®, Inc.](https://www.casinovendors.com/vendor/gondola-adventures-inc/) Henderson, Nevada Gondola Adventures®, Inc. is the largest purveyor of gondolas, gondola equipment, training, and operations in the United States. With three operations currently in Las Vegas, Dallas, and Newport Beach, California, and our boat fabricating arm, our staff has the most extensi... Category: Amusement Equipment |
| 460 | [GoneGambling](https://www.igamingsuppliers.com/vendor/gonegambling/) GoneGambling is a unique casino and gambling portal which has been specifically designed with the casino's interests in mind. Creative on-site incentives, as well as intense promotion for our sponsors, guarantee quality, consistent players and deposits. Our satisfied adver... Category: Consumer Portals |
| 461 | [GONG Gaming Technolgies](https://www.igamingsuppliers.com/vendor/gong-gaming-technolgies/) Category: Casino Software |
| 462 | [Gonzi & Associates, Advocates](https://www.casinovendors.com/vendor/gonzi-associates-advocates/) Fgura, Malta Categories: Other, Licensing and Regulation, Accounting, Licensing: Intellectual Property, Contract Management, Gaming Licensing, Compliance |
| 463 | [Good Day 4 Play Affiliate Program](https://www.igamingaffiliateprograms.com/affiliate-program/good-day-4-play-affiliate-program/) Category: Affiliate Programs |
| 464 | [Good Guy Productions](https://www.casinovendors.com/vendor/good-guy-productions/) Bloomingdale, New York We are a full service party planning event company that can render any style or theme imaginable. We do things in a tactful, yet fun, manner. We are also dealers of all casino products. We can sell them inexpensive because we buy them that way. We make our money on the p... Category: Casino Party Rental, Poker Chips |
| 465 | [Good Source Solutions](https://www.casinovendors.com/vendor/good-source-solutions/) Emmett, Idaho Category: Other |
| 466 | [GoodCore Software Ltd](https://www.casinovendors.com/vendor/goodcore-software-ltd/) Croydon, England, United Kingdom GoodCore is a software development company that designs, develops and supports bespoke software solutions and works with clients of various preferences, business needs, and organizational cultures. Category: Software Development |
| 467 | [GoodDep](https://www.igamingaffiliateprograms.com/affiliate-program/gooddep/) Saldus, Latvia GoodDep is an ultimate bridge between advertisers and publishers, specifically designed to empower gambling affiliates. Our dedicated support team is here to provide personalized assistance, analyzing your specific situation to ensure smooth operations and optimal result... Category: Affiliate Programs |
| 468 | [GoodFellas Gaming](https://www.casinovendors.com/vendor/goodfellas-gaming/) Birmingham, Alabama GoodFellas Gaming, located in Birmingham, AL, services the state of Alabama and the entire Southeast. Whether you're hosting a Corporate Party, Fundraiser, Reunion, Student Social or Private Affair, our commitment is to ensuring that your guests have a great time at your spe... Category: Casino Party Rental |
| 469 | [Goodwill Ship Management](https://www.casinovendors.com/vendor/goodwill-ship-management/) Chittagong, Chittagong bibhag, Bangladesh Goodwill Ship Management is one of the most trusted names in this region in the field of complete shipping solutions. Each company is focused on particular services. Category: Shipping |
| 470 | [Goodwyn Production Group](https://www.casinovendors.com/vendor/goodwyn-production-group/) Las Vegas, Nevada Goodwyn Production Group is a woman-owned, full service results-oriented video production company based in Las Vegas, Nevada. We understand that our job is to make our clients look their best. Goodwyn has 20 years of experience doing just that: creating award-winning prog... Category: Production |
| 471 | [Google Cloud](https://www.casinovendors.com/vendor/google-cloud/) Mountainview, Massachusetts Google Cloud is widely recognized as a global leader in delivering a secure, open, intelligent and transformative enterprise cloud platform. Our technology is built on Googles private network and is the product of nearly 20 years of innovation in security, network architect... Category: Computer Systems |
| 472 | [Goplay365 Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/goplay365-affiliates/) Category: Affiliate Programs |
| 473 | [GoProCasino Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/goprocasino-affiliates/) Category: Affiliate Programs |
| 474 | [Goral Partners](https://www.igamingaffiliateprograms.com/affiliate-program/goral-partners/) Goral Partners blends innovation and expertise to fuel every affiliate partnership, striving to pioneer digital solutions that redefine success. The company's mission is to empower affiliates with cutting-edge digital strategies. Category: Affiliate Programs |
| 475 | [GoRealTime](https://www.casinovendors.com/vendor/gorealtime/) St. George, Utah We have been providing the best in on-line, e-commerce enabled services since 1997. We provide fast, secure on-line credit card transactions for merchants, ISP's, shopping cart companies and anyone else doing business over the net. The GOrealtime Gateway is high capacity and... Category: Merchant Accounts |
| 476 | [Gorilla Gaming](https://www.casinovendors.com/vendor/gorilla-gaming/) Warwick, Rhode Island Gorilla Gaming is home to Legendary Gaming Tables, Custom Felts and Livestream Production. Located in Warwick, RI, Gorilla Gaming has become the industries go to suppler for the highest quality gaming tables. As the official table of the World Series of Poker, and the pr... Categories: Poker Tables, Synthetic Gaming Layouts, Poker Tables, Poker Tables, Poker Tables, Masks and Shields, Masks and Shields |
| 477 | [Gorilla Paper Inc](https://www.casinovendors.com/vendor/gorilla-paper-inc/) Elk Grove Village, Illinois Gorilla Paper offers same day shipping from IL and AZ warehouse, There is no minimum to purchase order online. No.1 source of Credit Card Thermal Receipt Paper Rolls, Cleaning Cards since 2009. Category: Bill Validator Cleaning Cards, ATM Products and Services |
| 478 | [Gorilla Playsets](https://www.casinovendors.com/vendor/gorilla-playsets/) Canton, Georgia Gorilla Playsets is the top manufacturer of swing sets and swing set accessories. Category: Amusement Equipment, Child Care Services |
| 479 | [Goslyn Grease Recovery Systems](https://www.casinovendors.com/vendor/goslyn-grease-recovery-systems/) Aurora, Ontario, Canada Goslyn is an automatic grease recovery device that is more efficient and cost-effective alternative to a traditional grease trap. The unique separation system continuously and permanently removes fats, oil and grease from waste effluent. There is no grease build up as is th... Category: Plumbing Products and Parts |
| 480 | [Goslyn West](https://www.casinovendors.com/vendor/goslyn-west/) Oakland, California Category: Restaurant Equipment |
| 481 | [GoTo Foods](https://www.casinovendors.com/vendor/goto-foods/) Atlanta, Georgia GoTo Foods, formerly Focus Brands, is the franchisor and operator of over 2,200 ice cream shoppes, bakeries, restaurants, and cafes in the United States, the District of Columbia, Puerto Rico, and 38 foreign countries under the brand names Carvel®, Cinnabon®, Schlotzskys®, ... Category: Other |
| 482 | [Gotta Have It Golf, Inc.](https://www.casinovendors.com/vendor/gotta-have-it-golf-inc/) Miami, Florida For 15 years Gotta Have It Golf has been the leader in supplying the memorabilia industry with the best Sports, Entertainment and Historical collectibles in the world. From our elegant and creative presentations to our handcrafted framework, and finally to our unique and dis... Category: Other |
| 483 | [Gourmet Display](https://www.casinovendors.com/vendor/gourmet-display/) Kent, Washington Category: Food Display, Other |
| 484 | [Gourmet Table Skirts and Linens](https://www.casinovendors.com/vendor/gourmet-table-skirts-and-linens/) Houston, Texas We manufacture and sell direct table linens, table skirting, conference cloths, along with many other table covering products. We are approved vendors for many buying organizations and have been in business over 25 years. We are very price competitive and known for the quali... Category: Linens |
| 485 | [GourmetGiftBaskets.com](https://www.casinovendors.com/vendor/gourmetgiftbaskets-com/) Kingston, New Hampshire GourmetGiftBaskets.com is an online retailer of award-winning, gourmet gifts. We design and build every gift by hand at our single location in Southern NH and truly consider our gifts to be works of art. With over 400 gifts to choose from, you can be certain that we have the... Category: Gift Merchandise |
| 486 | [Governance Associates](https://www.casinovendors.com/vendor/governance-associates/) Information security, AML/CFT, compliance, and governance consulting. Categories: Consulting, Security and Fraud, Regulatory Agency |
| 487 | [Gowell Group Technology Co., Ltd](https://www.casinovendors.com/vendor/gowell-group-technology-co-ltd/) Shenzhen, Guangdong, China Gowell group technology Co.,limited is a hi-tech enterprise specializing in developing, manufacturing and marketing CCTV products including Standalone DVR, DVR Kits, IP Camera, Analog Camera, etc., devoting ourselves to providing HD and intelligent IP surveillance systems at... Category: CCTV Systems |
| 488 | [Gowling WLG International Limited](https://www.igamingsuppliers.com/vendor/gowling-wlg-international-limited/) Toronto, Ontario, Canada Gowling WLG is an international law firm which represents a natural evolution for its founding firms - Gowlings and Wragge Lawrence Graham & Co. With roots tracing back to 1887, Gowlings has grown to become one of the largest and most respected law firms in Canada, with a re... Category: Licensing and Regulation |
| 489 | [GPE Vendors](https://www.casinovendors.com/vendor/gpe-vendors/) Fano, Italy GPE Vendors is a well-known and proven brand name in the European and International vending market. The wide selection of refrigerated and hot drinks vending machines has its main strengths in the excellent quality-price ratio, the reliability of the electronic parts and th... Category: Dispensers, Vending Machines |
| 490 | [GPO Display](https://www.casinovendors.com/vendor/gpo-display/) Livermore, California GPO Display offers a wide array of display solutions to meet your needs from video walls to 4K & 1080p commercial LCD monitors, interactive kiosks and touch-enabled display tables.The “GPO difference” is evident from the moment a project is conceived. We aid in preliminary d... Categories: Videowalls, Videowalls, Videowalls, Videowalls, Kiosks, Touchscreens, Touchscreens, Monitors, Monitors, Other |
| 491 | [GPS - Game Power System Co., Ltd.](https://www.casinovendors.com/vendor/gps-game-power-system-co-ltd/) New Taipei City, Taipei, Taiwan Established since 1979, Game Power System (GPS) is a video arcade game manufacturer and developer as well. We manufacture Video Game Machine, Video Arcade Machine, Vending Machine,LCD Gambling Machine, WHACK A MOLE, Touch Machine, Bar Game, Mario Game, Fruit (8 line) Games, ... Category: Slot Machines |
| 492 | [GR8 Tech](https://www.igamingsuppliers.com/vendor/gr8-tech/) Limassol, Lemesos, Cyprus GR8 Tech is the provider behind the Platform for Champions, delivering high-performance sportsbook and iGaming solutions for operators ready to lead and win in competitive markets. Categories: Gambling Operations, Platform Providers, Platform Providers, Affiliate Program Software |
| 493 | [Graciana Tortilla Factory](https://www.casinovendors.com/vendor/graciana-tortilla-factory/) Sylmar, California Graciana Tortilla Factory was establish in 1937, we serve all southern California and our major vendors include Sysco, MCI food, California State Prison, Navy, Army Base. Our prices are lower than any other manufacture in town and are guarantee. Category: Other |
| 494 | [GRAFIX Oncall, Inc.](https://www.casinovendors.com/vendor/grafix-oncall-inc/) Santa Rosa, California We help you separate your business from the competition! Grafix Oncall has 17+ years experience in providing top-notch real-world graphics. Count on us for your time sensitive projects and be assured deadlines will be met. We listen. We advise. We're there when you need us. ... Category: Graphic Design |
| 495 | [Graftek Systems](https://www.casinovendors.com/vendor/graftek-systems/) West Warwick, Rhode Island Graftek Systems is one of the leading providers of uniforms, promotional products, and printed documents in the Eastern United States. Recognized by their customers as a high quality provider with extremely attractive prices. An industry leading customer service team and unc... Categories: Uniforms, Specialties, Printers, Distributors |
| 496 | [Grainger](https://www.casinovendors.com/vendor/grainger/) Mobile, Alabama Grainger Industrial Supply has been America's leading distributor of Maintenance, Repair, & Operating supplies for over 75 years. We have maintained this status by offering our customers the very best brands at competitive prices with unmatched service after the sale. Our ne... Categories: Supplies, Other, Other, Batteries, Customer Service |
| 497 | [Grand Aire, Inc.](https://www.casinovendors.com/vendor/grand-aire-inc/) Swanton, Ohio Grand Aire is a premium Air Charter Management company, offering a wide variety of passenger and cargo charter aircraft throughout North America and beyond. Categories: Air Transportation, Other, Air Charter, Passenger |
| 498 | [Grand Betting Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/grand-betting-affiliates/) Category: Affiliate Programs |
| 499 | [Grand Canyon University](https://www.casinovendors.com/vendor/grand-canyon-university/) Phoenix, Arizona Grand Canyon University is a private Christian university located in Phoenix, Arizona. We are dedicated to helping our students change their lives for the better through education. We offer a wide range of programs at both the undergraduate and graduate levels that you can e... Category: Education |
| 500 | [Grand Club Partners](https://www.igamingaffiliateprograms.com/affiliate-program/grand-club-partners/) Category: Affiliate Programs |
| 501 | [Grand Korea Corp.](https://www.casinovendors.com/vendor/grand-korea-corp/) Seoul, Seoul Teugbyeolsi, South Korea Category: Management Systems |
| 502 | [Grand Parade Ltd](https://www.igamingsuppliers.com/vendor/grand-parade-ltd/) London, England, United Kingdom Grand Parade is an independently owned company founded by Andy Clerkson and Ed Needham - two pioneers of men's lifestyle publishing in the UK and USA. They edited and published mega-magazine brands such as Maxim, Rolling Stone, FHM and Stuff. They wanted to create engaging m... Categories: Other, Mobile Gaming, Social Media, Search Engine Optimization, Website Content |
| 503 | [Grand Prive Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/grand-prive-affiliates/) Category: Affiliate Programs |
| 504 | [Grand Prize Promotions](https://www.casinovendors.com/vendor/grand-prize-promotions/) Richardson, Texas With over 25 years of covering prize promotions, we have covered over 300,000 events throughout the world. Providing superior and exciting Prize programs for casinos, sporting events, odds contests and games of chance. We also provide weather promotions, weather insurance,... Categories: Insurance, Specialties, Driving Range Services, Production, Other, Planning, Consulting, Media Buying and Planning, Promotions, Promotions, Database Marketing, Promotions, Insurance: Jackpots, Promotions, Prizes, Public Relations and Publicity, Sales Building |
| 505 | [Grand Productions, Inc.](https://www.casinovendors.com/vendor/grand-productions-inc/) Naperville, Illinois Specialize in creating high-impact celebrity driven programs, promotions, and engaging interactive games that resonate with not just your existing gaming customers, but have proven drawing power to new customers in your local & mid-markets. Our programs utilize some of toda... Category: Promotions, Talent Buying |
| 506 | [Grand Products Incorporated](https://www.casinovendors.com/vendor/grand-products-incorporated/) Des Plaines, Illinois Grand Products Inc. is a full service contract assembler and manufacturer with complete turnkey operations from prototype engineering through production. Some of our capabilities include: wire harnesses, electromechanical assemblies, mechanical assemblies, cable assemblies a... Category: Slot Machines |
| 507 | [Grand Rapids Chair Company](https://www.casinovendors.com/vendor/grand-rapids-chair-company/) Grand Rapids, Michigan Grand Rapids Chair Co. prides itself on its unique designs. We offer customers fresh new looks that are appropriate for their specific installations. Each and every chair, barstool, and table that we manufacture reflects the pride of our craftsmanship and our quality. Pull... Categories: Furniture, Furniture Manufacturer, Other |
| 508 | [Grand Traverse Mobile Communications](https://www.casinovendors.com/vendor/grand-traverse-mobile-communications/) Traverse City, Michigan CASINO PROVEN SOLUTIONS We strive to create a more efficient, cost effective solution to problems our customers have. If their actual needs are simple, we provide a simple solution. If their needs are complex, we utilize the decades technical experience within our company t... Categories: Radios-2 Way, Radios-2 Way, Wireless Communication Systems, Monitoring |
| 509 | [Grand View Products, Inc.](https://www.casinovendors.com/vendor/grand-view-products-inc/) Miami, Florida Grandview products has been re-manufacturing and distributing casino gaming machines since 1991. Although our headquaters are located in Miami FL, we have state of the art facilities located globally which were designed to consistently deliver quality standards of reconditio... Categories: Slot Machines, Used, Slot Machines, Refurbished, Equipment, Equipment, Slot Machines, Video Devices (used), Progressive Jackpot Equipment, Repair, Slot Machines, Used |
| 510 | [Grand Vision Gaming, LLC](https://www.casinovendors.com/vendor/grand-vision-gaming-llc/) Billings, Montana Grand Vision Gaming (GVG) is a designer and manufacturer of Class III Video Gaming Machines. GVG boasts an engineering team responsible for revolutionary gaming products that employ state of the art technology, highly interactive and imaginary game themes, and proprietary ca... Category: Slot Machines |
| 511 | [GrandeAffiliates](https://www.igamingaffiliateprograms.com/affiliate-program/grandeaffiliates/) Category: Affiliate Programs |
| 512 | [Grandville Printing Company](https://www.casinovendors.com/vendor/grandville-printing-company/) Grandville, Michigan Grandville Printing Company is a family owned company located in the heart of Grandville, Michigan. We are commited to value in everything we do. Offering offest web printing, sheetfed, and HP Indigo digital variable data printing as our foundation, we believe in servicing e... Categories: Printers, Manufacturers, Player Tracking Cards, Large Format, Full Service Agency |
| 513 | [Grandwell Industries Inc.](https://www.casinovendors.com/vendor/grandwell-industries-inc/) Fuquay-Varina, North Carolina We have provided digital solutions to local, national, and international customers since 1989.Our customers achieve great results in both their digital marketing and advertising strategies. All of our tech support customers receive courteous, professional and thorough suppor... Category: LED Systems, LED Systems |
| 514 | [GrandX Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/grandx-affiliates/) Category: Affiliate Programs |
| 515 | [Granite Mountain Stone Design](https://www.casinovendors.com/vendor/granite-mountain-stone-design/) Fresno, California Granite Mountain Stone Design is under the umbrella of Cold Spring Granite. Cold Spring Granite has been in business for over 100 years and owns over 33 quarrys nation wide, that allows us the ability to not only provide custom granite countertops but to also provide specifi... Category: Other |
| 516 | [Grant Sound & Lighting Inc](https://www.casinovendors.com/vendor/grant-sound-lighting-inc/) Ventura, California Grant Sound & Lighting, formerly known as Luners has been in business for over 35 years and provides superior service along with over a hundred high quality lines of equipment to choose from. From lighting and Audio system design, through installation and on to maintenance a... Category: Audio Systems, Systems |
| 517 | [Grant Thornton LLP](https://www.casinovendors.com/vendor/grant-thornton-llp/) Reno, Nevada Grant Thornton is one of the world's largest and most dynamic accounting and management consulting organizations. Our goal is to help our clients grow faster by providing business services that deliver measurable value. Category: Accounting, Consulting |
| 518 | [Grape Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/grape-affiliates/) Category: Affiliate Programs |
| 519 | [Graphic Composition, Inc.](https://www.casinovendors.com/vendor/graphic-composition-inc/) Greenville, Wisconsin Graphic Composition has been servicing our clients for over sixty years. Offering an experienced design, production and distribution staff to provide full service to our customers, from concept to completion on their projects. We look for ways to spoil our customers by del... Categories: Direct Mail, Printers, Distributors |
| 520 | [Graphic Controls](https://www.casinovendors.com/vendor/graphic-controls/) Buffalo, New York Graphic Controls is the world's largest manufacturer of TITO Slot Machine Tickets. Our global operations combine the latest printing technologies with the expertise and service of more than 90 years. From shrink-wrap ticket packs and custom printing to local warehousing and ... Categories: Coinless Systems, TITO Tickets, Thermal Products, Promotional Tickets, Manufacturing, Player Tracking Systems, Receipt Paper Rolls |
| 521 | [Graphic Encounter Fine Art](https://www.casinovendors.com/vendor/graphic-encounter-fine-art/) Basalt, Colorado Graphic Encounter Fine Art provides art, mirrors, framing + professional fine art consulting services to prominent interior designers, architects, project managers and purchasing agents throughout North America, Europe and the Far East. Since 1970,our Single Source concept b... Categories: Art, Art, Mirrors, Art, Art |
| 522 | [Graphic House](https://www.casinovendors.com/vendor/graphic-house/) Wausau, Wisconsin Graphic House is the leading manufacturer and designer of custom signage in the Midwest. They offer superior custom design, fabrication, installation and service to national accounts as well as companies in the region. When you work with our dedicated sales staff, youll see... Category: Outdoor |
| 523 | [Graphic Impact](https://www.casinovendors.com/vendor/graphic-impact/) Tucson, Arizona One source for full color digital output, printed materials, mailings, large routed signs, posters, name tags, architectural signage and awards and plaques. Founded in 1989, locally owned. Largest supplier in Southern Arizona. Our website at www.graphic-impact.com includes p... Category: Large Format |
| 524 | [Graphic Interfaces, Inc.](https://www.casinovendors.com/vendor/graphic-interfaces-inc/) San Diego, California We are a custom label/tag/ticket producer that offers outstanding quality at very competitive prices. Our in-house graphics department can enhance the success of your promotion. Categories: Labels, Other, Promotions, Printed Materials |
| 525 | [Graphic Solutions](https://www.casinovendors.com/vendor/graphic-solutions/) Greenwood, Indiana We handle several types of graphic and sign projects that you would have a need for. Whether it be event signage, outdoor, vinyl banners, billboards, displays, bannerstands and more. From paper, photographic, backlit, PSV, vinyl, mesh, perforated window clings, fabric and ma... Category: Digital Output |
| 526 | [Graphics International](https://www.casinovendors.com/vendor/graphics-international/) Van Nuys, California Graphics International has been a leading Designer and Manufacturer of Framed Art products such as framed posters, mirrors and wall decors for the hospitality industry for the past 28 years. Category: Mirrors |
| 527 | [Graphite Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/graphite-affiliates/) Category: Affiliate Programs |
| 528 | [GraphoNET Ltd](https://www.casinovendors.com/vendor/graphonet-ltd/) Category: E-commerce |
| 529 | [Gravure Alain Robitaille](https://www.casinovendors.com/vendor/gravure-alain-robitaille/) Portneuf, Quebec, Canada Our company made signage for hotel since 1991. We are located in Québec city in Canada. When we make signage, we make it for you and exactly as you want it. We can give suggest to raise the quality, lifetime and restore capacity of your signage. When we work for you, we work... Categories: Interior, Engraved Signs Manufacturer, Bronze, Metal Finishing, Architectural Signage and Graphics |
| 530 | [Graybar](https://www.casinovendors.com/vendor/graybar/) City of Industry, California Graybar, a Fortune 500 company, is a specialist in supply chain management services and the leading North American distributor of high-quality components, equipment and materials for the electrical and telecommunications industries.With more than $5 billion in revenue (2006)... Category: Supplies |
| 531 | [Grazgame](https://www.igamingsuppliers.com/vendor/grazgame/) Yerevan, Erevan, Armenia Category: Live Dealer |
| 532 | [Great American Insurance Company](https://www.casinovendors.com/vendor/great-american-insurance-company/) Windsor, Connecticut Great Americans Fidelity/Crime Division provides insurance to cover losses caused by Employee Dishonesty, Forgery, Theft, Robbery, Computer Fraud and Kidnap, Ransom and Extortion. One of our specialty areas is the casino industry. The gaming industry has an enormous turnove... Category: Insurance |
| 533 | [Great American Recreation Equipment, Inc.](https://www.casinovendors.com/vendor/great-american-recreation-equipment-inc/) Cranston, Rhode Island There are many reasons why Great American is your best choice when it comes to coin-operated or non coin-operated commercial tables. We have a commitment to quality that stretches back over 10 years. We are family owned, operated and made in the USA. Our products have a du... Category: Amusement Equipment |
| 534 | [Great Creativity Smart Card,Co. Ltd](https://www.casinovendors.com/vendor/great-creativity-smart-card-co-ltd/) Shenzhen, China Established in 1999, Shenzhen Chuangxin jia smart card co., Ltd was specialized in producing and marketing of pvc card and smart card. Category: Plastic Card Manufacturer |
| 535 | [Great Lakes Amusement](https://www.casinovendors.com/vendor/great-lakes-amusement/) Green Bay, Wisconsin Great Lakes Amusement is a leading distributor in gaming systems and supplies. We are committed to providing superior quality products, rapid delivery, and outstanding technical support. Our website www.glastore.com is a trusted marketplace that offers customers thousands of... Categories: Accessories, Electronic Games, New Game Manufacturer, Multi-player Games |
| 536 | [Great Lakes Scenic Studios](https://www.casinovendors.com/vendor/great-lakes-scenic-studios/) Burlington, Ontario, Canada At Great Lakes Scenic Studios' 30,000 square foot facility, located within a day's drive of more than a dozen major east-coast cities, our team of creative craftspeople, technical experts, installers, artisans and tradespeople have earned a reputation for building complex an... Categories: Theming, Other, Theming, Fabrication, Decorative Painting, Millwork |
| 537 | [Great Live Games](https://www.igamingsuppliers.com/vendor/great-live-games/) London, England, United Kingdom GreatLiveGames offers a “Real Time” multiplayer skill games software platform and has developed a scalable and secure infrastructure for online casual game communities. Our unique platform and exclusive skill games portfolio has over 21 exclusive games of skill. The platform... Category: Mahjong Software, Skill Games Software |
| 538 | [Greater Pacific Industries](https://www.casinovendors.com/vendor/greater-pacific-industries/) Bellevue, Washington Greater Pacific is a direct manufacturer of custom OEM product. Internal product safety and compliance program ensures safe and compliant product. Wide range of product categories including drink ware, bags, head wear, custom metal and plastic gifts and accessories. Proven t... Category: Promotional Items, Promotions |
| 539 | [Greater Southern Home Recreation](https://www.casinovendors.com/vendor/greater-southern-home-recreation/) Smyrna, Georgia Here at Greater Southern Home Recreation, we pride ourselves on being the one place in Georgia that has it all. With the best customer service in the industry and the most knowledgeable sales staff, we will be sure to make your experience with us the most enjoyable. Please... Category: Other |
| 540 | [GreatMenuCovers.com](https://www.casinovendors.com/vendor/greatmenucovers-com/) Milwaukee, Wisconsin GreatMenuCovers.com makes high-quality long-lasting cafe menu covers that are available in 16 standard colors to match decor and theme branding designs. Made in the USA with credit terms available for large purchases. Custom sizes and design requests welcome. Free samples av... Category: Trade Shows and Conferences, Menu Covers |
| 541 | [Grecian Delight Foods](https://www.casinovendors.com/vendor/grecian-delight-foods/) Elk Grove Village, Illinois Grecian Delight Foods, A Pure Mediterranean Foods Company, is located in Elk Grove Village, IL. The company was founded in 1974 by Peter Parthenis, Sr., and is still family held and operated by the Parthenis family. Grecian Delight is a manufacturer and marketer of top qu... Category: Other |
| 542 | [Green Chiropractic](https://www.casinovendors.com/vendor/green-chiropractic/) Omaha, Nebraska Created in 2005, Green Chiropractic offers pain relief for low back pain, headaches, sciatica, tingling fingers. We also offer scoliotic remodeling, sports injuries pain relief, acupuncture and personal training. We are located at 184th and West Center in front of LOWE'S. Category: Health Care Services |
| 543 | [Green Choice Vendors Distribution LLC](https://www.casinovendors.com/vendor/green-choice-vendors-distribution-llc/) New York, New York Green Choice Vendors is a full service distributor of environmentally safe alternative food service products, bags and treeless paper products. We offer a wide range of biodegradable and compostable products made from renewable resources. We provide clients the convenience... Categories: Disposable Tableware, Promotions, Supplies, Supplies, Other |
| 544 | [Green Coin Machines, Inc.](https://www.casinovendors.com/vendor/green-coin-machines-inc/) Myrtle Beach, South Carolina Green Coin Machines Distributing has been in business for 46 years and is one of the leading distributors for home game room equipment East of the Mississippi. We sell pinballs, arcade videos, pool tables, jukeboxes, and much much more! We deliver to your door, NATIONWIDE. Category: Other |
| 545 | [Green Dragon (GD88)](https://www.igamingsuppliers.com/vendor/green-dragon-gd88/) Koh Thom District, Kandaal, Cambodia Category: Live Dealer |
| 546 | [Green Edge Systems Inc](https://www.casinovendors.com/vendor/green-edge-systems-inc/) Woodland Hills, California Leader in Signage, Hand Sanitizer Stands, Sneeze Guards, Crowd Control Social Distancing stanchions, Casino and waiting room Separation Shields Guard germ shields and separation wall shields for Casinos, Hospitals, Colleges and Universities and Schools. Categories: Masks and Shields, Masks and Shields, Hand Sanitizer, Theming, Surveys, Disinfection Equipment, Indoor Signage, Indoor Signage |
| 547 | [Green Energy Lighting Corporation](https://www.casinovendors.com/vendor/green-energy-lighting-corporation/) Cerritos, California Green Energy Lighting supplies the latest in energy efficient Lighting including: LED , Compact Fluorescent, Metal Halide, Halogen,and Miniature light bulbs. Category: Supplies |
| 548 | [Green Floral Crafts](https://www.casinovendors.com/vendor/green-floral-crafts/) San Jose, California We specialize in decorative accents made from natural and renewal resource materials. We sell one-of-a-kind real preserved/dried non-perishable florals that can be paired up with our bamboo and mango wood vases, which are light for easy transport, but large for stunning beau... Category: Interior Design |
| 549 | [Green Light Booking](https://www.casinovendors.com/vendor/green-light-booking/) Pleasant Grove, Utah Green Light Booking is a premier event entertainment company that works with many world-class entertainers and live bands, allowing individuals and event planning professionals to hire entertainment that wows crowds. We make it fun to find and book high quality corporate ent... Category: Production |
| 550 | [Green Squared](https://www.casinovendors.com/vendor/green-squared/) Meridian, Idaho At Green Squared, our purpose is to have a positive impact on our environment and to improve local communities through e-waste recycling fundraiser programs that uphold the highest quality environmental standards; all while making the world a better place. We provide free 91... Category: Waste Management |
| 551 | [Green Star Coffee - Santa Barbara Coffee LLC](https://www.casinovendors.com/vendor/green-star-coffee-santa-barbara-coffee-llc/) Santa Barbara, California Green Star Coffee sources only the finest, most intriguing coffees from the premier growing regions around the world. We offer 100% Certified Organic Fair Trade coffee, purchasing beans from villages and importers that are committed to fair trade and working towards better e... Category: Coffee |
| 552 | [Green Suites International](https://www.casinovendors.com/vendor/green-suites-international/) Upland, California Green Suites® International is the leading supplier of environmental products & programs to the lodging & hospitality industry. We've been "greening" hotels, resorts and casinos since 1993. We specialize in providing profitable solutions with environmental benefits. Call ... Category: Equipment, Amenities |
| 553 | [Green Trading, USA](https://www.casinovendors.com/vendor/green-trading-usa/) Chino, California Do your Bears Snore and Giggle? Ours do. We also feature wonderful Bear, Moose, Wolf, Buffalo, and all Wildlife Hats. Will fit from Children to Adults. Dozens of Plush Animal in all sizes. Prices starting at $2.50 each. No Min. Perfect for Casino Gifts and School Fund Raisin... Category: Plush Toys |
| 554 | [Greenberg Traurig](https://www.casinovendors.com/vendor/greenberg-traurig/) Miami, Florida Greenberg Traurigs global Gaming Practice advises clients on matters that a company operating in the gaming industry may face, including licensing, compliance, employment, real estate, intellectual property, litigation, corporate transactions, anti-money laundering regulati... Category: Other |
| 555 | [Greencorner USA](https://www.casinovendors.com/vendor/greencorner-usa/) Orlando, Florida In 1998, The Greencorner USA was established to manufacture Mediterranean umbrellas based on the 15 year experience of sister company Le Coinvert in Europe. Research of the American market had found that there was a need for extra large, heavy duty umbrellas with new square ... Category: Furniture, Outdoor |
| 556 | [Greene Forensic Accounting Solutions LLP](https://www.casinovendors.com/vendor/greene-forensic-accounting-solutions-llp/) Las Vegas, Nevada Greene Forensic Accounting Solutions LLP is a Certified Public Accounting and Consulting Firm providing professional services to the gaming industry. The firm provides financial investigation services, litigation support, internal audit, employer healthcare audits, employee... Category: Accounting, Auditing |
| 557 | [Greenfire Minerals](https://www.casinovendors.com/vendor/greenfire-minerals/) Lisbon, Portugal Greenfire Minerals is the leading & original manufacturer of luxury hospitality materiaals like semi precious stone on glass and ceramic,seashell tiles,coconut in resin,pebbles in resin and many other exotic stone tiles and slabs. Category: Architectural Design |
| 558 | [Greenheart Exchange](https://www.casinovendors.com/vendor/greenheart-exchange/) Chicago, Illinois Category: Temporary Personnel: Management and Financial |
| 559 | [Greenlight](https://www.igamingsuppliers.com/vendor/greenlight/) London, England, United Kingdom Category: Search Engine Optimization |
| 560 | [Greensleeves, Inc](https://www.casinovendors.com/vendor/greensleeves-inc/) Miami, Florida Since 1985, Greensleeves has installed and maintained extraordinary interior and exterior landscapes through Design, working in Europe, South America, Caribbean and the United States. Our purpose is to assist our clients to achieve their expectations in budget. Call today fo... Category: Interior Landscaping |
| 561 | [Greentube I.E.S. AG](https://www.igamingsuppliers.com/vendor/greentube-i-e-s-ag/) Vienna, Wien, Austria Greentube offers ready-to-use Skill Gaming solutions for the internet, mobile devices and iTV. Their white label solution generates gaming portals that fit the client's desired look and feel. As a developer of multiplayer games, Greentube's service offers multi-channel, mul... Categories: Backgammon Software, Skill Games Software, Poker Software |
| 562 | [Greenway Print Solutions](https://www.casinovendors.com/vendor/greenway-print-solutions/) Scottsdale, Arizona Greenway Print Solutions can print everything from simple brochures to full color annual reports, and everything in between. We manage every aspect of each project to produce the best end result in the fastest possible time, at the lowest possible price. We serve over 2,000... Categories: Tickets, Promotional Items, Promotions, Printed Materials, Newsletters, Direct Mail, Printers, Manufacturers, In-room Access |
| 563 | [Greenwell Chisholm Printing Company](https://www.casinovendors.com/vendor/greenwell-chisholm-printing-company/) Owensboro, Kentucky Greenwell Chisholm has been in business for over 85 years and our customer service and quality are superb. Greenwell Chisholm Printing Company will not accept a job unless we are sure we can meet the customers deadline. We would be happy to offer references if needed and sam... Categories: Printers, Manufacturers, Direct Mail, Promotions, Printed Materials |
| 564 | [Greenwich Technologies, Inc.](https://www.casinovendors.com/vendor/greenwich-technologies-inc/) Grosse Pointe, Michigan At Greenwich Technologies, our primary goal and main reason for our continued success is customer satisfaction. From casino hotels, to country clubs, to corporations around the world - our customers are our largest asset. As a Microsoft Certified Partner, Greenwich solution... Categories: Systems, Software, Systems, Software |
| 565 | [Greg Thompson Productions](https://www.casinovendors.com/vendor/greg-thompson-productions/) Seattle, Washington Greg Thompson Productions, the largest producer of casino musical revues in the world, has produced award-winning productions for Caesars, Casino Monte Carlo, Grand Casinos, Harrahs, Isle of Capri, Mirage, Sands, Trump, Microsoft, IBM, Boeing and many regional Indian Gaming ... Category: Music Production |
| 566 | [Gregory Friedlander & Assts.](https://www.casinovendors.com/vendor/gregory-friedlander-assts/) Mobile, Alabama Gregory M. Friedlander & Assts, P.C., www.gmfpc.com specializes in obtaining intellectual property protection and providing marketing assistance for clients. We provide information and services related to invention, innovation, new business startup and incorporating new tec... Category: Patent Attorney |
| 567 | [Gregory Gove Art](https://www.casinovendors.com/vendor/gregory-gove-art/) Chicago, Illinois Not an Art factory like most mural companies. You work directly with individual doing the work. Good communication. Easy to deal with. Distinguished client list. Centrally located, and will travel. Category: Art |
| 568 | [Gregory Signs](https://www.casinovendors.com/vendor/gregory-signs/) Toronto, Ontario, Canada Gregory Signs has been providing a variety of signage since 1981. Our educational staff have been trained in many fields like engineering, architecture and designing. Gregory Signs is a custom manufacturer so we build to your needs or we can even design you sign. When you... Categories: Exterior, Illuminated, Exterior, Design, Illuminated, Indoor, Exterior, Non-illuminated |
| 569 | [Gregory, Inc.](https://www.casinovendors.com/vendor/gregory-inc/) Buhler, Kansas Gregory is both a wholesale graphics manufacturer and an international distributor of sign materials and supplies. As a distributor we represent 3M, Oracal, Arlon, Sihl, SignGold, R-Tape and Transfer Rite to name a few. We can supply your casino sign shop with many of the co... Categories: Digital Output, Exterior, Interior, Banners, Digital Printing, Digital Graphics, Labels, Large Format, Screen Printing, Wallcoverings, Murals, Graphics, Windows, Signage, Banners, Visual Communications |
| 570 | [Gremillion and Pou Integrated Marketing](https://www.casinovendors.com/vendor/gremillion-and-pou-integrated-marketing/) Shreveport, Louisiana In the ever-changing and competitive realm of casino marketing, Gremillion and Pou Marketing understands the need to be available and aware 24/7. Our casino marketing team consists of former casino employees and directors, marketing specialists, strategic analysts and ga... Category: Full Service Agency, Consulting |
| 571 | [Grenald Waldron Associates](https://www.casinovendors.com/vendor/grenald-waldron-associates/) Narberth, Pennsylvania We provide quality lighting solutions to people who understand and appreciate the value of good lighting. At Grenald Waldron Associates, by integrating the fields of architecture, lighting design, and psychology, we are able to tailor our approach to each project, always se... Category: Consulting |
| 572 | [Greneker](https://www.casinovendors.com/vendor/greneker/) Los Angeles, California Greneker Solutions designs and manufactures Visual Merchandising and Thematic products. Visual merchandising products include forms and mannequins, specialized fixtures, and product display components. Theming products include custom theme fixturing, architectural displays... Category: Fabrication |
| 573 | [Gretna Bingo Palace](https://www.casinovendors.com/vendor/gretna-bingo-palace/) Gretna, Louisiana We offer 27 sessions weekly and all games are played as scheduled. The organizations served by the hall are: David Crockett Fire Company, German American Cultural Center, Westbank Rotary Club, Gretna Economic Development, Gretna Historical Society, Gretna Police Benevolent S... Category: Other |
| 574 | [Greyhound Lines, Inc.](https://www.casinovendors.com/vendor/greyhound-lines-inc/) New York, New York Greyhound “Lucky Streak” service offers coast to-coast schedules directly to casinos in Atlantic City, NJ; Las Vegas, Reno and Lake Tahoe. There is also service to the Native American casinos at Foxwoods in Ledyard, CT. Hotard, a wholly-owned Greyhound company, operates ser... Category: Other |
| 575 | [Greystone Energy Systems](https://www.casinovendors.com/vendor/greystone-energy-systems/) Somerset, Pennsylvania Manufacturer of HVAC Sensors and Instruments CO Monitors, CO2 Monitors, Humidity and Temperature Sensors Wall mount space sensors and HVAC duct mounted sensors for building automation systems. Category: Energy Management Systems |
| 576 | [GRG Banking Equipment Co Ltd](https://www.casinovendors.com/vendor/grg-banking-equipment-co-ltd/) Guangzhou, China GRGBanking is a leading provider of currency recognition and cash processing solutions in the global market with great potential and rapid development. We specialize in the development & manufacturing of Automatic Teller Machine (ATM) for financial institutions and retailers... Category: Bill Validators |
| 577 | [Griffin Investigations, Inc.](https://www.casinovendors.com/vendor/griffin-investigations-inc/) Las Vegas, Nevada Griffin Investigations, Inc. is the premiere trusted leader in the field of Gaming Investigation. We have been identifying advantage players, cheaters and casino criminals successfully since 1967. Our GOLD Database is an effective and affordable solution in helping you prote... Category: Information |
| 578 | [Griffin Valuation Group](https://www.casinovendors.com/vendor/griffin-valuation-group/) Chicago, Illinois Griffin Valuation Group provides Cost Segregation & Property Tax consulting to commercial and industrial property owners nationwide which provides substantial increases in cash flow and shareholder value. We provide Big-4 tax accounting experience and quality without the bi... Category: Accounting |
| 579 | [Griner Engineering, Inc.](https://www.casinovendors.com/vendor/griner-engineering-inc/) Bloomington, Indiana We do high-volume rotary transfer machining on turned parts.We do high-volume screw machining with secondary.We do some production CNC machining center work using 4 vertical and horizontal machining centers purchased this year.We have a new 6'x12'Flow water-jet which we want... Category: Engineering, Mechanical |
| 580 | [GRIPS USA](https://www.casinovendors.com/vendor/grips-usa/) La Jolla, California The GRIPS Display is the most accurate and reliable Reader Board on the market. We introduced the Roulette Display into the USA in 1990, and have since added Baccarat Displays and BJ Displays to our portfolio. For Roulette, our Optical Reader automatically detects the winnin... Categories: Equipment, Electronic Signs, Electronic Signs, Electronic Signs |
| 581 | [Grommes-Precision](https://www.casinovendors.com/vendor/grommes-precision/) Gurnee, Illinois Made in the U.S.A. commercial audio equipment. Including 70 volt amplifiers, microphone mixer, Hi-Fi Tube Gear, and custom audio electronics. A service oriented company with immediate answers to your questions...No voice mail system tio get lost in. Category: Parts |
| 582 | [Groove Leather](https://www.casinovendors.com/vendor/groove-leather/) Montvale, New Jersey Category: Other |
| 583 | [Groove Technologies](https://www.igamingsuppliers.com/vendor/groove-technologies/) Sliema, Malta Groove was founded in 2016 by a group of professionals who all had the dream of creating an exclusive service so entrepreneurs could meet the growing gaming needs of the world. Collectively we have over 150 years of experience in all aspects of online business and e-commerce... Categories: Casino Software, Mobile Gaming, Bingo Software, Lottery Software, Sportsbook Software, Gambling Operations |
| 584 | [Group III International, Inc.](https://www.casinovendors.com/vendor/group-iii-international-inc/) Pompano Beach, Florida Group III International, based in Pompano Beach, FL. Company founded 1982. Sales over $120 million per year. Offices in USA, China, Taiwan and Thailand. Category: Medical Gloves, Medical Gloves |
| 585 | [Group One Media](https://www.casinovendors.com/vendor/group-one-media/) Yuen Long, Hong Kong Group One Media is a dynamic internet marketing company operating numerous websites across a wide portfolio of niches in a vast array of countries. Our core business is email marketing to our members on a performance basis, clients only pay on results! Every month we drive t... Category: Internet |
| 586 | [Group West Companies PLLC](https://www.casinovendors.com/vendor/group-west-companies-pllc/) Seattle, Washington Group West Companies offers comprehensive services in architectural/interior design and development strategies with a major focus on gaming and hospitality. Category: Architectural Design, Interior Design |
| 587 | [Groupartners](https://www.igamingaffiliateprograms.com/affiliate-program/groupartners/) Category: Affiliate Programs |
| 588 | [Groupe Lucien Barriere (GLB)](https://www.casinovendors.com/vendor/groupe-lucien-barriere-glb/) Paris, France Created in 1912 by François André, Barrière has perfectly illustrated the prestige of French luxury and expertise for more than a century. Shaped by three generations of passionate, visionary entrepreneurs, today it serves as a shining example of French luxury hospitality an... Category: Other |
| 589 | [Grover Gaming, Inc.](https://www.casinovendors.com/vendor/grover-gaming-inc/) Greenville, North Carolina Grover Gaming has extensive experience in developing Video Slot and Casino Game Content and is now licensing their premium games for a variety of gaming markets including social and real money gaming. Lottery Solutions Online Lottery Gaming System Video Slot Game Desig... Categories: Mobile Gaming, Lottery Software, Game Design, Software, Class II Tabs-video Devices, Video Game Software, Casino Software, Bingo Software, Pull-tab Equipment, New Game Manufacturer, Skill Games Software, Electronic Systems, Lottery Software, Other |
| 590 | [Growe Partners](https://www.igamingaffiliateprograms.com/affiliate-program/growe-partners/) Category: Affiliate Programs |
| 591 | [GRS Global Recruitment Solutions Ltd](https://www.igamingsuppliers.com/vendor/grs-global-recruitment-solutions-ltd/) Limassol, Lemesos, Cyprus GRS is a specialist international recruitment consultancy based in Cyprus, the gateway to Europe and Middle East. We offer recruitment and managed recruitment services for clients and candidates across Cyprus and internationally. The GRS culture is underpinned by a basic ... Category: Recruitment |
| 592 | [Gruber Industries](https://www.casinovendors.com/vendor/gruber-industries/) Phoenix, Arizona Category: Fiber Optics Products |
| 593 | [Gruppo Extraball](https://www.casinovendors.com/vendor/gruppo-extraball/) San Cesareo, Lazio, Italy The Group Extraball is today one of the largest in central Italy in the rental of automatic equipment for entertainment such as: New Slot Machines, Video Lotteries, vending gadgets, mobiles, and much more, at public establishments such as bars, amusement arcades and betting,... Category: Vending Machines |
| 594 | [Gryndstone and Fusspot Press](https://www.casinovendors.com/vendor/gryndstone-and-fusspot-press/) North Vancouver, British Columbia, Canada Cartoonist Graham Harrop's gentle satires have been making people chuckle about politics, celebrity culture and other strange animals for more than 2 decades. His cartoon collections are lively and never unkind, and offer a lighter side to contemporary life. Graham also cr... Category: Books |
| 595 | [Gryphon, Inc.](https://www.casinovendors.com/vendor/gryphon-inc/) Buffalo Grove, Illinois Since 1985, Gryphon has been a distributor for ONEAC-POWERVAR. Gryphon provides its customers worldwide with the best power and environmental protection solutions for their sensitive microprocessor-based electronic equipment. POWERVAR manufactures premium-grade power prote... Category: Batteries |
| 596 | [GS Plastic Optics](https://www.casinovendors.com/vendor/gs-plastic-optics/) Rochester, New York G&H | GS Optics dates back to a small machine shop - located in Rochester, NY and founded in 1916. The business quickly grew to become a major supplier of replacement watch crystals made of plastic. Today, G&H | GS Optics specializes in the custom design and manufacture o... Category: LED Systems |
| 597 | [GSH Casino Parties](https://www.casinovendors.com/vendor/gsh-casino-parties/) Des Plaines, Illinois After working in the casino party industry for more than 5 years, the partners at The GSH Group knew it was time for a change. They recognized that better organized, more enthusiastic, and more fun events were needed. The GSH Group officially opened its doors to provide Casi... Categories: Equipment, Party Rental, Slot Machines, Blackjack Tables, Equipment, Accessories |
| 598 | [GSH Online Media](https://www.igamingaffiliateprograms.com/affiliate-program/gsh-online-media/) Bucuresti, Romania GSH Online Media is a high-quality online lead generation company within the iGaming industry, targeting Casino and Sportsbook players from multiple GEOs. Websites owned by GSH are representing authority in the industry. For example, BetBrain it the first and the best odds c... Category: Affiliate Programs |
| 599 | [GSN - Game Show Network LLC](https://www.igamingsuppliers.com/vendor/gsn-game-show-network-llc/) GSN is a multimedia entertainment company that offers original and classic game programming and competitive entertainment via its 80-million subscriber television network and online game sites. GSNs cross-platform content gives game lovers the opportunity to win cash and pr... Categories: Casino Software, Bingo Software, Skill Games Software |
| 600 | [GSP Systems, Inc.](https://www.casinovendors.com/vendor/gsp-systems-inc/) Bucheon City, Gyeonggido, South Korea Category: Other |
| 601 | [GSpin Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gspin-partners/) Category: Affiliate Programs |
| 602 | [GT Advertising, LLC](https://www.casinovendors.com/vendor/gt-advertising-llc/) Las Vegas, Nevada GT Advertising is a major provider of email appends for the casino hotel industry in both commercial and Native gaming and hospitality. Category: Internet, Internet |
| 603 | [GT Holdings (GamyTech)](https://www.igamingsuppliers.com/vendor/gt-holdings-gamytech/) Ta' Xbiex, Malta Gamytech develops and manages software platforms aimed for the iGaming industry. We deliver a holistic white labelled solution, which is scalable, consistent and enables real time gaming. We are a team of experts equipped with extensive knowledge and experience in the gaming... Categories: Backgammon Software, Skill Games Software, Mobile Gaming, Casino Software, Mobile Gaming, Affiliate Program Software, Mobile Gaming, Mobile Gaming, Gambling Operations |
| 604 | [GTE Localize](https://www.igamingsuppliers.com/vendor/gte-localize/) Singapore, Singapore GTE Localize is a fast-growing global translation and localization agency, providing services for all major languages in the world. Our solutions include translation, localization, interpretation, subtitling and transcription. Our experience has been solidly gathered by our ... Category: Translation Services |
| 605 | [GTG Advocates](https://www.igamingsuppliers.com/vendor/gtg-advocates/) Valletta, Malta GTG advocates is a full-service corporate and commercial firm spanning a diverse array of disciplines and distinguished by its unsurpassed expertise in shipping, financial services, information technology and i-gaming. At GTG, we have one compelling mission: to deliver value... Category: Licensing and Regulation, Consulting |
| 606 | [GTi Freight](https://www.casinovendors.com/vendor/gti-freight/) Coral Springs, Florida GTi Freight is a privately held, US based logistics company specializing in freight management services including LTL, Full Truckload, Supply Chain Management, and Domestic Air/Expedited shipping. We focus on innovative technology and partnering with sales professionals that... Categories: Shipping, Expediting Services, Equipment Trailers, Other, Trucking |
| 607 | [GTI GAMING SRL DBA as GTI - Giochi Tecnologici Italiani](https://www.casinovendors.com/vendor/gti-gaming-srl-dba-as-gti-giochi-tecnologici-italiani/) Milano, Lombardia, Italy GTI is the new leading Casino Currency manufacturer and (RFID) Casino Currency Inventory, Management and Security systems and products manufacturer and developer. GTI is a technology product and system provider for casino. We produce electronic chips, jetons and plaques and... Category: Chips, Chips |
| 608 | [GTreasury](https://www.casinovendors.com/vendor/gtreasury/) Lake Zurich, Illinois Founded in 1986, GTreasury has become a leading global provider of treasury management systems. The company offers a full suite of solutions, including cash management, funds transfers, accounting and more! Check out their website today for more information. Category: Accounting Systems |
| 609 | [GTSource, Inc.](https://www.casinovendors.com/vendor/gtsource-inc/) Kennesaw, Georgia GTSource offers complete turnkey Class-II/III gaming solutions including cabinet and cabinet design. GTSource compliments the cabinets with their LogixCube gaming specific computer platform, I/O Suite Hardware and game harness assemblies. GTSource also offers game refurbishm... Category: Slot Machines |
| 610 | [GTSS Minds](https://www.casinovendors.com/vendor/gtss-minds-1/) Hamilton, New Jersey Our vision is our framework within which our employees work. Our vision statement guides us through every endeavor and helps achieve sustainable growth for every person involved with GTSS. Category: Consulting |
| 611 | [GTT Co., Ltd.](https://www.casinovendors.com/vendor/gtt-co-ltd/) Goyang-shi, Gyeonggido, South Korea Rugged LCD Monitors Category: LCD |
| 612 | [GTT Communications, Inc.](https://www.casinovendors.com/vendor/gtt-communications-inc/) McLean, Virginia GTT connects people across organizations, around the world and to every application in the cloud. GTT owns and operates a global Tier 1 internet network and provides a comprehensive suite of cloud networking services. Category: Systems Integration Services, Network Services |
| 613 | [Guangdong Phoenix Lighting Co., Ltd.](https://www.casinovendors.com/vendor/guangdong-phoenix-lighting-co-ltd/) Guangzhou, Guangdong, China Guangdong Phoenix Lighting Co., Ltd., founded in 2002, manufactures a wide range of professional stage products, including Moving Head Light, Scanner Light,Follow Spot Light,Lighting Controller,Laser Light, LED light, Strobe Light, outdoor Light, Fog machine,Bubble Machine,S... Category: Effects |
| 614 | [Guangxi Pinglu Group Co., Ltd.](https://www.casinovendors.com/vendor/guangxi-pinglu-group-co-ltd/) Nanning, Guangxi, China Guangxi Pinglu Group Co., Ltd. is a comprehensive large-scale enterprise specializes in aluminum, curtainwall, wire and cable industry development, manufacturing and product development, as well as real estate, hotel, import and export business. Category: Materials |
| 615 | [Guangzhou 3Hz Solar Technology Co.,Ltd](https://www.casinovendors.com/vendor/guangzhou-3hz-solar-technology-co-ltd/) Guangzhou, China Guangzhou 3Hz Solar Technology Co.,Ltd is a leading PV product manufacturer and system integration service provider. We aim at providing customers with the design, manufacture, installation & maintenance service of individualized, professionalized and systematized PV applica... Category: Other |
| 616 | [Guangzhou Aolait Lighting Co.,Ltd](https://www.casinovendors.com/vendor/guangzhou-aolait-lighting-co-ltd/) Guangzhou, Guizhou, China Guangzhou Aolait Lighting Co.,Ltd is a professional stage lighting enterprise with integration of Research and development, production, sales and service. Main products range from intelligent moving head light series, led lighting series and accessories for stage equipment. ... Category: Manufacturer |
| 617 | [Guangzhou Blossom Stage Lighting Equipment Co., Ltd](https://www.casinovendors.com/vendor/guangzhou-blossom-stage-lighting-equipment-co-ltd/) Guangzhou, Guangdong, China Guangzhou Blossom stage lighting factory ,established in 2003, is a factory of lighting reproducing apparatus, specialized in R & D and manufacture & sale. Over the years, it continues to provide lighting and sound with high-quality, professional technology and great support... Category: Manufacturer |
| 618 | [Guangzhou Creative Stage Equipment Factory](https://www.casinovendors.com/vendor/guangzhou-creative-stage-equipment-factory/) Guangzhou, Guangdong, China Guangzhou Creative Stage Equipment Co.,Ltd. is the manufacturer in Guangzhou,CHINA, we are professional on designing ,manufacturing and marketing various high quality professional performance equipments , including all kinds of aluminium truss , stage truss, stage lighting ... Categories: Fixtures, Systems, Fixtures, Stage Equipment |
| 619 | [Guangzhou HOATOA Digital Technology Co.,Ltd](https://www.casinovendors.com/vendor/guangzhou-hoatoa-digital-technology-co-ltd/) GuangZhou, Guangdong, China Guangzhou HOATOA Digital Technology Co.,Ltd was incorporated in 2000. It is located in Bai Yun District of Guangzhou City. It is professional in car DVD player and car LCD monitor. The modernized factory takes up about 5000 square meters, there are several engineers and mor... Category: Other |
| 620 | [Guangzhou JR Lighting Equipment Co.,Ltd](https://www.casinovendors.com/vendor/guangzhou-jr-lighting-equipment-co-ltd/) Guangzhou, Guangdong, China Guangzhou JR Lighting, a professional manufacturer of Stage lighting, including LED PAR Light, LED BAR Light,Matrix Audience Blinder,Moving Head Light,Mirror Ball,Theatre Projector,Effect Machine, City Color/Sky Light,Controller,Accessories, etc. Category: Lighting Equipment |
| 621 | [Guangzhou Likang Electronic Technology Co., Ltd](https://www.casinovendors.com/vendor/guangzhou-likang-electronic-technology-co-ltd/) Guangzhou, Guangdong, China Guangzhou Likang Electronic Technology Co. Ltd. is a famous company in china. We are mainly producing electronic coin selector and ticket outlet. Category: Coin Handling Equipment |
| 622 | [Guangzhou LiQi Intelligent Technology Co., Ltd](https://www.casinovendors.com/vendor/guangzhou-liqi-intelligent-technology-co-ltd/) Guangzhou, China Guangzhou LiQi Intelligent Technology CO.,LTD. founded in year 2000, and obtained the Certificate of Verification for Software Enterprises and the Certificate of Verification for Software Products, is specialized in self-service touch screened equipments and the total soluti... Category: Kiosks |
| 623 | [Guangzhou Mingfine Electronic Co., ltd](https://www.casinovendors.com/vendor/guangzhou-mingfine-electronic-co-ltd/) Guangzhou, China Guangzhou Mingfine Electronic Co., Ltd. was established in 2001, which located in Guangzhou city, China, is a professional CCTV equipment designer and manufacturer. We have knowledgeable and young research, improving, manufacturing and sales teams. We can supply good aft... Category: CCTV Systems |
| 624 | [Guangzhou PURUI Electronic Co.,Ltd](https://www.casinovendors.com/vendor/guangzhou-purui-electronic-co-ltd/) Guangzhou, Guangdong, China Guangzhou purui Electronic Co., Ltd. locates in Guangzhou, China, found in 1995. It is a professional manufacturerer of LED display screen integrating R&D, design, production, marketing and after-sales service of LED displays. Guangzhou purui offer all types of indoor an... Category: LED Systems |
| 625 | [Guangzhou Rohin Electronic Co.](https://www.casinovendors.com/vendor/guangzhou-rohin-electronic-co/) Guangzhou City, China Rohin Electric is a factory which specializes in the development & manufacturing of all kinds of games and amusement machines. Our goal is to be committed to excellence in providing services and products to various markets and customers all over the world. Category: Themed Devices |
| 626 | [Guangzhou Ruixin Touch Control Technology Co., Ltd.](https://www.casinovendors.com/vendor/guangzhou-ruixin-touch-control-technology-co-ltd/) Guangzhou, Guangdong, China Guangzhou RUIXIN Touch Control Technology Co., Ltd, established in 2001, is a professional manufacturer of touch monitor and touch screen related products integrated with R&D and sales. Category: Touchscreens |
| 627 | [Guangzhou WATCHMAN Electronic Technology Co., LTD](https://www.casinovendors.com/vendor/guangzhou-watchman-electronic-technology-co-ltd/) Guangzhou, Guangdong, China Established in 1997, Guangzhou WATCHMAN Electronic Technology co., ltd is a large high tech enterprise specialized in R&D, manufacturing and supply, and marketing of product in security and surveillance electronics. Our high quality CCTV product and well designed system have... Category: CCTV Systems |
| 628 | [Guaranteed On Site](https://www.casinovendors.com/vendor/guaranteed-on-site/) Paulsboro, New Jersey State certified flame retardant applicators that will work with you and local Fire Marshals to bring your facility into compliance. Quick response and guaranteed work. Work can be performed on and off site. Fully insured and free estimates. Category: Dry Cleaning Design |
| 629 | [Guard Security](https://www.casinovendors.com/vendor/guard-security/) New York, New York Guard Security is fully licensed and insured. Due to our vast experience and motivated staff, we can offer far more than an ordinary security company. There is no comparison to our trained, experienced Security Officers to a 20-hour trained security guard. Guard Securi... Category: Officers |
| 630 | [Guardall Limited](https://www.casinovendors.com/vendor/guardall-limited/) Edinburgh, United Kingdom Category: Access Control, Other |
| 631 | [Guest Access International](https://www.casinovendors.com/vendor/guest-access-international/) Midland, Texas Guest Access, Intl offers premium quality laminated plastic guest access-related items direct from the factory. Stock and customized items are available(turnkey from card production to fulfillment and program management). Supplier and program management for many hotel hold... Category: Plastic Card Manufacturer |
| 632 | [Gul Group Industries](https://www.casinovendors.com/vendor/gul-group-industries/), Punjab, Pakistan We are pleased to introduce ourselves as a leading manufacturing and exporting company of highest standard Motorbike and Fashion Leather, Textile Garments & Gloves have been producing quality products for many years now. We have our own tannery where we produce best qual... Category: Apparel |
| 633 | [Gulf Islands Promotion](https://www.casinovendors.com/vendor/gulf-islands-promotion/) Biloxi, Mississippi Gulf Islands Promotion is your low cost choice for all things promotion. As part of a major buying group, we are able to offer almost unlimited product offerings at prices that will allow your promotional budget to stretch further! With over 14 years experince in the Casino... Category: Promotional Items |
| 634 | [Gulf Marine Products](https://www.casinovendors.com/vendor/gulf-marine-products/) Westwego, Louisiana Since 1988, Gulf Marine has become a leading processor of domestic and imported shrimp, crawfish tail meat and whole-cooked crawfish.Taking pride in excellent customer service and timely information, Gulf Marine's personnel create a seamless bridge between the producer and t... Category: Seafood |
| 635 | [Gulfport Industrial Supply](https://www.casinovendors.com/vendor/gulfport-industrial-supply/) Gulfport, Mississippi Locally owned, knowing the casino industry needs quick service and we have competitive pricing. Category: Wheels and Casters |
| 636 | [Gunderson, Palmer, Goodsell & Nelson LLP](https://www.casinovendors.com/vendor/gunderson-palmer-goodsell-nelson-llp/) Rapid City, South Dakota Category: Other |
| 637 | [Gunnebo Entrance Control, Inc.](https://www.casinovendors.com/vendor/gunnebo-entrance-control-inc/) Benicia, California We are world leading specialist in entrance control solutions and manufacturers of entrance gates for a broad range of applications including corporate offices, casinos, metro, airports and stadiums. From basic Tripod Turnstiles to our advanced SpeedGates, Revolving Securit... Categories: Access Control, Access Control, Access Control, Access Control |
| 638 | [GunsBet Affiliates](https://www.igamingaffiliateprograms.com/affiliate-program/gunsbet-affiliates/) Category: Affiliate Programs |
| 639 | [Guntex Industries, Inc.](https://www.casinovendors.com/vendor/guntex-industries-inc/) Chattanooga, Tennessee Our custom manufactured bags are designed for banks, casinos, and vending companies who use specialty bags in their daily operations. We offer custom printing services for customers wishing to personalize our bags with their company name and logo. Category: Coin Bags |
| 640 | [Guovin Technology Limited](https://www.casinovendors.com/vendor/guovin-technology-limited/) Shenzhen, Guangdong, China Established in 2008, Guovin Technology Limited is one of the leading manufacturer for high quality CCTV cameras and DVRs in Shenzhen China. Our product range including AHD/TVI/CVI Camera, IP Camera, PTZ Camera, DVR, NVR etc. GUOVIN focus on OEM & ODM, offer high-quality,best... Category: CCTV Systems |
| 641 | [Guowo Autoparts Co., Ltd](https://www.casinovendors.com/vendor/guowo-autoparts-co-ltd/) Qingdao, Shandong, China Guowo Autoparts Co.,Ltd is a leading auto parts manufacturer specialized in producing multi leaf spring,parabolic leaf springs, pin ,U-bolt,bush. We have more than 500 workers and 45 technicans, with the experienced R&D staff, advanced production equipments, strict quality c... Category: Assembly |
| 642 | [GVA Marquette Advisors](https://www.casinovendors.com/vendor/gva-marquette-advisors/) Minneapolis, Minnesota Leaders in feasibility consulting, market research, valuation, economic impact analysis and litigation support for casinos, hotels, resorts, golf, convention centers, RV parks, water parks, bowling, entertainment, retail, amusements and attractions. Category: Feasibility Studies |
| 643 | [GVG - Green Valley Games](https://www.igamingsuppliers.com/vendor/gvg-green-valley-games/) Categories: Casino Software, Lottery Software, Mobile Gaming |
| 644 | [GVision USA](https://www.casinovendors.com/vendor/gvision-usa/) Lake Forest, California GVISION is a leader in LCD display technologies, with their strategic blend of comprehensive product line, exceptional component sourcing consistency and high standards of cost-conscious quality manufacturing. This allows GVISION to deliver significant price/performance adva... Categories: Touchscreens, LCD, Monitors, Monitors, Open Frame |
| 645 | [GVZH Advocates](https://www.casinovendors.com/vendor/gvzh-advocates/) Valletta, Malta GVZH Advocates is one of Maltas leading legal practices actively involved in e-commerce and remote gaming law. The firm offers a full spectrum of services including company registration, preparation and co-ordination of all aspects of the application process with the Lotter... Categories: Licensing and Regulation, Gaming Licensing, Contract Management |
| 646 | [GWbet Affiliate](https://www.igamingaffiliateprograms.com/affiliate-program/gwbet-affiliate/) Category: Affiliate Programs |
| 647 | [GWIN Game](https://www.igamingsuppliers.com/vendor/gwin-game/) GWIN offers the white label solution services for Mobile web and PC gaming sites. We have 15 years of experience operating in the Asia Online Gaming market.The Most advanced functions of Mobile web gaming sites, and the integration of 15 Top Platforms of gaming product wi... Category: Platform Providers, Gambling Operations |
| 648 | [GX Trade Co., Ltd](https://www.casinovendors.com/vendor/gx-trade-co-ltd/) Caton, Guangdong, China Our company was founded in 2002,specialized in producing a series of marked cards and Europe Poker Club entertainment products. Golden Sunshine is a leading brand. We develop the newest luminous marked cards and Texas scanner system, which can be applied to any brand of poke... Category: Direct Marketing |
| 649 | [Gypsy Partners](https://www.igamingaffiliateprograms.com/affiliate-program/gypsy-partners/) Category: Affiliate Programs |
| 650 | [GZ Technologies, Inc.](https://www.casinovendors.com/vendor/gz-technologies-inc/) Taipei County, Taipei, Taiwan GZ TECHNOLOGIES, INC., member of Microsoft Embedded Partner, has more than 150 years of engineering experiences in Industrial and Gaming Solutions, especially ARM series and X86 based processors with Windows CE, Windows XP, XP Embedded, and Linux support. Our focus is to pr... Categories: Electronic Games, Electronic Games, Systems |
Featured Vendors
| [Casino Network](https://www.casinovendors.com/vendor/casino-network/) 20+ years experience selling refurbished slot machines, parts & glass for all major brands | [Casino City Press](https://www.casinovendors.com/vendor/casino-city-press/) A leading publisher and distributor of casino and gaming business data and market research reports. |
| --- | --- |
| [K2J Marketing Partners](https://www.casinovendors.com/vendor/k2j-marketing-partners/) Were not just a gifting provider—were an extension of your marketing team driving proven results. | [TribalHub](https://www.casinovendors.com/vendor/tribalhub/) 27th Annual TribalNet Conference Sept 20-24, 2026 at Hilton Anatole Dallas in Dallas, TX |
| [Oklahoma Indian Gaming Association (OIGA) Conference](https://www.casinovendors.com/vendor/oklahoma-indian-gaming-association-oiga-conference/) The biggest little show in Indian gaming! Save the date: July 20-22, 2026 Oklahoma City | [Innovative Configuration Inc.](https://www.casinovendors.com/vendor/innovative-configuration-inc/) I-Games Anywhere-Anytime - Win Product-Service-Activity-Attraction Discounts at Favorite Casinos. |
| [Patriot Gaming & Electronics, Inc.](https://www.casinovendors.com/vendor/patriot-gaming-electronics-inc/) Patriot Gaming…Parts is what we do. Visit us: www.patriotgaming.com | [Rymax Marketing Services, Inc.](https://www.casinovendors.com/vendor/rymax-marketing-services-inc/) Leader in creating award winning player & employee loyalty programs & events proven to increase ROI |
| [Slot Machines Unlimited](https://www.casinovendors.com/vendor/slot-machines-unlimited/) Exporter of IGT, Williams, AVP, Trimline, Aristocrat, Konami, Bally, & parts over 20 yrs experience | [Sunkist Graphics, Inc.](https://www.casinovendors.com/vendor/sunkist-graphics-inc/) Specializing in the creation of best-of-breed gaming graphics - slot glass, sign faces, and more |
| [Betson Imperial Parts & Service](https://www.casinovendors.com/vendor/betson-imperial-parts-service/) Your one stop shop for all your gaming and OEM needs! | [Regulatory Management Counselors, PC](https://www.casinovendors.com/vendor/regulatory-management-counselors-pc/) Over 45 years of experience serving the legal and regulatory needs of casino industry clients |
Your Guide to 13,687 Gaming Industry Suppliers
[ADD YOUR COMPANY](https://www.casinovendors.com/signup/default.aspx?action=add)| [ABOUT US](https://www.casinovendors.com/aboutus/)
Vendors By Category
»
[Legal Services & Licensing](https://www.casinovendors.com/category/administration-and-finance/legal-services-and-licensing/)
[Advertising, Marketing and Sales](https://www.casinovendors.com/category/advertising-marketing-and-sales/)
»
[Audio/Visual, Electrical and Signage](https://www.casinovendors.com/category/audio-visual-electrical-and-signage/)
»
»
[ATM & Credit Cards](https://www.casinovendors.com/category/cash-chips-money-cards/atm-credit-cards/)
[Magnetic Cards and Readers](https://www.casinovendors.com/category/cash-chips-money-cards/magnetic-cards-and-readers/)
[Disease Prevention and Safety](https://www.casinovendors.com/category/disease-prevention-and-safety/)
»
[Cleaning, Disinfection and Sanitation](https://www.casinovendors.com/category/disease-prevention-and-safety/cleaning-disinfection-and-sanitation/)
[Touchless Systems and Supplies](https://www.casinovendors.com/category/disease-prevention-and-safety/touchless-systems-and-supplies/)
[Entertainment and Special Events](https://www.casinovendors.com/category/entertainment-and-special-events/)
»
[Facility Security, Design and Construction](https://www.casinovendors.com/category/facility-security-design-and-construction/)
»
[Gaming Equipment and Supplies](https://www.casinovendors.com/category/gaming-equipment-and-supplies/)
»
[Hotel, Retail, Food and Beverage](https://www.casinovendors.com/category/hotel-retail-food-and-beverage/)
»
»
»
[Trade Shows & Seminars](https://www.casinovendors.com/category/miscellaneous/trade-shows-seminars/)
Vendors A-Z
---
Copyright © 1999-2026 Casino City Press. All Rights Reserved. [Terms of Use](https://www.casinovendors.com/terms-of-use/)| [Privacy Policy](https://www.casinocitypress.com/privacy/).

View File

@@ -1,189 +0,0 @@
Terms of Service Popiplay
# TERMS OF SERVICE
Version: 1.0Last updated: July, 2023.
## 1.GENERAL
Before using our website, please read these Terms of Service carefully. By registering a Player Account with the website, you agree and confirm your consent with the Terms and Conditions.
The website www.popiplay.com (“Game Provider”, “Website”, “Company”, “We”, “Us”, “Our”) is owned and operated by PP Solutions N.V. a company registered and established under the laws of Curaçao, with registration number 164235 and registered address at Scharlooweg 39, Willemstad, Curaçao.
It is the players sole responsibility to inquire about the existing laws and regulations of the given jurisdiction for online gambling.
## 2. CHANGES TO TERMS AND CONDITIONS
The Casino reserves the right to unilaterally change these Terms and Conditions when such need occurs. We will do our best to notify our players of any significant changes by email. However, we do recommend all players to revisit this page regularly and check for possible changes.
## 3. WHO CAN PLAY
The Casino accepts players only from those countries and geographic regions where online gambling is allowed by law. It is the players sole responsibility to inquire about the existing gambling laws and regulations of the given jurisdiction before placing bets on the website. The Casino accepts strictly adult players (the minimum age is 18) andplayers who have reached the age specified by the jurisdiction of players place of residence as eligible for online gaming. It is the players sole responsibility to inquire about the existing laws and regulations of the given jurisdiction regarding age limitations for online gambling. It is entirely and solely your responsibility to enquire and ensure that you do not breach laws applicable to you by participating in the games. Depositing real funds and playing for real money is subject to the laws of your country, and it is your sole responsibility to abide by your native regulations. TheCompany reserves the right to ask for proof of age from the player and limit access to the Website or suspend the Player Account to those players who fail to meet this requirement.
Any bonuses are not available to players from Sweden, including participation in any kind of promotional programs, receiving VIP rewards, as well as exchange of comp points. Users from the following countries and their territories (“Restricted Countries”) are not allowed to deposit and play real money games: United States of America, United Kingdom, Spain, France and its overseas territories (Guadeloupe, Martinique, French Guiana, Réunion, Mayotte, St. Martin, French Polynesia, Wallis and Futuna, New Caledonia), Netherlands, Israel, Lithuania, Dutch West Indies, Curacao, Gibraltar, Jersey, Greece, Belgium. The Casino cannot guarantee successful processing of withdrawals or refunds in the event that player breaches this Restricted Countries policy.
## 4. AVAILABILITY OF GAMES
Please bear in mind that some games may be unavailable in certain jurisdictions, as required by their respective regulation, which may change from time to time. Using VPN to bypass providers block is strictly prohibited and may lead to confiscation of winnings.
## 5. ACCEPTED CURRENCIES
Popiplay allows operators to chose their offering of currencies in their respectivemarkets, as long as legal tenders are being used for transactions.
## 6. FEES AND TAXES
You are fully responsible for paying all fees and taxes applied to your winnings according to the laws of the jurisdiction of your residence.
## 7. GAME RULES
By accepting these Terms of Service you confirm that you know and understand the rules of the games offered on the operators respective websites. It is at your discretion to familiarise yourself with the theoretical payout percentage of each game.
## 8. DISCLAIMER OF LIABILITIEST
By accepting these Terms of Service, you confirm your awareness of the fact that gambling may lead to losing money. Game provider is not liable for any possible financial damage arising from your use of any operator web-site.
The Game Provider is not liable of any hardware or software defects, unstable or lost Internet connection, or any other technical errors that may limit access to the Website or prevent any players from uninterrupted play. In the unlikely case where a wager is confirmed or a payment is performed by us in error, the Company reserves the right tocancel all wagers accepted containing such an error, or to correct the mistake by resettling all the wagers at the correct terms that should have been available at the time that the wager was placed in the absence of the error. If the Casino mistakenly credit your Player Account with a deposit, bonus or winnings that do not belong to you,whether due to a technical issue, error in the pay tables, human error or otherwise, the amount and/or the winnings from such bonus or deposit will remain the Casino property and will be deducted from your Player Account. If you have withdrawn funds that do not belong to you prior to us becoming aware of the error, the mistakenly paidamount will (without prejudice to other remedies and actions that may be available at law) constitute a debt owed by you to us. In the event of an incorrect crediting, you are obliged to notify us immediately by email. The Casino, its directors, employees, partners, service providers: • do not warrant that the software or the Website is/are fitfor their purpose; • do not warrant that the software and Website are free from errors; • do not warrant that the Website and/or games will be accessible without interruptions; • shall not be liable for any loss, costs, expenses or damages, whether direct, indirect, special, consequential, incidental or otherwise, arising in relation to your use of the Website or your participation in the games.
You hereby agree to fully indemnify and hold harmless the Game Provider, its directors, employees, partners, and service providers for any cost, expense, loss, damages, claims and liabilities howsoever caused that may arise in relation to your use of games or participation in games. You acknowledge that the Game Provider shall be the final decision-maker of whether you have violated the Game Providers Terms of Service in a manner that results in your suspension or permanent barring from participation in the Website.
## 9. USE OF PLAYER ACCOUNT
Each player is allowed to create only one (1) personal account. Creating multiple Player Accounts by a single player can lead, at the sole discretion of the respective operator, to termination of all such accounts and cancellation of all payouts to the player. The player shall not provide access to their Player Account or allow using operators respective websites to any third party including but not limited to minors. Any returns, winnings or bonuses which the player has gained or accrued during such time as the Duplicate Account was active may be reclaimed by us, and players undertake to return to us on demand any such funds which have been withdrawn from the Duplicate Account. The Website can only be used for personal purposes and shall not be used for any type of commercial profit. You must maintain your account and keep your details up-to-date. We reserve the right to make a phone call to the numberprovided in your user account, which at our own discretion can be a necessary part of the KYC procedure. Account and/or any actions in the account may be terminated until the account is fully verified. We will make reasonable efforts trying to contact you regarding the withdrawal of the funds, but if we are not able to reach you (by email orphone) in two (2) weeks as from the date of the request for withdrawal, account will be locked, since you have failed to pass the KYC procedure.
## 10. ANTI-MONEY LAUNDERING
## 10.1 ABBREVIATIONS USED
FATF Financial Action Task Force (http://www.fatf-gafi.org)RNG Random Number Generator
## 10.2. GUIDELINE IDENTITY CHECK
1. In order to do a first deposit with PP Solutions N.V. a customer needs to provide the following mandatory details:
● First name● Last name● Street and street number● City and postal code● Country● Email address (must be valid and unique within PP Solutions N.V.)● Date of birth● Password (will be encrypted)● Confirmation of password● Account currency● Mobile phone number
2. A newly registered account has to be checked immediately by the service department in order to find out if the details are correct (accounts with false names and addresses will be closed). Also, the registered country and the country IP need to be compared. A mismatch is automatically to be noted in the customers account. This helps us close fake accounts before any paying can be processed.
1. Players who are not registered are unable and not allowed to play for real money. Any online transaction, may it be pay-in or pay-out, will not be accepted or processed in cash.2. Once the registration process has been accomplished, customers will receive a welcome email with a link to access their accounts. This procedure aims at verifying the customers email address.3. Each new customer has to provide a copy of an ID document (passport, ID card or driving license) when thresholds set in section 4.1.1 are reached. This is in line with the 5th AML requirements.4. The identity check has to include a copy of a utility bill and/or bank statement showing the name and address, if there is any doubt on the authenticity of the provided ID document.5. Furthermore, the identity check may include additional measures such as the provision of a copy of each credit card used in the specific account.6. Any remaining doubts concerning the identity of a customer have to be reported to the supervisor.7. In such a case, further investigations have to be started.8. These may include • Check of the IP used by the customer • Check of the provided phone number and/or call to the provided phone number • Internet research on the customer details • Request to the official authorities in thecountry of the customer this has to be done by compliance management.9. Customers will not be able to register with a country of residence in the following list: US, Denmark, Belgium, Australia, Anguilla, Afghanistan, Czech Republic, Slovakia, Slovenia, Gibraltar, Israel, Iran, Jersey, Lithuania, Slovenia, Slovakia, UK, Ireland, Estonia, Italy, France, Turkey, Spain, Greece, China, Jamaica, Cambodia, Iraq, Syria, Myanmar, Lao PDR, Angola, Cape Verde, Paraguay, Macau, Hong Kong, Albania, Pakistan, Lebanon, Cote DIvoire, Iran, Afghanistan.10.Customer under the age of 18 will be denied to register an account. Customers will be required to register before playing for real money.
## 10. 3 GUIDELINE PAYOUT MANAGEMENT
## 10.3.1 Checks to be performed on each payout:
## 10.3.1.1 Account check
The owner of the PP Solutions N.V. account must be the same person as the owner of the bank account or credit card. All account information, like address, email, date of birth etc., must be complete and authentic. Withdrawals will be made to the same source where the funds originated (where possible).
## 10. 3.1.2 Deposits must have been used
On each payout it has to be checked if the deposits have been used for stakes. A payout cannot be processed if the deposited amount has not been used for stakes. If the deposited amount has not been used, the payout has to be denied. Furthermore, the latest winnings have to be checked for correctness.
## 10. 3.1.3 Fulfilment of bonus rules
Before a payout can be deducted from the customer´s account, the account has to be checked if a bonus has been given to the customer since the last payout. When a bonus has been credited, the account has to be checked for fulfillment of the bonus rules applicable to that bonus.
## 10.4 AML Procedures - The Risk Based Approach
The risk-based approach is introduced to promote a move away from a “one size fits all” approach to anti-money laundering procedures. By identifying and assessing the money laundering risks, PP Solutions N.V. can take the best steps to mitigate and monitor those risks.
## 10.4.1. Risk Profile for PP Solutions N.V.
Based on our business profile, the risk of money laundering and terrorist financing is minimal, especially compared to financial institutions. The main reason is that cash is not accepted and only credit cards, e-wallets and other licensed instruments can be used to effect deposits and withdrawals. Additionally, the average transaction is of a relatively small value. The only money laundering stage that could be of a risk potential for PP Solutions N.V., is the layering stage, which is mitigated by various daily screening measures described below.
## 10.4.1.1. Customer Due Diligence (CDD)
CDD information is needed to identify money laundering activity. The more the customer profile is updated, the more it will help to identify unusual and potentially suspicious activity. In accordance with the 4th AML directive, the verification and gathering of client information will be delayed until:
• Account deposits reach a pre-determined threshold of EUR 2,000;• Gaming activity reaches a pre-determined threshold of EUR 2,000;• Players seek to withdraw funds (initial payout);• A period of time since account opening lapses more than 60 days.
The following on-going monitoring measures describe CDD measures based on thecompanys risk profile:
• Identity verification for every new customer• Assessing the risk profile of every customer• Daily payout analysis• Analysis of the historical pattern of the customers payout activity• Ban of anonymous or fictitious accounts.
## 10.4.1.2. Customer Due Diligence Measures Applied
The daily CDD measures applied during the daily workflow are described in detail below.
## CDD: ID-Check
For every new customer the service department conducts individual checks whether the registered data is plausible and correct. The IP address check and double customer check are conducted as outlined below. Fake or double accounts are being closed immediately.
## CDD: IP-Check
The customers IP address is registered upon every log-in. Upon registration, a review is done as to whether the customers IP address corresponds with the registered country. If there is a mismatch, the customers account is marked for further checks.
## CDD: Double Customer Check
Every customer can open only one account. If a customer tries to open multiple accounts, these will be blocked, and the system will generate a warning.
## CDD: Passport check upon first pay-out
Customers may need to submit a passport copy before the first pay-out irrespective of the amount requested. Passport copies are checked individually by risk management. Furthermore, PP Solutions N.V. reserves the right to determine the payment means of the first pay-out: either by the same method used for the deposit, or by bank transfer in order to further validate the customers identity.
## 10.4.2. Customer Acceptance Policy
After the identity verification a risk profile is formed based on the behavioural pattern of the customer. Every customer is given an internal classification, which will be described further below. If suspicious behaviour is observed, evidence will be recorded on the customer profile, and enhanced customer due diligence is applied.Enhanced customer due diligence (EDD) is mandatory also for Politically Exposed Persons (PEPs) who are considered high-risk customers.
## 10.4.3. Enhanced Customer Due Diligence (EDD)
Enhanced Customer Due Diligence is applied when additional steps of examination are needed to identify the customer and to confirm that their activities and funds are legitimate. The following measures describe EDD measures based on the companys risk profile:
● Establishing the identity of the customer by requesting additional documents suchas: a copy of a utility bill to verify the home address and a statement of a credit orfinancial institution to prove the bank account holder.● Verifying documents by using supplementary measures.● Requesting certified confirmation of the documents from a credit/financialinstitution.● Ensuring that the first payment originates from customers own bank account /credit card.● Clarifying the source of the funds with the customer.
## 10.4.4. Enhanced Customer Due Diligence Measures Applied
The daily EDD measures applied during the daily workflow are described in detail below
## EDD: Enhanced ID Check
The customer has to submit ID, utility bill and bank statement for Enhanced ID Checkwithin 30 days. If the customer does not send these documents within 30 days, thegaming account will be blocked from all transactions. Enhanced IDCheck is carriedout whenever:
● The registered country is not part of the FATF white list.● A deposit or pay out request is equal or more than 2,000 EUR.
## Credit card verification
We use common tools like 3D Secure to verify credit cards.
## 10.4.5. Money Laundering Reporting Officer (MLRO)
The MLRO is the first person to notify when the suspicion of money launderingactivities evolves. The MLRO is appointed by senior management and is trained forthe money laundering risk factors that the company faces. When the companyappoints the MLRO, the competent authorities need to be notified. The main dutiesof the MLRO are:
a) Keeping up to date with AML/CTF legislations.b) Making sure that implementation takes place in line with the internal procedures.c) Making sure that anti-money laundering training is periodically given to staff.d) Recording and updating risk assessments.e) To receive and evaluate internal reports.f) To advise, guide and assist.g) To keep statistical data.h) Filing STRs to the respective financial authority.
All incidents involving a suspicious person or transaction in terms of moneylaundering or funding terrorism need to be reported to the respective financialauthority by the MLRO within 5 working days. In the Suspicious Transaction Report,the MLRO must give a clear and complete explanation of the suspicious behaviourincluding also customer identification and transaction records.
## 10.4.6. Additional Monitoring Tools
## Customer Classes
Every customer is vetted in a specific customer class according to his „risk potential.” Every customer class is subject to different deposit limits. For instance, all new customers are being rated with customer class N (white list markets) or M (non-white list countries). After the lapse of 4 weeks, customers will be moved to different classes in line with their observed behaviour. High risk customers will be followed closely.
## 10.4.7. Politically Exposed Persons (PEPs)
A Politically Exposed Person is someone who has been entrusted with a prominent public function, such as a senior political figure. Individuals who are closely related to this person, for instance, immediate family members and close associates, are also considered as PEPs. PEPs are classified as a money laundering risk since they may be exposed to property that has been generated by corruption and bribery because of their position. The current PEP lists provided by Acuris are consulted in order to identify a customer as PEP. The player is requested to confirm their PEP status within the first deposit. Once established as PEP, the users account is terminated. Screening for PEP status is carried out once a year and after a country election the resident of which the player is. Where player who was a PEP is no longer entrusted with a prominent public function, the requirements for PEPs will continue to apply for a period of at least 12 months after the date on which the person ceased to be entrusted with a public function or for a longer period to address the risks of money laundering or terrorist financing in relation to that person.
## 10.4.8. Record Keeping
The following records are kept: Identification Records: Copy of ID-document; Copy of bank/credit statement; References. Transaction Record Details: Deposit/withdrawal method used; ID of person performing the transaction; Destination of funds; The authorization of credit card payments performed by our clearing companies; Volumeof transactions. The records are kept for 5 years from the end of the business relationship in accordance to the directive.
## 10.4.9. Employee training
Periodical training ensures that the staff is aware and compliant with the anti-moneylaundering regulatory requirements.
## 10.4.10. Employee hiring
For all new employees hired by PP Solutions N.V.; PP Solutions N.V. will conduct a thorough background check and various due diligence documents will be collected for reference (birth certificate, clear police conduct, etc.). Interviews are carried out and requested references are checked, whenever available. It is a company policy that all new employees are also given training with regards to the anti-money laundering policy and the internal procedures used to mitigate this risk.
## 11. COMPLAINTS
You are free to contact our customer service team to share your opinion, your feedback, request or complaint. Please use: [[email protected]](https://www.popiplay.com/cdn-cgi/l/email-protection#3b484e4b4b54494f7b4b544b524b575a4215585456) for this purpose. We will endeavour to respond as soon as possible, but not later than 48-72 hours. Complaints are handled in the support department and escalated in the organisation of the respective Casino in the case that support personnel did not solve the case immediately. You shall be informed about the state of the complaint to a reasonable level. Casino is to acknowledge a complaint started by the account holder only. It is forbidden to and you can therefore not assign, transfer, hand over or sell your complaint to the third party. Casino will dismiss the complaint if the matter is handed over to be conducted by the third party and not the original account owner. In the event of any dispute, you agree that the server logs and records shall act as the final authority in determining the outcome of any claim. You agree that in the unlikely event of a disagreement between the result that appears on your screen and the game server, the result that was logged on the game server will prevail, and you acknowledge and agree that our records will be the final authority in determining the terms and circumstances of your participation in the relevant online gaming activity and the results of this participation. When we wish to contact you regarding such a dispute, we will do so by using any of the contact details provided in your Player Account.
## Welcome to
## You must be over 18 years old to enjoy our content.
## Please verify your age!
Yes, I am 18 years old
[No, take me back](https://google.com/)

View File

@@ -1,415 +0,0 @@
Best iGaming aggregation solution - iGaming API solution
# Casino Game Aggregator API
Our API integration is a powerful solution for fast and seamless integration of casino games and sportsbook content into your platform.
Integrate software from multiple game providers in a single day and scale your iGaming business without limits.
[Contact Us](https://igamingslots.com/contact/) [All Providers](https://igamingslots.com/casino-game-providers/)
Work with leading providers such as Pragmatic Play, Evolution, NetEnt, Playtech, and more. Access thousands of casino games and deliver a premium iGaming experience worldwide.
#### Fast Integration
Launch your platform quickly with easy API setup.
#### Multiple Providers
Connect to leading game developers worldwide.
#### Scalable System
Handle high traffic and expand without limits.
## One API to connect 15,000+ games, live casino and sportsbook
Plug a single REST endpoint into your iGaming platform and instantly unlock slots, live dealer tables, crash games, virtual sports and sportsbook feeds from 150+ certified providers — without rebuilding your stack.
[Contact Us →](https://igamingslots.com/contact/) [All Providers](https://igamingslots.com/casino-game-providers/)
15,000+Slot games
150+Providers
40+Countries
14 daysAvg. setup
### Start with leaders in the industry
Pragmatic PlayEvolutionNetEntPlaytech HacksawSpribeNovomaticAmatic IGTQuickspinNolimit CityBooming Games
What is our API
## A single aggregator built for serious iGaming operators
Our Casino Game Aggregator API is a production-grade integration layer that lets you connect thousands of casino games and sportsbook content to your platform through one unified interface. It was engineered specifically for online gambling operators who want to minimise engineering cost, shorten time-to-market and scale their business without being locked to a single provider.
Instead of negotiating, integrating and certifying each provider individually — which typically takes months of back-and-forth for every new studio — you sign one agreement with us and immediately receive access to 150+ top-tier studios and independent game labs. We handle provider onboarding, game catalogue normalisation, RTP reporting and player session tracking on the backend, so your team can focus on growth, marketing and product instead of infrastructure.
The aggregator was built from day one with the needs of real-world iGaming operators in mind: high concurrency during marketing peaks, burst traffic around major sporting events, complex multi-region routing, multi-language lobbies and strict reporting requirements from operations teams. Every decision — from the way we version endpoints to the way we expose webhook retries — exists because weve lived through the problem it solves, many times over, with operators across 40+ countries.
You connect once and keep receiving new content, new providers and new markets as our platform expands. There is no separate contract to renegotiate every time we add a studio — you simply flip a switch in the admin panel and the new provider appears in your game lobby, already normalised and ready for traffic.
Fast integrationSandbox credentials within 24 hours, production go-live in 14 days on average.
Multiple providersPragmatic, Evolution, NetEnt, Playtech, Hacksaw, Spribe and 140+ more, all via one API.
Scalable systemBattle-tested under millions of spins per day with multi-region failover.
Always-on contentNew game titles and providers are pushed to your lobby weekly without any downtime or redeploys.
YOUR APP`client.launchGame("book_of_dead")`
OUR API`POST /v1/games/launch`
AGGREGATOR`routes to Pragmatic · Evolution · NetEnt…`
PROVIDER`200 OK · game URL · 38 ms`
Key Features
## Everything your platform needs, shipped in one integration
A complete aggregation layer with the tools, data and reliability iGaming operators actually use in production. No puzzle-piece stack, no vendor spaghetti.
### All-in-One Game Aggregation
Access 15,000+ slots, live dealers, table games, crash, instant-win and fishing titles through a single integration. The aggregation layer normalises game data, session tokens, RTP reporting and player histories in one unified dashboard — no more juggling a dozen different provider schemas.
### Sportsbook & In-Play Feeds
Real-time pre-match and in-play odds for 40+ sports, low-latency websocket streams with automatic regional failover, settlement API and bet-builder support — everything you need to add sports betting to your casino audience without a second platform.
### Live Casino & Game Shows
Premium live dealer content from Evolution, Ezugi, Pragmatic Live, Vivo and more. Blackjack, roulette, baccarat, poker variants and next-generation game shows — streamed in HD, 24/7, with multilingual dealers and regional tables for your key markets.
### Real-time Analytics & BI
Track GGR, NGR, RTP, player acquisition costs, session duration, game performance and conversion funnels. Schedule automated reports, build custom dashboards, stream events to your BI stack and share insights across your team in real time.
### Any-GEO Deployment
Launch in North America, Europe, Asia, LATAM or Africa on the same code base. Regional endpoints with automatic routing, localised game catalogues, multi-language lobbies and time-zone-aware support — so entering a new market is a configuration change, not a rebuild.
### Fraud Protection & Security
Multi-layer defence purpose-built for iGaming: real-time fraud scoring, anti-bot protection, device fingerprinting, encrypted transactions and SOC 2-ready infrastructure. Your business and players stay protected at every point of the flow.
### Mobile-First Performance
Every game and sportsbook endpoint is optimised for mobile. Progressive Web App support means instant loads even on slower connections — keeping players engaged whether theyre on fibre at home or 3G on the move.
### 24/7 Dedicated Support
Round-the-clock assistance from iGaming engineers — not a ticketing bot. Technical integration, incident response, provider questions, tuning and optimisation are handled by a dedicated account manager assigned to your project from day one.
Technical Architecture
## Built for operators who cant afford downtime
Our API is designed around the reality of high-traffic iGaming: spikes during football weekends, marketing peaks that triple your concurrent users, and regulatory audits that can land without warning. Every endpoint is deployed across multiple cloud regions with automatic failover, aggressive caching where it makes sense, and signed, replay-protected requests where it matters.
Under the hood the platform runs on a distributed microservice architecture with independent game, sportsbook, CMS and analytics services. Each service scales horizontally and can be deployed closer to the player, so Brazilian users get responses from São Paulo while European players are served from Frankfurt, without you having to think about geography.
We also take backwards compatibility seriously. Breaking changes are rare and always announced through semantic versioning, a public changelog and a twelve-month deprecation window — so you can move at your own pace instead of scrambling to match an unannounced schema change.
The result is a platform that stays online when your players need it most, and an integration surface that your engineers can reason about without reading a fifty-page PDF.
REST + WebSocketJSON over HTTPS for game launches, WS streams for live odds and session events.
Multi-region failoverActive deployments in EU, UK, LATAM and APAC with automatic DNS-based routing.
OAuth2 + HMAC signingSigned requests, IP allow-listing, rotating keys and complete audit trails.
Low-latency edgep95 under 80 ms thanks to edge caching, optimised payloads and CDN routing.
Versioned APISemantic versioning with 12-month deprecation windows, detailed changelog.
Sandbox mirrorIdentical data shapes and latency profile as production for confident QA.
Webhook retriesExponential backoff with DLQ inspection and signed payload delivery.
Event streamingKafka-compatible event bus for bet, spin, session and game-lifecycle events.
How it works
## From first contact to live platform in four steps
We engineered the onboarding flow to be friction-free. Most operators move from “hello” to fully live in a matter of weeks, not quarters.
01
### Contact Us
Submit your request and book a discovery call. We take the time to understand your target market, traffic projections and roadmap before proposing the optimal setup.
02
### Setup & Config
We provision your sandbox, configure domains, servers, SSL and brand assets. Credentials land in your inbox, typically within 24 hours of signing.
03
### Integration
Games, sportsbook, analytics and back-office dashboards are connected, tested and verified against joint UAT checklists before go-live.
04
### Launch & Scale
Switch to production keys, push to real traffic and keep scaling. We stay on-call for optimisation, monitoring and new provider rollouts as you grow.
Supported Content
## All major iGaming verticals, one API
The aggregator serves every mainstream content type players expect from a modern online casino — plus the fast-growing niches that are driving engagement today. From classic three-reel slots to high-volatility megaways, from live-streamed roulette to community-driven crash rounds, the catalogue is curated to match real player behaviour across dozens of regulated and emerging markets.
Slots
### Video Slots
15,000+ certified slot titles from premium studios and boutique labs — megaways, cluster pays, buy-feature mechanics and classic fruit machines.
Live
### Live Dealer
Blackjack, roulette, baccarat, game shows and regional specialities streamed from Evolution, Ezugi, Pragmatic Live, Vivo and more.
Table
### Table & Card Games
Multi-hand poker, classic blackjack, European & American roulette, punto banco and a deep catalogue of regional card games.
Crash
### Crash & Instant Win
Aviator, JetX, Plinko, Mines, scratchcards and social-style instant-win formats — the content that keeps engagement graphs steep.
Sports
### Sportsbook & Virtual Sports
Pre-match, in-play, bet-builder, cash-out and a full virtual sports suite covering football, horse racing, tennis and esports.
More
### Bingo, Lottery & Fishing
Network-based bingo rooms, daily lotteries and arcade-style fishing games for Asia-facing operators, all through the same endpoint.
Global Reach
## Start your journey in any GEO
We ship iGaming software in almost any country and region, taking on the technical challenges so your team can focus on acquisition and product. Each region has its own player expectations, its own language preferences and its own content trends — we package all of that into ready-to-go regional profiles that you activate with a single click.
🌎
### North & South America
Localised content in Spanish, Portuguese and English, regional jackpots tuned for LATAM players and a content mix weighted toward the slot titles and live dealer studios that dominate the US, Brazilian and Mexican markets.
- English
- Spanish
- Portuguese
🌍
### Europe
Full EEA and UK coverage with localised content catalogues, regional live-dealer tables and dedicated European support desks across multiple time zones for both regulated and emerging European markets.
- English
- German
- Polish
- Italian
- French
🌏
### Asia
Dedicated Asian live-dealer studios, regional fishing and arcade-style titles, plus deep catalogues tuned for the biggest APAC markets — with on-the-ground support teams covering each key time zone.
- English
- Hindi
- Thai
- Vietnamese
- Bahasa
Why IGP
## 15 years of undefeated success in iGaming
Professionals with more than 15 years in iGaming software, trusted by operators across 40+ countries. The numbers speak louder than a sales pitch.
500+Successfully finished projects
13K+Games available on platform
150+Providers integrated
14 daysAverage setup time
What you get
## A complete turnkey operation, out of the box
### Full turnkey delivery
No in-house development required on your side — the entire stack, from casino frontend to admin back-office, is delivered ready to run.
### Cloudflare & servers
Complete cloud setup, domain transfer or purchase, DDoS protection, global CDN and dedicated servers for stable performance in any region.
### Account manager from day one
A dedicated iGaming specialist joins your project from the very first call and stays with you through launch, optimisation and scaling.
### Multi-GEO support
North America, Europe, Asia — each with localised languages, live dealer studios and content catalogues curated specifically for the region.
### Average response < 2h
Our support desk keeps an average reply time under two hours, with Telegram, WhatsApp and email always open during launches.
### Proven track record
500+ successfully launched projects over 15 years in iGaming. The team has seen every edge case, so your launch doesnt have to be the one that uncovers them.
Who its for
## Built for operators who want to move fast
The aggregator API fits a wide range of iGaming businesses — from first-time entrepreneurs launching their debut brand to established groups scaling into new markets. Whether youre starting from a blank page or replacing a legacy vendor, the onboarding flow is the same: a single discovery call, a tailored setup and a project timeline that moves in weeks rather than quarters. A few of the most common scenarios operators come to us with:
### New brand launch
Stand up a full casino & sportsbook under your own branding in weeks, with games, content and support ready from the first player sign-up.
### Existing casino expansion
Plug our aggregator into your current platform and instantly triple your game library, add sportsbook or roll out crash games without rebuilding.
### New GEO roll-out
Enter LATAM, Asia or a regulated European market with localised content, languages and a support team that already knows the landscape.
### Migration from a legacy provider
Move away from an outdated vendor with minimal downtime — we import your player base, sessions and game history and run a parallel sandbox until cutover.
### Affiliate or media group
Turn your traffic into a fully owned casino product instead of pushing users to someone elses brand — you keep the lifetime value.
### Land-based operator going online
Extend your physical brand into the digital world with a fully synchronised player account, loyalty program and unified cash management.
Integration Playbook
## Everything your engineers need on day one
We dont just hand you an endpoint and a wish of good luck. Every new operator gets a complete integration pack so the engineering team can move from “kick-off call” to “first real spin” without guesswork.
### Full API reference
OpenAPI 3.1 specification with request/response examples, error codes, rate limits and regional endpoint URLs. Auto-generated SDK stubs for Node, PHP, Python, Go and .NET.
### Postman & Insomnia collections
Ready-made collections pre-filled with sandbox credentials so your QA team can click through the whole player journey — session creation, game launch, live odds and round settlement — in minutes.
### Sandbox identical to production
Same data shapes, same latency profile, same error behaviour. What passes in sandbox passes in production, which removes an entire class of “works on my machine” incidents.
### Webhook playground
Replay any webhook event, inspect the signed payload, rotate secrets and simulate network failures to validate your idempotency logic before players ever touch the system.
### Engineering Slack channel
A shared Slack or Telegram channel connects your developers directly to ours. No tickets, no escalation trees — just the people who can actually answer the question in real time.
### Go-live checklist
A thirty-point launch checklist covering DNS, SSL, webhook signatures, fraud rules, responsible gaming limits, latency targets and analytics tags — all signed off before we flip production.
FAQ
## Frequently asked questions
A few of the most common questions operators ask before signing on — if yours isnt here, just reach out and well reply personally.
What exactly does your Casino Game Aggregator API include?
Its a unified REST and WebSocket interface to 15,000+ casino games, live dealer content, sportsbook feeds, crash and instant-win titles, plus full analytics and admin tooling — delivered through one integration and maintained on our side. You integrate once and automatically receive new providers, new titles and feature updates over time.
How fast can we go live?
Sandbox credentials are typically issued within 24 hours of onboarding. The average go-live time for a full casino + sportsbook platform is 14 days; casino-only integrations can ship in less than a week if your team is ready. Timelines depend on how much customisation you want on top of the default stack.
Which providers are connected out of the box?
Pragmatic Play, Evolution, NetEnt, Playtech, Hacksaw Gaming, Spribe, Nolimit City, Booming Games, Quickspin, Novomatic, Amatic, IGT, Red Tiger, Yggdrasil, Wazdan, Habanero, PGSoft, BGaming, KA Gaming, and 130+ more. The full catalogue is available in our providers directory and we add new studios every month.
What types of games are covered?
Video slots (classic, megaways, cluster pays, buy-feature), live dealer tables, blackjack, roulette, baccarat, poker variants, crash and instant-win titles, lotteries, bingo, virtual sports, sportsbook feeds and regional specialities like fishing games for Asian markets — all via the same API.
Can we bring our own provider?
Absolutely. The API is extensible — if you already have a direct contract with a game provider well certify the integration and plug it into the same unified interface so your team still has a single point of control. Custom provider integrations are typically delivered within two weeks at no extra cost for operators on the platform.
Is the platform scalable for high traffic?
Yes. The infrastructure has been battle-tested under millions of spins per day and sustained peaks during major sporting events. Multi-region deployments with automatic failover and horizontal scaling keep latency low even under sudden load spikes from viral marketing or paid acquisition pushes.
How is the platform secured against fraud and abuse?
Multiple layers: real-time fraud scoring, device fingerprinting, anti-bot protection, multi-account detection, encrypted transactions, SOC 2-ready infrastructure and continuous penetration testing. Our fraud team also provides actionable reports so your operations desk can act on emerging patterns quickly.
What kind of support do we get after launch?
24/7 technical support with an average first-response time under two hours, plus a dedicated account manager assigned to your project from day one. You reach us over Telegram, WhatsApp or email — whichever works best for your team.
Can the API power a mobile app or PWA?
Yes. Every endpoint is mobile-first; game launches return mobile-optimised URLs, sportsbook and content APIs return lightweight JSON, and the platform supports Progressive Web App distribution for markets where native app stores are restrictive. Native iOS and Android wrappers can be added on request.
Do you provide analytics and reporting?
Yes — GGR, NGR, RTP, cohort engagement, player LTV, session duration, game performance and many more metrics are available in real-time dashboards. You can also stream events to your own BI stack or receive scheduled reports by email.
Can we customise the casino lobby and UI?
Yes. The frontend is fully brandable — colours, logos, typography, game lobby categories, lobby sorting, promotional banners and landing page layouts are all configurable from the admin panel. Deeper custom work, like unique landing pages or gamified journeys, is delivered by our design and engineering team on request.
Can we deploy the platform in any GEO?
Yes — North America, South America, Europe, UK, LATAM, Africa, Middle East and APAC are all supported on the same code base. Each region has regional endpoints, localised game catalogues, language packs and time-zone-aligned support. Rolling out to a new GEO is a configuration change, not a rebuild — we usually have a fresh region in production within days, not weeks.
What happens if a provider has an outage?
Our monitoring picks up provider issues usually before the provider does. Affected games are automatically hidden from the lobby, running sessions are gracefully closed and players are notified — while the rest of your casino keeps running. You get a real-time status page and a post-incident report for every outage.
Ready to plug in?
## Lets connect your platform to 150+ providers
Fill in the contact form and our iGaming specialist will reach out within 24 hours to walk you through the integration and answer any technical questions your team has.
[Contact Us →](https://igamingslots.com/contact/) [Telegram: @igaming_production](https://t.me/igaming_production)

View File

@@ -1,514 +0,0 @@
About BGaming game provider | BGaming --
# BEYOND GAME PROVIDER
BGaming — your partner for collaborative success. Your iGaming provider that keeps players coming back.
Contact us
## TRUSTED ACROSS 3,000+ GLOBAL COMPANIES
Through our offerings, operators gain business benefits while having a tight bond with their players.
### 250+
Highly engaging games
### TOP 10
Global reach in gambling streaming
### 100%
Gambling fairness
## OUR TRADEMARK GAME FEATURES
TRUEWAYS™
The TRUEWAYS™ reel set offers 28 symbols per reel, resulting in up to 262,144 ways to win.
[All games with feature](https://bgaming.com/games?mechanics=Trueways)
MultiDice X™
A gameplay mode in which dice drops occur, triggering respins and awarding multipliers.
[All games with feature](https://bgaming.com/games?mechanics=MultiDice+X)
Merge UP™
Clusters of symbols upgrade into higher-value ones, resulting in chain-reaction wins. Patent pending.
[All games with feature](https://bgaming.com/games?name=merge)
SpinUp™
Enables various feature modes that enhance built-in functionality or add extra mechanics.
[All games with feature](https://bgaming.com/games?name=fortuna)
## PROMO TOOLS TO ELEVATE YOUR IGAMING BUSINESS
1
### Challenges
Let your players complete in-game challenges and earn extra rewards while enjoying their favorite games. Daily updates and different tasks suit all types of players.
2
### Drops
Turn ordinary play into a series of “wow” moments, keeping the game fresh and players keen, with random additional prizes dropped automatically to their balance.
3
### Game Sets Promo
Delight players with festive game reskins for special occasions and holidays, such as Christmas, St. Valentines Day, St. Patricks Day, Easter, Halloween, and more.
## WHY BGAMING?
- Comprehensive security for trusted entertainment
- Flexible integration options for quick game launches
- Advanced marketing tools to boost key business metrics
- Data-driven game development using analytical tools
- All-inclusive customer support with user-friendly software
- Established global presence, strong in Europe and LatAm
Contact us
## BGAMING TOP GAMES
Worldwide Asia LATAM Europe Africa
### Burning Chilli X
Its getting hot in here! BGaming has just produced a new Burning Chilli X slot!
[Learn More](https://bgaming.com/games/burning-chilli-x)
### Aviamasters™
Master the mission in BGamings viral banger! Set the bet and pace for your aircraft, and watch it soar through the sky, encountering random multipliers and rockets on its way. The gameplay will keep …
[Learn More](https://bgaming.com/games/aviamasters)
### Hot Chilli Bells
Simple mechanics, adjustable paylines with dynamic stake options, and an anticipation-filled Hold & Win Bonus game with multipliers and a progress bar make for a genuine online slot that brings togeth…
[Learn More](https://bgaming.com/games/hot-chilli-bells)
### Snoop Dogg Dollars
Drop the beat for BGamings first celebrity-branded slot featuring the legendary Snoop Dogg as the narrator and animated character! From the groovy hip-hop soundtrack to each carefully drawn-out detai…
[Learn More](https://bgaming.com/games/snoop-dogg-dollars)
### Wild Tiger
This Asian-inspired 5×4 online slot features graceful animal symbols, Scatters, and Wilds, with an option to switch between 20, 40, 60, 80, or 100 paying lines.
[Learn More](https://bgaming.com/games/wild-tiger)
### Bonanza Billion
BGaming is delighted to launch Bonanza Billion, the brands first title with cascading reels that allow players to make their experience more exciting!
[Learn More](https://bgaming.com/games/bonanza-billion)
### Hot Chilli Bells 100
The bells are jingling and the chilis are sizzling in Hot Chilli Bells 100, BGamings seasonal twist on a fan-favorite slot. Celebrate the festive period with expanding…
[Learn More](https://bgaming.com/games/hot-chilli-bells-100)
### Aviamasters™
Master the mission in BGamings viral banger! Set the bet and pace for your aircraft, and watch it soar through the sky, encountering random multipliers and rockets on its way. The gameplay will keep …
[Learn More](https://bgaming.com/games/aviamasters)
### Burning Chilli X
Its getting hot in here! BGaming has just produced a new Burning Chilli X slot!
[Learn More](https://bgaming.com/games/burning-chilli-x)
### Wild Tiger
This Asian-inspired 5×4 online slot features graceful animal symbols, Scatters, and Wilds, with an option to switch between 20, 40, 60, 80, or 100 paying lines.
[Learn More](https://bgaming.com/games/wild-tiger)
### Hot Chilli Bells
Simple mechanics, adjustable paylines with dynamic stake options, and an anticipation-filled Hold & Win Bonus game with multipliers and a progress bar make for a genuine online slot that brings togeth…
[Learn More](https://bgaming.com/games/hot-chilli-bells)
### Plinko 2
“You get to play Plinko your way” — thats the essence of this game. A unique spin on the classic Plinko experience, featuring multiplier madness you wont find elsewhere. With customizable gameplay, …
[Learn More](https://bgaming.com/games/plinko-2)
### Burning Chilli 243
Turn up the heat with Burning Chilli 243 — the blazing new chapter in classic slot excitement from BGaming! The beloved title now features 243 ways to win, giving more chances to hit big. With a high-…
[Learn More](https://bgaming.com/games/burning-chilli-243)
### Lady Wolf Moon
The Lady Wolf Moon slot is an excellent example of a well-developed and modern game. Take all the generous gifts hidden within this 5×3 slot machine!
[Learn More](https://bgaming.com/games/lady-wolf-moon)
### Wild Cash
Shiny classic 3×3 slot with just 5 paylines, but offering exciting potential with generous winning possibilities and features like a Bonus game with multipliers and Buy Bonus. Join the hunt for Wild C…
[Learn More](https://bgaming.com/games/wild-cash)
### Burning Chilli X
Its getting hot in here! BGaming has just produced a new Burning Chilli X slot!
[Learn More](https://bgaming.com/games/burning-chilli-x)
### Wild Tiger
This Asian-inspired 5×4 online slot features graceful animal symbols, Scatters, and Wilds, with an option to switch between 20, 40, 60, 80, or 100 paying lines.
[Learn More](https://bgaming.com/games/wild-tiger)
### Balloon Mania
How about a relaxing low-volatility game with simple but strategic gameplay? See how many clicks it will take you to pop balloons with a variety of multipliers, including the max win of x64, and mello…
[Learn More](https://bgaming.com/games/balloon-mania)
### Plinko 2
“You get to play Plinko your way” — thats the essence of this game. A unique spin on the classic Plinko experience, featuring multiplier madness you wont find elsewhere. With customizable gameplay, …
[Learn More](https://bgaming.com/games/plinko-2)
### Joker's Million
No wonder these reels scream “ENTERTAINMENT”: their ringmaster is the Joker herself! If you love a classic gambling session and are open to trying a fresh interpretation of a fruit slot with an iconic…
[Learn More](https://bgaming.com/games/jokers-million)
### Aviamasters™
Master the mission in BGamings viral banger! Set the bet and pace for your aircraft, and watch it soar through the sky, encountering random multipliers and rockets on its way. The gameplay will keep …
[Learn More](https://bgaming.com/games/aviamasters)
### Plinko
Plinko, in fact, is extremely elementary and random. There are no specific betting strategies, but many fans have been enjoying it for years. One helpful trick you can try, though, is tracking the liv…
[Learn More](https://bgaming.com/games/plinko)
### Hot Chilli Bells
Simple mechanics, adjustable paylines with dynamic stake options, and an anticipation-filled Hold & Win Bonus game with multipliers and a progress bar make for a genuine online slot that brings togeth…
[Learn More](https://bgaming.com/games/hot-chilli-bells)
### Burning Chilli X
Its getting hot in here! BGaming has just produced a new Burning Chilli X slot!
[Learn More](https://bgaming.com/games/burning-chilli-x)
### Gold Rush Johnny Cash
Remember Johnny Cash the daring cowboy who are searching for money and gold? Now, you have a chance to meet him again in the new BGaming slot!
[Learn More](https://bgaming.com/games/gold-rush-with-johnny-cash)
### Lady Wolf Moon
The Lady Wolf Moon slot is an excellent example of a well-developed and modern game. Take all the generous gifts hidden within this 5×3 slot machine!
[Learn More](https://bgaming.com/games/lady-wolf-moon)
### Snoop Dogg Dollars
Drop the beat for BGamings first celebrity-branded slot featuring the legendary Snoop Dogg as the narrator and animated character! From the groovy hip-hop soundtrack to each carefully drawn-out detai…
[Learn More](https://bgaming.com/games/snoop-dogg-dollars)
### Hot Chilli Bells 100
The bells are jingling and the chilis are sizzling in Hot Chilli Bells 100, BGamings seasonal twist on a fan-favorite slot. Celebrate the festive period with expanding…
[Learn More](https://bgaming.com/games/hot-chilli-bells-100)
### Fruit Million
Fruit Million is one more classic-style slot in BGamings lineup with impressive features and one hundred paylines that can boost your winnings every second!
[Learn More](https://bgaming.com/games/fruit-million)
### Burning Chilli X
Its getting hot in here! BGaming has just produced a new Burning Chilli X slot!
[Learn More](https://bgaming.com/games/burning-chilli-x)
### Wild Tiger
This Asian-inspired 5×4 online slot features graceful animal symbols, Scatters, and Wilds, with an option to switch between 20, 40, 60, 80, or 100 paying lines.
[Learn More](https://bgaming.com/games/wild-tiger)
### Aviamasters™
Master the mission in BGamings viral banger! Set the bet and pace for your aircraft, and watch it soar through the sky, encountering random multipliers and rockets on its way. The gameplay will keep …
[Learn More](https://bgaming.com/games/aviamasters)
### Fruit Million
Fruit Million is one more classic-style slot in BGamings lineup with impressive features and one hundred paylines that can boost your winnings every second!
[Learn More](https://bgaming.com/games/fruit-million)
### Lady Wolf Moon
The Lady Wolf Moon slot is an excellent example of a well-developed and modern game. Take all the generous gifts hidden within this 5×3 slot machine!
[Learn More](https://bgaming.com/games/lady-wolf-moon)
### Plinko 2
“You get to play Plinko your way” — thats the essence of this game. A unique spin on the classic Plinko experience, featuring multiplier madness you wont find elsewhere. With customizable gameplay, …
[Learn More](https://bgaming.com/games/plinko-2)
### Wild Cash x9990
Dreaming of something light and summer-like? The slot Wild Cash x9990 is definitely what you need!
[Learn More](https://bgaming.com/games/wild-cash-x9990-branded)
[Full list of geos and top games](https://bgaming.com/wp-content/uploads/2026/03/Top-Games-by-GEO-Sales-5.pdf)
## games with Asian theme
All Slots Casual
### Infinity Pull
Welcome to the endless card hunt, where theres always another waifu to unlock and add to your collection! Choose your companion in this gacha-style adventure and create your own way to play with a va…
[Learn More](https://bgaming.com/games/infinity-pull)
### Dragon's Crash
In this casual crash game, players place a bet and observe the win multiplier increase as coins fall from above near the sleeping dragon. They can cash out at any point, but the round concludes if thi…
[Learn More](https://bgaming.com/games/dragons-crash)
### Lucky Lu
Meet Xin, Beibei, and their uncle Lu, who has been saving up a fortune in his lucky pot his whole life and is finally ready to share it with players like you! Look for treasures in the Bonus game with…
[Learn More](https://bgaming.com/games/lucky-lu)
### Sakura Riches 60
Discover the beauty of Sakura Riches 60, where every spin brings you closer to an Oriental paradise. With 60 paylines and beautiful AI-polished visuals, the game combines simple, balanced gameplay, en…
[Learn More](https://bgaming.com/games/sakura-riches-60)
### Dragon Age Hold & Win
This 5×3 Asian-inspired slot features 2 Bonus games: Free Spins, triggered by 3+ Scatter symbols on reels 1-3-5, and Gold Respin, activated by 6+ Coin drops both in the main game and in the Free Spins…
[Learn More](https://bgaming.com/games/dragon-age-hold-win)
### Panda Luck
This 3×3 slot features Asian symbols on a 3×3 grid with a Panda hero as a Bonus symbol. When 3+ Pandas land, the game turns these symbols into sticky ones and triggers 3 respins, resetting each time a…
[Learn More](https://bgaming.com/games/panda-luck)
### Lucky Dragon MultiDice X
This Asian 5×3 slot shines with its special MultiDice X feature. Whenever 2+ Dragon Dice symbols drop, they roll, revealing their values and multiplying the initial bet. To trigger it immediately, pla…
[Learn More](https://bgaming.com/games/lucky-dragon-multidice-x)
### God of Wealth Hold And Win
This Asian-themed slot features the Chinese god of money and wealth Caishen, who grants players Wilds, Scatters, and free spins with 3-reel Giant symbols. The Hold & Win feature boasts Coin symbols wi…
[Learn More](https://bgaming.com/games/god-of-wealth-hold-and-win)
### Wild Tiger
This Asian-inspired 5×4 online slot features graceful animal symbols, Scatters, and Wilds, with an option to switch between 20, 40, 60, 80, or 100 paying lines.
[Learn More](https://bgaming.com/games/wild-tiger)
### 3 Kings Scratch
3 Kings Scratch consists of Green, Purple, and Red games, each with different bet values and playing layouts that players can switch in-game. At the start, one identical field for all titles gives pla…
[Learn More](https://bgaming.com/games/3-kings-scratch)
### Lucky Lu
Meet Xin, Beibei, and their uncle Lu, who has been saving up a fortune in his lucky pot his whole life and is finally ready to share it with players like you! Look for treasures in the Bonus game with…
[Learn More](https://bgaming.com/games/lucky-lu)
### Sakura Riches 60
Discover the beauty of Sakura Riches 60, where every spin brings you closer to an Oriental paradise. With 60 paylines and beautiful AI-polished visuals, the game combines simple, balanced gameplay, en…
[Learn More](https://bgaming.com/games/sakura-riches-60)
### Dragon Age Hold & Win
This 5×3 Asian-inspired slot features 2 Bonus games: Free Spins, triggered by 3+ Scatter symbols on reels 1-3-5, and Gold Respin, activated by 6+ Coin drops both in the main game and in the Free Spins…
[Learn More](https://bgaming.com/games/dragon-age-hold-win)
### Panda Luck
This 3×3 slot features Asian symbols on a 3×3 grid with a Panda hero as a Bonus symbol. When 3+ Pandas land, the game turns these symbols into sticky ones and triggers 3 respins, resetting each time a…
[Learn More](https://bgaming.com/games/panda-luck)
### God of Wealth Hold And Win
This Asian-themed slot features the Chinese god of money and wealth Caishen, who grants players Wilds, Scatters, and free spins with 3-reel Giant symbols. The Hold & Win feature boasts Coin symbols wi…
[Learn More](https://bgaming.com/games/god-of-wealth-hold-and-win)
### Wild Tiger
This Asian-inspired 5×4 online slot features graceful animal symbols, Scatters, and Wilds, with an option to switch between 20, 40, 60, 80, or 100 paying lines.
[Learn More](https://bgaming.com/games/wild-tiger)
### Book of Panda MEGAWAYS™
Powered by MEGAWAYS™ and Book mechanics, this oriental slot boasts a single symbol for both Wild and Scatter, an engaging Free Spins round that includes an Expanding symbol and x2 to x10 multipliers, …
[Learn More](https://bgaming.com/games/book-of-panda-megaways-tm)
### Adventures
This anime RPG slot showcases Bonanza mechanics with a cycle system. Every 10 spins, winning combinations reduce a monsters HP. Once its down to zero, one of 3 Bonus games is triggered. Using Buy Bo…
[Learn More](https://bgaming.com/games/adventures)
### 3 Kings Scratch
3 Kings Scratch consists of Green, Purple, and Red games, each with different bet values and playing layouts that players can switch in-game. At the start, one identical field for all titles gives pla…
[Learn More](https://bgaming.com/games/3-kings-scratch)
### Alchemist Bonanza
In this slot you will see an old man alchemist and hear the sound of turning pages of his book of secret recipes.
[Learn More](https://bgaming.com/games/alchemist-bonanza)
### Alice WonderLuck
Start your extraordinary adventure full of wonders and magical surprises, allowing every spin to be an amazing discovery! Modern art with surreal elements, a reinterpretation of world-beloved characte…
[Learn More](https://bgaming.com/games/alice-wonderluck)
### Infinity Pull
Welcome to the endless card hunt, where theres always another waifu to unlock and add to your collection! Choose your companion in this gacha-style adventure and create your own way to play with a va…
[Learn More](https://bgaming.com/games/infinity-pull)
### Dragon's Crash
In this casual crash game, players place a bet and observe the win multiplier increase as coins fall from above near the sleeping dragon. They can cash out at any point, but the round concludes if thi…
[Learn More](https://bgaming.com/games/dragons-crash)
## CASUAL GAMES BY BGAMING
Casual games are simple, easy-to-play online games with no special skills required, designed for a wide audience. Like video poker and other table games, they offer quick, big wins, making them highly engaging and appealing.
[All Casual games](https://bgaming.com/games?types=casual)
### Penalty Duel
Hot sand, scorching sun, and samba tunes make up memories of a summer you wont forget! Become a kicker or goalkeeper in this beach football game, switching to the golden ball or golden gloves for a c…
[Learn More](https://bgaming.com/games/penalty-duel)
### Aviamasters™
Master the mission in BGamings viral banger! Set the bet and pace for your aircraft, and watch it soar through the sky, encountering random multipliers and rockets on its way. The gameplay will keep …
[Learn More](https://bgaming.com/games/aviamasters)
### Golden Pinata Hold and Win
Every day is a cause for celebration, and this fun-tastic slot is a great way to live it up! Break the colorful pinata with your tool of choice, treating yourself to smashing wins and opportunities to…
[Learn More](https://bgaming.com/games/golden-pinata-hold-and-win)
## BRANDED GAMES
Weve taken game customization to the next level by partnering with both clients and celebrities to create unique gaming experiences. This new direction lets us blend personalized games with the excitement of celebrity involvement, making them more engaging for a wide range of players.
A great example is our collaboration with Roobet and Snoop Dogg on our first celebrity-branded slot, Snoop Dogg Dollars. With Snoop Dogg as the main game character and narrator and powered by Strmlytics AI, we created a slot that not only uses advanced gameplay features but also incorporates Snoops style. This shows how we can combine top technology with star power to create something truly special.
## Collaboration with local game studios
BGaming works with local game studios worldwide, including in Asia, to create games enriched by regional expertise and player insights. Such partnerships allow for a deeper understanding of player preferences and behavior in each market. Notable collaborations include Keepers Of The Secret and Grand Patron with 7Rings, Robospin with NowNow, and Lucky 8 Merge Up™ and Fishing Club with Creme.team. And were just getting started, lets create something amazing together!
Contact us
## GAME CUSTOMIZATION
At BGaming, we know that every player is unique, and so should their gaming experience! Thats why we offer customizable games that can be tailored just for your online casino platform and your audience. Whether youre looking to make small adjustments or want a completely exclusive game, our customization options allow you to connect with your players in a personal way.
Heres what we can customize:
Logos In-game symbols Start page Visual layouts Big win pop-ups RTP Game name Game design with unique features
## LETS CONNECT!
Would you like to start fruitful cooperation? Fill out the form below, and we will contact you shortly with an exclusive offer!
Stable Games Ltd, having its registered address at 206, Wisely house, Old Bakery Street, Valletta VLT 1451, Malta, is licensed and regulated by the Malta Gaming Authority to supply Type1 gaming services under a B2B Critical Gaming Supply Licence (Licence Number: MGA/B2B/785/2020, issued on 18th March 2021).© 2026 All Rights Reserved. BGaming is a registered trademark.
You can read the [Privacy Policy](https://bgaming.com/privacy-policy)
## LETS CONNECT!
Would you like to start fruitful cooperation? Fill out the form below, and we will contact you shortly with an exclusive offer!
[info@bgaming.com](mailto:info@bgaming.com?subject=General%20questions)
Stable Games Ltd, having its registered address at 206, Wisely house, Old Bakery Street, Valletta VLT 1451, Malta, is licensed and regulated by the Malta Gaming Authority to supply Type1 gaming services under a B2B Critical Gaming Supply Licence (Licence Number: MGA/B2B/785/2020, issued on 18th March 2021).
© 2025 All Rights Reserved. BGaming is a registered trademark.You can read the [Privacy Policy](https://bgaming.com/privacy-policy)
You are leaving bgaming.com.
Please note that the content of a website may be 18+. We are not responsible for the website you are going to visit. By clicking on the link, you agree to these conditions.
Stay here
Continue

Some files were not shown because too many files have changed in this diff Show More