Files
cursor/plans/weekly cashback-215d598c.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

109 lines
7.2 KiB
Markdown
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.

<!-- 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>