skycurtain dcf7a31c09 chore: 本地开发 PostgreSQL(docker-compose)与环境变量样例
- docker-compose.yml:postgres:17-alpine,宿主端口 5433(避开常见 5432 占用),含 healthcheck
- .env.example:DATABASE_URL 默认指向本地 compose;KEYS_MASTER_KEY 补生成提示
2026-09-15 00:03:46 +08:00
2026-09-09 00:38:37 +08:00

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/design/实施计划.md 开发推进方案:loop 模式 + 八阶段验收标准 + 进度表 定稿(2026-09-14;进度随 loop 更新)
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 角色、会话记忆。

架构的根本动因:为什么必须本地攒数据

这不是优化选项,是上游接口的物理约束决定的唯一路径:

  1. sk-key 可用的接口(/api/usage/token、/api/log/token 等)返回的都是累计值或最近 1000 条,没有任何接口支持时间范围过滤
  2. 真正适合算"当月用量"的接口(/api/log/self/stat,支持时间范围 + quota 汇总)需要账号登录态,sk-key 访问 401——这是"按时间段统计用量"无法纯客户端实现的核心障碍
  3. /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,此处仅索引。

  1. QuotaPerUnit = 500000:quota ÷ 500000 = 额度美元(接口①与④交叉实测吻合)——但它不是实付金额:折算到实付人民币还需乘「购买汇率」(由运营方定价、可变,历史上调整过一次)。完整折算机制见文档地图中的两张折算表设计
  2. 去重必须用 request_id:/api/log/token 返回的 id 是每次从 1 重编的展示序号,绝不能用于去重
  3. created_at 是 UTC Unix 秒(三字段交叉实测),北京时间输入需转换
  4. 1000 条硬上限:窗口只保留最近 1000 条——实测当前站点的日志速率下约等于 3 天;5 分钟级同步余量充分,但同步停摆超过约 3 天会永久丢数据
  5. TokenAuthReadOnly:用量/日志接口用宽松鉴权,key 过期 / 额度耗尽仍可查询(用完也能对账);显式禁用会被 401 拒绝(2026-09-13 源码复核)
  6. 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),类型检查与构建需解耦

下一步

  1. 实现:脚手架已落地(命令见 AGENTS.md)——按 docs/design/API契约.md 实现 11 个端点(查看面 /usage-log 先行),按 docs/design/同步引擎设计.md 实现采集引擎
  2. 部署前确认清单(开工前向实例运营方确认):服务器 OS / PostgreSQL 实例连接方式 / 有无反代与能否配置 /api 反代规则 / Bun 可安装性 / 后端必须单实例运行(同步引擎前提)
  3. 后议功能:充值折算、多订阅实测等见两张折算表设计文档的「待定事项」
S
Description
No description provided
Readme MIT
1.3 MiB
Languages
TypeScript 56.4%
Vue 43.1%
Dockerfile 0.2%
Shell 0.2%
HTML 0.1%