- docs/design:四张表字段设计 · 交互设计(方向层 + 细节层)· API 契约 · 同步引擎设计 - docs/upstream:sk-key 接口实证(430 行)· 接口范围(9 个接口) - README(全景入口)· AGENTS.md(AI 协作者指引) - 废弃旧稿已删除(不随仓库留存)
10 KiB
10 KiB
new-api-key-usage
针对 NewAPI 平台的 key 用量统计工具
定时用每个 sk-key 轮询网关日志接口,按 request_id 去重,攒全量日志到本地数据库;任意时间范围的用量查询,即一条本地聚合查询。
| 项目 | 内容 |
|---|---|
| 状态 | 实现起步(脚手架已落地:apps/web · apps/server · packages/shared;设计文档全部定稿) |
| 技术栈 | Bun + Hono + PostgreSQL · 前端 Vite + Vue 3 + naive-ui |
| 部署 | 实例运营方提供的服务器;交付方式为推送仓库 / 产物,由运营方执行部署 |
文档地图
| 文档 | 什么时候读 | 状态 |
|---|---|---|
docs/design/api_keys表字段设计.md |
数据模型第一张表:字段、语义与决策理由 | 定稿(2026-09-11;09-13 修订 key 登记与表名、新增 disabled_source) |
docs/design/usage_logs表字段设计.md |
数据模型第二张表:日志明细、去重与写入策略 | 定稿(2026-09-11) |
docs/design/purchases表字段设计.md |
数据模型第三张表:购买记录(实付人民币的唯一落点、折算链第二条) | 定稿(2026-09-13;同日修订查看面金额口径) |
docs/design/qpu_history表字段设计.md |
数据模型第四张表:换算参数时间线(自动采样、只读) | 定稿(2026-09-13) |
docs/design/交互设计.md |
界面设计:方向层 + 细节层(跨页共性、逐页细节、状态与文案) | 定稿(2026-09-13) |
docs/design/API契约.md |
前端 ↔ 服务端接口契约:约定层 + 逐页端点(前端实现看这篇) | 定稿(2026-09-13) |
docs/design/同步引擎设计.md |
采集侧引擎:调度、每轮动作、失败处理、可观测、部署初始化(后端实现看这篇) | 定稿(2026-09-13) |
docs/upstream/NewAPI-sk-key接口文档.md |
查 sk-key 可用接口的字段级事实(源码实证,430 行) | 事实依据 |
docs/upstream/NewAPI-接口范围.md |
本项目对接的接口范围(9 个接口的用途与鉴权) | 事实依据 |
- 命名与分区:目录用英文、文档名用中文;
docs/design/(我们定的方案与决策)·docs/upstream/(NewAPI 的实证事实,不做设计决策)·docs/deprecated/(已废弃的历史文档,只存档、不引用、不作依据)· 未来的docs/delivery/(给部署方看的部署文档) - 生命周期:设计文档定稿后不搬家、只改状态(草案 → 讨论中 → 待审阅 → 定稿(日期) → 已实现);被取代时删除(git 历史即考古),尚未入库的历史文档移入
docs/deprecated/
这是什么项目
- 名字直述用途:NewAPI 网关下按 key 查询用量(key usage)
- 全场景统一小写 kebab-case:仓库名 / 包名 / 文档标题一致,无大写变体
背景故事
- 本工具源于一个真实场景:NewAPI(Go + GORM 的开源 LLM 网关)实例提供订阅服务,多个使用者通过分发 API key 共享同一份订阅额度
- 项目作者是该实例的普通用户:购买了订阅额度,创建多个 sk- API key 分发给多名使用者分摊使用成本——非商业,纯成本分担
- 关键身份约束:项目作者只有 sk-key,没有实例的管理员账号。因此:
- 一切数据获取只能走 key 级接口(账号级接口用 sk-key 访问会 401)
- 工具部署在实例运营方提供的服务器上,作者不直接接触服务器——交付方式是推送仓库 / 产物,由运营方执行部署
核心需求(v2 定稿)
| # | 需求 | 说明 |
|---|---|---|
| 1 | key 用量查询 | 输入 sk-key + 时间范围 → 查模型请求日志与用量。支持一次输入多个 key 合并查询(项目作者借此获得全员视角) |
| 2 | key 登记 | 管理通道手动登记:登记后入库并加入轮询;查看面凭已登记的 key 查询(纯只读) |
明确不做的(v1 → v2 的收缩边界):费用分摊计算(后议;折算基础已就绪——两张折算表设计见文档地图)、计费周期管理、多组支持、登录页、admin 角色、会话记忆。
架构的根本动因:为什么必须本地攒数据
这不是优化选项,是上游接口的物理约束决定的唯一路径:
- sk-key 可用的接口(
/api/usage/token、/api/log/token等)返回的都是累计值或最近 1000 条,没有任何接口支持时间范围过滤 - 真正适合算"当月用量"的接口(
/api/log/self/stat,支持时间范围 + quota 汇总)需要账号登录态,sk-key 访问 401——这是"按时间段统计用量"无法纯客户端实现的核心障碍 /api/log/token硬上限 1000 条、不支持任何参数(分页 / limit / 时间过滤全被忽略)
→ 结论:轮询同步 + request_id 去重入库 + 本地数据库。上游接口的完整实证(含源码出处)见 docs/upstream/NewAPI-sk-key接口文档.md。
已定技术决策
| # | 项 | 决策 | 备注 |
|---|---|---|---|
| 1 | 部署形态 | 实例运营方提供的服务器,标准前后端 | 弃 Cloudflare Workers(v1 方案),因运营方愿意提供服务器资源 |
| 2 | 运行时 / 框架 | Bun + Hono | 单进程部署、原生 TS;Hono 轻量路由 |
| 3 | 数据库 | PostgreSQL | 服务器现有实例 |
| 4 | 鉴权 | 无 admin、无登录页;查看面凭已登记的 key 查询;管理面由 env 口令 | 写操作全部收拢在管理面(key 管理 + 折算数据);key 失效由轮询 401 自动摘除、管理面手动启停补位 |
| 5 | 信任模型 | 实例运营方(= 网关管理员 = 服务器管理员)不是威胁对象——他们本就能看到一切;真正的防护对象是第三方拖库(sk-key 应加密存库,实现时落地) | 无法在对方控制的机器上对抗对方,接受此公理 |
| 6 | 计费口径 | 展示 quota + $ 参考换算(÷500000),并支持折算为实付人民币 | 折算机制(两层时间线)见文档地图中的两张折算表设计 |
| 7 | 代码组织 | 前后端分离 monorepo(Bun workspaces:apps/web · apps/server · packages/shared) |
前后端独立部署、分别更新(2026-09-13 修订:前端静态产物独立托管;后端不托管前端产物);后端单进程(API + 同步引擎同进程、单实例);不引入 turbo 等编排工具 |
| 8 | 数据库访问 | Drizzle ORM + drizzle-kit | TS 定义 schema;迁移由 drizzle-kit 生成 |
| 9 | 前端 | Vite + Vue 3 | 页面结构与 UI 组件库选型留技术稿定 |
| 10 | 人民币折算 | 两层时间线(quota_per_unit 自动采样 + 购买记录人工登记),按购买时刻取尺 |
整笔订阅一把尺;历史永远用当时的尺子量;见文档地图中的两张折算表设计 |
| 11 | 管理通道 | /manage/* 独立路由 + env 口令;key 管理(登记 / 清单 / 启停)+ 购买记录的 CRUD + 换算参数时间线只读查看 |
本工具唯一写操作入口;查询域保持完全只读;见 docs/design/交互设计.md §0 |
关键事实清单(实测 / 源码确认,实现时不得违反)
出处均见
docs/upstream/NewAPI-sk-key接口文档.md,此处仅索引。
QuotaPerUnit = 500000:quota ÷ 500000 = 额度美元(接口①与④交叉实测吻合)——但它不是实付金额:折算到实付人民币还需乘「购买汇率」(由运营方定价、可变,历史上调整过一次)。完整折算机制见文档地图中的两张折算表设计- 去重必须用
request_id:/api/log/token返回的id是每次从 1 重编的展示序号,绝不能用于去重 created_at是 UTC Unix 秒(三字段交叉实测),北京时间输入需转换- 1000 条硬上限:窗口只保留最近 1000 条——实测当前站点的日志速率下约等于 3 天;5 分钟级同步余量充分,但同步停摆超过约 3 天会永久丢数据
TokenAuthReadOnly:用量/日志接口用宽松鉴权,key 过期 / 额度耗尽仍可查询(用完也能对账);显式禁用会被 401 拒绝(2026-09-13 源码复核)DisplayTokenStatEnabled已开启:billing 接口返回 token 级额度
工程注记
- CORS 必须由服务端代理解决(浏览器直连 NewAPI 网关会被拦)——指上游网关;本项目前后端之间的连线见下条
- 前后端连线(2026-09-13 修订):同域反代为主(
/api/*反代到后端端口——浏览器视角同源,无 CORS、前端用相对路径)、跨源直连为辅(后端 CORS 白名单可配 + 前端运行时 API base;X-Manage-Token自定义头会触发 OPTIONS 预检;凭证不进 Cookie,无需 credentials 模式) - bun runtime 跑 vue-tsc 存在已知 bug(bun#4754),类型检查与构建需解耦
下一步
- 实现:脚手架已落地(命令见
AGENTS.md)——按docs/design/API契约.md实现 11 个端点(查看面/usage-log先行),按docs/design/同步引擎设计.md实现采集引擎 - 部署前确认清单(开工前向实例运营方确认):服务器 OS / PostgreSQL 实例连接方式 / 有无反代与能否配置
/api反代规则 / Bun 可安装性 / 后端必须单实例运行(同步引擎前提) - 后议功能:充值折算、多订阅实测等见两张折算表设计文档的「待定事项」