Skip to content

Commit 710fc12

Browse files
committed
docs(diagrams): 整体架构图与文档同步 P0/P1 事实
- architecture.json:revision 更新至 3cd5a6f;新增「运维告警」节点(含 evaluate_alerts / GET /api/alerts / alert_events 来源)与 Webhook 外部节点; 协议出口改标 OpenAI + Anthropic(补 /v1/messages 来源);db 计数 10→11 表、 SCHEMA_VERSION 17;bg 7→8 类循环(含告警);registry 补出站代理来源; 全量校准各组件源码行号;卡片补 fallback / 按渠道代理 / 告警 / 11 表 35 项 - README/PROPOSAL/TECHNICAL:后台循环 7→8 类、DB 10→11 表 SCHEMA_VERSION 17、 Q8 标注由 Q59 落地、已知取舍中 Anthropic 出口改为已落地
1 parent 3cd5a6f commit 710fc12

5 files changed

Lines changed: 232 additions & 84 deletions

File tree

‎PROPOSAL.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Q5 | 前端 | React + Tailwind,从零新写 |
1616
| Q6 | 迁移方式 | 从零重写,旧项目仅作参考 |
1717
| Q7 | 凭证归属 | 公共池 + 按人统计 |
18-
| Q8 | 协议出口 | v1 仅 OpenAI;v1.1 加 Anthropic |
18+
| Q8 | 协议出口 | v1 仅 OpenAI;v1.1 加 Anthropic(**已由 Q59 落地**:P0-1 新增 `POST /v1/messages`,供 Claude Code 接入) |
1919
| Q9 | 存储 | SQLite,schema 重新设计,凭证入加密列 |
2020
| Q10 | 配额 | 不做配额,只做按人统计 |
2121
| Q11 | 前端范围 | Dashboard / 凭证 / API Key / 统计 / Playground / 任务与配置 / 登录(Q34 推翻「无设置页」:19 项可热更配置走管理台,其余配置仍走 env;Q38 把该页与后台任务合并,页名「任务与配置」) |
@@ -180,9 +180,9 @@
180180
║ 用户管理 · 审计 · 凭证运维 · API Key · 统计 · 任务与配置 ║
181181
╚══════════════════════════════════════════════════════════════════════╝
182182
183-
╔═ 后台面 ═══ 无 HTTP 入口 · 7 类循环 ═════════════════════════════════╗
183+
╔═ 后台面 ═══ 无 HTTP 入口 · 8 类循环 ═════════════════════════════════╗
184184
║ 额度探测 · token 预刷新 · 每日签到 · 成长中心 · 活跃上报 · 明细清理 ║
185-
║ · 模型目录刷新 ║
185+
║ · 模型目录刷新 · 运维告警 ║
186186
║ └──────────▶ Provider 客户端 ──────────▶ 上游 ║
187187
╚══════════════════════════════════════════════════════════════════════╝
188188
│ 三面共享
@@ -193,7 +193,7 @@
193193

194194
- **请求面**面向外部客户端,鉴权是 **API Key**(SHA-256 摘要 + 来源 IP 白名单 + 渠道绑定);链路「协议层 → 执行引擎 → Provider」全程无状态、可并发。它不知道「人」是谁,只认 Key 的归属用户(用于按人统计)。
195195
- **管理面**面向浏览器,鉴权是**签名会话 Cookie + 三角色 RBAC**(Q18/Q39,见 §4.7);角色每请求现读 DB,改密 / 降级 / 禁用立即吊销。管理与请求**共用同一个执行引擎与仓储**,不做成独立服务——2–10 人自托管实例里,进程隔离只换来部署复杂度。
196-
- **后台面**没有 HTTP 入口,由 `TaskRunner` 起 7 类循环([TECHNICAL.md §6.2](TECHNICAL.md)),与请求面**共用 Provider 客户端与节流器**:各渠道的风控按最小间隔生效,不能因为「后台签到」与「前台对话」是两条代码路径就各发各的。
196+
- **后台面**没有 HTTP 入口,由 `TaskRunner` 起 8 类循环([TECHNICAL.md §6.2](TECHNICAL.md)),与请求面**共用 Provider 客户端与节流器**:各渠道的风控按最小间隔生效,不能因为「后台签到」与「前台对话」是两条代码路径就各发各的。
197197
- **三面共享一份 SQLite**(WAL + `busy_timeout=5000`):账号、加密凭证、统计与审计同库,因此升级只需重启**一个**进程([TECHNICAL.md §6.4](TECHNICAL.md))。
198198

