feat: 新增版本管理系统,重构 /health → /api/meta
This commit is contained in:
129
DEVELOPMENT.md
129
DEVELOPMENT.md
@@ -30,11 +30,12 @@ src/
|
||||
static.ts 生产模式静态资源服务(SPA fallback、Content-Type 映射、immutable 缓存)
|
||||
helpers.ts 共享响应格式化工具(见下方函数清单)
|
||||
middleware.ts API 参数校验中间件(validateIdParam、validatePagination、validateTimeRange)
|
||||
routes/ API 路由 handler(按端点拆分)
|
||||
health.ts GET /health
|
||||
shared/
|
||||
api.ts 前后端共享 TypeScript 类型
|
||||
app.ts 应用全局常量(name、title、subtitle、description、version)
|
||||
routes/ API 路由 handler(按端点拆分)
|
||||
meta.ts GET /api/meta
|
||||
version.ts 运行时版本号读取(从 package.json 读取并验证)
|
||||
shared/
|
||||
api.ts 前后端共享 TypeScript 类型
|
||||
app.ts 应用全局常量(name、title、subtitle、description)
|
||||
web/ React 前端(通过 Vite 构建)
|
||||
index.html HTML 入口
|
||||
app.tsx 根组件(Admin 布局:Header + Sidebar + Content)
|
||||
@@ -43,8 +44,8 @@ src/
|
||||
styles.css 全局样式与自定义 CSS 变量
|
||||
css.d.ts CSS 模块类型声明
|
||||
pages/ 页面组件
|
||||
dashboard/
|
||||
index.tsx 仪表盘页(欢迎语 + /health 联调示例)
|
||||
dashboard/
|
||||
index.tsx 仪表盘页(欢迎语 + /api/meta 联调示例)
|
||||
users/
|
||||
index.tsx 用户管理页(占位)
|
||||
settings/
|
||||
@@ -62,10 +63,12 @@ src/
|
||||
time.ts 时间处理(formatCountdown、formatDurationUnit、formatRelativeTime、isOlderThan、subtractHours)
|
||||
menu.tsx 菜单配置(路由与菜单项统一数据源)
|
||||
routes.tsx 路由配置(定义所有页面路由)
|
||||
scripts/
|
||||
dev.ts 双进程开发服务(Bun API server + Vite dev server)
|
||||
build.ts Vite → codegen → Bun compile 三步构建流水线
|
||||
clean.ts 清理构建产物与临时文件
|
||||
scripts/
|
||||
dev.ts 双进程开发服务(Bun API server + Vite dev server)
|
||||
build.ts Vite → codegen → Bun compile 三步构建流水线(含版本号注入)
|
||||
bump-version-logic.ts 纯版本管理逻辑(parse、validate、bump、format)
|
||||
bump-version.ts 版本升迁 CLI 脚本
|
||||
clean.ts 清理构建产物与临时文件
|
||||
tests/ Bun test 测试(结构镜像 src 目录)
|
||||
setup.ts 全局测试配置(jsdom、polyfill)
|
||||
helpers.ts 测试辅助工具(rmRetry)
|
||||
@@ -85,7 +88,7 @@ config.example.yaml 配置文件示例
|
||||
|
||||
## 前后端边界
|
||||
|
||||
前端只通过 HTTP 调用后端,API 路径为 `/api/*` 和 `/health`。共享类型放在 `src/shared`,前端不得 `import src/server` 的运行时实现。
|
||||
前端只通过 HTTP 调用后端,API 路径为 `/api/*`。共享类型放在 `src/shared`,前端不得 `import src/server` 的运行时实现。
|
||||
|
||||
---
|
||||
|
||||
@@ -129,8 +132,8 @@ HTTP 请求:
|
||||
// server.ts 中的路由注册
|
||||
routes: {
|
||||
"/api/*": () => jsonResponse(createApiError("API route not found", 404), { mode, status: 404 }),
|
||||
"/health": {
|
||||
GET: () => handleHealth(mode),
|
||||
"/api/meta": {
|
||||
GET: async () => handleMeta(mode, await resolveVersion()),
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -138,8 +141,8 @@ routes: {
|
||||
Handler 函数签名:
|
||||
|
||||
```typescript
|
||||
// 无依赖的路由
|
||||
export function handleHealth(mode: RuntimeMode): Response;
|
||||
// 带版本号参数的路由
|
||||
export function handleMeta(mode: RuntimeMode, version: string): Response;
|
||||
```
|
||||
|
||||
**请求处理流程**:
|
||||
@@ -161,7 +164,7 @@ export function handleHealth(mode: RuntimeMode): Response;
|
||||
- **`helpers.ts`**:跨路由共用的响应工具函数
|
||||
- `createApiError(error, status)` — 构造 API 错误体
|
||||
- `createHeaders(mode, init)` — 创建响应 Headers(生产模式附加安全头:`X-Content-Type-Options`、`Referrer-Policy`)
|
||||
- `createHealthResponse()` — 构造健康检查响应 `{ ok: true, service, timestamp }`
|
||||
- `createMetaResponse(version)` — 构造应用元信息响应 `{ ok: true, service, timestamp, version }`
|
||||
- `formatDuration(ms)` — 毫秒转为可读时长字符串
|
||||
- `jsonResponse(body, options)` — JSON 响应构造
|
||||
|
||||
@@ -177,10 +180,11 @@ export function handleHealth(mode: RuntimeMode): Response;
|
||||
### 1.5 类型定义规范
|
||||
|
||||
- **共享类型**以 `src/shared/api.ts` 为唯一源头,前后端共同引用
|
||||
- **应用常量**以 `src/shared/app.ts` 为唯一源头,定义 `APP` 对象(name、title、subtitle、description、version),前后端及构建脚本共同引用
|
||||
- **应用常量**以 `src/shared/app.ts` 为唯一源头,定义 `APP` 对象(name、title、subtitle、description),前后端及构建脚本共同引用
|
||||
- **版本号**以 `package.json.version` 为唯一源头,通过 `src/server/version.ts` 运行时读取或构建时注入字面量
|
||||
- 前端不得 `import src/server/` 下的任何文件
|
||||
- **严格联合类型**优先于宽类型:如 `RuntimeMode: "development" | "production" | "test"` 而非 `RuntimeMode: string`
|
||||
- API 响应类型(`ApiErrorResponse`、`HealthResponse`)定义在 shared 中
|
||||
- API 响应类型(`ApiErrorResponse`、`MetaResponse`)定义在 shared 中
|
||||
|
||||
### 1.6 配置文件规范
|
||||
|
||||
@@ -208,7 +212,29 @@ server:
|
||||
port: 3000
|
||||
```
|
||||
|
||||
### 1.7 错误模式
|
||||
### 1.7 版本管理
|
||||
|
||||
项目使用 `package.json.version` 作为版本号唯一来源,严格 `MAJOR.MINOR.PATCH` 格式。
|
||||
|
||||
**版本获取方式**:
|
||||
|
||||
- 开发模式:`src/server/version.ts` 运行时从 `package.json` 读取版本号
|
||||
- 生产模式:`scripts/build.ts` 在构建时将版本号烘焙为 `APP_VERSION` 字面量注入 `server-entry.ts`
|
||||
|
||||
**版本升迁命令**:
|
||||
|
||||
```bash
|
||||
bun run version:patch # 升迁 patch 版本(0.1.0 → 0.1.1)
|
||||
bun run version:minor # 升迁 minor 版本(0.1.0 → 0.2.0)
|
||||
bun run version:major # 升迁 major 版本(0.1.0 → 1.0.0)
|
||||
bun run version:set 2.0.0 # 显式设置版本号
|
||||
```
|
||||
|
||||
版本升迁仅更新 `package.json.version`,不自动创建 git commit、tag 或 changelog。
|
||||
|
||||
**API 暴露**:`GET /api/meta` 返回 `{ ok, service, timestamp, version }`,前端通过此接口获取并展示版本号。
|
||||
|
||||
### 1.8 错误模式
|
||||
|
||||
- **API 错误**:`{ error: "描述", status: <code> }`,状态码 400/404
|
||||
- **日志**:非致命异常用 `console.warn`,启动失败用 `console.error` + `process.exit(1)`
|
||||
@@ -248,7 +274,7 @@ main.tsx
|
||||
│ │ │ └── Sidebar(TDesign Menu,菜单项点击导航)
|
||||
│ │ └── Content
|
||||
│ │ └── AppRoutes(路由配置)
|
||||
│ │ ├── / → DashboardPage(欢迎语 + /health 联调)
|
||||
│ │ ├── / → DashboardPage(欢迎语 + /api/meta 联调)
|
||||
│ │ ├── /users → UsersPage(占位)
|
||||
│ │ ├── /settings → SettingsPage(占位)
|
||||
│ │ └── * → NotFoundPage(404)
|
||||
@@ -288,7 +314,7 @@ utils/menu-config.ts(路由与菜单统一数据源)
|
||||
```typescript
|
||||
// 使用 structured array(非字符串),以便精确匹配和按 prefix 失效
|
||||
const queryKeys = {
|
||||
health: () => ["health"] as const,
|
||||
meta: () => ["meta"] as const,
|
||||
};
|
||||
```
|
||||
|
||||
@@ -300,8 +326,8 @@ const queryKeys = {
|
||||
```typescript
|
||||
// 全局级查询(需要持续刷新)
|
||||
useQuery({
|
||||
queryKey: queryKeys.health(),
|
||||
queryFn: () => fetchJson<HealthResponse>("/health"),
|
||||
queryKey: queryKeys.meta(),
|
||||
queryFn: () => fetchJson<MetaResponse>("/api/meta"),
|
||||
refetchInterval: 30000, // 30s 轮询
|
||||
refetchIntervalInBackground: false, // 切后台不轮询
|
||||
staleTime: 5000, // 5s 内视为 fresh
|
||||
@@ -344,7 +370,7 @@ new QueryClient({
|
||||
- 类型从 `../shared/api` 导入,使用 `type` 导入(`import type { ... }`)
|
||||
|
||||
```typescript
|
||||
import type { HealthResponse } from "../shared/api";
|
||||
import type { MetaResponse } from "../shared/api";
|
||||
|
||||
interface AppProps {
|
||||
title?: string;
|
||||
@@ -409,7 +435,7 @@ bun run dev [config.yaml]
|
||||
- **Bun API server**(端口 3000):后端 API 服务,`--watch` 监听后端文件变更自动重启
|
||||
- **Vite dev server**(端口 5173):前端 SPA + HMR 热更新
|
||||
|
||||
开发时访问 `http://127.0.0.1:5173`,Vite 自动将 `/api` 和 `/health` 请求代理到后端。
|
||||
开发时访问 `http://127.0.0.1:5173`,Vite 自动将 `/api` 请求代理到后端。
|
||||
|
||||
也可以单独启动:
|
||||
|
||||
@@ -426,7 +452,7 @@ bun run dev:web # 仅启动 Vite dev server
|
||||
|
||||
- Vite dev server 负责前端 SPA、HMR、模块热替换
|
||||
- Bun API server 负责后端 API 路由
|
||||
- Vite 通过 proxy 配置将 `/api/*` 和 `/health` 转发到 Bun
|
||||
- Vite 通过 proxy 配置将 `/api/*` 转发到 Bun
|
||||
|
||||
#### 生产模式架构
|
||||
|
||||
@@ -444,16 +470,16 @@ const server = Bun.serve({
|
||||
},
|
||||
routes: {
|
||||
"/api/*": () => ...,
|
||||
"/health": { GET: () => handleHealth(mode) },
|
||||
"/api/meta": { GET: async () => handleMeta(mode, await resolveVersion()) },
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### 路由优先级
|
||||
|
||||
Bun routes 的匹配规则:具体路径 > 通配符。`/health` 优先于 `/*`。
|
||||
Bun routes 的匹配规则:具体路径 > 通配符。`/api/meta` 优先于 `/api/*`。
|
||||
|
||||
未匹配 method 的请求(如 POST /health)会落入 `/api/*` 通配符返回 404;若无该通配符会落入 fetch fallback。
|
||||
未匹配 method 的请求(如 POST /api/meta)会落入 `/api/*` 通配符返回 404;若无该通配符会落入 fetch fallback。
|
||||
|
||||
非 API 路径由 fetch fallback 处理:有文件扩展名的返回对应静态资源或 404,无扩展名的返回 SPA index.html。
|
||||
|
||||
@@ -471,8 +497,8 @@ bun run build
|
||||
|
||||
```
|
||||
1. Vite build → dist/web/ (前端静态资源,含 code splitting)
|
||||
2. Code generation → .build/static-assets.ts + .build/server-entry.ts
|
||||
3. Bun compile → dist/dial-server (单可执行文件)
|
||||
2. Code generation → .build/static-assets.ts + .build/server-entry.ts(含版本号字面量注入)
|
||||
3. Bun compile → dist/my-app (单可执行文件)
|
||||
```
|
||||
|
||||
- Vite 构建前端资源到 `dist/web/`,自动 code splitting(vendor-react、vendor-tdesign、vendor-chart)
|
||||
@@ -482,10 +508,10 @@ bun run build
|
||||
|
||||
#### 产物
|
||||
|
||||
| 产物 | 用途 |
|
||||
| ------------------ | ---------------------------------------- |
|
||||
| `dist/dial-server` | 生产可执行文件(含前端资源,单文件部署) |
|
||||
| `dist/web/` | Vite 构建的前端资源(构建中间产物) |
|
||||
| 产物 | 用途 |
|
||||
| ------------- | ---------------------------------------- |
|
||||
| `dist/my-app` | 生产可执行文件(含前端资源,单文件部署) |
|
||||
| `dist/web/` | Vite 构建的前端资源(构建中间产物) |
|
||||
|
||||
#### 构建参数
|
||||
|
||||
@@ -496,14 +522,13 @@ bun run build
|
||||
#### 运行可执行文件
|
||||
|
||||
```bash
|
||||
./dist/dial-server [config.yaml]
|
||||
./dist/my-app [config.yaml]
|
||||
```
|
||||
|
||||
启动后:
|
||||
|
||||
- 访问 `http://127.0.0.1:3000/` → 返回前端 SPA
|
||||
- 访问 `http://127.0.0.1:3000/api/*` → 返回后端 API
|
||||
- 访问 `http://127.0.0.1:3000/health` → 返回健康检查 JSON
|
||||
- 访问 `http://127.0.0.1:3000/api/meta` → 返回应用元信息 JSON(含版本号)
|
||||
|
||||
#### 清理
|
||||
|
||||
@@ -534,13 +559,17 @@ bun run verify
|
||||
|
||||
### 3.5 脚本说明
|
||||
|
||||
| 脚本 | 文件 | 说明 |
|
||||
| -------------------- | ------------------- | ---------------------------------------- |
|
||||
| `bun run dev` | `scripts/dev.ts` | 双进程开发服务(Vite :5173 + API :3000) |
|
||||
| `bun run dev:server` | `src/server/dev.ts` | 仅启动后端 API server(--watch 模式) |
|
||||
| `bun run dev:web` | Vite CLI | 仅启动 Vite dev server |
|
||||
| `bun run build` | `scripts/build.ts` | Vite → codegen → Bun compile 三步构建 |
|
||||
| `bun run clean` | `scripts/clean.ts` | 清理构建缓存与临时文件 |
|
||||
| 脚本 | 文件 | 说明 |
|
||||
| ----------------------- | ------------------------- | ---------------------------------------- |
|
||||
| `bun run dev` | `scripts/dev.ts` | 双进程开发服务(Vite :5173 + API :3000) |
|
||||
| `bun run dev:server` | `src/server/dev.ts` | 仅启动后端 API server(--watch 模式) |
|
||||
| `bun run dev:web` | Vite CLI | 仅启动 Vite dev server |
|
||||
| `bun run build` | `scripts/build.ts` | Vite → codegen → Bun compile 三步构建 |
|
||||
| `bun run clean` | `scripts/clean.ts` | 清理构建缓存与临时文件 |
|
||||
| `bun run version:patch` | `scripts/bump-version.ts` | 升迁 patch 版本(x.y.Z) |
|
||||
| `bun run version:minor` | `scripts/bump-version.ts` | 升迁 minor 版本(x.Y.0) |
|
||||
| `bun run version:major` | `scripts/bump-version.ts` | 升迁 major 版本(X.0.0) |
|
||||
| `bun run version:set` | `scripts/bump-version.ts` | 显式设置版本号 |
|
||||
|
||||
### 3.6 环境变量
|
||||
|
||||
@@ -668,10 +697,10 @@ CI 或正式提交前执行完整验证(类型检查 + lint + 格式 + 测试
|
||||
|
||||
### 测试分层
|
||||
|
||||
| 层级 | 覆盖范围 | 位置 | 命令 |
|
||||
| -------- | ---------------------- | ------------------------------------------------------------------- | --------------------------------------------- |
|
||||
| 单元测试 | 后端函数、纯函数、常量 | `tests/server/**/*.test.ts`、`tests/web/{utils,hooks}/**/*.test.ts` | `bun test tests/server`、`bun test tests/web` |
|
||||
| 组件测试 | React 组件渲染和交互 | `tests/web/components/**/*.test.tsx` | `bun test tests/web` |
|
||||
| 层级 | 覆盖范围 | 位置 | 命令 |
|
||||
| -------- | ---------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------- |
|
||||
| 单元测试 | 后端函数、纯函数、常量 | `tests/server/**/*.test.ts`、`tests/scripts/**/*.test.ts`、`tests/web/{utils,hooks}/**/*.test.ts` | `bun test tests/server`、`bun test tests/web` |
|
||||
| 组件测试 | React 组件渲染和交互 | `tests/web/components/**/*.test.tsx` | `bun test tests/web` |
|
||||
|
||||
### 运行命令
|
||||
|
||||
|
||||
Reference in New Issue
Block a user