feat(wallet): 连续15天无活跃账户金币+现金自动清零 #137

Open
liujiahui wants to merge 1 commits from feat/inactive-account-clear into main
Member

功能

新增进程内定时任务:每天北京 0 点后扫描,对连续无活跃满 15 整天(既没发起比价、也没发起领券)的用户,清空其金币金币兑换现金;邀请奖励金物理隔离不动,每笔清零写 inactive_clear 流水可逐笔回溯。

关键设计

  • 活跃口径 = 发起比价 + 发起领券(real_compare_start / real_coupon_start / claim_started)。单纯登录不算活跃——光打开 App、不用核心功能视为流失。⚠️ 与 admin 大盘 DAU / 后台「最近活跃」列不同(那两处含登录),此处刻意去掉。
  • 新用户保护:注册未满 15 天(created_at)豁免,不会刚注册(有礼金)就被清。
  • workerdaily_exchange_worker 结构:文件锁同机互斥 + 北京日切(rewards.cn_today()) + 启动补跑。
  • 只扫有余额账户 + 清零走 grant_coins/grant_cash 负数入账 → 天然幂等(清完为 0 下轮跳过);grant_coins 负数不动 total_coin_earned,grant_cash 不碰邀请金。
  • 循环内读实时余额 + 行锁(lock=True)清零,防"算活跃集合→逐行清"间隙并发变动(如看广告发币)导致清不干净。
  • days = max(1, days) 钳位,防误配 0 导致全员清空。
  • 复用现有表,无需 Alembic 迁移(biz_type 自由字符串)。

开关 (config)

  • INACTIVE_CLEAR_ENABLED(默认 True)
  • INACTIVE_CLEAR_DAYS(默认 15,语义=满 15 整天之后清:最后活跃第 15 天仍留、第 16 天起清)
  • INACTIVE_CLEAR_CHECK_INTERVAL_SEC(默认 600)

测试

本地 10 个单元测试全过(清零 / 邀请金隔离两面 / 登录不算活跃 / 新用户保护 / 比价领券活跃 / shown 不算 / 满15天边界 / dry_run / days 防御)。⚠️ 测试文件按要求未包含在本 PR

未做

未真机、未部署。首次上线建议先看 worker 日志(result 有 scanned/cleared/skipped_active/skipped_new_user 计数),或临时 INACTIVE_CLEAR_ENABLED=false 后手动 dry_run 核对一轮。

🤖 Generated with Claude Code

## 功能 新增进程内定时任务:每天北京 0 点后扫描,对**连续无活跃满 15 整天**(既没发起比价、也没发起领券)的用户,清空其**金币**与**金币兑换现金**;邀请奖励金物理隔离不动,每笔清零写 `inactive_clear` 流水可逐笔回溯。 ## 关键设计 - **活跃口径 = 发起比价 + 发起领券**(`real_compare_start` / `real_coupon_start` / `claim_started`)。**单纯登录不算活跃**——光打开 App、不用核心功能视为流失。⚠️ 与 admin 大盘 DAU / 后台「最近活跃」列不同(那两处含登录),此处刻意去掉。 - **新用户保护**:注册未满 15 天(`created_at`)豁免,不会刚注册(有礼金)就被清。 - **worker** 照 `daily_exchange_worker` 结构:文件锁同机互斥 + 北京日切(`rewards.cn_today()`) + 启动补跑。 - **只扫有余额账户** + 清零走 `grant_coins`/`grant_cash` 负数入账 → 天然幂等(清完为 0 下轮跳过);`grant_coins` 负数不动 `total_coin_earned`,`grant_cash` 不碰邀请金。 - **循环内读实时余额 + 行锁**(`lock=True`)清零,防"算活跃集合→逐行清"间隙并发变动(如看广告发币)导致清不干净。 - `days = max(1, days)` 钳位,防误配 0 导致全员清空。 - 复用现有表,**无需 Alembic 迁移**(`biz_type` 自由字符串)。 ## 开关 (config) - `INACTIVE_CLEAR_ENABLED`(默认 True) - `INACTIVE_CLEAR_DAYS`(默认 15,语义=满 15 整天之后清:最后活跃第 15 天仍留、第 16 天起清) - `INACTIVE_CLEAR_CHECK_INTERVAL_SEC`(默认 600) ## 测试 本地 10 个单元测试全过(清零 / 邀请金隔离两面 / 登录不算活跃 / 新用户保护 / 比价领券活跃 / shown 不算 / 满15天边界 / dry_run / days 防御)。⚠️ 测试文件按要求**未包含在本 PR**。 ## 未做 未真机、未部署。首次上线建议先看 worker 日志(`result` 有 scanned/cleared/skipped_active/skipped_new_user 计数),或临时 `INACTIVE_CLEAR_ENABLED=false` 后手动 `dry_run` 核对一轮。 🤖 Generated with [Claude Code](https://claude.com/claude-code)
liujiahui added 1 commit 2026-07-15 19:47:37 +08:00
新增进程内定时任务:每天北京0点后扫描,对连续无活跃满15整天(既没发起比价、
也没发起领券)的用户,清空金币与金币兑换现金;单纯登录不算活跃,邀请奖励金物理
隔离不动,每笔清零写 inactive_clear 流水可逐笔回溯。

- 活跃口径=发起比价 real_compare_start + 发起领券 real_coupon_start/claim_started
  (登录 last_login_at 不算);新用户靠 created_at 兜底(注册未满15天豁免,不会刚注册就被清)
- worker 照 daily_exchange_worker 结构:文件锁同机互斥 + 北京日切 + 启动补跑
- 只扫有余额账户,清零走 grant_coins/grant_cash 负数入账 → 天然幂等
- 循环内读实时余额 + 行锁清零防并发;days<1 钳位防误配全员清空
- 新增 INACTIVE_CLEAR_ENABLED/DAYS/CHECK_INTERVAL_SEC 三开关(默认开,15天)
- 复用现有表无需迁移

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Checking for merge conflicts…
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/inactive-account-clear:feat/inactive-account-clear
git checkout feat/inactive-account-clear
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WonderableAI/shaguabijia-app-server#137