21 lines
24 KiB
JSON
21 lines
24 KiB
JSON
{"role":"user","message":{"content":[{"type":"text","text":"<user_query>\nSearch the slot monorepo for implementation related to \"首充前免费余额定格与分档释放\" / free credits freeze before first deposit / tiered release. Look in slot_wallet, slot_user, slot_pay, backend, slot-foundation, slot_lib, etc.\n\nFind:\n1. Key files, classes, services (e.g. FreeCredits, FrozenBalance, ReleaseTier, first deposit)\n2. API endpoints mentioned in requirements\n3. Database migrations/models\n4. What's implemented vs stub/TODO\n\nReturn a structured summary with file paths and brief description of each component found. Note any TODO/FIXME or missing pieces.\n</user_query>"}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"Searching the monorepo for free-credits freeze and tiered-release implementation.\n\n[REDACTED]"},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Searching free credits implementation"}},{"type":"tool_use","name":"Grep","input":{"pattern":"FreeCredits|FrozenBalance|ReleaseTier|free_credits|freeCredits","path":"/Users/ray/Documents/project/www/slot","-i":true}},{"type":"tool_use","name":"Grep","input":{"pattern":"首充|定格|分档释放|frozen.*balance|tiered.*release","path":"/Users/ray/Documents/project/www/slot","-i":true}},{"type":"tool_use","name":"Grep","input":{"pattern":"first.?deposit|firstDeposit|FirstDeposit","path":"/Users/ray/Documents/project/www/slot","-i":true}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"free.?credits|FreeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot","-i":true,"glob":"*.{php,vue,ts,js,sql,md}"}},{"type":"tool_use","name":"Grep","input":{"pattern":"TODO|FIXME|stub|未实现|待实现","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"*FreeCredits*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md"}},{"type":"tool_use","name":"Glob","input":{"glob_pattern":"**/*FreeCredits*","target_directory":"/Users/ray/Documents/project/www/slot"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"FreeCredits|free-credits|free_credits","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/route*.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|free_credits|FreeCredits","path":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"type":"tool_use","name":"Grep","input":{"pattern":"/api/|innerapi/|POST|GET","path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","head_limit":80}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/controller/FreeCreditsController.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"FreeCredits|freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_console"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/model/common/FreeCreditsPlayerModel.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/model/common/FreeCreditsPackageModel.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/db/install.sql","offset":30,"limit":60}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php","offset":555,"limit":120}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Glob","input":{"glob_pattern":"**/route/**","target_directory":"/Users/ray/Documents/project/www/slot/slot_console"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|FreeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot/slot_wallet","glob":"**/*"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/innerapi/controller/FreeCreditsController.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php","offset":60,"limit":90}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php","offset":80,"limit":40}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/.cursor/plans/free_credits_release_902566c9.plan.md"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|FreeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot/backend"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim|WALLET_TYPE_FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","offset":700,"limit":250}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/command/EventBus.php","offset":115,"limit":35}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/validator/FreeCreditsValidator.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"接口|API|/api/|innerapi","path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","head_limit":60}},{"type":"tool_use","name":"Grep","input":{"pattern":"FreeCredits|free_credits|freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_gateway"}},{"type":"tool_use","name":"Glob","input":{"glob_pattern":"**/*route*","target_directory":"/Users/ray/Documents/project/www/slot/slot_console"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim","path":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"type":"tool_use","name":"Grep","input":{"pattern":"TYPE_FREE_CREDITS|free_credit|FreeCredits","path":"/Users/ray/Documents/project/www/slot/slot_pay"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/config/route.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|FreeCredits","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_lib/src/services/WalletService.php","offset":1,"limit":200}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_pay/app/entity/WithdrawalOrderEntity.php","offset":55,"limit":90}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credit|FreeCredits|TYPE_FREE_CREDITS|free_credits","path":"/Users/ray/Documents/project/www/slot/slot-foundation"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim|FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api"}},{"type":"tool_use","name":"Grep","input":{"pattern":"FreeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot/slot_pwa"}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credits|FreeCredits|TYPE_FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/napi/controller/LobbyController.php","offset":60,"limit":30}},{"type":"tool_use","name":"Grep","input":{"pattern":"TODO|FIXME|@todo","path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|FreeCredits","path":"/Users/ray/Documents/project/www/slot/slot_wallet","type":"php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"case.*freeCredits|WALLET_TYPE_FREE","path":"/Users/ray/Documents/project/www/slot"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","offset":1040,"limit":100}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim","path":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"type":"tool_use","name":"Glob","input":{"glob_pattern":"**/WalletController.php","target_directory":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"type":"tool_use","name":"Grep","input":{"pattern":"innerapi.*free|FreeCredits","path":"/Users/ray/Documents/project/www/slot"}},{"type":"tool_use","name":"Grep","input":{"pattern":"tests.*[Ff]ree[Cc]redits|FreeCredits","path":"/Users/ray/Documents/project/www/slot"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"function update|freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/controller/WalletController.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"RechargeEvent|recharge.*Event","path":"/Users/ray/Documents/project/www/slot/slot_pay"}},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config|win_threshold|recharge_unlock","path":"/Users/ray/Documents/project/www/slot"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/controller/WalletController.php","offset":30,"limit":80}},{"type":"tool_use","name":"Grep","input":{"pattern":"TYPE_FREE_CREDITS|type.*11|free.?credit","path":"/Users/ray/Documents/project/www/slot/backend","-i":true}},{"type":"tool_use","name":"Grep","input":{"pattern":"innerapi/free|FreeCredits","path":"/Users/ray/Documents/project/www/slot/backend"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim|FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_pay/app/entity/WithdrawalOrderEntity.php","offset":115,"limit":50}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_pay/app/entity/WithdrawalOrderEntity.php","offset":230,"limit":30}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"function run|'freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"broadcast|广播|Free Play","path":"/Users/ray/Documents/project/www/slot/slot_console"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php","offset":40,"limit":80}},{"type":"tool_use","name":"Grep","input":{"pattern":"y1|Y1|wager.*multiplier|打码倍数","path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php","-i":true}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|FreeCredits","path":"/Users/ray/Documents/project/www/slot/slot_gateway"}},{"type":"tool_use","name":"Grep","input":{"pattern":"SOURCE_TYPE_FREE|createTask","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php","head_limit":20}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php","offset":1,"limit":50}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_pay/app/command/EventWithdrawal.php","offset":95,"limit":45}},{"type":"tool_use","name":"Grep","input":{"pattern":"first_recharge_order_id|frozen_amount_qf","path":"/Users/ray/Documents/project/www/slot/slot_console"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Summarizing search findings","final_summary":"Free Credits is implemented mainly in **slot_console** (domain logic, APIs, DB), with wallet freeze/claim in **slot_wallet**/**slot_lib** and first-cashout wiring in **slot_pay**. **backend**, **slot_user**, **slot-foundation**, **slot_pwa**, and **slot_gateway** have no feature-specific code; admin UI and broadcast APIs from the requirements doc appear missing.","completed_subtitle":"Mapped free credits codebase"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"# Free Credits / 首充前免费余额定格与分档释放 — Codebase Search Summary\n\nImplementation is **concentrated in `slot_console`**, with wallet primitives in **`slot_wallet` / `slot_lib`** and first-tier cashout in **`slot_pay`**. There is **no dedicated code** in `backend`, `slot_user`, `slot-foundation`, `slot_gateway`, or `slot_pwa`. Requirements live in `/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md` (product/UI spec, not REST path list).\n\n---\n\n## 1. Key files, classes, services\n\n### `slot_console` — core domain (primary)\n\n| Path | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php` | **Main orchestrator**: status, home-withdraw unlock, first-recharge freeze, tier unlock on recharge, claim, first cashout, callback handling |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/api/controller/FreeCreditsController.php` | Client API: `status`, `claim`, `firstCashout` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/api/validator/FreeCreditsValidator.php` | Validates `package_id`, cashout fields |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/model/common/FreeCreditsPlayerModel.php` | Player pool / state machine constants (`STATUS_*`, `HOME_WITHDRAW_*`) |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/model/common/FreeCreditsPackageModel.php` | Tier rows (`TYPE_FIRST_CASH`, `TYPE_RELEASE`; `STATUS_LOCKED`…`REJECTED`) |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php` | `TYPE_FREE_CREDITS = 11`; `getFreeCreditsActiveInfo()` reads active config from `s_recharge_gift_config` + `ext_config` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/innerapi/controller/FreeCreditsController.php` | Admin stats: `statistics`, `list` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/napi/controller/LobbyController.php` | Embeds `free_credits` in lobby/config payload |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php` | On recharge success → `FreeCreditsLogic::handleRecharge()` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/command/EventBus.php` | `win`/`reward`/… → `syncHomeWithdrawUnlocked()`; cashout MQ events → `handleFirstCashoutResult()` |\n| `/Users/ray/Documents/project/www/slot/slot_console/db/install.sql` | DDL for `s_common.free_credits_player` + `free_credits_package` |\n\n**Config keys** (in `RechargeGiftConfigModel.ext_config`, read by `FreeCreditsLogic`): `win_threshold`, `recharge_unlock_amount`, `first_cash_amount`, `package_amount`, `subsequent_min_recharge`, `max_unlock_per_recharge` (and optional `*_qf` variants).\n\n**Not present as named types**: `FrozenBalance`, `ReleaseTier` — behavior is modeled as `FreeCreditsPlayerModel` + `FreeCreditsPackageModel`.\n\n---\n\n### `slot_lib` — wallet client SDK\n\n| Path | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_lib/src/services/WalletService.php` | `WALLET_TYPE_FREE_CREDITS_FREEZE` / `CLAIM`; `freeCreditsFreeze()`, `freeCreditsClaim()` → `POST api/wallet/update` |\n\n---\n\n### `slot_wallet` — wallet atomic ops\n\n| Path | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php` | `freeCreditsFreeze()` (deduct gift balance + log); `freeCreditsClaim()` (credit deposit + `createTask(..., SOURCE_TYPE_FREE)` + console bus) |\n| `/Users/ray/Documents/project/www/slot/slot_wallet/app/api/controller/WalletController.php` | `update()` dispatches by `type` string → method name |\n| `/Users/ray/Documents/project/www/slot/slot_wallet/app/model/multi/WalletLogModel.php` | `BIZ_TYPE_FREE_CREDITS_FREEZE` / `CLAIM` |\n\n---\n\n### `slot_pay` — first-tier withdrawal\n\n| Path | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_pay/app/entity/WithdrawalOrderEntity.php` | `BIZ_TYPE_FREE_CREDITS_FIRST_CASHOUT = 'free_credit_first_cashout'`; skips `withdrawFrozen` on apply; rejection → console bus |\n| `/Users/ray/Documents/project/www/slot/slot_pay/app/command/EventWithdrawal.php` | Success/fail/reject → `FreeCreditsFirstCashoutSuccess/Fail` MQ to console |\n\n---\n\n### Other repos — no Free Credits feature code\n\n| Repo | Finding |\n|------|---------|\n| `backend` | No `FreeCredits` / `free_credits` |\n| `slot_user`, `slot-foundation`, `slot_gateway`, `slot_sdk`, `slot_pwa` | None |\n| `slot_agent` | “首充” = referral fission, unrelated |\n\n---\n\n## 2. API endpoints (inferred — Webman convention routing)\n\nRequirements doc describes **screens/flows**, not literal REST paths. Implemented controllers map to typical paths:\n\n### Client (`slot_console` → `app/api/controller/FreeCreditsController.php`)\n\n| Inferred path | Method | Handler | Purpose |\n|---------------|--------|---------|---------|\n| `/api/freeCredits/status` | GET/POST | `status` | Activity + player + packages |\n| `/api/freeCredits/claim` | POST | `claim` | Claim next release tier (`package_id`) |\n| `/api/freeCredits/firstCashout` | POST | `firstCashout` | Submit tier-1 no-wager withdrawal |\n\n### NAPI lobby\n\n| Inferred path | Field | Purpose |\n|---------------|-------|---------|\n| `/napi/.../LobbyController` config | `free_credits` | Same as `status()` when user logged in |\n\n### Admin inner API (`app/innerapi/controller/FreeCreditsController.php`)\n\n| Inferred path | Handler | Purpose |\n|---------------|---------|---------|\n| `/innerapi/freeCredits/statistics` | `statistics` | Aggregate frozen/first cashout/claimed/pending |\n| `/innerapi/freeCredits/list` | `list` | Paginated players + packages |\n\n### Wallet internal (`slot_lib` → `slot_wallet`)\n\n| Path | Body `type` | Purpose |\n|------|-------------|---------|\n| `POST api/wallet/update` | `freeCreditsFreeze` | Deduct free balance at freeze |\n| `POST api/wallet/update` | `freeCreditsClaim` | Credit deposit + wager task |\n\n### Events (not HTTP)\n\n- Recharge: `RechargeEvent` → `handleRecharge(uid, wallet_amount, orderId, isFirstRecharge)`\n- Cashout: `FreeCreditsFirstCashoutSuccess|Fail|Rejected` on console `EventBus`\n- Home unlock: `win` / `reward` / … on `EventBus` → `syncHomeWithdrawUnlocked`\n\n---\n\n## 3. Database / models\n\n| Table | Model | Migration |\n|-------|-------|-----------|\n| `s_common.free_credits_player` | `FreeCreditsPlayerModel` | `/Users/ray/Documents/project/www/slot/slot_console/db/install.sql` |\n| `s_common.free_credits_package` | `FreeCreditsPackageModel` | same file |\n| Config (existing) | `RechargeGiftConfigModel` (`type=11`, `ext_config` JSON) | pre-existing recharge-gift table |\n\n**Activity link**: `activity_id` → `s_recharge_gift_config.id` (not `recharge_gift_player`).\n\n---\n\n## 4. Implemented vs missing / gaps\n\n### Implemented (substantial backend core)\n\n| Area | Status |\n|------|--------|\n| Schema + models | Done |\n| Active config via `TYPE_FREE_CREDITS` + `ext_config` | Done |\n| Home withdraw unlock when balance ≥ `win_threshold` | Done (via wallet `win` bus + `syncHomeWithdrawUnlocked`) |\n| First real recharge freeze (`balance - wallet_amount`) + wallet freeze | Done |\n| Tier split (first cash + release packages) | Done |\n| Unlock first tier when cumulative recharge ≥ threshold (`wallet.r`) | Done |\n| Unlock release tiers per recharge (`subsequent_min_recharge`, `max_unlock_per_recharge`) | Done |\n| Ordered claim + wallet credit + idempotent `claim_biz_id` | Done |\n| First-tier cashout via `slot_pay` + status sync | Done |\n| Lobby `free_credits` embed | Done |\n| InnerAPI statistics + list | Done |\n| No `TODO`/`FIXME` in Free Credits PHP files | — |\n\n### Partial / gaps vs requirements doc\n\n| Gap | Notes |\n|-----|--------|\n| **`STATUS_FROZEN` (2)** | Defined on player model + DDL comment but **never set** in logic (jumps to `DEPOSIT_PENDING` / `FIRST_CASH_READY`) |\n| **Freeze idempotency by order** | Guards on `frozen_amount_qf <= 0`, not `first_recharge_order_id` match |\n| **Y1 wager multiplier** | Doc §17 `后续档打码倍数`; claim uses fixed `WagerTaskModel::SOURCE_TYPE_FREE` in wallet, **no config-driven multiplier** |\n| **Admin config UI** | `backend/slot_admin*` has generic `ext_config` activity editor, **no type-11 / Free Credits–specific fields** |\n| **Admin stats UI** | InnerAPI exists; **no Vue/admin pages** calling it found |\n| **Broadcast feed** (doc §13) | **Not implemented** |\n| **Dedicated activity/popup APIs** | Only `status` + lobby embed; no separate “Free Play to Go” endpoint |\n| **`累计充值金额` in admin list** | Not stored on player; would need live wallet stat or join |\n| **Tests** | No `FreeCredits` tests found in monorepo |\n| **Client UI** | `slot_pwa` has zero references (expected per plan: frontend elsewhere) |\n| **Plan todo** | `.cursor/plans/free_credits_release_902566c9.plan.md` still marks `implement-console-core` as **pending** though code exists |\n\n### Repos with zero involvement\n\n`slot_user`, `slot-foundation`, `slot_gateway`, `backend` (for this feature), `slot_notification`, `slot_center`, `slot_hub`, `slot_risk`.\n\n---\n\n## 5. State machine (as coded)\n\n**Player** (`FreeCreditsPlayerModel`): \n`0 NOT_STARTED` → `1 HOME_UNLOCKED` → after freeze: `3 DEPOSIT_PENDING` or `4 FIRST_CASH_READY` → `5 FIRST_CASH_PROCESSING` → `6 FIRST_CASH_DONE` → `7 RELEASING` → `10 COMPLETED`\n\n**Package**: `LOCKED` → `READY` → `PROCESSING` → `COMPLETED` (or `REJECTED` on tier-1 audit reject)\n\n**First deposit trigger**: `RechargeEvent` + `isFirstRecharge`; freeze amount = pre-recharge free balance; config type **11** on `s_recharge_gift_config`.\n\n---\n\n## 6. Quick architecture diagram\n\n```mermaid\nflowchart LR\n RechargeMQ[RechargeEvent MQ] --> FCLogic[FreeCreditsLogic]\n WinMQ[win/reward EventBus] --> FCLogic\n FCLogic --> WalletSDK[slot_lib WalletService]\n WalletSDK --> WalletAPI[slot_wallet freeCreditsFreeze/Claim]\n FCLogic --> DB[(free_credits_player/package)]\n FCLogic --> Pay[slot_pay first cashout]\n Pay --> CashoutMQ[FreeCreditsFirstCashout* events]\n CashoutMQ --> FCLogic\n ClientAPI[api/FreeCreditsController] --> FCLogic\n Lobby[napi LobbyController] --> FCLogic\n Admin[innerapi FreeCreditsController] --> DB\n```\n\n---\n\n**Bottom line**: Backend **domain logic for freeze, tiered release, claim, and first cashout is largely in place** in `slot_console` + wallet/pay integration. **Missing** pieces are mainly **admin UI**, **broadcast**, **configurable Y1 wagering**, stricter freeze state/idempotency, and **client/frontend** (out of these repos). No `TODO`/`FIXME` markers in the Free Credits PHP files themselves.\n\n[REDACTED]"}]}} |