1
0

feat: 前端指标体系增强 — Dashboard/Metrics API、2×4 统计区、趋势图面积+异常标记、连续状态列

- 新增 GET /api/dashboard 合并原 summary+targets 首屏接口
- 新增 GET /api/targets/:id/metrics 合并原 stats+trend 概览接口
- 后端指标纯函数:可用率、百分位、故障段分析、连续状态、UTC 小时分桶
- ProbeStore 窗口取数方法替代全量历史查询
- SummaryCards 扩展为 4 卡片(新增异常事件数)+ 数据新鲜度展示
- 表格新增「连续」列(Tag 渲染 capped 状态)
- OverviewTab 重构为 2×4 Statistic 多维度布局
- TrendChart 改为延迟范围面积图 + 红色异常标记点
- 删除旧路由(summary/targets/trend)和 computeTrendStats
- 同步 delta specs 到主 specs 并归档变更
This commit is contained in:
2026-05-14 12:32:41 +08:00
parent e983e5d75d
commit 1c5cfafda6
47 changed files with 1768 additions and 1231 deletions

View File

@@ -1,6 +1,6 @@
## Purpose
定义基于 SQLite 的拨测数据持久化存储targets 同步含分组信息、check_results 追加写入、结构化采样数据查询、时间范围和分页查询、索引与聚合查询。
定义基于 SQLite 的拨测数据持久化存储targets 同步含分组信息、check_results 追加写入、Dashboard 和 Metrics 数据查询支持、延迟百分位取数、时间范围和分页查询、索引与聚合查询。
## Requirements
@@ -61,26 +61,72 @@
- **WHEN** 查询所有 targets
- **THEN** 结果 SHALL 将 "default" 分组目标排在首位,其余分组按 YAML 配置中首次出现的顺序(即 id 自增顺序)排列
### Requirement: 结构化采样数据查询
系统 SHALL 提供 `getRecentSamples` 方法替代 `getSparkline`,返回包含状态信息的结构化采样数据
### Requirement: 聚合查询支持
数据存储 SHALL 支持按时间段获取指标计算所需数据,用于后端应用层计算可用率、平均耗时、延迟范围、趋势分桶和可靠性指标
#### Scenario: 获取最近采样数据
- **WHEN** 调用 `getRecentSamples(targetId, 30)`
- **THEN** 系统 SHALL 返回最多 30 条记录,每条包含 timestamp、duration_ms、matched
#### Scenario: 轻数据库计算边界
- **WHEN** 实现指标相关数据查询
- **THEN** 数据库 SHALL 主要负责存储、过滤、排序、分页、LIMIT 和标准 SQL 基础聚合,业务指标语义 SHALL 在后端应用层计算
#### Scenario: 采样数据排序
- **WHEN** 获取采样数据
- **THEN** 记录 SHALL 按 timestamp 降序排列(最新在前)
#### Scenario: 可使用的基础 SQL 聚合
- **WHEN** 查询需要减少返回数据
- **THEN** 系统 MAY 使用标准 SQL 的 COUNT、SUM(CASE)、AVG、MIN、MAX、GROUP BY 等基础能力
### Requirement: 趋势数据时间范围查询
系统 SHALL 支持按任意时间范围查询趋势聚合数据,替代固定 hours 参数。
#### Scenario: 避免数据库承载业务语义
- **WHEN** 实现状态翻转、故障段、MTTR、最长故障、连续状态、百分位或趋势分桶
- **THEN** 系统 SHALL 在后端应用层实现这些规则,不依赖 SQLite 专有函数或复杂窗口函数承载业务语义
#### Scenario: 按时间范围查询趋势
- **WHEN** 查询指定 target 在 from 到 to 时间范围内的趋势数据
- **THEN** 系统 SHALL 返回按小时分组的聚合数据,包括每小时的 avgDurationMs、availability 和 totalChecks
#### Scenario: UP/DOWN 判定
- **WHEN** 系统需要判定目标当前状态
- **THEN** 系统 SHALL 基于 latestCheck.matched 判定目标 UP 或 DOWNmatched=true 为 UPmatched=false 为 DOWN
### Requirement: Dashboard 数据查询支持
ProbeStore SHALL 提供 Dashboard 聚合响应所需的批量取数能力。
#### Scenario: 批量获取最新检查
- **WHEN** Dashboard API 需要计算当前 up/down 和 lastCheckTime
- **THEN** Store SHALL 支持批量获取每个 target 的最新检查记录,避免 N+1 查询
#### Scenario: 批量获取窗口统计基础数据
- **WHEN** Dashboard API 需要计算各 target 在指定 window 内的 totalChecks、upChecks、downChecks 和 availability
- **THEN** Store SHALL 支持按 target_id 批量返回指定时间窗口内的基础计数数据
#### Scenario: 批量获取最近样本
- **WHEN** Dashboard API 需要展示 recentSamples 和计算 capped currentStreak
- **THEN** Store SHALL 支持批量获取每个 target 最近 recentLimit 条检查记录,按 target_id 分组且每组按 timestamp 降序排列
#### Scenario: 获取 Dashboard 异常事件序列
- **WHEN** Dashboard API 需要计算 incidents
- **THEN** Store SHALL 支持获取指定时间窗口内所有 target 的 `{ target_id, timestamp, matched }` 序列,按 target_id 和 timestamp 升序排列,供后端应用层计算状态翻转
### Requirement: 单目标指标取数支持
ProbeStore SHALL 提供单目标 metrics 响应所需的取数能力。
#### Scenario: 获取目标检查点序列
- **WHEN** Metrics API 需要计算趋势分桶、故障段、MTTR、最长故障、故障次数和连续状态
- **THEN** Store SHALL 支持获取指定 target 在 from 到 to 时间范围内的 `{ timestamp, matched, duration_ms }` 数组,按 timestamp 升序排列
#### Scenario: 无检查记录
- **WHEN** 时间窗口内无检查记录
- **THEN** Store SHALL 返回空数组
### Requirement: 目标延迟百分位取数
ProbeStore SHALL 提供 `getTargetDurations(targetId, from, to)` 方法,返回时间窗口内所有成功检查的 duration_ms 数组。
#### Scenario: 获取延迟数据
- **WHEN** 调用 `getTargetDurations(targetId, from, to)`
- **THEN** 系统 SHALL 返回该目标在时间范围内所有 matched=1 且 duration_ms 不为 null 的 duration_ms 值数组
#### Scenario: 延迟数据排序
- **WHEN** 获取延迟数据
- **THEN** 返回数组 SHALL 按 duration_ms 升序排列,供后端应用层计算 P95/P99
#### Scenario: 无成功检查
- **WHEN** 时间窗口内无 matched=1 且 duration_ms 不为 null 的记录
- **THEN** 系统 SHALL 返回空数组
### Requirement: 历史记录时间范围和分页查询
系统 SHALL 支持按时间范围筛选并分页查询历史记录。
系统 SHALL 继续支持按时间范围筛选并分页查询历史记录。
#### Scenario: 按时间范围筛选历史记录
- **WHEN** 查询指定 target 在 from 到 to 时间范围内的历史记录
@@ -90,24 +136,6 @@
- **WHEN** 查询指定 page 和 pageSize 的历史记录
- **THEN** 系统 SHALL 返回对应页的数据和总记录数
### Requirement: 聚合查询支持
数据存储 SHALL 支持按时间段聚合查询用于计算可用率、平均耗时、P99 耗时等统计指标。
#### Scenario: 计算目标可用率
- **WHEN** 查询某目标在指定时间范围内的可用率
- **THEN** 系统 SHALL 返回 matched=true 的记录数占总记录数的百分比
#### Scenario: 计算目标平均耗时
- **WHEN** 查询某目标在指定时间范围内的平均耗时
- **THEN** 系统 SHALL 返回 duration_ms 的平均值(仅计算 matched=true 的记录)
#### Scenario: 按小时聚合趋势数据
- **WHEN** 查询某目标在指定时间范围内的趋势数据
- **THEN** 系统 SHALL 返回按小时分组的聚合数据,包括每小时的平均耗时和可用率
#### Scenario: UP/DOWN 判定
- **THEN** 系统 SHALL 基于 latestCheck.matched 判定目标 UP 或 DOWNmatched=true 为 UPmatched=false 为 DOWN
### Requirement: 目标展示摘要持久化
数据存储 SHALL 为每个 target 持久化一个领域无关的展示摘要字段 `target`