docs: 重构文档体系
This commit is contained in:
25
docs/development/README.md
Normal file
25
docs/development/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 开发文档
|
||||
|
||||
本目录承载 DiAL 的开发和维护专题。日常开发入口见 [`../../DEVELOPMENT.md`](../../DEVELOPMENT.md),新增或修改 checker 前先阅读 [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md)。
|
||||
|
||||
## 专题索引
|
||||
|
||||
| 文档 | 内容 |
|
||||
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
|
||||
| [architecture.md](architecture.md) | 项目结构、启动流程、运行时流程、HTTP 请求流程、前后端边界 |
|
||||
| [backend.md](backend.md) | 后端库优先级、API 路由、共享 helpers、类型规范、配置契约、store、engine、logger、expect、错误模型 |
|
||||
| [frontend.md](frontend.md) | React、TDesign、TanStack Query、组件、样式和前端测试规范 |
|
||||
| [checker-development.md](checker-development.md) | 新增或修改 checker 的实现机制和完整 checklist |
|
||||
| [build-release.md](build-release.md) | 开发服务、前后端集成、构建、Docker、release、脚本、环境变量 |
|
||||
| [testing-quality.md](testing-quality.md) | lint、format、typecheck、test、hooks 和测试编写规范 |
|
||||
| [../../DEVELOPMENT.md](../../DEVELOPMENT.md) | 包管理、依赖、目录、提交、OpenSpec 和项目级约定 |
|
||||
| [../README.md](../README.md) | 文档影响分析、文档归属矩阵和按任务阅读路径 |
|
||||
|
||||
## 事实来源
|
||||
|
||||
| 主题 | 事实来源 |
|
||||
| ---------------- | ---------------------------------------------------------- |
|
||||
| 代码结构和实现 | `src/`、`scripts/`、`tests/` |
|
||||
| 配置 schema | TypeBox fragments、`probe-config.schema.json`、schema 测试 |
|
||||
| 项目全局规则 | `openspec/config.yaml`、`DEVELOPMENT.md`、本目录专题文档 |
|
||||
| checker 贡献流程 | `CONTRIBUTING.md`、`checker-development.md` |
|
||||
106
docs/development/architecture.md
Normal file
106
docs/development/architecture.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 架构与边界
|
||||
|
||||
## 项目结构
|
||||
|
||||
```text
|
||||
src/
|
||||
server/
|
||||
bootstrap.ts
|
||||
config.ts
|
||||
dev.ts
|
||||
logger.ts
|
||||
main.ts
|
||||
server.ts
|
||||
helpers.ts
|
||||
middleware.ts
|
||||
version.ts
|
||||
routes/
|
||||
checker/
|
||||
config-loader.ts
|
||||
variables.ts
|
||||
schema/
|
||||
store.ts
|
||||
engine.ts
|
||||
expect/
|
||||
runner/
|
||||
shared/
|
||||
api.ts
|
||||
web/
|
||||
app.tsx
|
||||
main.tsx
|
||||
styles.css
|
||||
components/
|
||||
constants/
|
||||
hooks/
|
||||
utils/
|
||||
scripts/
|
||||
tests/
|
||||
docs/
|
||||
openspec/
|
||||
probe-config.schema.json
|
||||
```
|
||||
|
||||
## 启动流程
|
||||
|
||||
```text
|
||||
dev.ts / main.ts
|
||||
-> readRuntimeConfig(cli args)
|
||||
-> bootstrap({ configPath, mode })
|
||||
-> loadConfig(yaml)
|
||||
-> createRuntimeLogger(logging)
|
||||
-> ProbeStore(db)
|
||||
-> store.syncTargets(targets)
|
||||
-> ProbeEngine(...).start()
|
||||
-> startServer({ config, mode, store, logger })
|
||||
-> 注册 SIGINT/SIGTERM shutdown
|
||||
```
|
||||
|
||||
`loadConfig()` 的处理顺序:YAML 解析 -> Authoring normalize(变量替换 + expect 简写展开)-> Normalized 契约校验 -> 语义校验 -> resolve。
|
||||
|
||||
## 运行时流程
|
||||
|
||||
```text
|
||||
定时器 tick
|
||||
-> ProbeEngine.probeGroup()
|
||||
-> checkerRegistry.get(target.type).execute()
|
||||
-> runner/*/expect.ts 校验
|
||||
-> engine.writeResult()
|
||||
-> store.insertCheckResult()
|
||||
```
|
||||
|
||||
数据清理由 engine 定时调用 `store.prune(retentionMs)`,每小时执行一次。
|
||||
|
||||
## HTTP 请求流程
|
||||
|
||||
```text
|
||||
Request
|
||||
-> Bun.serve routes 声明式匹配
|
||||
-> routes/*.ts handler
|
||||
-> middleware.ts 参数校验
|
||||
-> helpers.ts 响应格式化
|
||||
-> Response
|
||||
```
|
||||
|
||||
生产模式下,非 API 路径由 fetch fallback 处理静态资源和 SPA fallback。开发模式下,Vite proxy 将 `/api` 和 `/health` 请求转发到 Bun API server。
|
||||
|
||||
## 前后端边界
|
||||
|
||||
- 前端只通过 HTTP 调用后端,API 路径为 `/api/*`。
|
||||
- 共享类型放在 `src/shared/`。
|
||||
- 前端不得 import `src/server/` 的运行时实现。
|
||||
- 后端不得依赖 `src/web/` 运行时代码,HTML import 集成除外。
|
||||
|
||||
## 主要模块职责
|
||||
|
||||
| 模块 | 职责 |
|
||||
| ------------------------------------- | ------------------------------------------- |
|
||||
| `src/server/bootstrap.ts` | 统一启动引导和 shutdown 编排 |
|
||||
| `src/server/server.ts` | Bun HTTP server 和 routes 注册 |
|
||||
| `src/server/routes/` | API handler,按端点拆分 |
|
||||
| `src/server/checker/config-loader.ts` | YAML 解析、契约校验、语义校验、resolve 调度 |
|
||||
| `src/server/checker/store.ts` | SQLite 数据存储 |
|
||||
| `src/server/checker/engine.ts` | 定时调度、并发控制、结果写入、数据清理 |
|
||||
| `src/server/checker/runner/` | 各 checker 自包含实现 |
|
||||
| `src/server/checker/expect/` | 跨 checker 复用的断言基础设施 |
|
||||
| `src/web/` | React Dashboard |
|
||||
| `src/shared/api.ts` | 前后端共享 API 类型 |
|
||||
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"`。
|
||||
107
docs/development/build-release.md
Normal file
107
docs/development/build-release.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# 构建与发布
|
||||
|
||||
## 开发期运行
|
||||
|
||||
```bash
|
||||
bun run dev probes.yaml
|
||||
```
|
||||
|
||||
`scripts/dev.ts` 同时启动两个进程:
|
||||
|
||||
| 进程 | 用途 |
|
||||
| --------------- | ------------------------------------------------- |
|
||||
| Bun API server | 后端 API 服务,`--watch` 监听后端文件变更自动重启 |
|
||||
| Vite dev server | 前端 SPA、HMR、模块热替换 |
|
||||
|
||||
也可以单独启动:
|
||||
|
||||
```bash
|
||||
bun run dev:server probes.yaml
|
||||
bun run dev:web
|
||||
```
|
||||
|
||||
## 前后端集成
|
||||
|
||||
开发模式下,Vite 通过 proxy 将 `/api/*` 和 `/health` 转发到 Bun。
|
||||
|
||||
生产模式下,前端通过 Vite 构建为静态资源,通过 `import with { type: "file" }` 嵌入 Bun 可执行文件。非 API 路径由 fetch fallback 处理:有文件扩展名的返回静态资源或 404,无扩展名的返回 SPA index.html。
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
bun run build
|
||||
```
|
||||
|
||||
构建流程:
|
||||
|
||||
```text
|
||||
1. Vite build -> dist/web/
|
||||
2. Code generation -> .build/static-assets.ts + .build/server-entry.ts
|
||||
3. Bun compile -> dist/dial-server
|
||||
```
|
||||
|
||||
构建参数:
|
||||
|
||||
| 环境变量 | 说明 |
|
||||
| -------------- | ---------------- |
|
||||
| `BUN_TARGET` | 交叉编译目标平台 |
|
||||
| `BUILD_TARGET` | 交叉编译目标平台 |
|
||||
|
||||
## Docker 镜像
|
||||
|
||||
Docker 镜像使用 Alpine 多阶段构建,保持与生产单可执行文件交付模型一致。
|
||||
|
||||
```text
|
||||
oven/bun:1-alpine -> bun install --frozen-lockfile
|
||||
-> BUN_TARGET=bun-linux-*-musl bun run build
|
||||
-> dist/dial-server
|
||||
|
||||
alpine -> 仅复制 /usr/local/bin/dial-server
|
||||
-> 安装 ca-certificates、iputils-ping、libgcc、libstdc++、tzdata
|
||||
-> 使用非 root dial 用户运行
|
||||
```
|
||||
|
||||
Dockerfile 通过 `TARGETARCH` 选择 Bun compile target。
|
||||
|
||||
| `TARGETARCH` | `BUN_TARGET` |
|
||||
| ------------ | ---------------------- |
|
||||
| `amd64` | `bun-linux-x64-musl` |
|
||||
| `arm64` | `bun-linux-arm64-musl` |
|
||||
|
||||
## Release
|
||||
|
||||
```bash
|
||||
bun run release
|
||||
bun run release --target linux-x64
|
||||
bun run release --target linux-x64,windows-x64,darwin-arm64
|
||||
```
|
||||
|
||||
release 流程:
|
||||
|
||||
```text
|
||||
1. Vite build -> dist/web/
|
||||
2. Code generation -> .build/
|
||||
3. 多目标 Bun compile -> dist/release/binaries/
|
||||
4. tar.gz 打包 -> dist/release/packages/
|
||||
```
|
||||
|
||||
支持的平台见 [用户部署文档](../user/deployment.md#跨平台发布包)。
|
||||
|
||||
## 脚本说明
|
||||
|
||||
| 脚本 | 文件 | 说明 |
|
||||
| ---------------------- | ----------------------------------- | ------------------------------ |
|
||||
| `bun run dev` | `scripts/dev.ts` | 双进程开发服务 |
|
||||
| `bun run dev:server` | `src/server/dev.ts` | 仅启动后端 API server |
|
||||
| `bun run dev:web` | Vite CLI | 仅启动 Vite dev server |
|
||||
| `bun run build` | `scripts/build.ts` | Vite -> codegen -> Bun compile |
|
||||
| `bun run release` | `scripts/release.ts` | 多目标交叉编译和打包 |
|
||||
| `bun run schema` | `scripts/generate-config-schema.ts` | 生成配置 JSON Schema |
|
||||
| `bun run schema:check` | `scripts/generate-config-schema.ts` | 检查配置 JSON Schema 同步 |
|
||||
| `bun run clean` | `scripts/clean.ts` | 清理构建缓存与临时文件 |
|
||||
|
||||
## 维护约定
|
||||
|
||||
- `scripts/build-common.ts` 中的 import specifier 输出必须使用 `/` 分隔符。
|
||||
- 跨平台路径测试不得用当前平台 `path.sep` 伪装其他平台,应使用 `node:path.win32` 或等价注入方式模拟。
|
||||
- 如本地 Docker 环境不支持 buildx 或多架构模拟,需在变更记录中说明未执行原因。
|
||||
161
docs/development/checker-development.md
Normal file
161
docs/development/checker-development.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Checker 开发
|
||||
|
||||
Checker 是 DiAL 的核心扩展单元。每个 checker 是 `src/server/checker/runner/<type>/` 下的自包含目录,包含该 checker 所需的类型、schema、校验、执行逻辑和断言。
|
||||
|
||||
新增或修改 checker 前请同时阅读 [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md)、[配置文件](../user/configuration.md)、[校验规则](../user/expectations.md) 和 [Checker 用户文档](../user/checkers/README.md)。
|
||||
|
||||
## 架构目标
|
||||
|
||||
```text
|
||||
checkerRegistry
|
||||
├── runner/index.ts
|
||||
├── schema/builder.ts
|
||||
├── schema/validate.ts
|
||||
├── config-loader.ts
|
||||
├── engine.ts
|
||||
└── store.ts
|
||||
```
|
||||
|
||||
注册后,中间层通过 registry 自动委托 schema 生成、契约校验、配置 resolve、执行和序列化。新增 checker 不应在中间层新增 `switch/case` 或类型分支。
|
||||
|
||||
## 标准文件结构
|
||||
|
||||
| 文件 | 职责 |
|
||||
| ------------- | ----------------------------------------------------- |
|
||||
| `index.ts` | 模块入口,re-export Checker 类 |
|
||||
| `types.ts` | Checker 专属类型 |
|
||||
| `schema.ts` | TypeBox 契约 schema,包含 config 和 expect |
|
||||
| `validate.ts` | 启动期语义校验 |
|
||||
| `execute.ts` | Checker 类,实现 resolve、execute、serialize |
|
||||
| `expect.ts` | Checker 专用断言函数 |
|
||||
| 其他文件 | 协议解析、编码、provider 适配、平台命令封装等专属逻辑 |
|
||||
|
||||
## 类型定义
|
||||
|
||||
在 `types.ts` 中定义:
|
||||
|
||||
- `RawXxxTargetConfig`
|
||||
- `RawXxxExpectConfig`
|
||||
- `ResolvedXxxExpectConfig`
|
||||
- `ResolvedXxxTarget extends ResolvedTargetBase`
|
||||
|
||||
不需要修改顶层 `checker/types.ts`。base interface 使用 index signature 支持扩展。
|
||||
|
||||
## Schema
|
||||
|
||||
checker 必须提供 `CheckerSchemas`,包含 Authoring 和 Normalized 两套 config/expect 片段。Authoring 描述用户 YAML 可写 DSL,Normalized 描述 normalizer 输出。
|
||||
|
||||
常用 fragments:
|
||||
|
||||
| Fragment | 用途 |
|
||||
| ----------------------------------- | ------------------------- |
|
||||
| `durationSchema` | 时长字符串 |
|
||||
| `sizeSchema` | 大小单位 |
|
||||
| `statusCodePatternSchema` | HTTP 状态码或范围 |
|
||||
| `stringMapSchema` | headers、env 等字符串映射 |
|
||||
| `createValueMatcherSchema()` | ValueMatcher |
|
||||
| `createContentExpectationsSchema()` | ContentExpectations |
|
||||
| `createKeyedExpectationsSchema()` | KeyedExpectations |
|
||||
|
||||
默认对象策略为 `additionalProperties: false`。只有明确的动态键值表可以开放任意键名。
|
||||
|
||||
## 语义校验
|
||||
|
||||
在 `validate.ts` 中实现 JSON Schema 无法表达的规则,统一返回 `ConfigValidationIssue[]`,不要直接拼接最终错误字符串。
|
||||
|
||||
共享校验工具包括:
|
||||
|
||||
| 函数 | 用途 |
|
||||
| -------------------------------- | ---------------------------- |
|
||||
| `validateRawValueExpectation` | 校验 Raw ValueExpectation |
|
||||
| `validateRawContentExpectations` | 校验 ContentExpectations |
|
||||
| `validateRawKeyedExpectations` | 校验 KeyedExpectations |
|
||||
| `validateJsonPath` | 校验项目支持的 JSONPath 子集 |
|
||||
| `isJsonValue` | 判断合法 JSON value |
|
||||
|
||||
## resolve 规范
|
||||
|
||||
`resolve()` 只做内置默认值填充、路径解析、单位转换,不执行校验。输入已经通过 Normalized schema 和语义校验,expect 已是 normalized 形态。
|
||||
|
||||
```typescript
|
||||
const expect = target.expect as ResolvedXxxExpectConfig | undefined;
|
||||
const resolvedExpect: ResolvedXxxExpectConfig = expect
|
||||
? { ...expect, status: expect.status ?? [200] }
|
||||
: { status: [200] };
|
||||
```
|
||||
|
||||
返回值使用 `satisfies ResolvedXxxTarget` 确保类型正确。
|
||||
|
||||
## execute 规范
|
||||
|
||||
- 始终记录 `timestamp` 和 `start = performance.now()`。
|
||||
- 通过 `ctx.signal` 支持超时取消。
|
||||
- 首个 expect 失败即停止,返回带 `failure` 的结果。
|
||||
- 成功时 `failure: null, matched: true`。
|
||||
- 异常时使用 `errorFailure()`。
|
||||
- 不匹配时使用 `mismatchFailure()`。
|
||||
- `expected` 参数应传用户可读值,必要时使用 `displayValueExpectation()`。
|
||||
|
||||
## expect 字段选择
|
||||
|
||||
| 场景 | 模型 |
|
||||
| ------------------------------------ | ------------------- |
|
||||
| 状态类结果且集合小而稳定 | enum 或 boolean |
|
||||
| 单值数字指标或字符串元数据 | ValueMatcher |
|
||||
| 文本、JSON、HTML、XML 或半结构化内容 | ContentExpectations |
|
||||
| 动态键值表 | KeyedExpectations |
|
||||
|
||||
不要为了统一而把状态类字段改成 ValueMatcher。一个 expect 字段只能对应一种断言模型。
|
||||
|
||||
## 注册
|
||||
|
||||
1. 创建 `src/server/checker/runner/<type>/index.ts`。
|
||||
2. 在 `src/server/checker/runner/index.ts` 添加导入。
|
||||
3. 在 registry 初始化数组中添加 checker 实例。
|
||||
|
||||
注册后,schema builder、validate、config-loader、engine、store 会自动按 registry 分发。
|
||||
|
||||
## 测试要求
|
||||
|
||||
测试文件放在 `tests/server/checker/runner/<type>/`,结构镜像源文件。
|
||||
|
||||
| 测试类别 | 覆盖内容 |
|
||||
| ------------ | ---------------------------------------- |
|
||||
| 契约测试 | TypeBox schema 与 JSON Schema 导出一致性 |
|
||||
| 语义校验测试 | 合法和非法配置 |
|
||||
| resolve 测试 | 默认值合并、路径解析、单位转换 |
|
||||
| execute 测试 | 成功、失败、超时、expect 组合 |
|
||||
| 注册测试 | registry 注册行为 |
|
||||
| 配置加载测试 | 含新 checker 的 YAML 完整加载流程 |
|
||||
|
||||
## 文档和 schema 更新
|
||||
|
||||
新增或修改 checker 时通常需要更新:
|
||||
|
||||
- `probes.example.yaml`
|
||||
- `probe-config.schema.json`,通过 `bun run schema` 生成
|
||||
- `docs/user/checkers/<type>.md`
|
||||
- `docs/user/checkers/README.md`
|
||||
- `docs/user/expectations.md`,仅当断言模型或通用规则变化
|
||||
- `docs/development/checker-development.md`,仅当开发机制变化
|
||||
- `CONTRIBUTING.md`,仅当贡献流程或 checklist 变化
|
||||
|
||||
## 完成检查清单
|
||||
|
||||
```text
|
||||
□ src/server/checker/runner/<type>/types.ts
|
||||
□ src/server/checker/runner/<type>/schema.ts
|
||||
□ src/server/checker/runner/<type>/validate.ts
|
||||
□ src/server/checker/runner/<type>/execute.ts
|
||||
□ src/server/checker/runner/<type>/expect.ts
|
||||
□ src/server/checker/runner/<type>/index.ts
|
||||
□ src/server/checker/runner/index.ts
|
||||
□ tests/server/checker/runner/<type>/
|
||||
□ probes.example.yaml
|
||||
□ probe-config.schema.json
|
||||
□ docs/user/checkers/<type>.md
|
||||
□ bun run schema
|
||||
□ bun run schema:check
|
||||
□ bun run check
|
||||
□ bun run verify
|
||||
```
|
||||
117
docs/development/frontend.md
Normal file
117
docs/development/frontend.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# 前端开发
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 层面 | 技术 | 用途 |
|
||||
| ------ | ------------------------------------- | ---------------------------------------------- |
|
||||
| 框架 | React 19 | UI 组件开发 |
|
||||
| 构建 | Bun HTML import + Vite dev server | 开发服务与生产构建 |
|
||||
| 语言 | TypeScript 6 | 类型安全 |
|
||||
| UI 库 | TDesign React + tdesign-icons-react | UI 组件与图标 |
|
||||
| 数据层 | TanStack Query + React Query Devtools | 服务端状态管理与自动轮询 |
|
||||
| 图表 | Recharts | 拨测趋势图 |
|
||||
| 动画 | @number-flow/react | 倒计时数字滚动过渡 |
|
||||
| 路由 | 无 | 单页面 Dashboard,通过 Drawer/Tab 做页面内导航 |
|
||||
|
||||
不引入 React Router 或额外状态管理库。TanStack Query 承担服务端状态,组件内状态使用 `useState`。
|
||||
|
||||
## 组件树与数据流
|
||||
|
||||
```text
|
||||
main.tsx
|
||||
└── StrictMode
|
||||
└── ErrorBoundary
|
||||
└── QueryClientProvider
|
||||
├── App
|
||||
│ ├── useThemePreference()
|
||||
│ ├── useDashboard(refreshInterval)
|
||||
│ ├── SummaryCards
|
||||
│ └── TargetBoard
|
||||
│ └── TargetGroup[]
|
||||
│ └── PrimaryTable
|
||||
│ └── TargetDetailDrawer
|
||||
│ └── useTargetDetail()
|
||||
│ ├── OverviewTab
|
||||
│ └── HistoryTab
|
||||
└── ReactQueryDevtools
|
||||
```
|
||||
|
||||
## TanStack Query 规范
|
||||
|
||||
Query key 使用 structured array,排序为 scope -> id -> 参数。
|
||||
|
||||
```typescript
|
||||
const queryKeys = {
|
||||
dashboard: () => ["dashboard", "24h", 30] as const,
|
||||
meta: () => ["meta"] as const,
|
||||
metrics: (targetId: number, from: string, to: string, bucket: "auto" | MetricsBucket) =>
|
||||
["metrics", targetId, from, to, bucket] as const,
|
||||
history: (targetId: number, from: string, to: string, page: number) => ["history", targetId, from, to, page] as const,
|
||||
};
|
||||
```
|
||||
|
||||
全局面板级查询可持续刷新,详情级查询必须按 Drawer 状态和 Tab 状态条件启用。
|
||||
|
||||
## fetch 封装
|
||||
|
||||
统一使用 `fetch`,不引入 axios。错误抛异常,由 TanStack Query 的 `error` 状态承接。
|
||||
|
||||
```typescript
|
||||
async function fetchJson<T>(url: string): Promise<T> {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
```
|
||||
|
||||
## 组件开发规范
|
||||
|
||||
- 每个 React 组件一个 `.tsx` 文件,文件名使用 PascalCase。
|
||||
- 组件 props 定义为 `interface XxxProps`,紧邻组件函数声明。
|
||||
- 类型从 `../../shared/api` 导入,使用 `import type`。
|
||||
- 展示组件放在 `components/`,通过 props 接收数据,通过回调返回事件。
|
||||
- 容器逻辑放在 hooks 中,组件只做数据消费。
|
||||
- 列定义、排序器、筛选器、颜色阈值等常量放在 `constants/`。
|
||||
- 时间处理等纯函数放在 `utils/`。
|
||||
|
||||
## 现有组件
|
||||
|
||||
| 组件 | 用途 |
|
||||
| -------------------- | ----------------------------------------------------------------- |
|
||||
| `App` | 根组件,Layout + HeadMenu 骨架、主题模式、刷新控制、Skeleton 加载 |
|
||||
| `ErrorBoundary` | React 错误边界 |
|
||||
| `SummaryCards` | 总览统计卡片 |
|
||||
| `TargetBoard` | 按分组渲染目标表格列表 |
|
||||
| `TargetGroup` | 单个分组 Card + PrimaryTable |
|
||||
| `TargetDetailDrawer` | 目标详情抽屉 |
|
||||
| `OverviewTab` | 目标详情概览 |
|
||||
| `HistoryTab` | 目标历史记录表格和分页 |
|
||||
| `TrendChart` | 趋势折线图 |
|
||||
| `StatusDot` | 圆形状态指示点 |
|
||||
| `StatusBar` | 最近采样状态条 |
|
||||
| `RefreshCountdown` | Header 刷新倒计时和手动刷新按钮 |
|
||||
|
||||
## 样式规范
|
||||
|
||||
前端基于 TDesign React 构建 UI,样式开发优先级:
|
||||
|
||||
1. TDesign 组件
|
||||
2. TDesign 组件 props
|
||||
3. TDesign CSS tokens(`--td-*`)
|
||||
4. `styles.css` CSS 类
|
||||
5. 自行开发组件
|
||||
|
||||
红线:
|
||||
|
||||
- 严禁在组件中使用 `style` 属性内联调整样式。
|
||||
- 严禁通过 CSS 覆盖 TDesign 组件内部类名。
|
||||
- 严禁使用 `!important`。
|
||||
- 颜色统一使用 TDesign CSS tokens,不使用硬编码色值。
|
||||
|
||||
## 前端测试
|
||||
|
||||
- 测试目录为 `tests/web/`,结构对应 `src/web/`。
|
||||
- 重点测试 `constants/` 中的纯函数。
|
||||
- 组件测试使用 jsdom 和 `@testing-library/react`。
|
||||
- 测试用户行为而非实现细节。
|
||||
- 只 mock 系统边界,例如 `fetch`。
|
||||
93
docs/development/testing-quality.md
Normal file
93
docs/development/testing-quality.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 测试与质量
|
||||
|
||||
## 质量命令
|
||||
|
||||
| 命令 | 说明 |
|
||||
| ---------------------- | -------------------------------------------------------------- |
|
||||
| `bun run lint` | ESLint 检查,含类型感知规则、导入排序、导入验证、Prettier 格式 |
|
||||
| `bun run format` | Prettier 自动格式化 |
|
||||
| `bun run schema:check` | 检查 `probe-config.schema.json` 是否与 TypeBox fragments 同步 |
|
||||
| `bun run typecheck` | TypeScript 类型检查 |
|
||||
| `bun test` | 运行所有测试 |
|
||||
| `bun run check` | `schema:check + typecheck + lint + test` |
|
||||
| `bun run verify` | `check + build` |
|
||||
|
||||
## ESLint
|
||||
|
||||
配置文件:`eslint.config.js`。
|
||||
|
||||
| 配置来源 | 用途 |
|
||||
| -------------------------------------------- | ---------------------------------------- |
|
||||
| `@eslint/js` recommended | JavaScript 基础规则 |
|
||||
| `typescript-eslint` recommended-type-checked | TypeScript 类型感知规则 |
|
||||
| `typescript-eslint` stylistic-type-checked | TypeScript 风格规则 |
|
||||
| `eslint-plugin-perfectionist` | 导入语句和命名导出排序 |
|
||||
| `eslint-plugin-import` | 导入路径验证、循环依赖检测、重复导入合并 |
|
||||
| `eslint-plugin-prettier` | 将 Prettier 格式集成为 ESLint 规则 |
|
||||
|
||||
后端运行时代码禁止直接使用 `console.*`,请通过注入的 Logger 实例输出日志。
|
||||
|
||||
## Prettier
|
||||
|
||||
配置文件:`.prettierrc.json`。显式声明格式化参数,包括 `printWidth: 120`、`semi: true`、`singleQuote: false`、`trailingComma: "all"`、`endOfLine: "lf"`。
|
||||
|
||||
## TypeScript 严格标志
|
||||
|
||||
| 标志 | 值 | 说明 |
|
||||
| ------------------------------------ | ----- | ------------------------------- |
|
||||
| `strict` | true | 全局严格模式 |
|
||||
| `noUnusedLocals` | true | 未使用局部变量视为错误 |
|
||||
| `noUnusedParameters` | false | 保留关闭 |
|
||||
| `noPropertyAccessFromIndexSignature` | true | 索引签名必须用括号访问 |
|
||||
| `noUncheckedIndexedAccess` | true | 数组和 Map 访问必须运行时检查 |
|
||||
| `noImplicitOverride` | true | 覆盖父类方法必须显式 `override` |
|
||||
| `verbatimModuleSyntax` | true | 强制 `import type` 纯类型导入 |
|
||||
|
||||
## Git hooks
|
||||
|
||||
| Hook | 行为 |
|
||||
| ------------ | ------------------------------------------ |
|
||||
| `pre-commit` | lint-staged 对变更文件运行 eslint/prettier |
|
||||
| `commit-msg` | commitlint 校验提交信息格式 |
|
||||
|
||||
提交信息格式为 `类型: 简短描述`,类型限定为 `feat`、`fix`、`refactor`、`docs`、`style`、`test`、`chore`。
|
||||
|
||||
## 测试分层
|
||||
|
||||
| 层级 | 覆盖范围 | 位置 |
|
||||
| -------- | ---------------------- | ----------------------------------------------------------------------------- |
|
||||
| 单元测试 | 后端函数、纯函数、常量 | `tests/server/**/*.test.ts`、`tests/web/{constants,utils,hooks}/**/*.test.ts` |
|
||||
| 组件测试 | React 组件渲染和交互 | `tests/web/components/**/*.test.tsx` |
|
||||
|
||||
## 测试命令
|
||||
|
||||
```bash
|
||||
bun test
|
||||
bun test tests/server
|
||||
bun test tests/web
|
||||
bun run check
|
||||
bun run verify
|
||||
```
|
||||
|
||||
## 组件测试环境
|
||||
|
||||
组件测试使用 jsdom,配置位于 `tests/setup.ts`,通过 `bunfig.toml` preload 加载。
|
||||
|
||||
包含的 polyfill 和 mock:
|
||||
|
||||
- ResizeObserver
|
||||
- IntersectionObserver
|
||||
- matchMedia
|
||||
- attachEvent
|
||||
- recharts 图表 mock
|
||||
|
||||
## 编写规范
|
||||
|
||||
- 优先使用 `@testing-library/react` 的语义化查询。
|
||||
- 测试用户行为而非实现细节。
|
||||
- 只 mock 系统边界。
|
||||
- 使用真实的 QueryClientProvider 包裹组件。
|
||||
- 组件测试文件命名为 `tests/web/components/ComponentName.test.tsx`。
|
||||
- 异步错误断言使用 helper 或显式 try/catch,避免依赖 Bun `expect(...).rejects` 与 `await-thenable` 规则的类型不匹配。
|
||||
- polyfill 中的 intentional no-op 使用显式可解释写法。
|
||||
- 对 `process.exit` 等系统 API 使用 `spyOn` 受控 mock。
|
||||
Reference in New Issue
Block a user