199199
两个鉴权面互不替代:API Key 进不了管理台,会话 Cookie 也进不了 `/v1`(各自独立依赖,见 [TECHNICAL.md §2](TECHNICAL.md) 的 `deps.py`)。

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ CodeBuddy 成长中心的「连登天数 / 活跃地图」按日统计客户端
429429
- 值存 `runtime_settings` 表(纯 key/value),新增可热更项无需迁移;白名单外的 key、非法类型 / 越界值写入前即拒,读取时坏行跳过并记警告。
430430
- 启动期项(`APP_SECRET` / `PORT` / `DATA_DIR` / `USERS_FILE` / 上游端点白名单)**不在**白名单:它们决定进程如何启动,运行期改只会让内存与磁盘静默分叉。
431431
- 接口:`GET /api/settings` 读快照,`PUT /api/settings` 写(admin + CSRF),body `{"values": {key: value}}`,传 `null` 恢复默认。
432-
- 该页同时展示**后台任务运行态**:7 类任务的周期、上次执行时间、最近结果与错误;页面按 tab 组织,每个任务一个 tab,无任务归属的配置(默认模型、黑名单、到期窗口、节流等)按后端下发的网关卡组各占一个 tab。
432+
- 该页同时展示**后台任务运行态**:8 类任务的周期、上次执行时间、最近结果与错误;页面按 tab 组织,每个任务一个 tab,无任务归属的配置(默认模型、黑名单、到期窗口、节流等)按后端下发的网关卡组各占一个 tab。
433433
- 运行态是**进程内**的(`GET /api/tasks`,admin,页面每 30 秒刷新):只显示「本次启动以来跑过没有」,**重启归零**,不落库、不留历史。未到点或未开启的轮次不算执行——否则签到会显示成「刚刚跑过」,而当天一次都没签。
434434

435435
## 部署注意

‎TECHNICAL.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ response.completed | response.incomplete
579579

580580
### 3.12 后台任务可视化(B4,「任务与配置」页)
581581

582-
**问题**:`TaskRunner` 跑着 7 类循环(额度探测 / token 预刷新 / 每日签到 / 成长中心 / 活跃上报 / 明细清理 / 模型目录刷新),但除失败时一行 `logger.warning`,没有任何地方能看到「上次何时跑的、结果如何」,也没有端点暴露。运维只能翻服务日志。
582+
**问题**:`TaskRunner` 跑着 8 类循环(额度探测 / token 预刷新 / 每日签到 / 成长中心 / 活跃上报 / 明细清理 / 模型目录刷新 / 运维告警),但除失败时一行 `logger.warning`,没有任何地方能看到「上次何时跑的、结果如何」,也没有端点暴露。运维只能翻服务日志。
583583

584584
**上一轮调研结论**:项目内**不存在**后台任务页(无 `TasksPage`、无 `/api/tasks`,git 全历史与文档均无),所以这不是「找回旧页面」而是新增;同类项目(ithtelab/workbuddy-manager)的做法是「任务记录页 + 30s 自动刷新 + 单次 200 条上限」,关键教训是**容器重建即丢、必须采集落库**。
585585

@@ -1114,7 +1114,7 @@ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/api/users
11141114

11151115
## 7. 数据库(T-Q2 定稿)
11161116

1117-
DDL 以 `src/db/schema.sql` 为准(users 为账号唯一源、users.txt 仅引导导入、凭证加密列、`usage_events.credit`/`cached_tokens` 可空)。当前 `SCHEMA_VERSION = 15`,共 10 张表:`api_keys` / `credentials` / `users` / `audit_events` / `usage_events` / `usage_hourly` / `growth_events` / `credit_events` / `credential_model_cooldowns` / `runtime_settings`。补充实现细节:
1117+
DDL 以 `src/db/schema.sql` 为准(users 为账号唯一源、users.txt 仅引导导入、凭证加密列、`usage_events.credit`/`cached_tokens` 可空)。当前 `SCHEMA_VERSION = 17`,共 11 张表:`api_keys` / `credentials` / `users` / `audit_events` / `usage_events` / `usage_hourly` / `growth_events` / `credit_events` / `credential_model_cooldowns` / `runtime_settings` / `alert_events`。补充实现细节:
11181118

