Files
new-api-key-usage/docs/design/purchases表字段设计.md
T
skycurtain 45b312b357 docs: 设计文档体系落定(七篇定稿)
- docs/design:四张表字段设计 · 交互设计(方向层 + 细节层)· API 契约 · 同步引擎设计
- docs/upstream:sk-key 接口实证(430 行)· 接口范围(9 个接口)
- README(全景入口)· AGENTS.md(AI 协作者指引)
- 废弃旧稿已删除(不随仓库留存)
2026-09-14 23:54:52 +08:00

6.8 KiB
Raw Blame History

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 ↔ 已录入记录比对)的交互 交互设计