4ee6de2548
- CpsActivityUpdate schema + repo update_activity(部分更新,非 None 覆盖) - router 按「合并后最终值」校验平台必填项(同新建口径),写审计 cps.activity.update - 可改名/平台/对应字段/落地页图/备注/状态 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
3.8 KiB
Markdown
47 lines
3.8 KiB
Markdown
# coin_transaction — 金币流水账本
|
||
|
||
> 模型 `app/models/wallet.py` · 仓库 `app/repositories/wallet.py`(写入口 `grant_coins`) · 接口 [wallet-coin-transactions](../api/wallet-coin-transactions.md) · [← 索引](./README.md) · [总览](./OVERVIEW.md)
|
||
|
||
金币每变动一笔就记一行(记变动后余额 `balance_after`),用于对账与 App「金币明细」展示。**只增不改不删**——账本不可篡改。
|
||
|
||
## 用在哪 / 增删改查
|
||
- **C(插入)**:唯一来源是 `wallet.grant_coins`(发金币入口),被以下动作调用,每次写一笔:
|
||
|
||
| 动作 / endpoint | `biz_type` | `amount` | `ref_id` 指向 |
|
||
|---|---|---|---|
|
||
| 签到 `POST /signin/do` | `signin` | + | 当天日期串(= `signin_record.signin_date` ISO) |
|
||
| 签到后看广告膨胀 `POST /signin/boost` | `signin_boost` | + | 广告 `trans_id`(= `signin_boost_record.ad_ref_id`);无 ad_ref_id 时回退当天日期 ISO 串 |
|
||
| 领任务 `POST /tasks/claim` | `task_<key>`(如 `task_enable_notification`) | + | 一次性任务=`user_task.task_key`;可重复任务(`enable_notification`)=带序号 `task_key:N` |
|
||
| 普通激励视频 S2S 回调 `POST /ad/pangle-callback` | `reward_video`(历史兼容:`ad_reward`) | + | `ad_reward_record.trans_id` |
|
||
| 信息流广告结算 `POST /ad/feed-reward` | `feed_ad_reward` | + | `ad_feed_reward_record.client_event_id` |
|
||
| 金币兑现金 `POST /wallet/exchange` | `exchange_out` | − | null(配套 `cash_transaction.exchange_in`) |
|
||
| admin 手动加金币 | `admin_grant` | + | null(`remark`=`admin:<reason>`) |
|
||
| admin 手动扣金币 | `admin_deduct` | − | null |
|
||
|
||
> ⚠️ 比价里程碑 `comparison_milestone_claim` **当前不发币、不写本表**(产品定暂不真发,详见该表文档)。
|
||
- **U / D**:无。账本只追加。
|
||
- **R**:`GET /wallet/coin-transactions`(金币明细,`id` 倒序游标分页);admin 跨用户金币流水(可按 `biz_type` 筛)。
|
||
|
||
## 字段
|
||
| 列 | 类型 | 约束 / 默认 | 说明(取值 / join) |
|
||
|---|---|---|---|
|
||
| `id` | Integer | PK, autoincrement | |
|
||
| `user_id` | Integer | FK→user.id, index, NOT NULL | 归属用户 |
|
||
| `amount` | Integer | NOT NULL | 本笔变动金币;**正=入账(赚),负=出账(花/兑换)** |
|
||
| `balance_after` | Integer | NOT NULL | 本笔后金币余额(= 当时 `coin_account.coin_balance`,对账用) |
|
||
| `biz_type` | String(32) | NOT NULL | 取值见上表:`signin` / `signin_boost` / `task_<key>` / `reward_video` / `ad_reward`(历史) / `feed_ad_reward` / `exchange_out` / `admin_grant` / `admin_deduct`。无 DB 枚举约束,靠写入方约定 |
|
||
| `ref_id` | String(64) | nullable | **关联业务键,指向随 `biz_type` 变(见上表)**;无关联时为 null |
|
||
| `remark` | String(128) | nullable | 备注(如签到「每日签到 第N天」、admin「admin:<reason>」) |
|
||
| `created_at` | DateTime(tz) | server_default now(), index | 时间 |
|
||
|
||
## 关系 / Join Key
|
||
- `user_id` → `user.id`(多对一)。
|
||
- `ref_id` 是**软关联**(无 FK),目标随 `biz_type`:`signin`→签到日(`signin_record.signin_date` ISO) / `signin_boost`→`signin_boost_record.ad_ref_id`(无则当天日期) / `task_<key>`→一次性任务=`user_task.task_key`、可重复任务=`task_key:N` / `reward_video`/`ad_reward`→`ad_reward_record.trans_id` / `feed_ad_reward`→`ad_feed_reward_record.client_event_id` / 其余 null。
|
||
|
||
## 索引与约束
|
||
- PK `id`;index `user_id`、`created_at`。
|
||
- 部分唯一索引 `ux_coin_transaction_task_ref`(`user_id`, `biz_type`, `ref_id`),条件 `biz_type LIKE 'task%' AND ref_id IS NOT NULL`:可重复任务(如打开消息提醒)按 `ref_id` 序号(`task_key:N`)去重,挡并发/连点重复发放;仅 `task_*` 且 `ref_id` 非空生效,不影响 signin/exchange/withdraw 等其它 `biz_type`。
|
||
|
||
## 注意
|
||
- 流水与余额快照(`coin_account`)、与对应业务记录(signin/task/ad_reward/feed_ad_reward 等)在**同一事务**写,不会只发币不留痕。
|