Files
LokiStack/docs/web-ui-guide/08-工程化与质量保障.md
T
logan f9c6c1d826 feat: opsx-loki 全面升级 — 前端重构/用户与LDAP/部署向导/日志查询
基于 WEB-UI-Development-Guide 标准的整体升级,并更名 LokiDeploy → opsx-loki。

前端(Gin+React+shadcn/ui):
- 按 02/07 章重构:页面域化拆分(无超 400 行文件)、PageContainer/ListQuery、
  反馈分级(成功静默/失败 toast/危险确认)、401 单飞刷新+队列重放
- 暗色模式(next-themes)+ 语义 Token(--primary 品牌色/success/warning/info)
- 部署向导(状态推导四步:环境→存储→Loki→采集,内嵌表单闭环)
- 日志查询页:LogQL 标签构建器/拖拽直方图/日志上下文/Live Tail/查询历史
- 按用户+标签策略的查询授权(服务端强制合并策略)

后端(Go+Gin+JSON DB):
- 简单用户管理(仅 admin,无 RBAC)+ TokenVersion 会话吊销 + 登录 IP 限流
- LDAP 接入:配置(AES 加密存储/hasPassword 脱敏)/测试连接/批量导入/登录
- 存储配置测试连接(SigV4 零依赖)+ 桶不存在自动创建
- Loki 三模式部署修复:SSH 密钥认证、3.x 配置模板、ruler 对象存储嵌套块、
  凭证解密、孤儿 deploying 状态恢复、Grafana 部署(可选默认关)+面板导入
- DaemonSet 采集纯 YAML(去 helm 依赖)+ DNS 自愈回退 ClusterIP + 集群名标签
- 日志查询代理:cluster-svc 经 kube-apiserver proxy/url 直连 + cursor 翻页
- 统一 log 命名空间;部署就绪探活;Grafana 访问地址自动记录

修复:run.sh 增量编译检测、Sanitized 脱敏补全、LokiDeployment Update 白名单、
健康检查 CreatedAt 零值等 10+ 存量 bug。

数据兼容:DB 沿用旧 lokideploy.json(新名优先);localStorage 一次性迁移;
HKDF 加密前缀保留(已加密凭证不受影响)。
2026-10-24 13:20:12 +08:00

