Files
cursor/projects/Users-ray-Documents-project-www-slot-backend/agent-transcripts/76a4b1e9-2bfd-4a5c-9ee7-61b02fbc08c6/subagents/e9b2b1ea-4347-434c-91f6-4d81788521a6.jsonl
2026-05-21 18:16:26 +08:00

19 lines
24 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

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

{"role":"user","message":{"content":[{"type":"text","text":"<user_query>\nSearch the slot monorepo for implementation related to \"首充前免费余额定格与分档释放\" / free credits freeze / tiered release before first deposit. Look in backend, slot_wallet, slot_user, slot_pay, slot_gateway, slot_sdk, etc.\n\nFind:\n1. Key files, classes, services implementing this feature\n2. Database migrations or models (frozen balance, release tiers, etc.)\n3. API endpoints\n4. Any TODO/FIXME or incomplete stubs\n\nReturn a structured summary with file paths and what each implements. Search for keywords: free_credits, frozen, freeze, release_tier, first_deposit, 首充, 定格, 分档释放, FreeCredits, etc.\n\nWorkspace roots include:\n- /Users/ray/Documents/project/www/slot/backend\n- /Users/ray/Documents/project/www/slot/slot_wallet\n- /Users/ray/Documents/project/www/slot/slot_user\n- /Users/ray/Documents/project/www/slot/slot_pay\n- /Users/ray/Documents/project/www/slot/docs\n\nBe thorough - check requirements doc references if found in code comments.\n</user_query>"}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"Searching the monorepo for free-credits freeze and tiered-release implementation across backend services.\n\n[REDACTED]"},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Searching free credits freeze"}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credits|FreeCredits|freeCredits","path":"/Users/ray/Documents/project/www/slot","-i":true}},{"type":"tool_use","name":"Grep","input":{"pattern":"release_tier|releaseTier|ReleaseTier","path":"/Users/ray/Documents/project/www/slot","-i":true}},{"type":"tool_use","name":"Grep","input":{"pattern":"frozen|freeze|定格","path":"/Users/ray/Documents/project/www/slot","glob":"*.{php,go,ts,js,vue,sql,md}","-i":true,"head_limit":150}},{"type":"tool_use","name":"Grep","input":{"pattern":"first_deposit|firstDeposit|首充|分档释放","path":"/Users/ray/Documents/project/www/slot","-i":true,"head_limit":150}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"FreeCredits|free_credits|freeCredits","path":"/Users/ray/Documents/project/www/slot","output_mode":"files_with_matches"}},{"type":"tool_use","name":"Grep","input":{"pattern":"TODO|FIXME|XXX|stub|未实现|待实现","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"*FreeCredits*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim|FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot"}},{"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","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/route*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"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/db/install.sql","offset":30,"limit":80}},{"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":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/controller/FreeCreditsController.php"}},{"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/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":"Grep","input":{"pattern":"FreeCredits|freeCredits|free_credits","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/*.{php,json,yml,yaml}"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Glob","input":{"glob_pattern":"**/route*.php","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/backend"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php","offset":555,"limit":120}},{"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/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php","offset":60,"limit":90}}]}}
{"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","glob":"**/*"}},{"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_pay/app/entity/WithdrawalOrderEntity.php","offset":55,"limit":90}},{"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":"freeCreditsFreeze|freeCreditsClaim|free_credits","path":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"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_console/app/napi/controller/LobbyController.php","offset":60,"limit":35}},{"type":"tool_use","name":"Grep","input":{"pattern":"TYPE_FREE_CREDITS|free_credits|FreeCredits","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.{vue,ts,js,php}"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCreditsFreeze|freeCreditsClaim|WALLET_TYPE_FREE","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":"freeCredits|FreeCredits|TYPE_FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/config/**"}},{"type":"tool_use","name":"Grep","input":{"pattern":"TODO|FIXME|待实现|未实现|stub","path":"/Users/ray/Documents/project/www/slot/slot_console/app","glob":"**/*FreeCredits*"}}]}}
{"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","limit":120}},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits|case.*type","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/controller"}},{"type":"tool_use","name":"Glob","input":{"glob_pattern":"**/middleware/**/*.php","target_directory":"/Users/ray/Documents/project/www/slot/slot_console"}},{"type":"tool_use","name":"Grep","input":{"pattern":"innerapi|napi|api/","path":"/Users/ray/Documents/project/www/slot/slot_console/config"}}]}}
{"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":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_pay/app/command/EventWithdrawal.php","offset":105,"limit":35}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credits|freeCredits|FreeCredits|TYPE_FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot/docs"}},{"type":"tool_use","name":"Grep","input":{"pattern":"test.*[Ff]ree[Cc]redits|FreeCredits","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/logic/WalletLogic.php","offset":35,"limit":80}},{"type":"tool_use","name":"Grep","input":{"pattern":"LobbyController|free-credits|FreeCredits","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/*"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/config/middleware.php"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/napi/controller/LobbyController.php","limit":30}},{"type":"tool_use","name":"Grep","input":{"pattern":"class Lobby|function ","path":"/Users/ray/Documents/project/www/slot/slot_console/app/napi/controller/LobbyController.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config|win_threshold|recharge_unlock","path":"/Users/ray/Documents/project/www/slot"}},{"type":"tool_use","name":"Grep","input":{"pattern":"STATUS_FROZEN|STATUS_FROZEN","path":"/Users/ray/Documents/project/www/slot/slot_console"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credits","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.sql"}},{"type":"tool_use","name":"Grep","input":{"pattern":"SOURCE_TYPE_FREE","path":"/Users/ray/Documents/project/www/slot/slot_wallet"}},{"type":"tool_use","name":"Grep","input":{"pattern":"TYPE_FREE_CREDITS|type.*11","path":"/Users/ray/Documents/project/www/slot/backend"}},{"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":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php","limit":95}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credit|FreeCredits|freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_gateway"}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credit|FreeCredits|freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_pwa"}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credit|FreeCredits|TYPE_FREE_CREDITS","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"FREE_CREDITS|free.?credits|type.*11","path":"/Users/ray/Documents/project/www/slot/slot_console/app/entity","-i":true}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credit_first_cashout","path":"/Users/ray/Documents/project/www/slot"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php","offset":125,"limit":35}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"freeCredits","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/validator"}},{"type":"tool_use","name":"Grep","input":{"pattern":"biz_id|bizId","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php","head_limit":30}},{"type":"tool_use","name":"Grep","input":{"pattern":"addLog","path":"/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php","head_limit":5}}]}}
{"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":830,"limit":50}},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Compiling implementation summary","final_summary":"The feature lives mainly in **slot_console** (domain logic, DB, APIs) with wallet freeze/claim in **slot_wallet**, SDK client in **slot_lib**, and first-cashout wiring in **slot_pay**. **backend**, **slot_user**, **slot_gateway**, and **slot_sdk** have no Free Credits code; requirements are only in docs. No dedicated tests or admin UI for type 11 were found; the dev plan still marks console core as pending despite substantial implementation.","completed_subtitle":"Mapped free credits implementation"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"## Summary: 首充前免费余额定格与分档释放 (Free Credits)\n\nImplementation is **concentrated in `slot_console`** (domain + APIs + DB). Supporting pieces are in **`slot_wallet`** (balance freeze/claim), **`slot_lib`** (wallet HTTP client), and **`slot_pay`** (first-tier cashout order type + MQ callbacks).\n\n**No matches** in: `backend/`, `slot_user/`, `slot_gateway/`, `slot_sdk/`, `slot_pwa/`, `slot_agent/`, `slot_center/`, `slot_hub/`, `slot_risk/`, `slot_notification/`.\n\nRequirements doc only: `/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md`\n\nDev plan: `/Users/ray/.cursor/plans/free_credits_release_902566c9.plan.md` (notes `implement-console-core` still **pending** despite substantial code existing)\n\n---\n\n## 1. Key files / classes / services\n\n### slot_console — core domain (orchestration)\n\n| File | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php` | **Main business logic**: activity status, home-withdraw unlock (`syncHomeWithdrawUnlocked`), first-recharge freeze (`freezeFirstRecharge`), tier package creation, recharge-driven unlock (`advanceByRecharge`), release claim, first-cashout submit + result 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 `type` |\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 helpers |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php` | `TYPE_FREE_CREDITS = 11`; `getFreeCreditsActiveInfo()` loads active config from `s_recharge_gift_config` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/napi/controller/LobbyController.php` | Embeds `free_credits` in lobby `frontData` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/innerapi/controller/FreeCreditsController.php` | Admin/inner stats: `statistics`, `list` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php` | On recharge MQ: calls `FreeCreditsLogic::handleRecharge()` |\n| `/Users/ray/Documents/project/www/slot/slot_console/app/command/EventBus.php` | On `win`/`bonusToDeposit`/etc.: `syncHomeWithdrawUnlocked`; handles `FreeCreditsFirstCashout{Success,Fail,Rejected}` |\n\n**Config keys** (in `ext_config` JSON on `s_recharge_gift_config`): `win_threshold`, `recharge_unlock_amount`, `first_cash_amount`, `package_amount`, `subsequent_min_recharge`, `max_unlock_per_recharge` (with `_qf` variants supported).\n\n**Defaults** in logic: win $50, unlock $50, first cash $20, package $10, min subsequent recharge $10, max 1 unlock per recharge.\n\n### slot_wallet — atomic wallet ops\n\n| File | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php` | `freeCreditsFreeze()` — deduct `deposit_balance` + `withdraw_balance`; `freeCreditsClaim()` — credit deposit, create Y1 wager task (`SOURCE_TYPE_FREE = 11`) |\n| `/Users/ray/Documents/project/www/slot/slot_wallet/app/api/controller/WalletController.php` | `POST api/wallet/update` dispatches by `type` field |\n| `/Users/ray/Documents/project/www/slot/slot_wallet/app/model/multi/WalletLogModel.php` | `BIZ_TYPE_FREE_CREDITS_FREEZE` / `BIZ_TYPE_FREE_CREDITS_CLAIM` |\n\n### slot_lib — wallet SDK\n\n| File | Role |\n|------|------|\n| `/Users/ray/Documents/project/www/slot/slot_lib/src/services/WalletService.php` | `freeCreditsFreeze()`, `freeCreditsClaim()` → `POST api/wallet/update` with types `freeCreditsFreeze` / `freeCreditsClaim` |\n\n### slot_pay — first-tier cashout\n\n| File | 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** normal `withdrawFrozen` on apply |\n| `/Users/ray/Documents/project/www/slot/slot_pay/app/command/EventWithdrawal.php` | Success/fail → MQ `FreeCreditsFirstCashoutSuccess` / `FreeCreditsFirstCashoutFail` |\n| Same entity (audit reject) | MQ `FreeCreditsFirstCashoutRejected` |\n\n---\n\n## 2. Database / models\n\n**DDL** (only in install SQL, no separate migration file found):\n\n`/Users/ray/Documents/project/www/slot/slot_console/db/install.sql` (lines 3686)\n\n| Table | Purpose |\n|-------|---------|\n| `s_common.free_credits_player` | Per-user pool: `frozen_amount_qf`, `first_cash_amount_qf`, `first_recharge_order_id`, status, home unlock flag |\n| `s_common.free_credits_package` | Tiers: `package_type` (1=first cashout, 2=release), `amount_qf`, status, `withdraw_order_id`, `claim_biz_id` |\n\n**Related config table** (existing): `s_common.s_recharge_gift_config` with `type = 11` (`TYPE_FREE_CREDITS`).\n\n**Not implemented**: separate “Free Credits Pool” wallet table; pool is logical (player + package rows + deducted wallet balance).\n\n---\n\n## 3. API endpoints\n\nWebman uses **convention routing** (`config/route.php` only defines `/metrics`). Typical paths:\n\n### Client (`api` + `AuthMiddleware`)\n\n| Method / path (conventional) | Controller action | Purpose |\n|------------------------------|-------------------|---------|\n| `/api/free-credits/status` | `FreeCreditsController::status` | Full activity state + packages |\n| `/api/free-credits/claim` | `FreeCreditsController::claim` | Claim next release tier → wallet |\n| `/api/free-credits/first-cashout` | `FreeCreditsController::firstCashout` | Submit tier-1 no-wager withdrawal |\n\n### Lobby (`napi` + `NAuthMiddleware`)\n\n| Path (conventional) | Action | Purpose |\n|---------------------|--------|---------|\n| `/napi/lobby/front-data` | `LobbyController::frontData` | Returns `free_credits` alongside lobby config |\n\n### Inner admin (`innerapi` + `InnerAuthMiddleware`)\n\n| Path (conventional) | Action | Purpose |\n|---------------------|--------|---------|\n| `/innerapi/free-credits/statistics` | `statistics` | Aggregates: frozen users/amount, cashout, claimed, pending |\n| `/innerapi/free-credits/list` | `list` | Paginated player list + packages |\n\n### Wallet service (called by slot_console via slot_lib)\n\n| Path | `type` param | 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---\n\n## 4. Event / integration flow\n\n```mermaid\nflowchart LR\n recharge[Recharge MQ] --> RechargeEvent\n RechargeEvent --> FCLogic[FreeCreditsLogic.handleRecharge]\n FCLogic --> freeze[freeCreditsFreeze via slot_lib]\n FCLogic --> packages[free_credits_player/package]\n\n win[win/bonus/etc MQ] --> EventBus\n EventBus --> unlockHome[syncHomeWithdrawUnlocked]\n\n claim[API claim] --> FCLogic2[FreeCreditsLogic.claim]\n FCLogic2 --> walletClaim[freeCreditsClaim]\n\n cashout[API firstCashout] --> PayService\n PayService --> slot_pay[slot_pay withdrawal]\n slot_pay --> bus[FreeCreditsFirstCashout* MQ]\n bus --> EventBus\n```\n\n- **Freeze trigger**: first recharge (`recharge_count <= 0` before increment in `RechargeEvent`); `frozenAmount = balance_after_recharge - wallet_amount` (pre-recharge free balance).\n- **Idempotency (partial)**: skip freeze if `frozen_amount_qf > 0`; claim uses unique `claim_biz_id` on package table.\n- **Home withdraw unlock**: wallet events `win`, `bonusToDeposit`, `withdrawFrozen`, `reward`, `switchBonus`, `addBonus` → `syncHomeWithdrawUnlocked` when balance ≥ `win_threshold`.\n\n---\n\n## 5. TODO / FIXME / gaps (no literal TODOs in FreeCredits files)\n\n| Gap | Detail |\n|-----|--------|\n| **No TODO/FIXME** in `*FreeCredits*` files | Clean of explicit stubs |\n| **Plan vs code** | Plan item `implement-console-core` still **pending**; code is largely present |\n| **`STATUS_FROZEN = 2`** | Defined on `FreeCreditsPlayerModel` but **never set** in `FreeCreditsLogic` (jumps to `DEPOSIT_PENDING` / `FIRST_CASH_READY`) |\n| **Admin UI** | No `TYPE_FREE_CREDITS` / Free Credits UI in `backend/slot_admin*`; config likely manual DB/`ext_config` |\n| **Tests** | No unit/integration tests referencing FreeCredits |\n| **Frontend** | No PWA/Vue references; plan says client UI is out of repo |\n| **Deposit Lot** | Plan mentions Deposit Lot; claim only does deposit increment + `createTask(SOURCE_TYPE_FREE)` |\n| **Dedicated pool account** | No separate wallet shard for “Free Credits Pool”; balance removed from gift wallet |\n| **Wallet biz_id dedup** | `addLog` stores `biz_id` but freeze/claim paths dont show explicit duplicate-biz guard in wallet layer |\n| **Y1 multiplier config** | Doc mentions configurable Y1; code uses fixed `createTask(0, fee, SOURCE_TYPE_FREE)` |\n\n---\n\n## 6. Repos searched — result matrix\n\n| Repo | Free Credits implementation |\n|------|------------------------------|\n| **slot_console** | Full backend feature |\n| **slot_wallet** | Freeze + claim wallet ops |\n| **slot_lib** | Wallet client methods |\n| **slot_pay** | First cashout order + callbacks |\n| **docs** | Requirements only |\n| **backend** | None |\n| **slot_user** | None |\n| **slot_gateway** | None |\n| **slot_sdk** | None (only unrelated “first deposit” referral entities) |\n\n---\n\n## 7. State machine reference (implemented)\n\n**Player** (`FreeCreditsPlayerModel`): `0` not started → `1` home unlocked → `3` deposit pending / `4` first cash ready → `5` processing → `6` done → `7` releasing → `10` completed.\n\n**Package** (`FreeCreditsPackageModel`): `0` locked → `1` ready → `2` processing → `3` completed (also `4` failed, `5` rejected).\n\nIf you want next steps, the highest-value follow-ups are: admin config UI for `type=11`, aligning `STATUS_FROZEN` with the spec, automated tests for freeze idempotency and ordered claim, and confirming Webman route prefixes in your deployment config.\n\n[REDACTED]"}]}}