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

14 KiB
Raw Permalink Blame History

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(质量项,排期改)

  1. 新文件是否 TS / 存量是否补 JSDoc?接口函数是否存在「无类型也无注释」
  2. 路由渲染是否声明式(禁止 entries+三元链)?
  3. HTTP 客户端是否统一 axios?
  4. 状态三分法是否被遵守(URL 状态不进 store、列表不进全局 store)?

P2(演进项)

  1. 是否需要 typings/ 目录承接全局契约类型(soybean 四区范式)?
  2. 构建指纹(版本/commit 注入)是否配置?

下一篇:02-项目架构与目录结构 —— 目录是架构的最后陈述。