diff --git a/docs/deployment.md b/docs/deployment.md index 7696a6c..9ae73ed 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -59,14 +59,14 @@ **双因子启用条件(`SAF-DEBUG-GATE`,两者必须同时成立)** -1. 进程命令行必须带 `--debug`(读取于 `src/main.rs:96`)。 -2. `DEBUG_TOKEN` 环境变量必须存在且非空(读取于 `src/main.rs:97-100`)。 +1. 进程命令行必须带 `--debug`(读取于 `src/main.rs:82`)。 +2. `DEBUG_TOKEN` 环境变量必须存在且非空(读取于 `src/main.rs:82-89`)。 -缺一即不挂载:`debug_router()` 本身会构造出全部 7 条路由(`src/debug.rs:72-80`),但主入口**只在双因子成立时才合并它**(`src/notify.rs:1321-1322`)。所以未开启时 `/debug/*` 路由根本不存在,请求走 axum 兜底返回普通 `404 not found`——**不是** 401,也不会泄露「此路径存在」。开启成功时打一条 WARN 日志标记该面已打开(`src/main.rs:107-109`,`SAF-LOG-PURITY`:只记开启状态,从不记录 token 值)。 +缺一即不挂载:`debug_router()` 本身会构造出全部 7 条路由(`src/debug.rs:72-80`),但主入口**只在双因子成立时才合并它**(`src/notify.rs:1321-1322`)。所以未开启时 `/debug/*` 路由根本不存在,请求走 axum 兜底返回普通 `404 not found`——**不是** 401,也不会泄露「此路径存在」。开启成功时打一条 WARN 日志标记该面已打开(`src/main.rs:90-92`,`SAF-LOG-PURITY`:只记开启状态,从不记录 token 值)。 **鉴权** -7 条路由全部要求 `Authorization: Bearer `,统一走 `debug_authorized`(`src/debug.rs:45`),它委托生产同款 `worker_authorized`,因此令牌是**常数时间比较**(`src/notify.rs:1136`)。失败回 `401 unauthorized`,且不设 `Retry-After`(`src/debug.rs:52-54`)。 +7 条路由全部要求 `Authorization: Bearer `,统一走 `debug_authorized`(`src/debug.rs:45`),它委托生产同款 `worker_authorized`(`src/notify.rs:446`),因此令牌是**常数时间比较**(`src/notify.rs:1136`)。失败回 `401 unauthorized`,且不设 `Retry-After`(`src/debug.rs:52-54`)。 **7 条路由与预期状态码**(注册于 `src/debug.rs:72-80`,路径为字面量,无常量抽取) diff --git a/docs/design.md b/docs/design.md index ff658e4..5477631 100644 --- a/docs/design.md +++ b/docs/design.md @@ -692,7 +692,7 @@ Push 事件经 Streams 消费并投递到 Telegram,其关键路径交付语义 ### 11.4 已由代码回答的早期问题(不再待确认) 以下问题在设计阶段以 Q6–Q30 形式列出,**代码落地时已各自给出答案**,因此不再是"待确认项",此处只记结论: -- **消息格式**(Q6):出站只有 `send_text`(`src/channel.rs:134`),其载荷结构体 `SendMessage`(`src/channel.rs:80`)只有 `chat_id` + `text` 两个字段,**没有 `parse_mode`**——Telegram 收到后按纯文本渲染,既不用 HTML 也不用 MarkdownV2。 +- **消息格式**(Q6):出站只有 `send_text`(`src/channel.rs:114`),其载荷结构体 `SendMessage`(`src/channel.rs:60`)只有 `chat_id` + `text` 两个字段,**没有 `parse_mode`**——Telegram 收到后按纯文本渲染,既不用 HTML 也不用 MarkdownV2。 - **长邮件 / 原文直发**(Q7、Q29):不存在"正文超过 4000 字符不发全文"的策略。`read_email` 拉全文送 LLM;AI 失败时回退为前 300 字符且**无"已截断"标注**(见 §12.3/§12.5)。 - **附件**(Q8、Q28):完全未实现。领域模型只有 `has_attachment: bool`,出站只有 `sendMessage`,没有 `send_document` 也没有 `Blob/get`(见 §12.3)。 - **推送范围**(Q9):对账拉全量 `changes`,Bot 侧不做文件夹/发件人/关键词过滤,也没有 Sieve 依赖(Q11 因此无影响)。 @@ -736,7 +736,7 @@ LLM 能力只存在于 `src/ai.rs` 一个文件;**没有**配置 / 回退 / | 变量 | 类型 | 默认 | 用途 | |---|---|---|---| | `LLM_ENABLED` | bool | `false` | 总开关;默认关闭,未启用时不校验 `LLM_API_KEY`/`LLM_BASE_URL`/`LLM_MODEL` | -| `LLM_ALLOW_NET` | bool | `false` | 运行时出站许可;`LLM_ENABLED && LLM_ALLOW_NET` 同时为真才构造 `LlmClient`,否则 `llm` 字段为 `None`(`src/main.rs:125`) | +| `LLM_ALLOW_NET` | bool | `false` | 运行时出站许可;`LLM_ENABLED && LLM_ALLOW_NET` 同时为真才构造 `LlmClient`,否则 `llm` 字段为 `None`(`src/main.rs:111-127`) | | `LLM_API_KEY` | string | 可省略 | Bearer token;仅 `LLM_ENABLED=true` 时必填 | | `LLM_BASE_URL` | URL | 可省略 | 仅启用时必填,且必须 `https`,否则 `AiError::InvalidEndpoint` | | `LLM_MODEL` | string | 可省略 | 仅启用时必填;透传给 `/chat/completions` 的 `model` | diff --git a/docs/reference.md b/docs/reference.md index b4c63fd..9fb667f 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -202,7 +202,8 @@ string `"30"`: All HTTP API routes are registered in `router_with_worker_state_runtime_bootstrap_config` (`notify.rs:1276`), with the routes wired at `notify.rs:1305-1319`. The three static SPA routes in the last table row are the exception: they live in `web::router()` (`src/web.rs:19-24`) and -are merged into the production router at `src/main.rs:62` and `src/main.rs:194`. +are merged into the router via `.merge(web::router())`: the setup-mode router at `src/main.rs:62`, +the production router at `src/main.rs:180`. | Method | Path | Handler | |---|---|---| @@ -224,7 +225,7 @@ are merged into the production router at `src/main.rs:62` and `src/main.rs:194`. | GET | `/`, `/assets/config.js`, `/assets/styles.css` | `index` / `script` / `styles` | The remote-debug surface (`src/debug.rs:72-80`) is merged **only when the process is started -with `--debug` and `DEBUG_TOKEN` is non-empty** (`SAF-DEBUG-GATE`, `src/main.rs:96-100`, +with `--debug` and `DEBUG_TOKEN` is non-empty** (`SAF-DEBUG-GATE`, `src/main.rs:82-89`, `src/notify.rs:1321-1322`); otherwise none of these routes exist and requests fall through to axum's generic `404`, not a 401. All seven require `Authorization: Bearer `, checked by `debug_authorized` (`src/debug.rs:45`), which delegates to the production