hyapp-deploly/docs/modular-development-guideline.md
2026-05-20 16:49:19 +08:00

922 lines
19 KiB
Markdown
Raw Permalink 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.

# 运维管理平台模块化开发规范
依据:
- [液态玻璃后台 UI 设计规范](./liquid-glass-admin-ui-guideline.md)
- [运维管理平台第一版开发内容](./v1-development-scope.md)
目标:建立一套可长期维护的开发规范,让第一版能快速落地,同时避免后续接入真实 Kubernetes、日志、监控、数据库资源、审批流时推倒重来。
## 1. 技术方向
第一版默认按前后端分离设计,前端先使用 Mock 数据完成完整业务闭环,后端接口后续按相同契约接入。
推荐前端技术栈:
| 类型 | 推荐 |
| --- | --- |
| 语言 | TypeScript |
| UI 框架 | React |
| 构建工具 | Vite |
| 路由 | React Router |
| 服务端状态 | TanStack Query |
| 客户端状态 | Zustand 或 React Context |
| 表单 | React Hook Form |
| 校验 | Zod |
| Mock | MSW |
| 单元测试 | Vitest |
| 组件测试 | Testing Library |
| E2E | Playwright |
| 样式 | CSS Variables + CSS Modules |
| 图标 | lucide-react |
| 图表 | Recharts 或 ECharts |
技术选择原则:
- 服务端数据用 Query 管理,不放进全局 Store。
- 项目、环境、集群这类 UI 上下文可以放全局 Store。
- UI Token 必须通过 CSS 变量统一管理。
- Mock 层必须和真实 API 共用类型定义。
- 业务模块优先纵向切分,不按文件类型横向堆叠。
## 2. 模块化架构
推荐使用“业务垂直切片 + 分层依赖”的结构。
目录结构:
```text
src/
app/
App.tsx
router.tsx
providers/
QueryProvider.tsx
AppStateProvider.tsx
styles/
tokens.css
glass.css
layout.css
components.css
pages/
overview/
services/
service-detail/
releases/
resources/
logs-events/
audit/
widgets/
app-shell/
top-context-bar/
service-table/
release-drawer/
restart-dialog/
metric-dashboard/
event-timeline/
features/
switch-project-context/
filter-services/
release-service/
restart-service/
search-logs/
filter-audits/
entities/
project/
cluster/
service/
release/
resource/
event/
audit/
user/
shared/
api/
config/
constants/
lib/
types/
ui/
hooks/
mocks/
assets/
```
分层职责:
| 层级 | 职责 | 示例 |
| --- | --- | --- |
| `app` | 应用启动、路由、全局 Provider、全局样式 | `router.tsx``QueryProvider` |
| `pages` | 页面编排,只组合 widgets/features/entities | `OverviewPage` |
| `widgets` | 页面级业务区块,可包含多个 feature | `ServiceTable``ReleaseDrawer` |
| `features` | 用户可执行的业务动作 | 发布服务、重启服务、筛选服务 |
| `entities` | 业务实体模型、实体 API、实体展示组件 | `service``release` |
| `shared` | 无业务含义的通用能力 | Button、Table、fetcher、formatDate |
依赖方向:
```text
app -> pages -> widgets -> features -> entities -> shared
```
规则:
- 下层不能 import 上层。
- `shared` 不能 import 任何业务模块。
- `entities` 之间尽量不直接互相 import跨实体组合放在 `features``widgets`
- 页面不能直接写复杂业务逻辑,页面只做布局和组合。
- 同一业务动作只允许有一个入口模块,例如发布服务统一放在 `features/release-service`
## 3. 模块目录规范
每个业务模块使用相同结构,便于查找。
```text
features/release-service/
api/
createRelease.ts
model/
schema.ts
types.ts
useReleaseService.ts
ui/
ReleaseForm.tsx
ReleaseSteps.tsx
lib/
buildReleasePayload.ts
index.ts
```
`index.ts` 只导出模块的公开 API。
允许导出:
- 页面或组件需要使用的 UI。
- Hook。
- 类型。
- 纯工具函数。
禁止导出:
- 内部私有组件。
- 临时常量。
- Mock 实现细节。
- 只为绕过依赖规则而暴露的对象。
## 4. 命名规范
文件命名:
| 类型 | 规范 | 示例 |
| --- | --- | --- |
| React 组件 | PascalCase | `ServiceTable.tsx` |
| Hook | camelCase`use` 开头 | `useServicesQuery.ts` |
| 工具函数 | camelCase | `formatDuration.ts` |
| 类型文件 | `types.ts` | `entities/service/model/types.ts` |
| Schema | `schema.ts` | `release/model/schema.ts` |
| 常量 | `constants.ts` | `shared/constants/status.ts` |
| 样式模块 | 同组件名 | `ServiceTable.module.css` |
| 测试 | 同文件名 + `.test` | `formatDuration.test.ts` |
类型命名:
- 业务实体:`Service``ReleaseRecord``DataResource`
- API 请求:`CreateReleaseRequest`
- API 响应:`ServiceListResponse`
- 表单值:`ReleaseFormValues`
- 组件 Props`ServiceTableProps`
状态枚举:
- TypeScript 使用字符串联合类型优先。
- 后端返回值必须稳定,不使用中文作为状态码。
示例:
```ts
export type ServiceStatus = "healthy" | "warning" | "critical" | "unknown" | "running";
```
## 5. TypeScript 规范
必须开启:
```json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}
```
规则:
- 禁止使用 `any`,确实无法确定时使用 `unknown` 并收窄。
- API 返回值必须有类型。
- 表单提交值必须有 Zod Schema 校验。
- 组件 Props 必须显式定义。
- 复杂类型放在 `model/types.ts`
- 跨模块共享类型只能从模块 `index.ts` 导入。
- 不在组件里直接拼接后端数据结构,使用 mapper 转成前端 ViewModel。
推荐:
```ts
type ServiceTableRow = {
id: string;
name: string;
status: ServiceStatus;
version: string;
instanceText: string;
cpuUsage: number;
memoryUsage: number;
owner: string;
};
```
## 6. API 层规范
统一入口:
```text
shared/api/
httpClient.ts
queryKeys.ts
errors.ts
```
实体 API
```text
entities/service/api/
getServices.ts
getServiceDetail.ts
getServiceInstances.ts
getServiceMetrics.ts
```
规则:
- 所有请求必须经过 `shared/api/httpClient.ts`
- API 函数只负责请求和数据转换,不处理 UI Toast。
- 请求参数统一使用对象,不使用多个位置参数。
- 列表接口必须支持 `projectId``environment``clusterId`
- 写操作必须返回可用于刷新缓存的业务 ID。
- API 错误统一转成标准错误对象。
标准错误:
```ts
type ApiError = {
code: string;
message: string;
requestId?: string;
details?: unknown;
};
```
Query Key 规范:
```ts
export const queryKeys = {
services: (params: ServiceListParams) => ["services", params] as const,
serviceDetail: (id: string) => ["service", id] as const,
releases: (params: ReleaseListParams) => ["releases", params] as const,
};
```
## 7. 状态管理规范
状态分三类:
| 类型 | 管理方式 | 示例 |
| --- | --- | --- |
| 服务端状态 | TanStack Query | 服务列表、发布记录、数据资源 |
| 全局 UI 上下文 | Zustand / Context | 项目、环境、集群、当前用户 |
| 局部 UI 状态 | React `useState` | 抽屉开关、当前 Tab、表单中间态 |
全局 Store 只放:
- 当前项目。
- 当前环境。
- 当前集群。
- 当前用户和角色。
- 全局布局状态。
禁止放入全局 Store
- 服务列表。
- 发布记录。
- 日志列表。
- 监控图表数据。
- 临时表单值。
原因:这些数据属于服务端状态,应该由 Query 缓存、刷新和失效控制。
## 8. UI 组件规范
组件分三类:
| 类型 | 目录 | 说明 |
| --- | --- | --- |
| 通用 UI | `shared/ui` | Button、Table、Badge、Drawer |
| 实体组件 | `entities/*/ui` | ServiceStatusBadge、ResourceTypeIcon |
| 业务组件 | `features` / `widgets` | ReleaseDrawer、ServiceTable |
通用 UI 规则:
- 不包含业务字段。
- 不直接请求接口。
- 不读取全局业务 Store。
- 通过 Props 接收数据。
- 支持 `className`
- 支持键盘焦点。
- 支持 disabled、loading、error 状态。
业务组件规则:
- 可以组合实体组件和通用 UI。
- 可以调用 feature 内 Hook。
- 不直接写全局样式。
- 危险操作必须显式传入 `environment`
组件文件结构:
```text
Button/
Button.tsx
Button.module.css
Button.test.tsx
index.ts
```
## 9. 样式规范
样式分层:
```text
app/styles/
tokens.css
glass.css
layout.css
components.css
```
规则:
- 颜色、圆角、阴影、字号、间距必须使用 Token。
- 组件局部样式使用 CSS Modules。
- 禁止在业务组件里硬编码主色和状态色。
- 禁止使用行内样式写核心布局。
- 不使用负字距。
- 不使用大面积单色主题覆盖液态玻璃风格。
- 图表颜色从 Token 或统一常量中读取。
CSS 命名:
```css
.root {}
.header {}
.body {}
.footer {}
.title {}
.meta {}
.actions {}
.isActive {}
.isDisabled {}
```
玻璃样式统一使用类:
- `.glass-surface`
- `.glass-surface-strong`
- `.glass-subtle`
不要在每个组件里重复实现玻璃效果。
## 10. 页面开发规范
页面只做三件事:
- 读取路由参数。
- 组合 widgets/features。
- 控制页面级布局。
页面不做:
- 直接调用底层 HTTP。
- 写复杂数据转换。
- 处理发布和重启流程细节。
- 写超过 80 行的业务逻辑。
页面示例:
```tsx
export function ServicesPage() {
return (
<PageLayout title="微服务">
<ServiceFilters />
<ServiceTable />
</PageLayout>
);
}
```
## 11. 业务模块规范
### 11.1 服务模块
目录:
```text
entities/service/
api/
model/
ui/
lib/
index.ts
```
职责:
- 服务类型定义。
- 服务列表接口。
- 服务详情接口。
- 服务状态展示。
- 服务数据格式化。
不负责:
- 发布服务。
- 重启服务。
- 服务筛选表单。
### 11.2 发布模块
目录:
```text
features/release-service/
api/
model/
ui/
lib/
index.ts
```
职责:
- 版本选择。
- 发布策略选择。
- 预检查展示。
- 发布提交。
- 发布状态反馈。
规则:
- `prod` 必须要求二次确认。
- 发布完成后必须刷新服务详情和发布记录。
- 发布成功或失败都必须生成事件和审计记录。
### 11.3 重启模块
职责:
- 单实例重启。
- 全部实例重启。
- 滚动重启和立即重启。
- 影响范围展示。
规则:
- `prod` 默认滚动重启。
- 立即重启必须二次确认。
- 操作完成后必须生成事件和审计记录。
### 11.4 数据资源模块
职责:
- 展示 MySQL、MongoDB、Redis、Kafka 状态。
- 展示容量、连接数、备份、关联服务。
- 展示异常事件。
规则:
- 第一版不开放查询入口。
- 第一版不开放恢复入口。
- 生产环境不显示任何直接执行数据库命令的能力。
## 12. 表单规范
所有表单必须:
- 使用 Schema 校验。
- 提交前做客户端校验。
- 提交中禁用提交按钮。
- 提交失败展示错误原因。
- 危险操作展示影响范围。
发布表单必须校验:
- 目标版本不能为空。
- 发布策略不能为空。
- `prod` 环境必须勾选确认。
重启表单必须校验:
- 重启范围不能为空。
- 立即重启必须二次确认。
- 单实例重启必须有实例 ID。
## 13. 权限规范
前端权限用于控制体验,后端权限用于保证安全。第一版即使没有真实后端,也要按这个结构设计。
权限点:
```ts
type Permission =
| "service:read"
| "service:release"
| "service:restart"
| "release:read"
| "resource:read"
| "logs:read"
| "audit:read";
```
规则:
- 权限不足的危险操作显示禁用态,不直接隐藏。
- 禁用态必须说明原因。
- 生产环境操作必须额外判断角色和确认状态。
- 审计页面只对有 `audit:read` 权限的角色开放。
## 14. Mock 规范
Mock 使用 MSW 或等价方案。
目录:
```text
shared/mocks/
browser.ts
handlers.ts
data/
projects.ts
services.ts
releases.ts
resources.ts
events.ts
audits.ts
```
规则:
- Mock 数据结构必须复用实体类型。
- Mock 行为要模拟真实写操作。
- 发布成功后更新服务版本。
- 重启成功后新增事件和审计。
- 支持模拟失败场景。
- 支持模拟空状态。
必须覆盖:
- Healthy、Warning、Critical 服务。
- 发布成功、失败、执行中。
- MySQL、MongoDB、Redis、Kafka 多种状态。
- `prod` 环境二次确认。
- 权限不足禁用操作。
## 15. 错误处理规范
错误分三层:
| 层级 | 处理 |
| --- | --- |
| API 层 | 转换为 `ApiError` |
| 业务层 | 判断是否可重试、是否需要刷新 |
| UI 层 | 展示错误状态、Toast、下一步操作 |
页面错误态必须提供:
- 错误原因。
- 重试按钮。
- 可选的查看事件入口。
写操作失败必须提供:
- 失败原因。
- requestId如果有。
- 是否可以重试。
- 是否需要查看事件。
禁止:
- 只显示“操作失败”。
- 把原始异常对象直接渲染到页面。
- 静默吞掉接口错误。
## 16. 日志和审计规范
前端事件日志用于排查,审计记录用于追责。
发布、重启、回滚必须产生审计记录。
审计记录字段:
- 操作时间。
- 操作人。
- 角色。
- 操作对象。
- 操作类型。
- 环境。
- 集群。
- 执行结果。
- 关联记录 ID。
生产环境操作必须有明显标识。
## 17. 测试规范
测试分层:
| 类型 | 工具 | 覆盖内容 |
| --- | --- | --- |
| 单元测试 | Vitest | 工具函数、mapper、权限判断、表单校验 |
| 组件测试 | Testing Library | Button、Table、Badge、ReleaseDrawer |
| 集成测试 | Testing Library + MSW | 发布流程、重启流程、筛选流程 |
| E2E | Playwright | 核心用户路径 |
必须测试:
- 服务状态 Badge 文案和颜色类。
- 服务搜索和筛选。
- `prod` 发布确认。
- 发布成功后版本更新。
- 发布失败后错误反馈。
- 重启成功后事件和审计新增。
- 权限不足时按钮禁用。
- Secret 不显示明文。
E2E 核心路径:
1. 进入总览页。
2. 切换到 `prod`
3. 打开 `user-service` 详情。
4. 打开发版抽屉。
5. 选择目标版本。
6. 勾选生产确认。
7. 执行发布。
8. 验证发布记录和审计记录。
## 18. 代码质量规范
必须配置:
- ESLint。
- Prettier。
- TypeScript strict。
- lint-staged。
- 单元测试命令。
- 构建命令。
建议脚本:
```json
{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"lint": "eslint .",
"format": "prettier --write .",
"test": "vitest run",
"test:watch": "vitest",
"e2e": "playwright test",
"check": "npm run lint && npm run test && npm run build"
}
}
```
提交前最低要求:
- TypeScript 无错误。
- ESLint 无错误。
- 单元测试通过。
- 构建通过。
涉及 UI 的改动还要:
- 浏览器预览。
- 检查桌面宽度 1280px。
- 检查表格文字不重叠。
- 检查抽屉内容可滚动。
- 检查 `prod` 危险操作二次确认。
## 19. Git 和提交规范
分支命名:
```text
feature/overview-page
feature/release-drawer
fix/prod-release-confirm
chore/setup-eslint
```
提交信息:
```text
feat: add service release drawer
fix: require confirmation before prod restart
chore: setup testing pipeline
docs: add modular development guideline
```
提交类型:
| 类型 | 含义 |
| --- | --- |
| `feat` | 新功能 |
| `fix` | 修复 |
| `docs` | 文档 |
| `style` | 格式和样式调整 |
| `refactor` | 重构 |
| `test` | 测试 |
| `chore` | 工程配置 |
规则:
- 一个提交只做一类事情。
- 不把大范围格式化混进功能提交。
- 不提交本地环境文件。
- 不提交密钥、Token、数据库连接串。
## 20. 环境变量规范
命名:
```text
VITE_API_BASE_URL=
VITE_ENABLE_MOCK=
VITE_APP_ENV=
```
规则:
- 前端环境变量必须以 `VITE_` 开头。
- `.env.example` 必须维护。
- `.env.local` 不提交。
- 不在前端存储真实密钥。
- 生产环境配置由部署平台注入。
## 21. 性能规范
第一版性能目标:
- 首屏可交互时间控制在合理范围。
- 表格 100 条数据内交互不卡顿。
- 路由页面按需加载。
- 图表组件按页面懒加载。
- 日志列表避免一次渲染过多行。
规则:
- 路由级代码分割。
- 大图表库懒加载。
- 表格筛选优先使用 memoized selector。
- 不在 render 中做重型计算。
- 日志列表超过 500 行时考虑虚拟列表。
## 22. 安全规范
第一版必须遵守:
- 不展示 Secret 明文。
- 不在 localStorage 存储敏感 Token。
- 所有危险操作必须检查权限。
- 所有生产环境操作必须二次确认。
- 后端接入后必须校验权限,不能只依赖前端。
- 日志内容渲染要避免 XSS。
- 用户输入不能直接拼接到 URL path必须 encode。
数据库资源限制:
- 第一版不做 SQL 查询。
- 第一版不做 Mongo 查询。
- 第一版不做备份恢复。
- 生产环境不显示直接执行命令入口。
## 23. 可访问性规范
最低要求:
- 所有按钮可键盘访问。
- 抽屉和弹窗可按 Esc 关闭。
- 菜单可键盘导航。
- 状态 Badge 必须有文字。
- 表单错误信息和字段绑定。
- 点击目标不小于 32px x 32px。
- 颜色不能作为唯一状态表达。
## 24. 开发顺序
推荐顺序:
1. 初始化项目和质量工具。
2. 建立 Token、玻璃样式、App Shell。
3. 建立 Mock 数据和 API 适配层。
4. 开发通用 UI 组件。
5. 开发实体模块service、release、resource、event、audit。
6. 开发首页和微服务列表。
7. 开发服务详情页。
8. 开发发布抽屉和重启流程。
9. 开发发布记录、数据资源、日志事件、审计页。
10. 补齐测试、空状态、错误状态。
11. 浏览器视觉验收。
12. 构建验收。
## 25. Definition of Done
一个功能完成必须满足:
- 代码按模块边界放置。
- 类型完整,无 `any`
- 样式使用全局 Token。
- Loading、Empty、Error 状态完整。
- 权限不足有禁用态和原因。
- `prod` 危险操作有二次确认。
- 写操作成功和失败都有反馈。
- 相关事件和审计记录更新。
- 单元测试或集成测试覆盖关键逻辑。
- `lint``test``build` 通过。
- 浏览器中验证 UI 不重叠、不溢出、抽屉可滚动。
## 26. 禁止项
- 禁止页面直接调用 `fetch`
- 禁止在页面里堆业务逻辑。
- 禁止业务模块跨层反向依赖。
- 禁止在组件里硬编码设计 Token。
- 禁止把服务端状态放进全局 Store。
- 禁止生产环境危险操作绕过确认。
- 禁止展示 Secret 明文。
- 禁止生产数据库直接查询入口。
- 禁止只做成功态,不做失败态和空状态。
- 禁止没有审计记录的发布、重启、回滚。
## 27. 第一版推荐任务拆分
### 基础工程
- 初始化 Vite + React + TypeScript。
- 配置 ESLint、Prettier、Vitest。
- 配置路由和 Query Provider。
- 建立 `src` 分层目录。
- 建立全局样式 Token。
### UI 基础
- Button。
- IconButton。
- StatusBadge。
- GlassSurface。
- Table。
- Select。
- Tabs。
- Drawer。
- Dialog。
- Toast。
- EmptyState。
### 业务闭环
- Mock 数据。
- 总览页。
- 微服务页。
- 服务详情页。
- 发布抽屉。
- 重启确认。
- 发布记录页。
- 数据资源页。
- 日志与事件页。
- 权限与审计页。
### 验收
- 单元测试。
- 发布流程集成测试。
- 重启流程集成测试。
- Playwright 核心路径。
- 构建验证。
- 视觉检查。