11191119
```sql
11201120
-- conn.py 打开时执行
@@ -1155,9 +1155,9 @@ fixture 存于 `src/provider/fixtures/`(真实 SSE/JSON 样本,覆盖正文
11551155

11561156
- **同步 sqlite3 而非 aiosqlite**(T-Q2):本地微秒级操作,asyncio 封装开销大于收益
11571157
- **双 httpx 客户端**(T-Q4):聊天流 `read=None` 防长流截断;短请求总超时 30s 防悬挂;共享 `trust_env=False`。非流式路径由引擎聚合同一流式上游(无独立 HTTP),悬挂兜底是引擎层的聚合整体超时(`UPSTREAM_COMPLETE_TIMEOUT_SECONDS`,默认 600s,超时按瞬态错误换号重试)
1158-
- **手写 SQL 而非 ORM**:10 张表规模下 ORM 收益为负
1158+
- **手写 SQL 而非 ORM**:11 张表规模下 ORM 收益为负
11591159
- **polling OAuth 不转回调**(Q17=C):上游协议决定;TRAE 回调走主端口 + `PUBLIC_BASE_URL`。`/authorize` 无鉴权(浏览器 302 不带 key),防滥用靠两条:无进行中登录一律拒绝;待完成登录有 600s TTL(长期挂着的 pending 会被同网络任何人用自己的 refreshToken 完成兑换——凭证入池、归属记为发起登录的管理员)。`app.state` 只保留 pending 的 state,不驻留含 refreshToken 的完整回调 URL
1160-
- **v1 无 Anthropic**(Q8=A):Event 层已预留,v1.1 只加 `compat/anthropic/` 适配器
1160+
- **Anthropic 出口已落地**(Q8 原定 v1.1,P0-1/Q59 实现):`compat/anthropic/` + `api/messages.py` 提供 `POST /v1/messages` 与 `/v1/messages/count_tokens`,供只走 Anthropic 协议的客户端(Claude Code)接入,复用同一 `executor`(详见 §3.18)
11611161
- **Responses 出口只做 Codex CLI 用到的子集**(Q32,详见 §3.7):不做 `store=true` / `previous_response_id`(服务端无状态,不假装支持);`include=["reasoning.encrypted_content"]` 按实测接受并忽略——Codex CLI 每轮必带,400 会直接打死主客户端;流式终止用 `response.completed` / `response.incomplete` / `response.failed`,**不发 `[DONE]`**(Responses 协议无该哨兵)。形状取自官方 `openai` SDK 类型并用其作客户端验证,对真实 CB 上游冒烟过;**未经真实 Codex CLI 端到端验证**(开发环境无 CLI)
11621162
- **不做 reasoning 注入 / effort 档位映射**(原 B1.2,实测后取消):原计划对「强制推理模型族」注入 `thinking` + `reasoning_effort` 并回填历史 `reasoning_content`,实测前提不成立——(1)客户端已自带 `reasoning_effort`(仅 `low`/`medium`)且上游直接接受;(2)客户端已回传历史 `reasoning_content` 且上游接受;(3)原计划的默认模型清单与实际在用命名无关,且 `glm-5.1` 在 `MODEL_BLOCKLIST` 里,硬编码白名单会空转;(4)真要做「客户端丢弃时回填」必须服务端存对话内容,与脱敏纪律冲突。参考实现 IceeAn/codebuddy2api 走相反取向(对白名单模型强制 `reasoning_effort=max` 覆盖客户端),属单来源且会改写客户端意图,不采纳
11631163
- **统计一律以 `usage_hourly` 为准**:`overview` / `by_provider` / `timeline` / `model-timeline` 均读小时汇总,只有 `events`(逐请求明细)读 `usage_events`。统一口径是为了让选「全部」时总览与图表同值(明细只留 90 天,汇总永久)。代价:最近 ≤5 分钟未进汇总的请求不计入,刷新一次即可

0 commit comments

Comments
 (0)