- docs/design:四张表字段设计 · 交互设计(方向层 + 细节层)· API 契约 · 同步引擎设计 - docs/upstream:sk-key 接口实证(430 行)· 接口范围(9 个接口) - README(全景入口)· AGENTS.md(AI 协作者指引) - 废弃旧稿已删除(不随仓库留存)
94 lines
6.8 KiB
Markdown
94 lines
6.8 KiB
Markdown
# purchases 表字段设计
|
||
|
||
> 数据模型第三张表:购买记录——每笔支付事件(订阅购买 / 充值)一行,是「实付人民币」这一唯一只有作者知道的信息的落点,也是折算链第二层(额度美元 → 实付人民币)的事实来源。本文记录字段清单、语义与决策理由。
|
||
|
||
| 项目 | 内容 |
|
||
|------|------|
|
||
| 状态 | 定稿(2026-09-13,多轮讨论收敛;同日修订:查看面金额口径改「折算实付人民币」,§6 边界相应放开) |
|
||
| 关联 | `docs/design/qpu_history表字段设计.md`(折算链第一条:quota → 额度美元)· `docs/design/API契约.md` §2.3(登记 / 编辑端点)· `docs/upstream/NewAPI-sk-key接口文档.md`(`other.subscription_*` 字段依据) |
|
||
| 范围 | 列结构 + 语义 + 写入时机;登记入口见 API 契约 §2.3 |
|
||
| 字段数 | 9 = 1 主键 + 8 人工录入(登记 4 · 期间 2 · 订阅 2) |
|
||
|
||
---
|
||
|
||
## 1. 表定位
|
||
|
||
- **一行 = 一笔支付事件**(订阅购买 / 充值)——同一模型兼容两种形态;**实现先做订阅路径**(实测当前用量 100% 为订阅)
|
||
- **折算链全貌**:`日志.quota ÷ quota_per_unit` = 额度美元 → `× 购买汇率` = 实付人民币;两条链的系数**都取该日志所属购买的购买时刻**(整笔订阅一把尺,见 `qpu_history表字段设计.md` §3.3)。购买比率 = `paid_amount ÷ (quota_granted ÷ quota_per_unit)`——**只存事实、不存比率**(见 3.2)
|
||
- 与日志的分流:日志 `other.billing_source = "subscription"` → 按本表匹配(优先 `subscription_id`,同 ID 跨期时按时间区间);`"wallet"`(充值)→ 池子近似(后议)
|
||
- 数据规模:年个位数行(订阅按周期购买)——无需索引设计
|
||
|
||
## 2. 字段清单
|
||
|
||
### 2.1 主键与登记字段(5 个)
|
||
|
||
| 列 | 类型 | 值来源 | 说明 |
|
||
|----|------|--------|------|
|
||
| `id` | bigserial PK | 自增 | |
|
||
| `kind` | text | 人工选择 | `subscription`(订阅)/ `topup`(充值) |
|
||
| `paid_at` | timestamptz | 人工填写 | 支付时间 |
|
||
| `paid_amount` | numeric | **人工必填** | **实付人民币**——唯一「只有作者知道」的信息 |
|
||
| `note` | text | 人工填写 | 备注 |
|
||
|
||
### 2.2 期间与订阅字段(4 个)
|
||
|
||
| 列 | 类型 | 值来源 | 说明 |
|
||
|----|------|--------|------|
|
||
| `period_start` | timestamptz? | **人工录入**(钱包页面) | 仅订阅:该笔覆盖的用量期间起点;左闭 |
|
||
| `period_end` | timestamptz? | **人工录入**(钱包页面) | 期间终点;左开;未结束可空 |
|
||
| `subscription_id` | bigint? | **人工录入**(钱包页面「订阅 #N」) | 上游订阅实例 ID;多订阅并存时用于精确分流(与日志 `other.subscription_id` 匹配) |
|
||
| `quota_granted` | bigint? | **人工录入**(钱包页面「总额度」) | 本笔额度(订阅:钱包页面总额度;充值:充值记录) |
|
||
|
||
## 3. 决策记录(含理由)
|
||
|
||
### 3.1 登记 = 手工抄录(来源只有两处)
|
||
|
||
购买记录全部由作者手工录入,来源仅两处:**支付记录**(`kind` / `paid_at` / `paid_amount`)与**钱包页面**(订阅 ID / 期间 / 总额度)。订阅关键信息只有作者可见(没有免 auth 接口可查)——系统不做回填与推断,日志观测仅用于核对提示(见 §4);必填 / 可空的校验细节归技术稿。
|
||
|
||
### 3.2 折算比率不存储——存事实、不存派生数
|
||
|
||
- `paid_amount` 是唯一不可替代的人工信息;比率是派生数——「记实付」比「记汇率」更省心(不用心算)且可事后核对;只存派生比率会丢失核对依据
|
||
- **日志同样不加汇率列**(`usage_logs` 零 schema 改动):入库有滞后(1000 条窗口内可能几天后才补回)→「入库时的配置值」会错标给「更早消费的日志」,且**无从发现**;半准确的数字比没有数字更危险
|
||
- 折算全部发生在展示 / 聚合层;关联线索(`billing_source` / `subscription_id` / 金额分解)本就在日志 `other` 里,零 schema 改动即可用
|
||
|
||
### 3.3 为什么额度也手工录入(不采用日志感知)
|
||
|
||
日志逐条自带 `subscription_total`(实测),但回填它需要「订阅 ID → 该 ID 日志 total」的关联逻辑;钱包页面已直接给出总额度——手工抄录一步到位。**系统对购买记录零回填、零推断**,观测仅用于核对(见 §4)。
|
||
|
||
### 3.4 命名与类型
|
||
|
||
- 金额列用 `numeric`(人民币金额不用浮点);时间列统一 `timestamptz`
|
||
- 期间左闭右开(`[period_start, period_end)`)——与全项目期间惯例一致
|
||
- 订阅实例 ID 与日志同名 `subscription_id`——同一体系、同一含义(分流匹配即用此列)
|
||
|
||
## 4. 写入时机与维护
|
||
|
||
| 时机 | 动作 |
|
||
|------|------|
|
||
| 人工登记(管理通道) | INSERT:录入支付信息(时间 / 实付)与订阅信息(ID / 期间 / 总额度,抄自钱包页面)→ 确认 |
|
||
| 系统观测(仅核对) | 日志观测到的订阅 ID / `subscription_total` 仅作核对提示(如「观测到 #N 未对应任何购买记录」),不参与回填 |
|
||
| 编辑 / 删除 | 数据为人工登记,改错即修(见 API 契约 §2.3) |
|
||
|
||
## 5. 明确不存的(已否决字段与理由)
|
||
|
||
| 字段 | 否决理由 |
|
||
|------|----------|
|
||
| 折算比率(购买汇率) | 派生数——存事实(实付 + 额度)即可事后核对,只存比率会丢失核对依据(见 3.2) |
|
||
|
||
## 6. 展示层边界(界面设计的输入)
|
||
|
||
- **明细应展示「订阅归属」**(数据源 = 日志 `other`):订阅名称、额度实况、(本表登记后)期间范围——给所有使用者可见
|
||
- **查看面金额口径(2026-09-13 修订)**:卡片 / 明细的「消费」类金额 = **折算实付人民币**(按购买期间分段,每段 `quota 占比 × 该笔实付`);原「天然不含实付金额」的边界就此放开。**仍不上查看面**:实付总额、购买比率、购买记录(含 `note`)本身——管理面独占
|
||
- 已知代价(接受):明细含 quota 列、QPU 公开(500000 可查),使用者理论上可由两者反推购买比率——本工具是成本分担场景、非对抗关系
|
||
- 「按订阅维度统计」(本期用量/占比)数据天然支持——**待评估**,暂不列入
|
||
- 管理页相关见 `docs/design/交互设计.md` §3.3 与 `docs/design/API契约.md` §2.3
|
||
|
||
## 7. 待定事项(关联后续环节)
|
||
|
||
| 事项 | 归属 |
|
||
|------|------|
|
||
| 充值(`topup`)路径的折算近似算法 | 池子加权平均等方案,后议 |
|
||
| 多订阅并存的日志行为 | 按源码结构推理(每笔标所属 ID);实现期以真实场景实测验证 |
|
||
| 期间与订阅 ID 的匹配细节 | 技术稿细化(ID 优先、同 ID 跨期按时间) |
|
||
| 核对提示(观测到的订阅 ID ↔ 已录入记录比对)的交互 | 交互设计 |
|