257 lines
11 KiB
Markdown
Raw 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.
# 08 — 工程化与质量保障
> 参考:vue-vben-admin(Vite 配置工厂 + lefthook 流水线)、soybean-admin(eslint-config 工厂 + sa CLI)、vue-pure-admin(build/ 拆分 + env 开关能力)、ant-design-pro(Biome + 测试范式 + CI 矩阵)
---
## 一、构建配置组织
### 1.1 配置组织范式
```
vben:配置即内部包
internal/vite-config/ 提供 defineConfig({ application | library }) 工厂,
app 的 vite.config.ts 只剩 15 行(proxy 声明)
pure:根目录 build/ 拆分
build/{plugins,cdn,compress,optimize,utils,info}.ts,vite.config.ts 只做组装
(env 用 wrapperEnv 类型化读取)
soybean:build/plugins/ 按域拆文件
{router,unplugin,html,unocss,devtools}.ts 一文件一插件域
```
单工程标准:**必须**把 vite 配置按职责拆文件(plugins/env/proxy/compress),主配置只做组装;双栈工程的两个 vite 配置**结构镜像**(插件列表、alias、产物命名、proxy 规则逐项对齐)。
### 1.2 env 分层(三层结构)
| 层 | 形态 | 语义 | 说明 |
|----|------|------|------|
| 构建期烧录 | `VITE_*` | 打进产物,改了要重新构建 | API 前缀、功能开关 |
| 运行时可改 | `VITE_GLOB_*`(vben) | 构建时抽成 `_app-config-{hash}.js` 挂 window | **改 API 地址无需重构建** |
| 运行时 JSON | `public/platform-config.json`(pure) | 构建产物旁的配置文件,启动拉取注入 | 免重构建、免 window 挂载 |
| 纯 dev | proxy 端口等 | 只在 dev server 用 | — |
env 类型契约:每个 `VITE_*` 变量在 `vite-env.d.ts` 有类型与注释(soybean:联合类型直接收窄如 `'static' | 'dynamic'`)。
### 1.3 dev server 要点(必须)
```
strictPort: true # 端口被占直接报错,不悄悄漂移
proxy '/api' → 后端端口
ws: true # 供 WebSocket(必须显式开)
changeOrigin: true
```
### 1.4 产物与指纹
- 构建注入版本:`define: { __APP_VERSION__, __COMMIT_HASH__ }`(adp 用 git rev-parse 兜底)——设置页「关于」直接展示,排障救命
- 手工分包保留(radix/icons/charts/motion 等);新大依赖(图表/编辑器)**必须**评估独立 chunk + 懒加载
- 可选:构建压缩 env 开关(pure `VITE_COMPRESSION = none|gzip|brotli|both`)、CDN 开关(`VITE_CDN`)、构建时间戳 banner
---
## 二、代码规范流水线
### 2.1 分层流水线(vben lefthook 范式)
```
pre-commit(仅 staged 文件):
快修复:oxlint --fix → oxfmt → eslint --fix → stylelint --fix
(stage_fixed 回填暂存区)
commit-msg:commitlint(conventional)
push/CI:慢检查全量 vue-tsc/tsc --noEmit + lint + madge 循环依赖
```
原则:**快的在本地 pre-commit 自动修,慢的在 CI 卡**。
soybean 的同构版本:`@soybeanjs/eslint-config-vue` 工厂(eslint.config.mjs 仅 14 行)+ `vp lint`(oxc 快扫)→ `eslint`(精修)双层;commit 由自研 `sa` CLI 交互生成并校验,scope 白名单单一数据源。pure 再补两块:stylelint(recess-order 属性排序)与 eslint-plugin-better-tailwindcss(校验 class 书写)。
### 2.2 必配清单(必须)
| 工具 | 要求 |
|------|------|
| ESLint(flat)+ Prettier | 双端同大版本、规则集可复制 |
| Stylelint | standard-scss + recommended-vue + 属性排序 |
| commitlint + husky + lint-staged | pre-commit 快修复、commit-msg 校验 |
| `preinstall: only-allow pnpm` | 锁包管理器 |
**Conventional Commits 类型集**(commitlint type-enum,统一):`feat / fix / docs / style / refactor / perf / test / chore / revert`;scope 用功能域(`user`、`rbac`、`cron`、`react`……)。
**any 管控**:TS strict 端**禁止裸 any**——`as any` 需同行注释原因与消除计划;JS 端以 JSDoc `@param/@returns` 过渡,**不允许**出现「既无类型注释也无类型定义」的接口函数。
### 2.3 项目级 lint 增强(把各章规则自动化)
```js
// eslint 配置片段(示意)
'no-console': ['warn', { allow: ['warn', 'error'] }] // 生产禁 console.log
'no-restricted-imports': // 示例层禁 import 系统层内聚单元
{ patterns: [{ group: ['@/views/system/*'], message: '示例层不得依赖系统层' }] }
vue/name: 'error' // 页面组件必须 defineOptions name(keep-alive 前置)
import/no-cycle: 'error' // 循环依赖
```
---
## 三、测试策略
### 3.1 管理端测试金字塔(务实版)
```
▲ E2E 冒烟(Playwright)
│ 登录→进列表→CRUD→登出 3-5 条主线,别贪多
├─ 组件/页面测试(Vitest + Testing Library)
│ 列表组件三态、表单弹窗校验与提交、菜单失败重试
├─ 组合函数测试(重点投入区,性价比最高)
│ usePagedQuery(取消/错序/分页边界)
│ permission 纯函数穷举
│ 请求层拦截器分支(401刷新/重放/静默)
└─ 纯函数单测
格式化、confirm、色阶算法
```
### 3.2 adp 测试范式(直接照抄)
```ts
// 重依赖 mock + 动态 import(vi.mock 提升到顶部,import 在 test 内)
vi.mock('@/services/user', () => ({ queryCurrentUser: vi.fn() }))
test('未登录访问受保护页重定向 login 并保留 redirect', async () => {
queryCurrentUser.mockRejectedValueOnce({ /* 401 */ })
const { getInitialState } = await import('@/app')
const redirect = await getInitialState()
expect(redirect).toContain('/user/login?redirect=')
})
```
关键点:**纯函数穷举测试**(permission/access 这类零成本高回报)、**拦截器分支测试**(请求层是事故高发区,mock adapter 驱动各分支)。
### 3.3 覆盖要求
- coverage 阈值必须配置(如 lines 70 / statements 70 / functions 60 / branches 70),排除生成代码
- E2E 至少覆盖:登录主线、一条 CRUD 主线、模块开关生效(若为底座)
- vben 是组件测试深度的标杆:连 Modal 的 keep-alive 场景都有单测
---
## 四、性能优化清单
| 手段 | 做法 | 出处 |
|------|------|------|
| 路由懒加载 | 全部页面 `() => import()`;示例层可构建期 tree-shake | 通行 |
| 首屏占位 | index.html 注入 loading HTML(#root 空时先渲染骨架) | adp |
| 路由预取 | 菜单 hover prefetch / vite `server.warmup` 预热核心目录 | adp/vben/pure |
| 图表懒加载 | Suspense/条件 import 包裹 ECharts 区块 | 通行 |
| chunk 失效恢复 | ChunkLoadError → 提示/自动 reload 一次(发版后旧 hash 404) | adp + 路由 onError |
| 请求防抖取消 | 列表页「取消 + 版本号」(见 03 章) | 本标准 |
| 大日期库治理 | moment→dayjs / 按需 locale | adp |
| WebSocket | 卸载断开 + 重连指数退避 + 心跳 | 监控类页面 |
| 长列表 | 虚拟滚动(日志类页面 >1000 行时) | 按需 |
**度量先行**:CI 加 `rollup-plugin-visualizer` 产物报告,chunk 超阈值(如 500KB)报警。
---
## 五、双端一致性规范(迁移期)
### 5.1 契约清单(迁移开始前统一,不等迁移完成)
| 项 | 统一值(推荐) | 说明 |
|----|----------------|------|
| token key | `<app>.auth.token` | 迁移期「读旧写新」一个版本 |
| 暗色 key | `<app>.theme.mode` | 同上 |
| 模块开关键 | `<app>.modules.<name>.enabled` | 常量两端同名,注释指向后端 API |
| 会话存储结构 | 字段名一致 | localStorage 布局对齐 |
| 响应契约 | 同一份 code/data/msg + 错误分级 | 见 03 章 |
| 权限语义 | 权限码清单同源(单一文档维护) | 见 04 章 |
| 路由路径 | 两端一致 | 互通书签 |
| ESLint / Prettier | 同大版本、同规则 | 配置可复制 |
**执行方式**:契约清单进 `docs/`(一页表),双端各引用;改任何一项 = 双端 PR 同步。副端纪律:不抢先实现主端没有的功能;mock 显式开关、生产禁用;每对齐一个域删除对应 mock(向真实收敛)。
---
## 六、CI/CD
### 6.1 标准流水线(adp 范式裁剪)
```
PR 触发:
job lint eslint + prettier --check + vue-tsc/tsc
job test vitest --coverage(阈值卡点)
job build vite build
job e2e 主分支 PR:playwright(webServer 自动拉起前后端)
main 合并:
构建产物部署(嵌入后端二进制 / 静态托管)
```
CI 增强项:madge 循环依赖检查、styles 入口引用检查、产物体积报告。**CI 与本地命令同源**(CI 里跑 make 目标,不另写一套脚本)。
---
## 七、文档与可观测性
### 7.1 文档治理(制度)
| 文档 | 责任 |
|------|------|
| 新模块指南 | 新模块五列表(菜单/路由/页面/API/权限码)同步 |
| 信息架构文档 | 分组/菜单行为描述与实现同步 |
| 删除性重构 | 过期段落归档,不留「描述已删除组件」的漂移文档 |
| CHANGELOG | 只描述现存功能 |
**规则**:实现与文档不一致 = 文档 bug,同一 PR 修复。
### 7.2 版本可观测
- 设置页「关于」展示 `__APP_VERSION__` / commit hash / 构建时间(构建指纹注入)
- 全局错误上报预留钩子(gva `core/error-handel.js` 式),先 console.error 收口,接 Sentry 留接口
- 可选:页面版本更新提示(pure 的 version-rocket:新版本发布后提醒用户刷新)
---
## 八、最佳实践清单
✅ **要做**
1. pre-commit 快修复 + CI 慢检查的分层流水线
2. 请求层与权限纯函数优先补测试
3. 双端 vite 配置结构镜像;契约清单一页表维护
4. CI 与本地同源(make 目标)
5. 每次构建带版本指纹,关于页可见
❌ **不要**
1. 不要双份 e2e/eslint 配置文件并存(配置漂移源头)
2. 不要 CI 跑本地跑不通的命令(或反之)
3. 不要 console.log 进生产(尤其 token 片段)
4. 不要在 mock 数据里放真实用户名/密钥样式的假数据
5. 不要为「以后可能用到」保留死配置、死样式、空目录
---
## 九、AI 检查清单(对比目标工程逐项核对)
**P0(安全与一致性)**
1. 生产路径上是否有 console.log(尤其 token 片段打印)?
2. 双端(若有)token/主题 key 是否同名?配置文件是否双份并存?
3. mock 是否显式开关(是否存在网络错误静默回退假数据)?
**P1(质量基建)**
4. lint 流水线是否分层(pre-commit 快修 + CI 慢查)?stylelint/commitlint 是否齐配?
5. 请求层与权限纯函数是否有测试?coverage 阈值是否配置?
6. CI 是否有循环依赖检查、产物体积报告?
7. 构建指纹是否注入并在关于页展示?
**P2(体验与治理)**
8. 文档漂移清单(描述已不存在实现的文档段落)列出并归档
9. 运行时配置(VITE_GLOB / platform-config.json)是否值得引入
10. 错误上报钩子是否预留
---
> 至此八章完毕。回到 [00-目录与概览](00-目录与概览.md) 复查十大黄金法则,或按各章「AI 检查清单」逐项对比目标工程输出优化任务。