1
0
Files
DiAL/openspec/specs/probe-api/spec.md
lanyuanxiaoyao 31aeee6d60 refactor: 前端架构重构 — hook拆分、组件拆分、类型筛选器动态化、Meta API
- 后端新增 GET /api/meta 端点(checkerRegistry.supportedTypes)及 MetaResponse 类型
- 前端 hook 拆分为 use-queries.ts(全局查询+useMeta)和 use-target-detail.ts(Drawer状态)
- TargetDetailDrawer 拆分为 OverviewTab + HistoryTab + history-table-columns + stats.ts
- 类型筛选器由 meta API 动态驱动,删除 target-type-display 静态映射
- 列定义改为工厂函数 createTargetTableColumns(checkerTypes),TargetGroup 新增 columns prop
- 修复 StatusDonut key、StatusBar maxSlots prop、TrendChart 移除 loading prop
- 补充 utils/time、utils/stats、动态列工厂测试,删除旧 mapping 测试
- 同步 delta specs 到主 specs,归档 frontend-architecture-refactor change
2026-05-13 20:55:42 +08:00

159 lines
7.6 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.
## Purpose
定义拨测系统的 REST API 端点:总览统计、目标列表含分组和结构化采样数据、带时间范围和分页的历史记录、按时间范围的趋势聚合。
## Requirements
### Requirement: 总览统计 API
系统 SHALL 提供 `GET /api/summary` 端点,返回所有目标的总体统计信息(不含平均耗时)。
#### Scenario: 获取总览统计
- **WHEN** 客户端请求 `GET /api/summary`
- **THEN** 系统 SHALL 返回 JSON 包含 total总目标数、up正常数、down异常数、lastCheckTime最近一次检查时间
### Requirement: 目标列表 API
系统 SHALL 提供 `GET /api/targets` 端点,返回所有 typed target 及其最新状态、分组信息和结构化采样数据。
#### Scenario: 获取目标列表
- **WHEN** 客户端请求 `GET /api/targets`
- **THEN** 系统 SHALL 返回 JSON 数组每个元素包含目标基本信息id、name、group、type、target、interval、最近一次检查结果timestamp、matched、durationMs、statusDetail、failure、统计摘要totalChecks、availability和结构化采样数据 recentSamples代替原 sparkline
#### Scenario: 目标无历史记录
- **WHEN** 某目标尚未执行过任何拨测
- **THEN** 其 latestCheck 为 nullrecentSamples 为空数组
### Requirement: 历史记录 API
系统 SHALL 提供 `GET /api/targets/:id/history` 端点,支持时间范围筛选和分页返回指定目标的拨测记录。
#### Scenario: 获取指定时间范围内的历史记录
- **WHEN** 客户端请求 `GET /api/targets/1/history?from=ISO&to=ISO&page=1&pageSize=20`
- **THEN** 系统 SHALL 返回带分页信息的历史记录,包含 items、total、page、pageSize按时间倒序排列
#### Scenario: 使用默认分页参数
- **WHEN** 客户端请求 `GET /api/targets/1/history?from=ISO&to=ISO`(未指定 page 或 pageSize
- **THEN** 系统 SHALL 使用默认 page=1, pageSize=20
#### Scenario: from 或 to 参数缺失
- **WHEN** 客户端请求 `GET /api/targets/1/history` 未提供 from 或 to 参数
- **THEN** 系统 SHALL 返回 400 状态码和错误信息
### Requirement: 趋势 API 支持时间范围
系统 SHALL 提供 `GET /api/targets/:id/trend` 端点,支持 `from``to` 查询参数指定时间范围。
#### Scenario: 指定时间范围查询趋势
- **WHEN** 客户端请求 `GET /api/targets/1/trend?from=ISO&to=ISO`
- **THEN** 系统 SHALL 返回指定时间范围内按小时分组的聚合数据
#### Scenario: from 或 to 参数缺失
- **WHEN** 客户端请求 `GET /api/targets/1/trend` 未提供 from 或 to 参数
- **THEN** 系统 SHALL 返回 400 状态码和错误信息
### Requirement: 目标列表返回分组和采样数据
`GET /api/targets` SHALL 返回每个目标的分组信息和结构化采样数据,替代原有 sparkline。
#### Scenario: 返回分组信息
- **WHEN** 客户端请求 `GET /api/targets`
- **THEN** 响应中每个目标 SHALL 包含 `group` 字段,值为该目标所属的分组名称
#### Scenario: 返回 recentSamples
- **WHEN** 客户端请求 `GET /api/targets`
- **THEN** 响应中每个目标 SHALL 包含 `recentSamples` 数组,每个元素包含 `timestamp`ISO 8601`durationMs`number | null`up`booleanmatched === true
#### Scenario: recentSamples 数量
- **WHEN** 客户端请求 `GET /api/targets`
- **THEN** 每个目标的 recentSamples SHALL 最多包含 30 个元素,按时间倒序排列
#### Scenario: 目标无历史记录
- **WHEN** 某目标尚未执行过任何拨测
- **THEN** 其 recentSamples SHALL 为空数组
### Requirement: 新增共享类型
系统 SHALL 在 `src/shared/api.ts` 中定义 `CheckResult``RecentSample``HistoryResponse` 类型。
#### Scenario: CheckResult 类型
- **WHEN** 前后端共享 `CheckResult` 类型
- **THEN** 该类型 SHALL 包含 `timestamp: string``matched: boolean``durationMs: number | null``statusDetail: string | null``failure` 字段,不包含 success 字段
#### Scenario: RecentSample 类型
- **WHEN** 前后端共享 `RecentSample` 类型
- **THEN** 该类型 SHALL 包含 `timestamp: string``durationMs: number | null``up: boolean` 字段,其中 up 为 boolean 且等于 matched
#### Scenario: HistoryResponse 类型
- **WHEN** 前后端共享 `HistoryResponse` 类型
- **THEN** 该类型 SHALL 包含 `items: CheckResult[]``total: number``page: number``pageSize: number` 字段
### Requirement: 保留健康检查端点
系统 SHALL 保留 `GET /health` 端点,不受拨测功能影响。
#### Scenario: 访问健康检查
- **WHEN** 客户端请求 `GET /health`
- **THEN** 系统 SHALL 返回与之前格式一致的健康检查响应
### Requirement: API 错误处理
系统 SHALL 对不存在的目标 ID、无效参数和超出范围的分页参数返回适当的 HTTP 错误响应。
#### Scenario: 查询不存在的目标
- **WHEN** 客户端请求 `GET /api/targets/999/history`
- **THEN** 系统 SHALL 返回 404 状态码和错误信息
#### Scenario: 无效的 from/to 参数
- **WHEN** 客户端请求 `GET /api/targets/1/history?from=invalid`
- **THEN** 系统 SHALL 返回 400 状态码和错误信息
#### Scenario: 无效的分页参数
- **WHEN** 客户端请求 `GET /api/targets/1/history?from=ISO&to=ISO&page=abc`
- **THEN** 系统 SHALL 返回 400 状态码和错误信息
#### Scenario: pageSize 超过上限
- **WHEN** 客户端请求 `GET /api/targets/1/history?from=ISO&to=ISO&pageSize=201`
- **THEN** 系统 SHALL 返回 400 状态码和错误信息,提示 pageSize 不能超过 200
#### Scenario: pageSize 等于上限
- **WHEN** 客户端请求 `GET /api/targets/1/history?from=ISO&to=ISO&pageSize=200`
- **THEN** 系统 SHALL 正常返回数据
#### Scenario: from 或 to 参数缺失
- **WHEN** 客户端请求 `GET /api/targets/1/trend` 未提供 from 或 to 参数
- **THEN** 系统 SHALL 返回 400 状态码和错误信息
#### Scenario: 无效的目标 ID
- **WHEN** 客户端请求 `GET /api/targets/abc/history`
- **THEN** 系统 SHALL 返回 400 状态码和错误信息
### Requirement: 失败信息 API 契约
系统 SHALL 通过 API 返回结构化 failure 信息,供 Dashboard 展示和后续排查。
#### Scenario: 返回 expect 不匹配信息
- **WHEN** 最近一次检查结果包含 failure.kind=`mismatch`
- **THEN** `/api/targets``/api/targets/:id/history` SHALL 返回该 failure 的 kind、phase、path、expected、actual、message 字段
#### Scenario: 无失败信息
- **WHEN** 检查结果 matched=true
- **THEN** API SHALL 返回 failure 为 null
### Requirement: Meta 信息 API
系统 SHALL 提供 `GET /api/meta` 端点,返回系统运行时元数据。
#### Scenario: 获取 checker 类型列表
- **WHEN** 客户端请求 `GET /api/meta`
- **THEN** 系统 SHALL 返回 JSON `{ checkerTypes: string[] }`,包含所有已注册的 checker 类型标识符
#### Scenario: 类型列表来源
- **WHEN** 系统启动并注册了 checker
- **THEN** `/api/meta` 返回的 `checkerTypes` SHALL 与 `CheckerRegistry.supportedTypes` 完全一致
#### Scenario: 仅允许 GET/HEAD 方法
- **WHEN** 客户端使用 POST/PUT/DELETE 等方法请求 `/api/meta`
- **THEN** 系统 SHALL 返回 405 状态码
#### Scenario: HEAD 请求返回空体
- **WHEN** 客户端使用 HEAD 方法请求 `/api/meta`
- **THEN** 系统 SHALL 返回 200 状态码和正确的 Content-Type headerbody 为空
### Requirement: MetaResponse 共享类型
系统 SHALL 在 `src/shared/api.ts` 中定义 `MetaResponse` 类型。
#### Scenario: MetaResponse 类型定义
- **WHEN** 前后端引用 `MetaResponse` 类型
- **THEN** 该类型 SHALL 包含 `checkerTypes: string[]` 字段