Files
JRedisDesktop/docs/PROJECT_REVIEW.md
T
Jokul ad21900a6f feat(N4): virtual scrolling for Set/Zset/List editors
- Create VirtualScrollList.vue component using @tanstack/vue-virtual
  - Props: items, itemHeight, overscan, height
  - Events: scrollEnd (for infinite loading)
  - Slots: default (item rendering), empty
- SetEditor: replace v-for with VirtualScrollList, handles 100k+ members
- ZsetEditor: replace v-for with VirtualScrollList, preserves filter/sort
- ListEditor: replace pagination with virtual scroll + infinite loading
  - Initial load 100 items, auto-loads 100 more on scrollEnd
  - Shows loaded/total count + loading indicator
- HashEditor: kept as-is (HSCAN limits to 100 items, el-table handles fine)
- docs: mark N4 complete, update problem E priority to medium
2026-07-12 15:04:08 +08:00

212 lines
10 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.
# 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 空模式规范化为 `'*'`
**仍存在的系统性问题**:
- KeyList 树视图大数据量时渲染卡顿
- 无 SCAN 结果缓存,频繁切换 DB 重复扫描
- `scanKeys` 全量加载到前端,无分页/懒加载
**架构级方案**:
- KeyList 树视图使用 `el-tree-v2`(虚拟滚动树)
- SCAN 结果分页:前端维护 cursor,滚动到底部加载下一页
- 连接级别的 SCAN 结果缓存(LRU)
优先级:**中** -- 编辑器虚拟滚动已解决,剩余 KeyList 树视图和 SCAN 分页问题。
---
## 二、可开发需求清单
### 已完成需求
| # | 需求 | 完成方式 |
|---|------|---------|
| 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 | 虚拟滚动 | 创建 `VirtualScrollList.vue`(@tanstack/vue-virtual);Set/Zset/List 编辑器改造完成 |
### 高优先级需求
| # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|---|------|---------|--------|---------|
| 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 虚拟滚动是独立的高价值任务,建议优先单独开发