1
0

feat: 基础设施加固 — 修复构建、数据保留、错误边界、bundle 拆分

- 修复 build script 引用已删除的 registerCheckers,恢复生产构建
- 生产入口添加 SIGINT/SIGTERM 优雅关闭(与 dev.ts 一致)
- 新增 runtime.retention 配置(默认 7d),ProbeStore.prune() 定时清理过期数据
- parseDuration 扩展支持 h/d 单位
- 新增前端 ErrorBoundary 组件,防止渲染错误白屏
- Vite codeSplitting.groups 拆分 vendor chunks(业务代码 1180KB → 47KB)
- 同步 delta specs 到主规范
This commit is contained in:
2026-05-13 16:48:56 +08:00
parent 26f0bfe104
commit bcfb907bd3
25 changed files with 458 additions and 26 deletions

View File

@@ -0,0 +1,43 @@
## Purpose
定义历史拨测数据的自动清理机制:可配置的保留时长和定时清理调度。
## Requirements
### Requirement: 数据保留配置
系统 SHALL 支持通过 `runtime.retention` 配置项指定历史数据保留时长,格式为持续时间字符串(`<数字><单位>`,单位支持 `d`/`h`/`m`)。
#### Scenario: 配置 7 天保留
- **WHEN** 配置文件中 `runtime.retention` 设置为 `"7d"`
- **THEN** 系统 SHALL 保留最近 7 天的检查结果,清理更早的数据
#### Scenario: 配置小时级保留
- **WHEN** 配置文件中 `runtime.retention` 设置为 `"24h"`
- **THEN** 系统 SHALL 保留最近 24 小时的检查结果
#### Scenario: 未配置 retention
- **WHEN** 配置文件中未指定 `runtime.retention`
- **THEN** 系统 SHALL 使用默认值 `"7d"`
#### Scenario: 无效 retention 格式
- **WHEN** 配置文件中 `runtime.retention` 格式不合法(如 `"abc"``"7x"`
- **THEN** 系统 SHALL 在配置校验阶段报错,拒绝启动
### Requirement: 定时清理调度
系统 SHALL 以固定间隔1 小时)定期执行数据清理,删除超过保留时长的历史检查结果。
#### Scenario: 引擎启动后首次清理
- **WHEN** ProbeEngine 启动
- **THEN** 系统 SHALL 立即执行一次清理,然后每隔 1 小时再次执行
#### Scenario: 清理执行
- **WHEN** 清理定时器触发
- **THEN** 系统 SHALL 删除 `check_results` 表中 `timestamp` 早于 `now - retentionMs` 的所有记录
#### Scenario: 引擎停止时清除定时器
- **WHEN** ProbeEngine.stop() 被调用
- **THEN** 系统 SHALL 清除清理定时器,不再执行后续清理
#### Scenario: retention 为 0 时不清理
- **WHEN** 配置的 retention 解析为 0 毫秒
- **THEN** 系统 SHALL 不注册清理定时器,数据永久保留

View File

@@ -0,0 +1,31 @@
## Purpose
定义前端全局错误边界:捕获渲染错误防止白屏,展示友好的错误兜底 UI。
## Requirements
### Requirement: 全局渲染错误捕获
前端应用 SHALL 在最外层包裹 ErrorBoundary 组件,捕获所有子组件树的渲染错误,防止白屏。
#### Scenario: 子组件渲染抛出异常
- **WHEN** 任意子组件在渲染过程中抛出 JavaScript 异常
- **THEN** ErrorBoundary SHALL 捕获该异常,展示错误兜底 UI而非白屏
#### Scenario: 错误兜底 UI 内容
- **WHEN** ErrorBoundary 捕获到渲染错误
- **THEN** 系统 SHALL 使用 TDesign Result 组件type="500")展示错误提示,并提供"刷新页面"按钮
#### Scenario: 刷新页面恢复
- **WHEN** 用户点击错误兜底 UI 中的"刷新页面"按钮
- **THEN** 系统 SHALL 调用 `window.location.reload()` 重新加载页面
#### Scenario: 错误信息记录
- **WHEN** ErrorBoundary 捕获到渲染错误
- **THEN** 系统 SHALL 通过 `console.error` 输出错误信息和组件堆栈
### Requirement: ErrorBoundary 包裹位置
ErrorBoundary SHALL 包裹在 QueryClientProvider 外层,确保 React Query 相关的渲染错误也能被捕获。
#### Scenario: 包裹层级
- **WHEN** 应用渲染树构建
- **THEN** 层级 SHALL 为 StrictMode > ErrorBoundary > QueryClientProvider > App

View File

