Files
LokiStack/docs/web-ui-guide/01-框架选型与技术栈.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

218 lines
14 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.
# 01 — 框架选型与技术栈
> 参考:vue-vben-admin(★★★★★ Vue 标准标杆)、ant-design-pro(★★★★★ React 标准标杆)、soybean-admin(★★★★☆ 强烈推荐)、vue-pure-admin(★★★★☆ 推荐);对照:gin-vue-admin(★★☆☆☆ Gin 全栈)
---
## 一、选型的第一性问题:单栈还是双栈
### 1.1 标杆项目的单栈现实
| 项目 | 框架 | 为什么不双栈 |
|------|------|--------------|
| ant-design-pro | React 19 | 生态深度绑定 Umi Max 运行时(约定式路由、运行时配置、插件体系) |
| gin-vue-admin | Vue 3 | Element Plus + 国内管理端生态,Go 后端配套脚手架默认 Vue(★★☆ 仅对照) |
| vue-vben-admin | Vue 3 | 用 monorepo + adapter 层支持 5 个 UI 库,但**框架始终只有 Vue** |
| soybean-admin | Vue 3 | 文件路由 + 生成物策略,规范优先(★★★★☆ 强烈推荐) |
| vue-pure-admin | Vue 3 | 单包直出、轻量实用,官方精简版 thin(★★★★☆ 推荐) |
> **结论**:标杆项目全部单栈。多 UI 库共存靠的是「适配器层」(vben 的 `effects/*` adapter),而不是多框架。**框架级双栈的成本(请求层、状态、权限、构建、测试全部 ×2)只有迁移期才值得付。**
>
> 参考优先级:**Vue 架构看 vben、规范写法看 soybean、同栈 EP 实操看 pure、React 看 adp**;gva 仅作 Gin 全栈视角补充,不作前端代码质量的首选参考。
### 1.2 双栈只在迁移期
```
┌─────────────────────────────────────┐
│ 后端 REST API(Gin / FastAPI ...) │
│ 单一契约:/api/* │
└───────────┬─────────────┬───────────┘
│ │
┌───────────▼────┐ ┌─────▼──────────────┐
│ 主端(功能源) │ │ 副端(迁移参照) │
│ 承接全部新功能 │ │ 只对齐、不抢先 │
│ 进入产物 │ │ 迁移完成即退役 │
└────────────────┘ └────────────────────┘
```
迁移期三条纪律(**必须**):
1. **功能以主端为准**:副端只做「对齐」同步,不抢先实现。
2. **契约以两端共同名为准**:token key、主题 key、模块开关键、权限码、响应格式——迁移开始前就统一命名(推荐命名空间 `<app>.auth.token` / `<app>.theme.mode`),而不是迁移后再改。
3. **不共享代码,只共享约定**:两端各自实现同一份「契约文档」(见 08 章),不引入 monorepo 这种为双栈兜底的重型方案。
### 1.3 何时值得上 monorepo(vben 模式)
vben 用 pnpm workspace + Turbo 支撑 5 个 UI 库 app + 30+ 框架包,代价是:
- `pnpm-workspace.yaml` 维护 300+ 依赖 catalog,`overrides` 强制统一版本
- 循环依赖检查(`check:circular`)、依赖合规检查(`check:dep`)成为必跑任务
- 构建配置收敛为内部包 `internal/vite-config`,app 配置才能薄到 15 行
**判断标准**:当「框架层代码」(布局引擎、请求客户端、权限系统)需要被 ≥3 个应用复用时,才值得付 monorepo 成本。普通单产品工程(1-2 个前端)——**不值得**,独立 Vite 工程 + 统一 Makefile 编排即可。soybean 的「轻 workspace」(单应用 + 8 个工具包)是中间形态,适合工具链需要沉淀的团队。
### 1.4 何时允许偏离默认栈
**必须**:新项目 / 新模块使用本章默认栈(见 00 章「默认技术栈」);存量代码**不因「不合推荐」而大规模重写**——渐进迁移:新文件执行新标准,旧文件随功能迭代就近升级。
**允许偏离**的场景(需在 PR / ADR 中说明理由):组件库确缺关键能力(虚拟表格、复杂甘特等);性能热点需要更轻方案;与后端生态强绑定(如脚手架生成的默认产物)。
**禁止**:同一工程内并存两套 UI 库、两套状态库、两种 CSS 方案——偏离只允许发生在「整工程」粒度。
---
## 二、UI 组件库选型
### 2.1 三种流派对照
| 维度 | Element Plus(本标准 Vue 主推;gva 补充) | Ant Design + ProComponents(adp) | shadcn/ui(React 品牌差异化) |
|------|--------------------------|-----------------------------------|-----------------------------|
| 形态 | 传统全量组件库 | 组件库 + 中后台增强层 | 源码复制型(Radix + Tailwind) |
| 中后台生产力 | 高(表格/表单/弹层齐全) | **极高**(ProTable/ProForm 声明式 CRUD) | 中(原子件全,业务件自建) |
| 主题定制 | CSS 变量 + SCSS 双通道 | Design Token(configProvider) | **完全可控**(Token 就是你的 CSS 变量) |
| 暗色模式 | `dark/css-vars.css` 一行接入 | `data-theme="dark"` + token | `.dark` class 天然支持 |
| TS 支持 | 一般(类型宽松) | 好 | 极好(TSX 源码进仓库) |
| 体积 | 全量较大,靠 unplugin 按需 | 较大 | 用多少复制多少 |
| 适合谁 | Vue 主栈、快速交付 | React 中后台重 CRUD | React、要品牌差异化 |
### 2.2 选型决策树
```
需要管理端全家桶、快速交付?
├─ Vue 栈 ──────────▶ Element Plus(+ unplugin 按需引入)
├─ React 栈、CRUD 为主 ▶ Ant Design + ProComponents
└─ React 栈、要品牌感 ─▶ shadcn/ui + Tailwind
双栈迁移期?
└─▶ 主端选全量组件库保效率(EP),
副端选 shadcn 保可读性 —— 常见组合
```
两个 ★★★★☆ 参考的选型启示:soybean-admin(Naive UI + UnoCSS)证明「hook 优先 + 组件薄壳」也能撑起完整中后台;vue-pure-admin 证明了 **Tailwind v4 `@theme` 把 `--el-*` 变量桥接为原子色 token** 是 EP 工程引入原子类的最短路径(详见 06 章)。
### 2.3 图标体系(易被忽视的选型)
- **glob 注册模式(gva,补充)**:`import.meta.glob` 自动收集 `assets/icons/**/*.svg` 注册为全局组件,菜单存 icon 字符串即可 `<component :is>` 渲染;插件图标加 `插件名-` 前缀防冲突。适合「菜单图标由后端配置下发」的场景。
- **路由声明模式(adp)**:路由 `icon: 'crown'` 字符串 + 图标映射表,与路由集中声明天然契合。
- **按需编译模式(pure/soybean)**:unplugin-icons 虚拟模块(`import Upload from '~icons/ri/upload-line'`)+ Iconify 离线/在线双模式。
- **通用规则**:**图标名是数据(存在菜单表里),渲染是前端映射**——不要把图标组件硬编码进菜单模板。
---
## 三、构建工具与运行时
### 3.1 Vite 是唯一现实选择(2026)
| 能力 | 说明 | 标杆用法 |
|------|------|----------|
| 按需引入 | `unplugin-auto-import` + `unplugin-vue-components` | EP 组件零 import(vben/soybean 系均如此) |
| `import.meta.glob` | 动态路由的组件映射基石 | gva/vben/pure 的 backend 菜单模式 |
| env 分层 | `.env.development` / `.env.production` + `import.meta.env` | 全部项目;vben 另分 `VITE_GLOB_*` 运行时可改(见 08 章) |
| proxy | dev 反代 `/api` 到后端端口,避免 CORS 配置漂移 | `'/api' → 后端端口`(含 `ws: true` 供 WebSocket) |
| 构建指纹 | `define` 注入版本/commit hash | adp:`__APP_VERSION__` + git rev-parse 兜底 |
**必须**按需引入,**禁止**全量 `app.use(组件库)` + 全量 CSS(gva 全量引入是反面教材,首屏体积大)。
### 3.2 路由库
- Vue:`vue-router@4`,`createWebHistory`(hash 模式是历史包袱,新工程用 history)
- React:`react-router@7`,用**路由配置数组 + `<Route>` 声明式**或 `createBrowserRouter`;**禁止**用 `Object.entries().map` + 三元链选页面渲染
### 3.3 HTTP 客户端
| 库 | 使用方 | 要点 |
|----|--------|------|
| axios | vben / soybean / pure / gva | 拦截器、取消(AbortController)生态成熟 |
| umi-request / axios | adp | 错误契约挂载在 request config 上(skipErrorHandler 等) |
| fetch | — | 零依赖,但拦截器/超时/取消需自建,**不推荐**作为管理端基础 |
> **必须**统一 axios:拦截器结构、错误对象形态在全员脑中保持一致,排障不用切换心智模型。
---
## 四、TypeScript 采用策略
### 4.1 三档策略
| 档位 | 适用 | 做法 | 标杆 |
|------|------|------|------|
| **纯 JS + JSDoc** | 快速交付的存量 Vue 主端 | 关键模块(request/permission/stores)写 JSDoc 类型注释 | gva |
| **渐进 TS** | 存量 JS 工程演进 | 新文件 `.ts`,老文件不动;`allowJs: true`;先建 `typings/` 写 `.d.ts` | soybean 路线 |
| **TS strict** | 新工程(**默认**) | `strict: true`,类型即文档 | adp、vben、soybean、pure |
**新项目必须 TS strict**;存量工程按上表渐进,但接口函数**不允许**「既无类型注释也无类型定义」。
### 4.2 类型放哪里(adp/soybean 范式)
- 全局契约类型集中声明:`declare namespace API { interface RuleListItem {...} }`,服务层函数签名 `request<API.RuleList>(...)` 收口
- 页面私有类型随页面 co-location(`data.d.ts` / `utils/types.ts`)
- 路由 meta 用 `vue-router.d.ts` 模块扩充强类型化(vben 30+ 字段全 JSDoc;soybean 17 字段同款)
- soybean 补充:全局类型按 namespace 组织(`typings/` 下 Api/App/Storage/Env 四区,storage 与 env 均有**键级类型**,i18n key 递归派生)——**JS 工程渐进 TS 的最低成本路径**:先建 `typings/` 写 `.d.ts`,不动业务代码
---
## 五、状态管理选型
### 5.1 先分类再选库
```
状态三类:
├─ 客户端全局状态(token、用户信息、菜单、UI 偏好)→ Pinia / Zustand
├─ 服务端状态(列表、详情、缓存失效) → TanStack Query / ProTable request / 自研 usePagedQuery
└─ URL 状态(筛选、分页、Tab) → 路由 query,永远不要复制进 store
```
### 5.2 三种落法
| 落法 | 出处 | 说明 |
|------|------|------|
| adp 三层 | initialState(useModel)+ React Query + ProTable request | 服务端状态交给 Query:`queryKey` 按资源命名,mutation 成功后 `invalidateQueries` |
| vben 分域 store | Pinia setup 风格,按域拆 modules(gva 同构,补充参考) | token/user/router/app/dictionary 各一,持久化手动分层 |
| pure StoreHook | `useXxxStoreHook()` 包装 store + pinia 实例 | 在 setup 外(拦截器、守卫、工具函数)也能安全取 store |
| soybean 模块化 | 每模块一目录 `index.ts`(状态编排)+ `shared.ts`(可单测纯函数) | 纯逻辑与响应式状态强制分离 |
**经验值**:列表页优先「组件内管理 + 请求取消」(AbortController + 版本号方案,见 03 章),只有跨页面共享的数据才进 store。**不要为了「规范」把每个列表都塞进全局 store。**
---
## 六、技术栈对照总表
| 维度 | ant-design-pro | vue-vben-admin | soybean-admin | vue-pure-admin | gin-vue-admin | 本标准推荐值 |
| ---- | -------------- | -------------- | ------------- | -------------- | ------------- | ------------------ |
| 框架 | React 19 | Vue 3 | Vue 3.5 | Vue 3.5 | Vue 3 | Vue 3 或 React(单栈) |
| 语言 | TS strict | TS strict | TS strict(namespace 组织) | TS(strict 关闭) | JS | 新项目 TS strict;存量渐进 |
| UI 库 | antd v6 + Pro | antd-vue/EP/naive 适配 | Naive UI + UnoCSS | Element Plus + TW v4 | Element Plus | Vue: EP;React: antd 或 shadcn |
| 构建 | Umi Max(utoopack) | Vite + Turbo monorepo | Vite(轻 workspace) | Vite 8/rolldown 单包 | Vite | Vite + pnpm |
| 状态 | useModel + RQ | Pinia + 持久化插件 | Pinia(index+shared) | Pinia(StoreHook 模式) | Pinia 分域 | Pinia(Vue)/ Zustand+RQ(React) |
| 请求 | umi-request + 错误契约 | RequestClient 类 | 五钩子工厂 + flat 返回 | PureHttp 类(196 行) | axios 单例 | axios 封装(见 03 章) |
| 样式 | Tailwind v4 + antd-style | HSL Token + TW v4 | ThemeSetting 三端同步 | EP↔TW v4 变量桥接 | SCSS + UnoCSS + EP 变量 | 语义 Token 单源(见 06 章) |
| 规范 | Biome + commitlint | oxlint + eslint + lefthook | soybeanjs/eslint-config + sa CLI | eslint + stylelint + husky | ESLint flat + Prettier | ESLint flat + Prettier + commitlint |
| 测试 | Vitest + Playwright | Vitest(内核组件全覆盖) | —(未见体系化) | —(未见体系化) | 无(短板) | Vitest + Playwright(见 08 章) |
---
## 七、AI 检查清单(对比目标工程逐项核对)
**P0(结构性的,立即改)**
1. 工程是否单栈?若双栈并存,是否有明确的「主端/副端 + 退役计划」与统一契约命名?
2. 是否存在同工程两套 UI 库 / 两套状态库 / 两种 CSS 方案?
3. 组件库是否按需引入(unplugin 或手动)?全量 `app.use()` 即不合格
4. 包管理器是否 pnpm?`preinstall: only-allow pnpm` 是否配置?
**P1(质量项,排期改)**
5. 新文件是否 TS / 存量是否补 JSDoc?接口函数是否存在「无类型也无注释」
6. 路由渲染是否声明式(禁止 entries+三元链)?
7. HTTP 客户端是否统一 axios?
8. 状态三分法是否被遵守(URL 状态不进 store、列表不进全局 store)?
**P2(演进项)**
9. 是否需要 `typings/` 目录承接全局契约类型(soybean 四区范式)?
10. 构建指纹(版本/commit 注入)是否配置?
---
> 下一篇:[02-项目架构与目录结构](02-项目架构与目录结构.md) —— 目录是架构的最后陈述。