afe2894c35
- Remove section 一 (all 54 defects fixed and committed) - Deepen section 二: each architecture problem now shows '已解决' vs '仍存在' vs '架构级方案' - Update section 三: mark 7 completed needs (N1/N2/N6/N15/N16/N17/N25), refine remaining 19 - Update roadmap: 4 phases with architecture improvement suggestions per phase
214 lines
10 KiB
Markdown
214 lines
10 KiB
Markdown
# JRedisDesktop 项目架构分析与需求规划
|
||
|
||
> 审查日期:2026-07-12
|
||
> 缺陷修复:54 个问题已全部处理(P0×6 + P1×11 + P2×14 + P3×9)
|
||
> 本文档聚焦:系统性架构问题深度分析 + 可开发需求规划
|
||
|
||
---
|
||
|
||
## 一、系统性架构问题分析
|
||
|
||
经过全量缺陷修复后,以下 5 个架构级问题中部分已通过点修复解决,但系统性方案仍需推进。
|
||
|
||
### 问题 A:资源生命周期管理
|
||
|
||
**已解决的点**:
|
||
- `app.on('will-quit')` 调用 `disconnectAll()` + `stopAllPubSubClients()` -- 退出时连接/订阅/监控不再泄漏
|
||
- KeyDetail TTL 定时器移入 `onMounted`,`onUnmounted` 清理
|
||
- CliView IPC 监听器(publishMessage/monitorMessage)返回清理函数,卸载时调用
|
||
- PubSub/Monitor 添加 `sender.isDestroyed()` 检查 + `destroyed` 事件自动清理
|
||
|
||
**仍存在的系统性问题**:
|
||
- 各组件/store 仍各自管理 `setInterval`/`addEventListener`/IPC 监听,无统一注册机制
|
||
- `stores/connection.ts` 的 `healthTimers` Map 无 dispose 路径(HMR 时泄漏)
|
||
- `stores/app.ts` 的 `theme.onOsUpdated` 回调永不移除
|
||
- `StatusView.vue` 的 `refreshTimer`、`SlowLogView.vue` 的定时器仍各自管理
|
||
|
||
**架构级方案**:
|
||
```
|
||
引入 useDisposable composable:
|
||
const { register, dispose } = useDisposable()
|
||
register(setInterval(...)) // 自动在 onScopeDispose 时清理
|
||
register(ipcListener) // 自动移除
|
||
|
||
或使用 VueUse 的 tryOnScopeDispose:
|
||
tryOnScopeDispose(() => clearInterval(timer))
|
||
```
|
||
|
||
优先级:**中** -- 当前点修复已解决崩溃级问题,剩余的是 HMR 场景下的泄漏,生产环境影响小。
|
||
|
||
---
|
||
|
||
### 问题 B:安全模型
|
||
|
||
**已解决的点**:
|
||
- 凭据加密:`storage:saveConnection` 加密 auth/sshPassword/sshPassphrase,`getConnections` 解密
|
||
- safeStorage 不可用时抛出错误而非明文回退
|
||
- `customFormat` 白名单(xxd/jq/python3/python/php/column)
|
||
- `redis:execute` 拦截 FLUSHALL/FLUSHDB/SHUTDOWN/DEBUG,新增 `executeUnsafe` 供 CLI
|
||
- 移除 `dangerouslyUseHTMLString`,改用纯文本
|
||
|
||
**仍存在的系统性问题**:
|
||
- `executeUnsafe` 在渲染进程中可被任意调用,妥协的渲染进程仍能执行危险命令
|
||
- 凭据解密在 `getConnections` 中批量进行,解密后的明文密码在渲染进程内存中停留
|
||
- SSH 私钥路径和 TLS 证书路径未校验(路径遍历)
|
||
|
||
**架构级方案**:
|
||
- `executeUnsafe` 加来源校验:仅允许从 CliView 的 IPC 事件调用(检查 `event.senderFrame` 来源)
|
||
- 渲染进程不持有明文密码:连接时传递密码到主进程,主进程自行解密使用,渲染进程只存加密串
|
||
- 路径校验:`expandHomePath` 后检查路径不在敏感目录外
|
||
|
||
优先级:**低** -- `contextIsolation: true` + `nodeIntegration: false` 已提供基础隔离,当前安全水平可接受。
|
||
|
||
---
|
||
|
||
### 问题 C:错误处理策略
|
||
|
||
**已解决的点**:
|
||
- `withLog` 提取实际连接 ID
|
||
- `win-state.ts` 写错误 `console.error`
|
||
- TLS/SSH 文件读取失败 `console.warn`
|
||
- Monitor `.catch()` 处理 rejection
|
||
- `updater.ts` 防重复注册
|
||
|
||
**仍存在的系统性问题**:
|
||
- `redis:connect` 捕获错误返回 `{ success: false, error }` 对象,其他 handler 直接 throw -- 两种模式混用
|
||
- `redis:disconnect` 无 try/catch,内部错误成为未处理 rejection
|
||
- PubSub `sub.subscribe()`/`sub.psubscribe()` 返回的 Promise 未 await
|
||
- 渲染进程各处 IPC 调用的错误处理不统一(有的 try/catch + ElMessage,有的无处理)
|
||
|
||
**架构级方案**:
|
||
```typescript
|
||
// 主进程:统一 IPC wrapper
|
||
function safeHandle(channel: string, handler: (...args) => Promise<any>) {
|
||
ipcMain.handle(channel, async (e, ...args) => {
|
||
try { return await handler(e, ...args) }
|
||
catch (err) { throw new Error(serializeError(err)) }
|
||
})
|
||
}
|
||
|
||
// 渲染进程:统一调用封装
|
||
async function safeInvoke<T>(fn: () => Promise<T>, errorMsg?: string): Promise<T | undefined> {
|
||
try { return await fn() }
|
||
catch (err) { ElMessage.error(errorMsg || err.message); return undefined }
|
||
}
|
||
```
|
||
|
||
优先级:**中** -- 不影响功能,但调试困难,用户体验不一致。
|
||
|
||
---
|
||
|
||
### 问题 D:类型安全
|
||
|
||
**已解决的点**:
|
||
- `preload/index.d.ts` 15+ 处 `any` 替换为具体类型(connect/scanKeys/hashScan/dialog.openFile/stream 等)
|
||
- 内联定义 ConnectionConfig/AppSettings/CommandEntry 接口
|
||
- `ConnectionConfig` 添加 `version` 字段 + `migrateConnections()` 迁移函数
|
||
- `WRITE_COMMANDS` 补全 30+ 写命令
|
||
|
||
**仍存在的系统性问题**:
|
||
- `connection.ts` 中 `sshConfig: any`、`tlsOpts: any`、`clusterOptions: any`、`redis as any` 仍未消除
|
||
- `stream.ts` 多处 `as any` 绕过 ioredis 类型
|
||
- `ipc-handlers.ts` 的 `withLog` 参数仍为 `any[]`
|
||
- 渲染进程组件中多处 `(item: any)` 类型断言
|
||
|
||
**架构级方案**:
|
||
- 从 ioredis 导入 `Cluster` 类型替换 `redis as any`
|
||
- 定义 `SSHClientConfig`、`TLSOptions` 接口替换 `any`
|
||
- `stream.ts` 使用 ioredis 的 `xgroup`/`xinfo` 方法签名
|
||
- 渲染进程定义 Redis 命令结果的类型接口
|
||
|
||
优先级:**低** -- 类型不准确不影响运行,但影响可维护性和 IDE 体验。
|
||
|
||
---
|
||
|
||
### 问题 E:性能策略
|
||
|
||
**已解决的点**:
|
||
- KeyList 批量导出改为 `Promise.allSettled` 分批并行(每批 20)
|
||
- `key.ts` 从 `useConnectionStore()` 获取 separator,消除每次 SCAN 的 IPC 往返
|
||
- HashEditor HTTL 改为点击字段时按需加载
|
||
- SCAN 空模式规范化为 `'*'`
|
||
|
||
**仍存在的系统性问题**:
|
||
- 所有编辑器无虚拟滚动,数万条记录一次性渲染 DOM
|
||
- KeyList 树视图大数据量时渲染卡顿
|
||
- 无 SCAN 结果缓存,频繁切换 DB 重复扫描
|
||
- `scanKeys` 全量加载到前端,无分页/懒加载
|
||
|
||
**架构级方案**:
|
||
- 编辑器引入 `el-table-v2`(Element Plus 虚拟滚动表格)或自定义虚拟列表
|
||
- KeyList 树视图使用 `el-tree-v2`(虚拟滚动树)
|
||
- SCAN 结果分页:前端维护 cursor,滚动到底部加载下一页
|
||
- 连接级别的 SCAN 结果缓存(LRU)
|
||
|
||
优先级:**高** -- 生产环境(百万级 key)下当前实现会卡死,这是用户最直接感知的性能问题。
|
||
|
||
---
|
||
|
||
## 二、可开发需求清单
|
||
|
||
### 已完成需求
|
||
|
||
| # | 需求 | 完成方式 |
|
||
|---|------|---------|
|
||
| N1 | 凭据加密加固 | P0#1 修复:`storage:saveConnection` 加密敏感字段 |
|
||
| N2 | 资源生命周期管理器 | P0#4 + P1#8/9/10 修复:退出清理 + 定时器/监听器清理 |
|
||
| N6 | 命令白名单中间件 | P0#3 修复:`BLOCKED_COMMANDS` + `executeUnsafe` |
|
||
| N15 | TTL 实时倒计时优化 | P1#8 修复:定时器移入 `onMounted` |
|
||
| N16 | 主题完整适配 | P2#19 修复:ReJsonEditor `:theme="monacoTheme"` |
|
||
| N17 | i18n 补全 | P3#37 修复:KeyDetail/TitleBar/Sidebar 硬编码替换 |
|
||
| N25 | TypeScript 严格化(部分) | P3#36/42 修复:preload d.ts 15+ 处 any 消除 |
|
||
|
||
### 高优先级需求
|
||
|
||
| # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|
||
|---|------|---------|--------|---------|
|
||
| N4 | **虚拟滚动** | 数万字段/成员不卡顿,生产环境刚需 | 中 | Hash/List/Set/ZsetEditor 用 `el-table-v2`;KeyList 用 `el-tree-v2` |
|
||
| N5 | **Stream Consumer Group 完整化** | ACK 已实现但未用,消费组可视化不全 | 中 | StreamEditor 接入 `redis:streamAck`;加 pending entries 列表、XPEL CLAIM 功能 |
|
||
| N3 | **CLI 事务体验优化** | 当前 MULTI/EXEC 功能正确但 UX 不佳(未显示 QUEUED 状态) | 低 | 事务模式下检查返回值是否为 "QUEUED",非 QUEUED 时警告用户 |
|
||
|
||
### 中优先级需求
|
||
|
||
| # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|
||
|---|------|---------|--------|---------|
|
||
| N7 | **Cluster/Sentinel 完善** | 生产环境主流部署,当前 cluster 分支已有但拓扑不可视 | 高 | 节点拓扑可视化(`CLUSTER NODES`)、failover 操作、slot 分布图 |
|
||
| N8 | **ACL 用户管理** | Redis 6+ ACL 已普及,当前只能用 CLI | 中 | 新建 ACL 视图:用户 CRUD、权限矩阵、`ACL WHOAMI`/`ACL LIST` |
|
||
| N9 | **数据导入导出** | 迁移/备份场景,KeyList 已有导出雏形 | 中 | 导出:RDB/DUMP/JSON 格式;导入:批量 SET/pipeline |
|
||
| N10 | **Function 管理(Redis 7+)** | 替代 EVAL 的服务端函数 | 中 | 新建 Function 视图:`FUNCTION LIST`/`LOAD`/`DELETE`/调用 |
|
||
| N11 | **大 Key 扫描** | 生产排障刚需,`MEMORY USAGE` 扫描已有 | 中 | 扩展为后台任务 + 排序 + 导出报告 + 可视化分布 |
|
||
| N12 | **Latency Monitor** | 补充慢日志的延迟诊断 | 低 | `LATENCY HISTORY`/`LATENCY DOCTOR` 视图 |
|
||
| N13 | **PubSub 可视化** | 当前仅 CLI 内嵌,无独立视图 | 中 | 新建 PubSub 视图:频道树、消息流、JSON 高亮、订阅状态 |
|
||
| N14 | **连接分组/标签** | 连接多了难管理 | 低 | ConnectionList 加分组折叠、颜色标签 |
|
||
|
||
### 低优先级需求
|
||
|
||
| # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|
||
|---|------|---------|--------|---------|
|
||
| N18 | **Key 详情对比** | 编辑前后 diff | 中 | StringEditor/HashEditor 加 diff 视图 |
|
||
| N19 | **命令收藏夹** | 常用命令快速调用 | 低 | CliView 加收藏侧栏,localStorage 持久化 |
|
||
| N20 | **连接 SSH 跳板机** | 多跳 SSH 场景 | 中 | ssh2 隧道级联 |
|
||
| N21 | **慢日志分析图表** | 趋势可视化 | 中 | SlowLogView 加 ECharts 时间分布图 |
|
||
| N22 | **快捷键体系完善** | 当前仅 5 个 | 低 | 加 Ctrl+F 搜索、Ctrl+1~9 切 tab、Ctrl+L 聚焦 CLI |
|
||
| N23 | **测试体系** | 当前无测试 | 高 | Vitest 渲染进程单元测试;主进程 Redis 模块用 ioredis-mock |
|
||
| N24 | **CI/CD** | 自动化构建发布 | 中 | GitHub Actions:lint+typecheck+build 三平台 |
|
||
| N26 | **错误上报** | 收集崩溃信息 | 低 | 主进程 crashReporter + 渲染进程 errorHandler |
|
||
|
||
---
|
||
|
||
## 三、路线图建议
|
||
|
||
```
|
||
第一阶段(高优先级): N4 虚拟滚动 -> N5 Stream 完整化 -> N3 CLI 事务体验
|
||
第二阶段(中优先级): N7 Cluster -> N9 导入导出 -> N11 大Key扫描 -> N13 PubSub视图
|
||
第三阶段(中优先级): N8 ACL -> N10 Function -> N12 Latency -> N14 连接分组
|
||
第四阶段(低优先级): N23 测试 -> N24 CI/CD -> N22 快捷键 -> N18-N21/N26
|
||
```
|
||
|
||
### 架构改进建议(伴随功能开发渐进推进)
|
||
|
||
1. **资源管理**:开发 N5/N13 时顺手引入 `useDisposable` composable,逐步迁移现有定时器/监听器
|
||
2. **错误处理**:开发 N9 时引入 `safeInvoke` 封装,统一 IPC 错误提示
|
||
3. **类型安全**:开发 N7/N8 时消除 `connection.ts` 的 `as any`,定义完整的 Redis 操作类型
|
||
4. **性能**:N4 虚拟滚动是独立的高价值任务,建议优先单独开发
|