Files
LokiStack/docs/web-ui-guide/02-项目架构与目录结构.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

232 lines
12 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.
# 02 — 项目架构与目录结构
> 参考:vue-vben-admin(三层包划分)、soybean-admin(文件路由 + store 纯函数分离)、ant-design-pro(页面 co-location)、vue-pure-admin(页面内聚五件套);补充:gin-vue-admin(分域 api/view)
---
## 一、组织目录的三种流派
### 1.1 流派对照
| 流派 | 代表 | 结构 | 优点 | 代价 |
|------|------|------|------|------|
| **按层分**(layer-first) | 早期中台 | `components/ views/ api/ stores/` 每层内平铺全部业务 | 上手简单 | 业务散在 5 个目录,删模块要全局找 |
| **按域分**(domain-first) | **本标准(Vue 单包)/ gva** | 层目录保留,但 `api/user/`、`views/user/`、`stores/` 域内聚合 | 删域=删目录,心智清晰 | 需要约定维持层内域目录一致 |
| **按功能分包**(feature-first) | adp 页面级、vben 包级 | 页面目录自带 service/mock/类型/样式;框架能力独立成包 | 高内聚,可整体搬移 | 需要晋升机制防止复制泛滥 |
**结论:中小工程用「按域分 + 页面 co-location」混合式**——全局按域(api/views 域目录对齐),页面私有代码留在页面目录内。
### 1.2 四标杆的目录精髓
```
vue-vben-admin(依赖方向三层,分层标杆)
apps/* ──▶ packages/effects/* ──▶ packages/@core/*
(app 是唯一允许直接依赖具体 UI 库的层;
@core 零 UI 依赖零业务;effects 通过 adapter 适配 UI 生态)
ant-design-pro(页面五件套 co-location)
src/pages/table-list/
├── index.tsx # 页面(ProTable 声明式列配置)
├── service.ts # 本页接口(手写层)
├── data.d.ts # 本页类型
├── _mock.ts # 本页 mock(config 显式 include)
└── components/
├── CreateForm.tsx # 新建弹窗(trigger 模式)
└── UpdateForm.tsx # 编辑弹窗(StepsForm 进 Modal)
soybean-admin(生成物 + store 纯函数分离,★★★★☆)
src/
├── router/elegant/ # 文件路由生成物(routes/transform/imports + RouteKey 类型 d.ts)
├── service/{api,request}/ # api=纯请求函数、request=实例拦截器,两层分离
├── store/modules/<mod>/ # 每模块 index.ts(状态编排) + shared.ts(可单测纯函数)
├── typings/{api,...} # 全局 namespace 类型(Api/App/Storage/Env)
└── views/_builtin/ # 403/404/500/login 内置页统一收纳,业务页平级
vue-pure-admin(页面内聚五件套,★★★★☆)
src/views/system/user/
├── index.vue # 纯模板(零逻辑,只解构 hook)
├── form/index.vue # 弹窗表单
├── tree.vue # 左树
└── utils/{hook.tsx,rule.ts,types.ts} # 逻辑/校验/类型全在本域
gin-vue-admin(补充:全局分域 + 指令/钩子独立)
src/
├── api/ # 一域一文件:user.js menu.js ...
├── pinia/modules/ # 一域一 store
├── view/superAdmin/ view/example/ # 按业务分组
├── directive/auth.js # v-auth 指令独立目录
├── hooks/responsive.js # 组合式函数独立目录
└── plugin/<name>/ # 业务插件 = 自带 view/api/assets 的小应用
```
---
## 二、标准目录结构(Vue 工程)
### 2.1 目标结构
```
src/
├── main.js # 入口:仅装配(EP按需、pinia、router、指令、全局组件)
├── App.vue
├── api/ # ★ 按功能域分目录,与 views 域目录同名
│ ├── auth/ # captcha.js mfa.js
│ ├── user/ # users.js roles.js permissions.js
│ ├── rbac/ # 域小可单文件,大了再拆
│ ├── system/ # menu.js modules.js logs.js ...
│ └── <domain>/ # 业务域
├── views/ # ★ 域目录与 api/ 一一对应
│ ├── user/ # Users.vue + components/XxxFormDialog.vue ...
│ ├── <domain>/
│ └── _builtin/ # 403/404/500/login 内置页统一收纳(soybean 范式)
├── stores/ # Pinia:一域一文件(auth.js menu.js site.js ...)
├── composables/ # useXxx(依赖业务上下文的钩子)
├── components/ # ★ 全局组件(需晋升,见第四章)
├── layout/ # 布局骨架(业务页只挂内容区,禁止重写布局)
├── router/ # index.js(含守卫) modules/(路由分文件)
├── config/ # theme.js modules.js(纯配置,无副作用导入)
├── typings/ # 全局契约类型(TS 渐进路线,soybean 四区)
├── utils/ # request.js permission.js(无状态工具)
└── styles/ # 全部文件必须有入口引用链
```
React 工程同构映射:`views→pages`、`composables→hooks`、`stores→store`(zustand slices)、`components→components`(含 barrel 出口)。
### 2.2 层内规则(必须)
1. **api 域目录与 views 域目录强制同名**(`api/cron/` ↔ `views/cron/`);**禁止**在 api 根级别放散文件
2. **store 文件名 = 导出名**(`stores/auth.js` → `useAuthStore`);单 store ≤300 行;推荐 soybean 的「index + shared」目录式(状态编排与纯函数分离)
3. **layout/ 是禁改区**:业务页通过页面容器组件的 header/slot 定制,不碰布局骨架(可裁剪底座的前提)
4. **components/ 只放「晋升组件」**(见第四章晋升机制),新页面私有组件一律 `views/<域>/components/`
### 2.3 可裁剪分层与模块开关(底座/脚手架推荐)
```
┌─────────────────────────────────────────────────────┐
│ 壳层 shell 登录/MFA/403/500 —— 不挂主布局 │
├─────────────────────────────────────────────────────┤
│ 系统层 system 用户/RBAC/审计/设置 —— 底座自带 │
├─────────────────────────────────────────────────────┤
│ 示例层 examples 演示模块 —— fork 后可整层删除 │
└─────────────────────────────────────────────────────┘
```
- 路由 `meta.layer: 'shell' | 'system' | 'examples'` 声明归属
- 运行时开关:**源真相在后端**(如 `GET/PUT /api/system/modules`),localStorage 仅作缓存——**禁止**把 localStorage 当源真相
- 构建期裁剪:环境变量(如 `VITE_ENABLE_EXAMPLES=false`)+ 路由中字面量比较,保证打包器 tree-shake 掉示例 chunk
- 示例层代码**不得 import 系统层**内聚单元,保证整层可摘除;示例域附删除指引文档(EXAMPLES.md 惯例)
**分层是目录结构之外的第二根轴**:每个新模块必须先回答「我在哪一层」。
### 2.4 命名规范与类型目录
| 对象 | 规范 | 示例 |
|------|------|------|
| 组件文件 | PascalCase | `UserFormDialog.vue` |
| 工具 / composable | camelCase,composable 带 use 前缀 | `request.js`、`usePagedQuery.js` |
| 目录 | kebab-case(views 域目录用业务域名) | `user-management/`、`cron/` |
| store 文件 | 文件名与导出同名 | `stores/auth.js` → `useAuthStore` |
| API 文件 | 资源名复数 | `api/user/users.js` |
| 常量 | UPPER_SNAKE_CASE | `SYSTEM_ORDER` |
类型目录(TS 渐进路线,soybean 范式):全局契约类型集中 `typings/`(Api / App / Storage / Env 四区 namespace,storage 与 env 均键级类型);页面私有类型随页面(`data.d.ts` / `utils/types.ts`);**禁止**同一类型定义在多个组件内重复出现。
---
## 三、页面 co-location(adp 五件套)
### 3.1 什么时候页面自带 service
```
全局 api/<域>/xxx.js # 多页面复用、域级语义(users.js 的 list/create/delete)
页面内 service.ts # 只服务本页的接口(dashboard 聚合、报表导出)
```
判定:**接口第二个消费者出现时**,从页面 `service.ts` 提升到 `api/<域>/`。反向不成立——不要预防性提升。
### 3.2 页面目录模板
```
views/<domain>/<Page>.vue # 页面骨架:容器 + 列表组件 + 子组件编排(≤400 行)
views/<domain>/components/ # 本页私有组件(表单弹窗、详情抽屉、单元格渲染器)
views/<domain>/composables/ # 本页私有逻辑(可选,超过 2 个页面组件共享时建)
views/<domain>/utils/ # 本页 hook/rule/types(pure 范式,可选)
views/<domain>/EXAMPLES.md # 仅示例层:删除指引
```
---
## 四、公共组件晋升机制
```
第 1 次使用:写在页面 components/ 里
第 2 次使用:复制一份,页面内注明来源 ← 允许的重复
第 3 次使用:晋升 src/components/,删除两份复制 ← 必须执行
```
晋升时同步做三件事:
1. **去业务化**:props 收口(`fetcher`/`permissions` 进来,具体 API 调用出去)
2. **注册出口**:Vue 端全局组件在 `main.js` 注册;React 端进 `components/index.ts` barrel(adp:按「布局组件 / 业务组件」分组导出)
3. **写使用说明**:组件头部注释 3 行(用途/必需 props/已知限制)
必备的两个全局页面组件(详见 05/07 章):**PageContainer**(页面容器:页头/面包屑/slot)与 **ListPage**(分页列表:fetcher + 筛选 slot + 表格透传 + 分页)。
---
## 五、架构守护:让目录约定不被腐蚀
| 守护手段 | 出处 | 可落地做法 |
|----------|------|------------|
| 循环依赖扫描 | vben `check:circular` | `npx madge --circular src/` 进 CI |
| 依赖方向检查 | vben `check:dep`(@core 禁依赖 UI 库) | 示例层禁 import 系统层:ESLint `no-restricted-imports` 按路径分组 |
| 死代码检测 | adp coverage 排除生成物 | CI 跑 `knip`/`depcheck`,styles 无入口文件直接报错 |
| 生成物隔离 | adp `services/ant-design-pro/`(OpenAPI 生成,禁手改) | 生成物独立目录 + lint ignore |
| 路由自动收集 | pure `router/modules/` + `import.meta.glob` | 新增路由文件零注册代码 |
---
## 六、最佳实践清单
✅ **要做**
1. api 域目录与 views 域目录同名;新域从脚手架起步(自动生成五处对照:菜单/路由/页面/API/权限码)
2. 页面私有组件不出页面目录;晋升走「三次法则」
3. 每个新模块先声明 `meta.layer`,示例层保持可整层摘除
4. store 按域拆分、文件名=导出名、单 store ≤300 行
5. 目录结构变化(新增域/晋升组件/删示例)在同一 PR 内更新架构文档
❌ **不要**
1. 不要在 api 根级别放散文件
2. 不要把页面私有组件直接丢进 `src/components/`
3. 不要让业务页 import layout 内部组件(只准用 slot 协议)
4. 不要建「future/」「temp/」「new/」这类无语义目录
5. 不要保留无入口引用的样式文件和空目录
---
## 七、AI 检查清单(对比目标工程逐项核对)
**P0**
1. api 与 views 域目录是否同名对齐?有无 api 根级散文件?
2. store 文件名与导出名是否一致?有无超 300 行的 store?
3. 有无空目录、无引用样式、描述已不存在目录的文档残留?
**P1**
4. 页面骨架是否 ≤400 行?超 400 行的视图列出拆分建议(参照 07 章)
5. 私有组件是否越界进全局 components/?全局组件是否都有注册出口与头注释?
6. 若为可裁剪底座:meta.layer 是否全覆盖?模块开关源真相是否在后端?
7. CI 是否有循环依赖与死代码检查?
**P2**
8. 是否值得引入路由文件自动收集(`router/modules/` + glob)或文件路由(soybean @elegant-router)?
9. `typings/` 全局类型目录是否建立(Api/App/Storage/Env 四区)?
---
> 下一篇:[03-请求层与数据流](03-请求层与数据流.md) —— 前端工程的血管系统。