ok
This commit is contained in:
115
plans/Reward Pool V1-2a311123.plan.md
Normal file
115
plans/Reward Pool V1-2a311123.plan.md
Normal file
@@ -0,0 +1,115 @@
|
||||
<!-- 2a311123-9045-4246-b265-7e37ecfbf924 -->
|
||||
---
|
||||
todos:
|
||||
- id: "ddl"
|
||||
content: "编写 reward_pool / reward_pool_item 建表 DDL(AUTO_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/admin:RewardPool(Item)Controller/Logic/Validate(saithink 范式)+ 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.4(reward_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]
|
||||
```
|
||||
Reference in New Issue
Block a user