docs(database): 补全 19 表文档 + 新增 OVERVIEW 总览
- 重写 15 张已有表文档:每张补「用在 App 哪/增删改查时机/字段取值/join key 指向」 - 新建 4 张缺失表文档:wechat_transfer_authorization / ad_watch_log / price_report / app_config - 新增 OVERVIEW.md:功能↔表映射 + 写入路径 + 表间关系(含语义 join key)+ ER + 资金模型 - README 索引补齐到 19 表 + 置顶 OVERVIEW + 通用约定补全 - 纠正过时:withdraw_order(reviewing/rejected/user_name)、savings_record(/order/report 真实写入)、coin_transaction(biz_type) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,31 +1,50 @@
|
||||
# savings_record — 省钱记录(profile 省钱战绩源)
|
||||
|
||||
> 模型 `app/models/savings.py` | 关联接口 [savings-summary](../api/savings-summary.md) / [savings-battle](../api/savings-battle.md) / [savings-records](../api/savings-records.md) | [← 表索引](./README.md)
|
||||
> 模型 `app/models/savings.py` · 仓库 `app/repositories/savings.py` · 接口 [savings-summary](../api/savings-summary.md) / [savings-battle](../api/savings-battle.md) / [savings-records](../api/savings-records.md) · 写入源 `POST /api/v1/order/report`([compare-record 相关](../api/compare-record-report.md)) · [← 索引](./README.md) · [总览](./OVERVIEW.md)
|
||||
|
||||
profile 页「累计帮你省了 / 省钱战绩 / 省钱明细」的唯一数据源:**真正下单成交后**省了多少记一行。
|
||||
profile 页「累计帮你省了 / 省钱战绩 / 省钱明细」的唯一数据源:**真正下单成交后**省了多少记一行。是「记账闭环」的落库终点——客户端比价后点结果链接跳走付款,无障碍 watcher 捕获支付成功 + 金额归因(±1 元/5 分钟窗口)→ 上报 `POST /order/report`。
|
||||
|
||||
> ⚠️ **当前为 demo 假数据**:`crud/savings.py:ensure_seeded` 按 user_id 幂等灌 ~23 条(`source='demo'`),聚合(SUM/分组/连续天数)是生产级真实计算。真数据要靠**"用户真下单"信号**(app 目前无:AI 比价止于结算页/结果展示,付款用户手动)——**不是**把比价记录 `comparison_record` 喂过来(那是"比价行为",这是"成交省钱",两个维度)。详见 [[project_shaguabijia_app_server]]。
|
||||
> **两种来源(`source` 字段区分)**:
|
||||
> - `source='compare'`:**真实下单上报**(经 `/order/report` 的 `create_from_report` 写,2026-06 已接通)。
|
||||
> - `source='demo'`:用户从无任何记录时,首次进省钱页**懒种子** `ensure_seeded` 按 user_id 幂等灌 ~23 条演示数据。
|
||||
> 统计口径:**只要有 ≥1 条 `compare` 记录,就只用 compare**(demo 全忽略);否则用 demo 兜底。聚合(SUM/分组/连续天数/分位)都是生产级真实计算。
|
||||
|
||||
## 用在哪 / 增删改查
|
||||
- **C(插入)**:
|
||||
- `POST /order/report`(`create_from_report`)→ 写一行 `source='compare'`,省额 = `original_price_cents − paid`(下限 0)。按 `(user_id, client_event_id)` 幂等,重复上报返回旧行不新增。
|
||||
- `ensure_seeded` → 用户无任何 savings 记录时,懒灌 demo(`source='demo'`),进 summary/battle/records 接口时触发。
|
||||
- **U / D**:无。
|
||||
- **R**:`GET /savings/summary`(累计省/单数/均省)、`/savings/battle`(本周省/连续天数/超过 X% 用户/比价次数)、`/savings/records`(明细分页);`comparison.py` 读本表 `shop_name`(source=compare)集合给比价记录打「已下单」。
|
||||
|
||||
## 字段
|
||||
| 列 | 类型 | 约束 / 默认 | 说明 |
|
||||
| 列 | 类型 | 约束 / 默认 | 说明(取值 / join) |
|
||||
|---|---|---|---|
|
||||
| `id` | Integer | PK, autoincrement | |
|
||||
| `user_id` | Integer | FK→user.id, index, NOT NULL | 归属用户 |
|
||||
| `order_amount_cents` | Integer | NOT NULL | 订单到手价(分) |
|
||||
| `saved_amount_cents` | Integer | NOT NULL | 本单省下(分,可为 0) |
|
||||
| `order_amount_cents` | Integer | NOT NULL | 订单到手价/实付(分) |
|
||||
| `saved_amount_cents` | Integer | NOT NULL | 本单省下(分,可为 0;= original − 实付,下限 0) |
|
||||
| `platform` | String(32) | nullable | 下单平台(美团外卖/淘宝闪购/京东外卖) |
|
||||
| `title` | String(128) | nullable | 标题 |
|
||||
| `shop_name` | String(128) | nullable | 店铺名 |
|
||||
| `title` | String(128) | nullable | 明细卡标题(compare 来源 = 门店名) |
|
||||
| `shop_name` | String(128) | nullable | 店铺名。**与 `comparison_record.store_name` 字符串相等关联**(打「已下单」) |
|
||||
| `dishes` | JSON(PG: JSONB) | NOT NULL, default [] | 菜名列表(前 2 道展示,其余"还有 N 道") |
|
||||
| `source` | String(16) | NOT NULL, default `compare` | 来源:`demo`(演示)/ `compare`(真实下单上报,待启用) |
|
||||
| `source` | String(16) | NOT NULL, default `compare` | 取值:`compare`(真实下单上报)/ `demo`(演示种子) |
|
||||
| `original_price_cents` | Integer | nullable | 源平台原价(分);compare 上报带,demo 为 null |
|
||||
| `compared_price_cents` | Integer | nullable | 我们当时给出的比价价(分,审计/备用) |
|
||||
| `pay_channel` | String(16) | nullable | 支付渠道:`wechat` / `alipay`(归因 watcher 判定) |
|
||||
| `platform_package` | String(128) | nullable | 实际下单平台包名 |
|
||||
| `source_platform_name` | String(32) | nullable | 源平台展示名(如「美团」),用于"原价 ¥X(美团)" |
|
||||
| `source_deeplink` | String(512) | nullable | 源平台重进链接(预留) |
|
||||
| `client_event_id` | String(64) | nullable | 客户端幂等键(UUID);demo 行为 null |
|
||||
| `device_id` | String(128) | nullable | 上报设备号 |
|
||||
| `created_at` | DateTime(tz) | server_default now(), index | 时间 |
|
||||
|
||||
## 关系 / Join Key
|
||||
- `user_id` → `user.id`(多对一)。
|
||||
- ≈ `comparison_record`(语义 join,无 FK):本表 `shop_name`(source=compare)== `comparison_record.store_name` → 给那条比价记录标「已下单」。注意是**店名对齐、店级**(下单上报不带 trace_id,无法逐条精确对应)。
|
||||
|
||||
## 索引与约束
|
||||
- PK: `id`;index: `user_id`、`created_at`
|
||||
- PK `id`;index `user_id`、`created_at`;UNIQUE(`user_id`, `client_event_id`) = `uq_savings_user_event`(真实上报幂等;demo 行 `client_event_id=NULL` 不参与冲突,允许多 NULL)。
|
||||
|
||||
## 关系
|
||||
- `user_id` → `user.id`(多对一)
|
||||
|
||||
## 说明
|
||||
## 注意
|
||||
- `dishes` 用 `JSON().with_variant(JSONB(),"postgresql")`(SQLite 退化 JSON)。
|
||||
- `beat_percent`(超过百分之多少用户)按各用户累计省下金额做真实分位;为有可比人群造了 5 个种子用户(`register_channel='seed'`)。
|
||||
- `beat_percent`(超过百分之多少用户)按各用户累计省下金额做真实分位,每用户口径与展示一致(有 compare 用 compare 之和,否则 demo 之和)。
|
||||
|
||||
Reference in New Issue
Block a user