@@ -276,3 +276,18 @@
#### Scenario: 不配置 expect
- **WHEN** target 未配置任何 expect 规则
- **THEN** 系统 SHALL 正常处理expect 字段为 undefined
### Requirement: 数据保留配置字段
配置 schema 的 `runtime` 段 SHALL 支持 `retention` 字段,类型为字符串,格式为 `<数字><单位>`(单位:`d` 天、`h` 小时、`m` 分钟),用于指定历史数据保留时长。
#### Scenario: retention 字段校验通过
- **WHEN** 配置文件中 `runtime.retention` 为合法格式(如 `"7d"``"24h"``"30m"`
- **THEN** 配置校验 SHALL 通过
#### Scenario: retention 字段格式非法
- **WHEN** 配置文件中 `runtime.retention` 为非法格式(如 `"abc"``"7x"``""`
- **THEN** 配置校验 SHALL 失败并报告格式错误
#### Scenario: retention 字段缺省
- **WHEN** 配置文件中未指定 `runtime.retention`
- **THEN** 系统 SHALL 使用默认值 `"7d"`

View File

@@ -32,3 +32,14 @@ Dashboard SHALL 使用 TDesign 组件正确处理加载状态和 API 错误。
#### Scenario: API 请求失败
- **WHEN** 前端 API 请求失败
- **THEN** 页面 SHALL 使用 TDesign Alert 组件theme=error显示错误提示
### Requirement: 前端构建产物拆分
前端生产构建 SHALL 将 vendor 依赖拆分为独立 chunk利用浏览器并行加载和长期缓存。
#### Scenario: vendor chunk 拆分
- **WHEN** 执行前端生产构建
- **THEN** 构建产物 SHALL 包含独立的 vendor chunkreact、tdesign、recharts 各自独立),而非单个 bundle
#### Scenario: 业务代码变更不影响 vendor 缓存
- **WHEN** 仅修改业务代码src/web/ 下非 node_modules 文件)并重新构建
- **THEN** vendor chunk 的文件名(含 hashSHALL 保持不变,浏览器缓存 SHALL 继续有效

View File

@@ -126,3 +126,18 @@
#### Scenario: command target config 序列化
- **WHEN** 同步 command target
- **THEN** targets.config SHALL 存储 JSON包含 exec、args、cwd、env、maxOutputBytes
### Requirement: 数据清理方法
ProbeStore SHALL 提供 `prune(retentionMs: number)` 方法,删除超过保留时长的历史检查结果并返回删除行数。
#### Scenario: 清理过期数据
- **WHEN** 调用 `prune(604800000)`7 天毫秒数)
- **THEN** 系统 SHALL 删除 `check_results` 表中 `timestamp` 早于当前时间减去 604800000 毫秒的所有记录,并返回实际删除的行数
#### Scenario: 无过期数据
- **WHEN** 调用 `prune()` 但所有记录都在保留期内
- **THEN** 系统 SHALL 返回 0不删除任何记录
#### Scenario: 清理不影响保留期内数据
- **WHEN** 调用 `prune()` 且存在保留期内和保留期外的记录
- **THEN** 系统 SHALL 仅删除保留期外的记录,保留期内的记录 SHALL 不受影响

View File

@@ -230,3 +230,18 @@ HTTP checker SHALL 将运行期失败归属到实际失败阶段。请求、网
#### Scenario: 选择 command runner
- **WHEN** target.type 为 `command`
- **THEN** 系统 SHALL 使用 command runner 执行该目标
### Requirement: 定期数据清理
ProbeEngine SHALL 在启动时注册数据清理定时器,定期调用 ProbeStore.prune() 清理过期数据。
#### Scenario: 引擎启动注册清理
- **WHEN** ProbeEngine.start() 被调用且 retentionMs > 0
- **THEN** 系统 SHALL 立即执行一次 prune然后每隔 1 小时再次执行
#### Scenario: 引擎停止清除定时器
- **WHEN** ProbeEngine.stop() 被调用
- **THEN** 系统 SHALL 清除清理定时器,不再执行后续清理
#### Scenario: retentionMs 为 0 不注册清理
- **WHEN** ProbeEngine 构造时 retentionMs 为 0
- **THEN** 系统 SHALL 不注册清理定时器

View File

@@ -27,7 +27,7 @@
- **THEN** 生成的嵌入资源模块 SHALL 保持语义一致且不依赖文件系统遍历顺序
### Requirement: 单 executable 输出
生产构建 SHALL 输出一个 standalone executable其中包含 Bun 后端、必要 server 依赖和构建后的前端资源。构建成功后 SHALL 自动清理中间产物目录(`.build/`),构建失败时 SHALL 保留中间产物以便排查。
生产构建 SHALL 输出一个 standalone executable其中包含 Bun 后端、必要 server 依赖和构建后的前端资源。构建成功后 SHALL 自动清理中间产物目录(`.build/`),构建失败时 SHALL 保留中间产物以便排查。生成的入口代码 SHALL 通过 import config-loader 模块隐式触发 checker 注册,而非显式调用注册函数。生成的入口 SHALL 注册 SIGINT 和 SIGTERM 信号处理器,在收到信号时依次调用 engine.stop() 和 store.close() 后退出进程。
#### Scenario: 在目标机器运行 executable
- **WHEN** 生成的 executable 在兼容目标平台上运行
@@ -49,6 +49,14 @@
- **WHEN** 生产构建在任意步骤失败前端构建、中间产物生成、Bun 编译)
- **THEN** `.build/` 目录 SHALL 保留在磁盘上以供排查
#### Scenario: checker 注册通过 import 链触发
- **WHEN** 生成的入口代码 import config-loader 模块
- **THEN** checkerRegistry 单例 SHALL 通过模块依赖链自动完成注册,入口代码 SHALL NOT 显式调用任何注册函数
#### Scenario: 生产入口优雅关闭
- **WHEN** executable 进程收到 SIGINT 或 SIGTERM 信号
- **THEN** 系统 SHALL 调用 engine.stop() 停止所有定时器,调用 store.close() 关闭数据库连接,然后以退出码 0 退出进程
### Requirement: 外部运行时配置
executable MUST 将环境相关运行时配置保留在嵌入的前端和 server bundle 之外。