Files
cpa-plugin/docs/modules/ui.md
T

262 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 管理与展示 UI 模块
## 1. 定位
UI 模块负责把数据、计费、Key 路由、配额和诊断能力投影成可使用的页面。信息架构和统计展示主要参考 `cpa-usage-keeper`Key 套餐与金额操作参考 `cpa-plugin-key-billing`
UI 不计算价格、不重新聚合账本、不保存业务真相。页面中的所有数字都来自 [api.md](api.md) 定义的权限化查询 APIUI 不直接读取 Repository 或 CPA Auth 原文。
## 2. 两种视图必须分离
### 2.1 用户视图
用户通过自己的 API Key 登录,只能看到与该 Key 所属账户有关的数据。根据已经确定的产品原则,用户可见的计费核心单位只有金额:
- 总额度;
- 已消费金额;
- 剩余金额;
- 本周期起止;
- 今日/本月消费;
- 按日金额趋势;
- 最近请求的模型、时间、状态和最终金额;
- Key 状态和到期时间。
用户界面不显示 Token 数、credits、倍率、每百万 Token 价格、上游账户配额或内部核算字段。金额统一显示 settlement currency,并使用服务器返回的格式化字符串/定点值,不能由浏览器 float 重算。
### 2.2 管理员视图
管理员拥有完整运维与审计能力,可以查看:
- 金额及 Token 明细;
- 价格和 Fast/long-context 规则;
- 下游账户、Key、套餐和余额;
- 上游账号、订阅、配额和健康状态;
- 请求/执行、重试、实际路由与失败;
- 统计分析、同步状态、数据库和插件诊断。
管理员页面中的“用户花费”和“上游配额”必须视觉与命名分离,避免把两种额度混为一谈。
本项目采用请求结束后结算的软金额额度。用户页必须写“软额度/请求后结算”,不得宣传“绝不超额”;余额很低时仍可能由最后一个在途请求产生有限负余额。
## 3. 管理员信息架构
主要沿用 usage-keeper 的七个区域,并加入本项目的计费/路由管理:
### 3.1 总览 Overview
首屏回答“现在系统是否正常、花了多少钱、谁在使用”:
- 今日/本周期总金额、请求数、成功率;
- RPM、金额/分钟;管理员可切换查看 TPM/Token;
- 日均请求、日均金额;
- 金额、请求、缓存命中率时间序列;
- Recent Activity 活动格;
- 实时请求速率、金额速率、TTFT/Latency P50/P95
- 当前模型、下游账户/Key、上游账户 Top;
- 上游账户即将耗尽、Key 已阻断、未定价事件、采集延迟告警。
参考组件:`StatCards``RecentActivityPanel``OverviewRealtimePanel`
### 3.2 分析 Analysis
- 金额和 Token 时间序列;
- 金额分项:输入、cache read、cache write、output
- 模型效率:每请求金额、输出量、缓存率;
- Top models
- TTFT/Latency 分布和异常点;
- 下游账户/Key、模型、Auth File、AI Provider 构成;
- Key×模型热力图;
- Fast 使用金额与占比;
- strict/preferred 路由命中和 fallback 分析。
参考 `analysis/AnalysisPanel.tsx`。金额始终使用已经入账的 `ChargedAmount`,不能按当前价格重算历史。
### 3.3 请求 Events
可分页、筛选、排序和导出。管理员可配置显示列:
- 时间、RequestID、Key/账户;
- requested/upstream/billing model 与 alias
- requested/reported/effective service tier
- success/failure/canceled/rejected
- endpoint、stream、reasoning effort
- TTFT、Latency、速度;
- Token 各分项与缓存率;
- 最终金额、价格版本、倍率、核算质量;
- 期望上游账户、实际账户、retry/fallback
- 请求日志受控查看/下载入口。
参考 `RequestEventsDetailsCard` 的列偏好、分页、筛选、导出和 request log 交互。默认不展示 Prompt/Response;查看 CPA 请求日志必须显式授权、短期 token、审计记录和脱敏。
### 3.4 下游账户与 Key
这是本项目相对 keeper 的核心新增页:
- 账户名称、状态、套餐、本期额度/已用/剩余金额;
- 所属 Key、preview、alias、状态、有效期、最近使用;
- 创建/轮换/禁用/撤销 Key
- 绑定/解绑套餐、充值、扣减、重置周期;
- 模型、endpoint、Fast 使用权限;
- route mode 与指定上游账户/池;
- 实际路由与 fallback 最近记录;
- 批量操作和 CPA Key 同步。
额度操作必须二次确认,并展示变更前后金额及将写入的账本原因。
### 3.5 上游账户 Auth Files / Providers
沿用 usage-keeper 两个独立 tab
- Auth FilesOAuth/Codex 账户;
- AI Provider:配置型 API Key provider。
展示身份别名、provider、状态、priority、disabled、订阅层级/有效期、首次/最近使用、成功失败、用量、当前配额窗口和重置时间。支持:
- provider 筛选、分页、排序;
- 编辑本地别名;
- 刷新单个或当前页配额;
- Codex quota inspection
- 可用时执行 quota reset
- 查看哪些下游 Key 严格/优先绑定到该账户。
- 显示 `scheduler-visible/bindable`;MVP 阻止绑定不在最高可用 priority tier 的 Auth,并解释当前 CPA scheduler 只能看到该 tier。
不要在 UI 返回上游 token、完整文件内容或 API Key。
### 3.6 价格与套餐 Settings
- 模型价格目录、来源、版本和生效时间;
- 同步预览、确认发布、管理员覆盖;
- Fast 2.5x、long-context 和条件规则;
- 未定价模型告警;
- 套餐金额、周期、绑定账户数量;
- 安全/readiness 设置、数据库备份和保留策略;当前无插件管理 session,不把 Management Key 持久化。
参考 keeper 的 `PriceSettingsCard`、pricing rules,以及 key-billing 的 Plans/Prices 页面。禁止后台同步后无确认地改变生产计价。
### 3.7 系统诊断
- 插件版本、CPA ABI/RPC schema 与兼容状态;
- SQLite 路径、大小、WAL、最近备份和 integrity
- runtime topologycallback-driven/sidecar/worker soak status)、required-plugin readiness 和 sentinel/gateway 状态(不显示 secret);
- pending request 数、采集/写入队列深度;
- 各 aggregation checkpoint lag
- 未定价、missing、partial、inconsistent 计数;
- CPA identity/model/quota 最近同步结果;
- 插件运行事件和错误。
诊断日志与账本分开;清理诊断日志不会清除金额、请求事实或累计。
## 4. 用户页面布局
用户页面保持极简:
```text
[当前 Key / 状态] [退出]
[本周期额度 $20.00] [已消费 $7.25] [剩余 $12.75] [周期结束 8/31]
[金额趋势:今天 / 7 天 / 本月 / 自定义]
[最近请求]
时间 | 模型 | 状态 | 金额
```
可以参考 usage-keeper 的 `KeyOverviewPage``StatCards``RecentActivityPanel` 与 realtime 交互,但将 Token/RPM/TPM/cache 等内容替换成用户需要的金额、请求和可用状态。
## 5. 交互原则
- 时间范围统一支持 today、yesterday、7/30 天、本月和自定义;
- Overview 可在页面可见时每 10 秒刷新,隐藏时暂停;
- Events 第一页可自动刷新,其他页保持稳定;
- 大表支持列显示/排序偏好、分页和导出;
- 空状态、加载、部分加载、数据延迟和价格不可用必须分别表达;
- Analysis 的慢查询分区并行加载,某一区失败不遮挡其他已完成卡片;
- 桌面和移动端都可用,表格横向滚动、tooltip 可键盘访问;
- 支持明暗主题和中英文,但第一版中文优先;
- 金额、时间、百分比由统一 formatter 处理。
## 6. 技术承载方式
第一版建议构建静态 React/Vite bundle,使用 `go:embed` 打入动态库,通过 CPA `management_api` 注册:
- 受 CPA Management Key 保护的 JSON API 位于 `/v0/management/plugins/<plugin-id>/...`
- browser resource 位于 `/v0/resource/plugins/<plugin-id>/...`;CPA 当前只支持未经过 Management Key 的精确 GET resource 路径;
- 管理员数据必须由受保护 Management API 获取,不能嵌入公开 resource HTML
- MVP 用户页只注册少量只读 resource GET JSON 路径,由插件自行校验 `Authorization: Bearer <downstream-key>` 并按 Credential scope 返回金额投影;
- 用户 Key 只保存在页面内存,不进入 URL、cookie 日志或 localStorage;刷新后需要重新输入;
- 当前 CPA plugin route 不足以安全实现完整的用户 POST API 和 HttpOnly 登录 session。需要这些能力时应增加独立 sidecar/public API 或扩展 CPA 的 authenticated user plugin routes
- HTML/JSON/CSV 导出全部转义,响应设置 CSP、`nosniff``no-store`(敏感接口)。
resource 只支持 exact GET,因此前端构建必须遵守:
- Vite 使用相对 `base`build manifest 中每个 JS/CSS/font 都注册成独立 ResourceRoute
- 页面路由使用 HashRouter,不依赖 history fallback
- 第一版不注册 service worker,避免公开资源或敏感 JSON 被离线缓存;
- CSP 禁止 inline 时使用独立资源或固定 hash;
- 用户 JSON 设置 `Cache-Control: no-store``Vary: Authorization`
公开 resource shell 不会自动获得 CPA Management Key。管理员首次进入时手工输入 Key,只保存在当前页面 JS 内存,刷新即失效;不得读取或复用 CPA 控制面板的 localStorage/sessionStorage。用户 Key 采用相同的“当前页面内存”原则,但只调用用户只读 resource GET。
当前 CPA Management adapter 会对 JSON 字符串做 HTML entity 转义。客户端对服务端 JSON 字符串最多执行一次兼容性 entity decode,然后仍由 React text node 渲染;禁止 `dangerouslySetInnerHTML`。测试必须覆盖 `A & B <x>` 写入/读取往返。CSV 导出还要防 `= + - @` 开头的公式注入,不能把 HTML escape 当成 CSV 安全。
不能照搬 key-billing 在浏览器 session state 中借用 Management Key 的方式作为最终安全模型。
CPA `home.enabled` 时 Management 和 resource route 都返回 404,因此 cpa-ext 第一版整体不支持 Home;页面不能把它表现成普通“暂无数据”。
## 7. API 投影原则
- 用户 API 只返回自己的金额投影,不先返回管理员对象再让前端隐藏字段;
- 管理员 API 返回 Token/价格/上游身份等完整审计字段;
- 所有列表使用服务端分页、筛选和稳定游标;
- 图表 API 返回预聚合,不把几十万条事件交给浏览器计算;
- API 金额返回 currency + micros + display,前端不得自行从 Token 算钱;
- realtime、overview、analysis、events 独立接口,避免一个慢请求阻塞整个页面。
## 8. MVP 与后续
MVP 页面:
1. 用户金额总览;
2. 管理员 Overview
3. 下游账户/Key/套餐/账户路由;
4. 请求明细;
5. 上游 Codex 账户与配额;
6. 价格;
7. 系统诊断。
后续补齐 Analysis、复杂热力图、排名、更多 provider、导出与 request log。底层数据/API 契约从第一版就应容纳它们。
## 9. 参考路径
`cpa-usage-keeper` 为主要 UI 参考:
- `web/src/pages/UsagePage.tsx`
- `web/src/pages/KeyOverviewPage.tsx`
- `web/src/components/usage/StatCards.tsx`
- `RecentActivityPanel.tsx``OverviewRealtimePanel.tsx`
- `RequestEventsDetailsCard.tsx`
- `analysis/AnalysisPanel.tsx`
- `credentials/`
- `PriceSettingsCard.tsx``ApiKeySettingsCard.tsx`
- `web/src/lib/api.ts``types.ts`
`cpa-plugin-key-billing` 参考:
- `internal/plugin/ui.html`
- `internal/plugin/management.go`
- `internal/billing/keys.go``log.go`
## 10. 验收标准
- 用户登录后只能看到本账户且只有金额计费单位;
- 管理员能完成 Key、套餐、余额、路由、价格和上游账户管理;
- Overview、Events、上游配额与账本数字一致;
- 历史金额不因当前价格变化而改变;
- 权限校验在服务端执行;
- 页面不泄露下游/上游秘密、Prompt 或完整 Response
- Management Key/用户 Key 只驻留当前页面内存,刷新失效,用户 JSON 不缓存;
- exact resource assets、HashRouter、CSP 和 entity-decode 往返测试通过;
- Home 模式由 readiness 明确拒绝,不显示误导性的空页面;
- 大数据量下使用分页和聚合,UI 不冻结;
- 关键动作有确认、审计、错误反馈和可恢复路径。