docs: 重构文档体系
This commit is contained in:
123
docs/development/backend.md
Normal file
123
docs/development/backend.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 后端开发
|
||||
|
||||
## 库使用优先级
|
||||
|
||||
| 优先级 | 来源 | 典型用途 |
|
||||
| ------ | ------------ | -------------------------------------------------------------- |
|
||||
| 1 | Bun 内置 API | `Bun.serve`、`bun:sqlite`、`Bun.spawn`、`Bun.file`、`Bun.YAML` |
|
||||
| 2 | es-toolkit | 类型判断、深度比较、错误判断、并发控制、集合操作 |
|
||||
| 3 | 标准 Web API | `Object.fromEntries`、`Headers`、`fetch`、`AbortController` |
|
||||
| 4 | 主流三方库 | cheerio、xpath、@xmldom/xmldom |
|
||||
| 5 | 自行实现 | 仅在以上都无法满足时 |
|
||||
|
||||
新增依赖前必须先检查上述每一层是否已有可用方案。
|
||||
|
||||
## API 路由开发
|
||||
|
||||
路由文件位于 `src/server/routes/`,每个端点一个文件。路由通过 `server.ts` 的 `Bun.serve({ routes })` 声明式注册,使用 per-method handler 对象。
|
||||
|
||||
新增路由步骤:
|
||||
|
||||
1. 在 `src/server/routes/` 下创建 `<name>.ts`。
|
||||
2. 实现 handler 函数并 export。
|
||||
3. 在 `server.ts` 的 `routes` 对象中注册路径和 method handler。
|
||||
4. 在 `tests/server/app.test.ts` 中添加集成测试。
|
||||
|
||||
请求参数校验使用 `middleware.ts` 提供的 `validateTargetId`、`validateTimeRange`、`validatePagination`、`validateDashboardWindow`、`validateRecentLimit`、`validateMetricsBucket`。
|
||||
|
||||
## 共享 helpers
|
||||
|
||||
| 函数 | 用途 |
|
||||
| ------------------------------- | ------------------------------------ |
|
||||
| `createApiError(error, status)` | 构造 API 错误体 |
|
||||
| `createHeaders(mode, init)` | 创建响应 Headers,生产模式附加安全头 |
|
||||
| `createHealthResponse()` | 构造健康检查响应 |
|
||||
| `formatDuration(ms)` | 毫秒转为可读时长字符串 |
|
||||
| `jsonResponse(body, options)` | JSON 响应构造 |
|
||||
| `mapCheckResult(row, type)` | 数据库行转 API CheckResult |
|
||||
|
||||
## 类型规范
|
||||
|
||||
- 共享类型以 `src/shared/api.ts` 为唯一源头。
|
||||
- 严格联合类型优先于宽类型。
|
||||
- 存储层类型与 API 类型分离。
|
||||
- checker 具体类型在各自目录定义,中间层通过 base interface 和 registry 完成类型擦除。
|
||||
- 纯类型导入使用 `import type`。
|
||||
|
||||
## 配置契约与校验
|
||||
|
||||
配置加载流程固定为:`unknown -> AuthoringProbeConfig -> NormalizedProbeConfig -> ValidatedProbeConfig -> ResolvedConfig`。
|
||||
|
||||
| 层级 | 职责 |
|
||||
| ---------- | ------------------------------------------------ |
|
||||
| Authoring | 用户 YAML 可书写形态,允许变量引用和 expect 简写 |
|
||||
| Normalized | 变量替换和 expect 简写展开后的契约校验形态 |
|
||||
| Validated | 通过契约校验和语义校验的形态 |
|
||||
| Resolved | checker `resolve()` 后的运行期配置 |
|
||||
|
||||
Ajv 保持严格拒绝模式:`allErrors: true`、不启用类型强制转换、不注入默认值、不自动删除未知字段。默认对象策略是 `additionalProperties: false`,只有明确的动态键值表可以开放任意键名。
|
||||
|
||||
新增或修改配置字段时必须同步更新 TypeBox schema fragments、`probe-config.schema.json`、语义 validator、测试和对应用户文档,并运行 `bun run schema:check`。
|
||||
|
||||
## 数据存储
|
||||
|
||||
存储层基于 `bun:sqlite`,WAL 模式运行,数据库文件位于配置的 `dataDir` 下。
|
||||
|
||||
| 方法 | 用途 |
|
||||
| ------------------------------------------ | ---------------------------------- |
|
||||
| `syncTargets(targets)` | 启动期同步 targets |
|
||||
| `insertCheckResult()` | 写入单条检查结果 |
|
||||
| `getTargets()` | 查询全部 targets |
|
||||
| `getLatestChecksMap()` | 批量获取每个 target 的最新检查结果 |
|
||||
| `getAllTargetWindowStats(from, to)` | 批量获取窗口基础计数 |
|
||||
| `getDashboardIncidentStates(from, to)` | 获取 Dashboard 窗口状态序列 |
|
||||
| `getAllRecentSamples(limit)` | 批量获取最近采样 |
|
||||
| `getTargetCheckpoints(targetId, from, to)` | 获取单目标窗口检查点序列 |
|
||||
| `getTargetDurations(targetId, from, to)` | 获取单目标成功耗时数组 |
|
||||
| `getHistory()` | 分页查询历史记录 |
|
||||
| `prune(retentionMs)` | 清理过期数据 |
|
||||
|
||||
数据库只负责存储、筛选、排序、分页、LIMIT 和基础聚合。指标语义在后端应用层实现。
|
||||
|
||||
## 拨测引擎
|
||||
|
||||
- 按 interval 分组,每组独立定时触发。
|
||||
- 使用 `es-toolkit/Semaphore` 限制全局最大并发数。
|
||||
- 通过 `checkerRegistry.get(target.type)` 选择 runner。
|
||||
- 每次检查创建 `AbortController` 并按 `target.timeoutMs` 触发 abort。
|
||||
- 状态变化通过注入的 `Logger` 输出结构化日志。
|
||||
|
||||
## 日志模块
|
||||
|
||||
后端运行时代码统一通过 `Logger` 接口输出日志,禁止直接使用 `console.*`。配置加载失败前使用 `ConsoleFallbackLogger`。
|
||||
|
||||
| 实现 | 用途 |
|
||||
| ----------------------- | --------------------------------------------- |
|
||||
| `PinoLoggerWrapper` | 生产运行时,封装 Pino、pino-pretty、pino-roll |
|
||||
| `NoopLogger` | 静默丢弃日志 |
|
||||
| `MemoryLogger` | 测试替身 |
|
||||
| `ConsoleFallbackLogger` | 配置加载失败前的降级日志 |
|
||||
|
||||
敏感信息会自动 redact `authorization`、`cookie`、`set-cookie`、`authToken`、`key`、`password`、`token`、`apiKey` 及其嵌套路径。
|
||||
|
||||
## expect 系统
|
||||
|
||||
共享断言基础设施位于 `src/server/checker/expect/`。新增或修改 checker 的 expect 字段时,按以下原则选择模型:
|
||||
|
||||
| 模型 | 用途 | 典型字段 |
|
||||
| --------------------- | ---------------------------- | ------------------------------------------------------------------- |
|
||||
| enum / boolean | 状态类结果,结果集合小且稳定 | HTTP status、Cmd exitCode、TCP connected、UDP responded、ICMP alive |
|
||||
| `ValueMatcher` | 数字指标和字符串元数据 | durationMs、rowCount、finishReason、usage |
|
||||
| `ContentExpectations` | 返回内容或半结构化内容 | body、stdout、stderr、banner、response、output、result |
|
||||
| `KeyedExpectations` | 动态键值断言 | headers、DB rows 列值 |
|
||||
|
||||
详细 checker 开发流程见 [Checker 开发](checker-development.md)。
|
||||
|
||||
## 错误模型
|
||||
|
||||
| 类型 | 结构 |
|
||||
| ------------ | ----------------------------------- | ------------------------------------------------------- |
|
||||
| API 错误 | `{ error: "描述", status: <code> }` |
|
||||
| CheckFailure | `{ kind: "error" | "mismatch", phase, path, expected?, actual?, message }` |
|
||||
|
||||
expect 校验失败记录首个失败原因;网络、超时、进程崩溃统一为 `kind: "error"`。
|
||||
Reference in New Issue
Block a user