1
0

docs: 完善 DEVELOPMENT.md,按前端/后端/其他三大章节重构开发指引

This commit is contained in:
2026-05-12 15:26:49 +08:00
parent f7facb7232
commit e1c33b4002

View File

@@ -4,6 +4,17 @@
用户使用说明请参阅 [README.md](README.md)。 用户使用说明请参阅 [README.md](README.md)。
## 目录
- [项目结构](#项目结构)
- [一、后端开发指引](#一后端开发指引)
- [二、前端开发指引](#二前端开发指引)
- [三、项目运行、集成与打包](#三项目运行集成与打包)
- [代码质量](#代码质量)
- [已知限制](#已知限制)
---
## 项目结构 ## 项目结构
```text ```text
@@ -11,8 +22,8 @@ src/
server/ server/
app.ts Bun HTTP 路由入口(路由分发 + API 汇聚) app.ts Bun HTTP 路由入口(路由分发 + API 汇聚)
config.ts CLI 参数解析 config.ts CLI 参数解析
dev.ts 开发启动入口 dev.ts 生产/开发启动入口
server.ts HTTP server 启动 server.ts HTTP server 启动工厂
helpers.ts 共享响应格式化工具jsonResponse、createHeaders 等) helpers.ts 共享响应格式化工具jsonResponse、createHeaders 等)
middleware.ts API 参数校验中间件guardGetHead、validateTargetId 等) middleware.ts API 参数校验中间件guardGetHead、validateTargetId 等)
static.ts 静态资源服务与 SPA fallback static.ts 静态资源服务与 SPA fallback
@@ -47,53 +58,15 @@ tests/ Bun test 测试
openspec/ OpenSpec 变更与规格文档 openspec/ OpenSpec 变更与规格文档
``` ```
## 构建 executable
```bash
bun run build
```
构建流程:
1. 运行 `vite build`,输出前端资源到 `dist/web`
2. 生成临时 `.build/static-assets.ts`,嵌入 Vite 产物
3. 生成临时 `.build/server-entry.ts`,作为生产入口
4. 运行 `Bun.build({ compile })`,输出 `dist/dial-server`
运行 executable
```bash
./dist/dial-server probes.yaml
```
## 代码质量
```bash
bun run lint
bun run format:check
bun run format
bun run check
```
- `check` 依次运行 `typecheck``lint``format:check` 和单元测试。
## 测试
```bash
bun run check
bun run verify
```
- `check` 适合日常开发包含类型检查、lint、格式检查和单元测试。
- `verify` 先运行 `check`,再重新构建生产 executable 并运行 smoke test。
## 前后端边界 ## 前后端边界
前端只通过 HTTP 调用后端API 路径为 `/api/*`。共享类型放在 `src/shared`,前端不得 import `src/server` 的运行时实现。 前端只通过 HTTP 调用后端API 路径为 `/api/*`。共享类型放在 `src/shared`,前端不得 import `src/server` 的运行时实现。
## 后端开发指引 ---
### 架构概览 ## 一、后端开发指引
### 1.1 架构概览
``` ```
启动流程: 启动流程:
@@ -110,7 +83,7 @@ HTTP 请求:
→ middleware.ts(参数校验) → helpers.ts(响应格式化) → Response → middleware.ts(参数校验) → helpers.ts(响应格式化) → Response
``` ```
### 库使用优先级 ### 1.2 库使用优先级
后端代码开发遵循严格的库选择顺序: 后端代码开发遵循严格的库选择顺序:
@@ -122,7 +95,9 @@ HTTP 请求:
| 4 | 主流三方库 | cheerioHTML 解析、xpath + @xmldom/xmldomXML 解析) | | 4 | 主流三方库 | cheerioHTML 解析、xpath + @xmldom/xmldomXML 解析) |
| 5 | 自行实现 | 仅在以上都无法满足时(如 `parseDuration``parseSize``evaluateJsonPath` 等专项逻辑) | | 5 | 自行实现 | 仅在以上都无法满足时(如 `parseDuration``parseSize``evaluateJsonPath` 等专项逻辑) |
### API 路由开发 **原则**:新增依赖前先检查上述每一层级是否已有可用方案。禁止随意引入新依赖。
### 1.3 API 路由开发
路由文件位于 `src/server/routes/`每个端点一个文件。handler 函数签名统一为: 路由文件位于 `src/server/routes/`每个端点一个文件。handler 函数签名统一为:
@@ -142,24 +117,25 @@ export function handleXxx(params, store: ProbeStore, method: string, mode: Runti
1.`src/server/routes/` 下创建 `<name>.ts` 1.`src/server/routes/` 下创建 `<name>.ts`
2. 实现 handler 函数并 export 2. 实现 handler 函数并 export
3.`app.ts``handleApiRoute` 中注册路径匹配和调用 3.`app.ts``createFetchHandler` 中注册路径匹配和调用
4.`tests/server/app.test.ts` 中添加对应测试 4.`tests/server/app.test.ts` 中添加对应测试
### 共享工具 ### 1.4 共享工具
- **`helpers.ts`**:跨路由共用的响应工具函数(`jsonResponse``createHeaders``createApiError``mapCheckResult``formatDuration``createHealthResponse` - **`helpers.ts`**:跨路由共用的响应工具函数(`jsonResponse``createHeaders``createApiError``mapCheckResult``formatDuration``createHealthResponse`
- **`middleware.ts`**API 参数校验函数(`guardGetHead``validateTargetId``validateTimeRange``validatePagination` - **`middleware.ts`**API 参数校验函数(`guardGetHead``validateTargetId``validateTimeRange``validatePagination`
- **`static.ts`**:生产模式下的静态资源服务与 SPA fallback - **`static.ts`**:生产模式下的静态资源服务与 SPA fallback
### 类型定义规范 ### 1.5 类型定义规范
- **共享类型**以 `src/shared/api.ts` 为唯一源头,前后端共同引用 - **共享类型**以 `src/shared/api.ts` 为唯一源头,前后端共同引用
- 前端不得 `import src/server/` 下的任何文件 - 前端不得 `import src/server/` 下的任何文件
- **严格联合类型**优先于宽类型:如 `phase: "status" | "duration" | ...` 而非 `phase: string` - **严格联合类型**优先于宽类型:如 `phase: "status" | "duration" | ...` 而非 `phase: string`
- **后端内部扩展**`checker/types.ts``CheckResult` 通过 `extends` 共享版本的 `ApiCheckResult` 增加 `targetName` 等内部字段 - **后端内部扩展**`checker/types.ts``CheckResult` 通过 `extends` 共享版本的 `ApiCheckResult` 增加 `targetName` 等内部字段
- 存储层类型(`StoredTarget``StoredCheckResult`)独立定义,与 API 类型分离 - 存储层类型(`StoredTarget``StoredCheckResult`)独立定义,与 API 类型分离
- 配置类型(`ProbeConfig``TargetConfig`)支持 discriminated union通过 `type` 字段区分 http/command
### 数据存储规范 ### 1.6 数据存储规范
基于 `bun:sqlite`WAL 模式运行,数据库文件位于配置的 `dataDir` 下。 基于 `bun:sqlite`WAL 模式运行,数据库文件位于配置的 `dataDir` 下。
@@ -182,15 +158,16 @@ export function handleXxx(params, store: ProbeStore, method: string, mode: Runti
- `check_results`target_idFK CASCADE、timestamp、matched0/1、duration_ms、status_detail、failureJSON - `check_results`target_idFK CASCADE、timestamp、matched0/1、duration_ms、status_detail、failureJSON
- 复合索引:`(target_id, timestamp)` - 复合索引:`(target_id, timestamp)`
### 拨测引擎 ### 1.7 拨测引擎
- **调度**`ProbeEngine``es-toolkit/groupBy` 按 interval 分组,每组独立 `setInterval` 定时触发 - **调度**`ProbeEngine``es-toolkit/groupBy` 按 interval 分组,每组独立 `setInterval` 定时触发
- **并发控制**`es-toolkit/Semaphore` 限制全局最大并发数(`maxConcurrentChecks``acquire()` 阻塞等待 - **并发控制**`es-toolkit/Semaphore` 限制全局最大并发数(`maxConcurrentChecks``acquire()` 阻塞等待
- **Runner 选择**`engine.runCheck()``target.type` 分发到 `runHttpCheck``runCommandCheck` - **Runner 选择**`engine.runCheck()``target.type` 分发到 `runHttpCheck``runCommandCheck`
- **超时控制**HTTP 用 `AbortController`Command 用 `setTimeout` + `proc.kill()` - **超时控制**HTTP 用 `AbortController`Command 用 `setTimeout` + `proc.kill()`
- **结果写入**:检查结果通过 `store.insertCheckResult()` 写入 SQLiteengine 通过 `targetNameToId` 缓存 name→id 映射 - **结果写入**:检查结果通过 `store.insertCheckResult()` 写入 SQLiteengine 通过 `targetNameToId` 缓存 name→id 映射
- **生命周期**`start()`/`stop()` 管理定时器,`stop()` 清理所有 `setInterval`
### expect 断言系统 ### 1.8 expect 断言系统
两层模型:**观测值收集** → **规则校验** 两层模型:**观测值收集** → **规则校验**
@@ -220,21 +197,191 @@ runCommandCheck → 收集观测(exitCode/stdout/stderr/durationMs)
**操作符**`equals`(深度比较,`es-toolkit/isEqual`)、`contains``match`(正则)、`empty``isNil`+`isEmptyObject`)、`exists``gte`/`lte`/`gt`/`lt` **操作符**`equals`(深度比较,`es-toolkit/isEqual`)、`contains``match`(正则)、`empty``isNil`+`isEmptyObject`)、`exists``gte`/`lte`/`gt`/`lt`
### 错误模式 ### 1.9 错误模式
- **API 错误**`{ error: "描述", status: <code> }`,状态码 400/404/405/503 - **API 错误**`{ error: "描述", status: <code> }`,状态码 400/404/405/503
- **CheckFailure**`{ kind: "error"|"mismatch", phase, path, expected?, actual?, message }` - **CheckFailure**`{ kind: "error"|"mismatch", phase, path, expected?, actual?, message }`
- **错误处理**expect 校验失败记录首个失败原因;网络/超时/进程崩溃统一为 `kind:"error"` - **错误处理**expect 校验失败记录首个失败原因;网络/超时/进程崩溃统一为 `kind:"error"`
- **日志**:解析失败等非致命异常用 `console.warn`,启动失败用 `console.error` + `process.exit(1)` - **日志**:解析失败等非致命异常用 `console.warn`,启动失败用 `console.error` + `process.exit(1)`
### 测试规范 ### 1.10 测试规范
- 测试文件与源文件对应:`tests/server/checker/store.test.ts``src/server/checker/store.ts` - 测试文件与源文件对应:`tests/server/checker/store.test.ts``src/server/checker/store.ts`
- 使用 `bun:test` 框架(`describe`/`test`/`expect`),测试数据库用临时目录 + `tmpdir()` - 使用 `bun:test` 框架(`describe`/`test`/`expect`),测试数据库用临时目录 + `tmpdir()`
- 新增 store 方法必须编写单元测试;新增 API 端点必须在 `app.test.ts` 中添加集成测试 - 新增 store 方法必须编写单元测试;新增 API 端点必须在 `app.test.ts` 中添加集成测试
- 测试后清理:`afterAll``store.close()` + `rm(tempDir, { recursive: true })` - 测试后清理:`afterAll``store.close()` + `rm(tempDir, { recursive: true })`
## 前端样式规范 ---
## 二、前端开发指引
### 2.1 技术栈概览
| 层面 | 技术 | 用途 |
| -------- | ----------------------------------- | ------------------------------ |
| 框架 | React 19 | UI 组件开发 |
| 构建 | Vite 8 | 开发服务与生产构建 |
| 语言 | TypeScript 6 | 类型安全 |
| UI 库 | TDesign React + tdesign-icons-react | UI 组件与图标 |
| 数据层 | TanStack Query (React Query) | 服务端状态管理与自动轮询 |
| 图表 | Recharts | 拨测趋势折线图与状态环状图 |
| 路由 | 无(单页面 Dashboard | 仅需 Drawer/Tab 做页面内导航 |
**不引入的依赖**React Router单页面场景不需要、状态管理库TanStack Query 即服务端状态层,组件内用 `useState` 足够)
### 2.2 组件树与数据流
```
main.tsx
└── QueryClientProviderTanStack Query 全局挂载)
└── App根组件
├── SummaryCards总览统计卡片
│ └── useSummary() ─── GET /api/summary8s 轮询)
└── TargetBoard目标列表
├── useTargets() ─── GET /api/targets8s 轮询)
└── TargetGroup[](按 group 字段分组)
└── PrimaryTable ← TARGET_TABLE_COLUMNS列定义排序/筛选/渲染)
└── TargetDetailDrawer目标详情抽屉
└── useTargetDetail() ── 按需发起 trend + history 查询
├── Tab: 概览 → Statistic + TrendChart + StatusDonut + Descriptions
└── Tab: 记录 → PrimaryTable分页历史记录
```
**数据层架构**
```
hooks/useTargetDetail.ts唯一的数据层入口
├── queryKeys结构化 query key确保缓存粒度精确
├── useSummary() → /api/summary8s 自动轮询)
├── useTargets() → /api/targets8s 自动轮询)
└── useTargetDetail()(组合 hook管理 Drawer 全部状态)
├── 内部复用 useTargets() 的缓存来查找 selectedTarget
├── useQuery(/api/targets/:id/trend)条件查询enabled 仅当 Drawer 打开且时间范围有效)
└── useQuery(/api/targets/:id/history)(条件查询:含分页)
```
### 2.3 TanStack Query 数据层
#### Query Key 规范
```typescript
const queryKeys = {
summary: () => ["summary"] as const,
targets: () => ["targets"] as const,
trend: (targetId: number, from: string, to: string) => ["trend", targetId, from, to] as const,
history: (targetId: number, from: string, to: string, page: number) => ["history", targetId, from, to, page] as const,
};
```
- Key 使用 **structured array**(非字符串),以便精确匹配和按 prefix 失效
- 使用 `as const` 保持字面量类型
- 排序scope → id → 参数(粒度从粗到细)
#### 查询配置规范
```typescript
// 全局面板级查询(需要持续刷新)
useQuery({
queryKey: queryKeys.summary(),
queryFn: () => fetchJson<SummaryResponse>("/api/summary"),
refetchInterval: 8000, // 自动轮询间隔
refetchIntervalInBackground: false, // 切后台不轮询
});
// 详情级查询(按需加载)
useQuery({
queryKey: selectedTargetId ? queryKeys.trend(id, from, to) : ["trend", "disabled"],
queryFn: () => fetchJson(`/api/targets/${id}/trend?...`),
enabled: selectedTargetId !== null && !!timeFrom && !!timeTo, // 条件查询
});
```
#### fetch 封装
```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>;
}
```
- 统一使用 `fetch`(不引入 axios与后端共享 Web API 生态
- 错误抛异常,由 TanStack Query 的 `error` 状态承接
#### QueryClient 全局配置
```typescript
new QueryClient({
defaultOptions: {
queries: {
retry: 1, // 失败重试 1 次
refetchOnWindowFocus: true, // 窗口聚焦时刷新
staleTime: 5000, // 5s 内视为 fresh避免重复请求
},
},
});
```
### 2.4 组件开发规范
#### 文件命名与导入
- 每个 React 组件一个 `.tsx` 文件,文件名使用 PascalCase`StatusDot.tsx`
- 组件 props 定义为 `interface XxxProps`,紧邻组件函数声明
- 类型从 `../../shared/api` 导入,使用 `type` 导入(`import type { ... }`
```typescript
import type { TargetStatus } from "../../shared/api";
import { StatusDot } from "./StatusDot";
interface TargetGroupProps {
name: string;
targets: TargetStatus[];
onTargetClick: (target: TargetStatus) => void;
}
export function TargetGroup({ name, targets, onTargetClick }: TargetGroupProps) {
// ...
}
```
#### 组件拆分原则
- **展示组件**`components/`):纯渲染逻辑,通过 props 接收数据,通过回调返回事件
- **容器逻辑**放在 hooks 中,组件只做数据消费
- **常量数据**(列定义、排序器、筛选器)放在 `constants/`,不放在组件内部
- **工具函数**(时间处理等)放在 `utils/`,保持纯函数无副作用
#### 现有组件清单
| 组件 | 文件 | 用途 |
| ----------------------- | -------------------------- | ---------------------------- |
| `App` | `app.tsx` | 根组件,编排全局状态与布局 |
| `SummaryCards` | `components/SummaryCards.tsx` | 总览统计卡片(全部/正常/异常) |
| `TargetBoard` | `components/TargetBoard.tsx` | 按分组渲染目标表格列表 |
| `TargetGroup` | `components/TargetGroup.tsx` | 单个分组标题 + PrimaryTable |
| `TargetDetailDrawer` | `components/TargetDetailDrawer.tsx` | 目标详情抽屉(概览/记录 Tab |
| `TrendChart` | `components/TrendChart.tsx` | Recharts 双轴折线图(耗时/可用率) |
| `StatusDonut` | `components/StatusDonut.tsx` | Recharts 环状图UP/DOWN 分布) |
| `StatusDot` | `components/StatusDot.tsx` | 圆形状态指示点(绿/红) |
| `StatusBar` | `components/StatusBar.tsx` | 最近采样状态条(多色块) |
| `GroupHeader` | `components/GroupHeader.tsx` | 分组标题(名称 + 统计) |
### 2.5 新增功能开发步骤
以"新增一个详情页面 Tab"为例:
1. **确认数据需求**:是已有 API 数据还是需要新端点?
- 如有新端点,先在 `src/server/routes/` 添加,参考 [1.3 新增路由步骤](#13-api-路由开发)
- 如有新字段,更新 `src/shared/api.ts` 类型定义
2. **实现 hooks**:在 `src/web/hooks/useTargetDetail.ts` 中新增 `useQuery`(写好 `queryKey``enabled` 条件)
3. **编写组件**:在 `src/web/components/` 创建组件文件
-`TargetDetailDrawer.tsx` 中新增 `<Tabs.TabPanel>` 引用
4. **编写常量**:如有列定义/排序器/筛选器,放在 `src/web/constants/`
5. **编写测试**:在 `tests/web/` 下添加对应的单元测试
### 2.6 样式开发规范
前端基于 TDesign React 构建 UI样式开发遵循以下优先级从高到低 前端基于 TDesign React 构建 UI样式开发遵循以下优先级从高到低
@@ -251,6 +398,256 @@ runCommandCheck → 收集观测(exitCode/stdout/stderr/durationMs)
- **严禁使用 `!important`** - **严禁使用 `!important`**
- 颜色统一使用 TDesign CSS tokens`--td-success-color``--td-error-color``--td-warning-color` 等),不使用硬编码色值 - 颜色统一使用 TDesign CSS tokens`--td-success-color``--td-error-color``--td-warning-color` 等),不使用硬编码色值
**styles.css 组织**
- 自定义 CSS 变量(如可用率渐变色 `--avail-0` ~ `--avail-9`)定义在 `:root`
- 布局类(`.dashboard``.dashboard-header`)定义全局页面结构
- 组件修饰类(`.status-dot--up``.latency-ok`)为自定义视觉组件提供样式变体
- TDesign 表格行高亮(`.row-down`)通过 `rowClassName` prop 应用
### 2.7 前端测试规范
- 测试目录:`tests/web/`,结构对应 `src/web/`
- 重点测试 **constants/** 中的纯函数(排序器、筛选器、颜色阈值等)
- 使用 `bun:test` 框架
---
## 三、项目运行、集成与打包
### 3.1 开发期运行
#### 同时启动前后端
```bash
bun run dev probes.yaml
```
`scripts/dev.ts` 通过 `Bun.spawn` 同时启动两个子进程:
```
bun run dev probes.yaml
├── bun run dev:server probes.yaml → Bun HTTP 后端(默认 3000 端口)
└── bun run dev:web → Vite 前端开发服务器5173 端口)
```
- 任一子进程退出会导致整体退出
- `SIGINT`/`SIGTERM` 信号会同时终止两个子进程
- `BACKEND_PORT` 环境变量可覆盖后端端口
#### 分别启动
```bash
# 启动后端(含 watch 模式自动重启)
bun run dev:server probes.yaml
# 另开终端启动前端
bun run dev:web
```
### 3.2 前后端集成方式
#### 开发期代理
Vite 配置了开发代理(`vite.config.ts`
```typescript
server: {
proxy: {
"/api": {
target: `http://127.0.0.1:${backendPort}`,
changeOrigin: true,
},
},
}
```
前端访问 `/api/*`Vite 开发服务器自动转发到后端 `http://127.0.0.1:${backendPort}`,无需 CORS 配置。
前端开发地址为 `http://127.0.0.1:5173`(严格端口 `strictPort: true`)。
后端在开发模式下不提供静态资源服务,访问 `http://127.0.0.1:3000` 会提示"请通过 Vite 前端地址访问"。
#### 生产期集成
生产可执行文件是单体应用:前端静态资源嵌入 binary后端同时提供 API 和静态文件服务。
```
./dist/dial-server probes.yaml
启动后:
访问 http://127.0.0.1:3000/ → 返回前端 SPAindex.html
访问 http://127.0.0.1:3000/api/* → 返回后端 API
访问 /assets/* → 返回带不可变缓存的静态资源
```
SPA fallback 逻辑(`src/server/static.ts`
- `/` → index.html
- 匹配 `/assets/*` → 返回对应文件(未匹配则 404
- 其他路径(如 `/dashboard`)→ fallback 到 index.htmlSPA 路由)
### 3.3 构建打包
#### 构建命令
```bash
bun run build
```
#### 构建流程详解
`scripts/build.ts` 执行以下步骤:
```
1. vite build
├── 入口src/web/index.html
└── 输出dist/web/index.html + assets/
2. 生成 .build/static-assets.ts临时文件
├── import Vite 产物为 Bun.file
└── 导出 staticAssets: StaticAssets 对象
3. 生成 .build/server-entry.ts临时文件
└── import 后端入口模块 + staticAssets作为 Bun.build 入口
4. Bun.build({ compile, minify, sourcemap: "linked" })
└── 输出dist/dial-server单文件可执行 binary
```
#### 产物
| 产物 | 用途 |
| ---------------------------- | ------------------------ |
| `dist/dial-server` | 生产可执行文件 |
| `dist/web/` | Vite 构建产物(中间产物) |
| `.build/` | 临时生成文件(构建后清理) |
#### 构建参数
| 环境变量 | 说明 |
| ------------------- | ----------------------------------------- |
| `BUN_TARGET`/`BUILD_TARGET` | 交叉编译目标平台(如 `bun-linux-x64` |
#### 运行可执行文件
```bash
./dist/dial-server probes.yaml
```
#### 清理
```bash
bun run clean
# 清理 .build/ 缓存和 *.bun-build 临时文件
```
### 3.4 开发工作流
#### 日常开发循环
```bash
bun run dev probes.yaml # 启动开发环境
# 修改代码 → Vite HMR前端/ bun --watch后端自动重启
bun run check # 提交前运行完整质量检查
```
#### 完整验证流程
```bash
bun run verify
# = bun run check + bun run build + bun run test:smoke
```
`verify` 适合 CI 或正式提交前会完整验证类型检查、lint、格式、单元测试、构建、smoke test。
### 3.5 Smoke Test
```bash
bun run test:smoke
```
`scripts/smoke.ts` 构建后验证流程:
1. 动态分配空闲端口
2. 用临时配置文件启动 `dist/dial-server`
3. 等待健康检查通过
4. 验证所有 API 端点返回正确数据
5. 验证静态资源服务(含 SPA fallback 和 404 处理)
6. 验证安全 headers
7. 测试结束清理临时目录和进程
### 3.6 脚本说明
| 脚本 | 文件 | 说明 |
| ----------------------- | ------------------ | ---------------------------------- |
| `bun run dev` | `scripts/dev.ts` | 同时启动前后端开发服务 |
| `bun run build` | `scripts/build.ts` | Vite 构建 + Bun 编译可执行文件 |
| `bun run test:smoke` | `scripts/smoke.ts` | 构建后的端到端验证 |
| `bun run clean` | `scripts/clean.ts` | 清理构建缓存与临时文件 |
### 3.7 环境变量
| 变量 | 用途 | 默认值 |
| ----------------------- | ------------------------------------------- | ------ |
| `PORT`/`BACKEND_PORT` | 后端监听端口(开发期 Vite 代理目标、生产期监听端口) | `3000` |
| `BUN_TARGET`/`BUILD_TARGET` | 交叉编译目标平台(仅在 `bun run build` 时有效) | 当前平台 |
### 3.8 项目配置文件
| 文件 | 用途 |
| --------------------- | -------------------------------------- |
| `package.json` | 项目信息、脚本、依赖声明 |
| `tsconfig.json` | TypeScript 配置ESNext 模块、严格模式)|
| `vite.config.ts` | Vite 开发代理与构建配置 |
| `eslint.config.js` | ESLint 规则(含前端不得 import server 的检查) |
| `.prettierrc.json` | Prettier 格式化规则(`printWidth: 120` |
| `.prettierignore` | Prettier 排除路径 |
| `probes.example.yaml` | 配置文件示例 |
| `opencode.json` | OpenCode 工具配置TDesign MCP server |
### 3.9 依赖管理
- **包管理器**:仅使用 `bun`,禁止使用 npm、pnpm、yarn
- **安装依赖**`bun install`
- **运行工具**:使用 `bunx`,禁止使用 `npx``pnpx`
- **锁文件**`bun.lock`
### 3.10 目录约定
| 目录 | 约定 |
| --------------- | ------------------------------------------ |
| `src/server/` | 后端代码,不能 import `src/web/` |
| `src/web/` | 前端代码,不能 import `src/server/` |
| `src/shared/` | 前后端共享类型,双向可引用 |
| `scripts/` | 独立运行脚本,可 import 项目源码 |
| `tests/` | 测试目录,结构镜像 src 目录 |
| `dist/` | 构建产物gitignore |
| `.build/` | 构建临时文件gitignore |
| `openspec/` | OpenSpec 变更管理与规格文档 |
| `data/` | 默认数据目录gitignore运行期生成 SQLite|
---
## 代码质量
```bash
bun run lint # ESLint 检查
bun run format:check # Prettier 格式检查
bun run format # Prettier 自动格式化
bun run typecheck # TypeScript 类型检查
bun test # 运行所有测试
bun run check # 一键运行 typecheck + lint + format:check + test
```
`check` 是日常开发推荐的质量检查命令。
## 测试
```bash
bun run check # 日常开发(类型检查 + lint + 格式 + 单元测试)
bun run verify # 完整验证check + 构建 + smoke test
```
## 已知限制 ## 已知限制
当前不做告警通知、数据自动清理、拨测目标动态增删、认证鉴权和分布式部署。Command 类型拨测不支持 Windows 环境。 当前不做告警通知、数据自动清理、拨测目标动态增删、认证鉴权和分布式部署。Command 类型拨测不支持 Windows 环境。