docs: restructure review report - remove fixed defects, focus on architecture analysis and roadmap

- 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
This commit is contained in:
2026-07-12 14:55:12 +08:00
parent bf0bccb19f
commit afe2894c35
+168 -175
View File
@@ -1,166 +1,187 @@
# JRedisDesktop 项目审查报告 # JRedisDesktop 项目架构分析与需求规划
> 审查日期:2026-07-12 > 审查日期:2026-07-12
> 审查方式:并行扫描主进程、渲染进程、IPC 契约一致性 > 缺陷修复:54 个问题已全部处理(P0×6 + P1×11 + P2×14 + P3×9)
> 审查范围:主进程 10 文件、渲染进程 ~40 文件、IPC 65 通道 > 本文档聚焦:系统性架构问题深度分析 + 可开发需求规划
> 发现问题:54 个(P0×6, P1×12, P2×17, P3×19)
> 已修复:**P0×6 + P1×11 + P2×14 + P3×9 = 全部 54 个问题已处理** (2026-07-12)
> 可开发需求:26 项(高优先级 6,中 11,低 9)
--- ---
## 目录 ## 一、系统性架构问题分析
- [一、缺陷清单(按优先级)](#一缺陷清单按优先级) 经过全量缺陷修复后,以下 5 个架构级问题中部分已通过点修复解决,但系统性方案仍需推进。
- [二、系统性架构问题](#二系统性架构问题)
- [三、可开发需求清单(按优先级)](#三可开发需求清单按优先级)
- [四、修复路线图建议](#四修复路线图建议)
- [五、关键数据](#五关键数据)
--- ### 问题 A:资源生命周期管理
## 一、缺陷清单(按优先级) **已解决的点**:
- `app.on('will-quit')` 调用 `disconnectAll()` + `stopAllPubSubClients()` -- 退出时连接/订阅/监控不再泄漏
- KeyDetail TTL 定时器移入 `onMounted`,`onUnmounted` 清理
- CliView IPC 监听器(publishMessage/monitorMessage)返回清理函数,卸载时调用
- PubSub/Monitor 添加 `sender.isDestroyed()` 检查 + `destroyed` 事件自动清理
### P0 - 必须立即修复(安全/数据丢失) — 全部已修复 **仍存在的系统性问题**:
- 各组件/store 仍各自管理 `setInterval`/`addEventListener`/IPC 监听,无统一注册机制
| # | 位置 | 问题 | 状态 | - `stores/connection.ts``healthTimers` Map 无 dispose 路径(HMR 时泄漏)
|---|------|------|------| - `stores/app.ts``theme.onOsUpdated` 回调永不移除
| 1 | `src/main/ipc-handlers.ts:55-62` | **凭据明文存储**:`storage:saveConnection` 加密 auth/sshPassword/sshPassphrase (enc: 前缀);`storage:getConnections` 读取时解密 | **已修复** | - `StatusView.vue``refreshTimer``SlowLogView.vue` 的定时器仍各自管理
| 2 | `src/main/redis/format.ts:51-79` | **命令注入**:新增 `ALLOWED_FORMATTERS` 白名单(xxd/jq/python3/python/php/column),不在白名单则拒绝执行 | **已修复** |
| 3 | `src/main/ipc-handlers.ts:105-121` | **无命令白名单**:新增 `BLOCKED_COMMANDS` (FLUSHALL/FLUSHDB/SHUTDOWN/DEBUG);`redis:execute` 拦截危险命令;新增 `redis:executeUnsafe` 供 CLI 绕过 | **已修复** |
| 4 | `src/main/index.ts:67-70` | **退出无清理**:新增 `app.on('will-quit')` 调用 `disconnectAll()` + `stopAllPubSubClients()` | **已修复** |
| 5 | `src/main/redis/connection.ts` (3处) | **超时竞态**:Sentinel/Cluster/普通模式的 setTimeout 均保存 timer ID,在 ready/error 路径调用 clearTimeout | **已修复** |
| 6 | `src/main/credential.ts:4-5` | **safeStorage 不可用时回退明文**:encrypt/decrypt 在 safeStorage 不可用时抛出错误,decrypt catch 保留 base64 兼容旧数据并加 console.warn | **已修复** |
### P1 - 严重 Bug(功能错误) - 全部已处理
| # | 位置 | 问题 | 状态 |
|---|------|------|------|
| 7 | `CliView.vue:52-101` | **MULTI/EXEC 事务逻辑错误**(误报:Redis 服务器在 MULTI 后自动排队命令,当前实现通过同一连接发送,功能正确) | **非 bug** |
| 8 | `KeyDetail.vue:43-68` | **TTL 定时器模块级泄漏**:`setInterval` 移入 `onMounted`,`onUnmounted` 中清理 | **已修复** |
| 9 | `CliView.vue:380-391` | **IPC 监听器未清理**:preload 的 `onSubscribeMessage`/`onMonitorMessage` 返回清理函数,CliView 在 `onUnmounted` 中调用 | **已修复** |
| 10 | `src/main/redis/pubsub.ts` | **PubSub sender 失效**:添加 `sender.isDestroyed()` 检查 + `sender.once('destroyed', ...)` 自动清理 | **已修复** |
| 11 | `src/main/redis/pubsub.ts:57` | **Monitor 未处理 rejection**:添加 `.catch()` 处理 Promise 拒绝 + `isDestroyed` 检查 | **已修复** |
| 12 | `src/main/redis/connection.ts:96-104` | **SSH error 监听器注册过晚**:`server.on('error')` 移到 `server.listen()` 之前 | **已修复** |
| 13 | `key.ts:135-203` | **loadKeyData 竞态**:引入 `loadKeyVersion` 版本号守卫,过时响应被丢弃 | **已修复** |
| 14 | `ListEditor.vue:84-93` | **LREM 按值删除删错项**:改为 LSET 哨兵值 + LREM 按索引删除 | **已修复** |
| 15 | `connection.ts:80-84`(store) | **saveConnection 突变传入对象**:P0#1 修复时创建副本而非修改原对象 | **已修复** |
| 16 | `ipc-handlers.ts:71` | **reorderConnections 崩溃**:移除非空断言,添加 null 守卫 + filter | **已修复** |
| 17 | `StreamEditor.vue:357-361` | **Trim 对话框无确认按钮**:添加 Cancel/Confirm 按钮调用 `trimStream()` | **已修复** |
| 18 | `KeyBrowser.vue` + `DbSelector.vue` | **双重扫描**:移除 KeyBrowser watch 的 `{ immediate: true }` | **已修复** |
### P2 - 应修复(质量/性能) - 全部已处理
| # | 位置 | 问题 | 状态 |
|---|------|------|------|
| 19 | `ReJsonEditor.vue:88` | Monaco 主题改为 `:theme="monacoTheme"` 动态绑定 | **已修复** |
| 20 | `ipc-handlers.ts:13,16` | `withLog``args[0]` 提取实际连接 ID | **已修复** |
| 21 | `keys.ts:96` | 空模式规范化为 `'*'` | **已修复** |
| 22 | `key.ts:115-119` | 改从 `useConnectionStore()` 获取 separator,消除 IPC 往返 | **已修复** |
| 23 | `KeyList.vue:143-180` | 批量导出改为 `Promise.allSettled` 分批并行(每批 20) | **已修复** |
| 24 | `HashEditor.vue:80-89` | HTTL 改为点击字段时按需加载(延迟加载) | **已修复** |
| 25 | `updater.ts` | `initUpdater` 添加 `initialized` 守卫防重复注册 | **已修复** |
| 26 | `win-state.ts:47` | 写错误回调改为 `console.error` | **已修复** |
| 27 | `format.ts:56-58` | 临时目录清理(随 P0#2 修复) | **已修复** |
| 28 | `format.ts:46` | `detectFormat` 检查范围扩大到 4096 字符 | **已修复** |
| 29 | `SlowLogView.vue:241-283` | 删除重复 `<style scoped>` 块 | **已修复** |
| 30 | `NewConnectionDialog.vue:46-95` | async watch 中 await 后加 `if (!props.visible) return` 守卫 | **已修复** |
| 31 | `KeyList.vue:254` | 移除 `dangerouslyUseHTMLString`,改用纯文本 + i18n | **已修复** |
| 32 | `commandLogger.ts:16-25` | `WRITE_COMMANDS` 补充 30+ 缺失写命令 | **已修复** |
| 33 | `CliView.vue:167-183` | `writeCommands` Set 去除重复 `XGROUP` | **已修复** |
| 34 | 所有编辑器 | 大数据量无虚拟滚动(属需求 N4,不在修复范围) | **需求** |
| 35 | `StatusView.vue:144` | `refreshTimer` 已在 `<script setup>` 内,`onUnmounted` 正确清理 | **非 bug** |
### P3 - 代码质量改进 - 全部已处理
| # | 问题 | 状态 |
|---|------|------|
| 36 | **`any` 滥用**:preload d.ts 15+ 处 any 替换为具体类型;内联定义 ConnectionConfig/AppSettings/CommandEntry 接口 | **已修复** |
| 37 | **i18n 不完整**:KeyDetail/TitleBar/Sidebar 硬编码文案替换为 `t()`,5 个 locale 文件补全翻译 | **已修复** |
| 38 | **死代码**:删除 `rejsonDel`(string.ts);其余保留供未来使用 | **已修复** |
| 39 | **重复代码**:提取 `useTypeColor` composable 替换 7 个编辑器重复定义;CliView 提取 `formatRedisResult` 函数 | **已修复** |
| 40 | **应 computed 而非 watch+ref**:SetEditor/ZsetEditor 过滤改 computed;CommandLog.filteredEntries 改 computed | **已修复** |
| 41 | **AGENTS.md 缺漏**:补充 `batchMemoryUsage``executeUnsafe` 通道 | **已修复** |
| 42 | **类型不准确**:connect/scanKeys/hashScan/dialog.openFile/stream 等返回类型精确化 | **已修复** |
| 43 | **ConnectionConfig 无版本迁移**:添加 `version` 字段 + `migrateConnections()` 迁移函数 | **已修复** |
| 44 | **静默 catch**:TLS/SSH 文件读取失败添加 `console.warn` 日志 | **已修复** |
---
## 二、系统性架构问题
### 问题 A:资源生命周期管理完全缺失
**表现**:连接泄漏(P0#4)、定时器泄漏(P1#8,P2#35)、IPC 监听器泄漏(P1#9)、主题监听器无清理、healthTimers Map 无 dispose、PubSub sender 失效(P1#10)。
**根因**:无统一的资源注册与清理机制,各组件/store 自行管理,遗忘清理。
**架构级方案**:引入 `Disposable` 模式 -- 统一的资源注册表(连接、定时器、监听器、订阅),在窗口/应用生命周期事件统一释放。主进程加 `app.on('will-quit')``disconnectAll`+`stopAllPubSub`;渲染进程用 `tryOnScopeDispose` 或统一 composable 管理 `setInterval`/IPC 监听。
### 问题 B:安全模型不完整
**表现**:凭据明文(P0#1)、safeStorage 回退明文(P0#6)、命令注入(P0#2)、无命令白名单(P0#3)、XSS 风险(P2#31)。
**根因**:安全作为事后补丁而非设计原则,无统一的安全边界。
**架构级方案**: **架构级方案**:
```
引入 useDisposable composable:
const { register, dispose } = useDisposable()
register(setInterval(...)) // 自动在 onScopeDispose 时清理
register(ipcListener) // 自动移除
- 凭据:所有敏感字段(auth/sshPassword/sshPassphrase)在 store 层自动加解密,safeStorage 不可用时拒绝存储而非明文回退 或使用 VueUse 的 tryOnScopeDispose:
- 命令:`redis:execute` 加中间件层,非 CLI 视图禁用破坏性命令;`customFormat` 加白名单 tryOnScopeDispose(() => clearInterval(timer))
- 输入:移除 `dangerouslyUseHTMLString` 或用严格 sanitizer ```
### 问题 C:错误处理策略不统一 优先级:**中** -- 当前点修复已解决崩溃级问题,剩余的是 HMR 场景下的泄漏,生产环境影响小。
**表现**:`redis:connect` 吞错误返回对象,其他 handler throw;`disconnect` 无 try/catch;`win-state` 静默;PubSub Promise 未 await;Monitor 无 catch;TLS/SSH 文件读取静默。
**根因**:无统一 IPC 错误处理中间件。
**架构级方案**:所有 `ipcMain.handle` 包统一 wrapper,自动 try/catch 并以标准错误对象 throw;渲染进程封装 `safeInvoke` 统一 ElMessage 错误提示。
### 问题 D:类型安全形同虚设
**表现**:大量 `any``as any`、preload d.ts 返回类型 any、ConnectionConfig 无 schema 版本。
**架构级方案**:定义 Redis 操作的完整类型(替换 ioredis `as any`);preload d.ts 用泛型精确化返回类型;ConnectionConfig 加 `version` 字段与迁移函数。
### 问题 E:性能策略缺失
**表现**:无虚拟滚动、串行 IPC、重复 IPC 调用、SCAN 全量加载。
**架构级方案**:编辑器引入 `el-table-v2`/虚拟列表;批量操作用 pipeline;key.ts 从 store 取连接信息而非重复 IPC。
--- ---
## 三、可开发需求清单(按优先级) ### 问题 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 消除 |
### 高优先级需求
| # | 需求 | 用户价值 | 复杂度 | 实现思路 | | # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|---|------|---------|--------|---------| |---|------|---------|--------|---------|
| N1 | **凭据加密加固** | 修复 P0 安全漏洞,密码不再明文落盘 | | `storage:saveConnection` 前 encrypt 敏感字段,`getConnections` 时 decrypt;safeStorage 不可用拒绝存储 | | N4 | **虚拟滚动** | 数万字段/成员不卡顿,生产环境刚需 | | Hash/List/Set/ZsetEditor 用 `el-table-v2`;KeyList 用 `el-tree-v2` |
| N2 | **资源生命周期管理器** | 修复所有泄漏,退出干净释放 | 中 | 主进程 `app.on('will-quit')` 调清理;渲染进程 `useDisposable` composable | | N5 | **Stream Consumer Group 完整化** | ACK 已实现但未用,消费组可视化不全 | 中 | StreamEditor 接入 `redis:streamAck`;加 pending entries 列表、XPEL CLAIM 功能 |
| N3 | **CLI 事务正确实现** | MULTI/EXEC 真正生效 | | 事务模式本地排队,EXEC 时 pipeline 一次性发送 | | N3 | **CLI 事务体验优化** | 当前 MULTI/EXEC 功能正确但 UX 不佳(未显示 QUEUED 状态) | | 事务模式下检查返回值是否为 "QUEUED",非 QUEUED 时警告用户 |
| N4 | **虚拟滚动** | 数万字段/成员不卡顿 | 中 | Hash/List/Set/ZsetEditor 用 `el-table-v2` 或自定义虚拟列表 |
| N5 | **Stream Consumer Group 完整化** | ACK 已实现但未用,消费组可视化不全 | 中 | StreamEditor 接入 `redis:streamAck`;加消费组详情面板、pending entries 列表、claim 功能 |
| N6 | **命令白名单中间件** | 防误操作 FLUSHALL/SHUTDOWN | 低 | `redis:execute` 加危险命令二次确认 |
### 中优先级 ### 中优先级需求
| # | 需求 | 用户价值 | 复杂度 | 实现思路 | | # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|---|------|---------|--------|---------| |---|------|---------|--------|---------|
| N7 | **Cluster/Sentinel 支持** | 生产环境主流部署方式,当前仅单机+SSH | 高 | `connection.ts` 已有 cluster 分支需完善;加节点拓扑可视化、failover 操作 | | N7 | **Cluster/Sentinel 完善** | 生产环境主流部署,当前 cluster 分支已有但拓扑不可视 | 高 | 节点拓扑可视化(`CLUSTER NODES`)、failover 操作、slot 分布图 |
| N8 | **ACL 用户管理** | Redis 6+ ACL 已普及 | 中 | 新建 ACL 管理视图:用户 CRUD、权限矩阵、`ACL WHOAMI`/`ACL LIST` | | N8 | **ACL 用户管理** | Redis 6+ ACL 已普及,当前只能用 CLI | 中 | 新建 ACL 视图:用户 CRUD、权限矩阵、`ACL WHOAMI`/`ACL LIST` |
| N9 | **数据导入导出** | 迁移/备份场景 | 中 | 导出:RDB/DUMP/JSON 格式;导入:批量 SET/管道;KeyList 已有导出雏形需完善 | | N9 | **数据导入导出** | 迁移/备份场景,KeyList 已有导出雏形 | 中 | 导出:RDB/DUMP/JSON 格式;导入:批量 SET/pipeline |
| N10 | **Function 管理(Redis 7+)** | 替代 EVAL 的服务端函数 | 中 | 新建 Function 视图:LIST/LOAD/DELETE/调用 | | N10 | **Function 管理(Redis 7+)** | 替代 EVAL 的服务端函数 | 中 | 新建 Function 视图:`FUNCTION LIST`/`LOAD`/`DELETE`/调用 |
| N11 | **大 Key 扫描** | 生产排障刚需 | 中 | `MEMORY USAGE` 扫描已有,扩展为后台任务 + 排序 + 导出报告 | | N11 | **大 Key 扫描** | 生产排障刚需,`MEMORY USAGE` 扫描已有 | 中 | 扩展为后台任务 + 排序 + 导出报告 + 可视化分布 |
| N12 | **Latency Monitor** | 补充慢日志的延迟诊断 | 低 | `LATENCY HISTORY`/`LATENCY DOCTOR` 视图 | | N12 | **Latency Monitor** | 补充慢日志的延迟诊断 | 低 | `LATENCY HISTORY`/`LATENCY DOCTOR` 视图 |
| N13 | **PubSub 可视化改进** | 当前仅 CLI 内嵌,无独立视图 | 中 | 新建 PubSub 视图:频道树、消息流、JSON 高亮、订阅状态 | | N13 | **PubSub 可视化** | 当前仅 CLI 内嵌,无独立视图 | 中 | 新建 PubSub 视图:频道树、消息流、JSON 高亮、订阅状态 |
| N14 | **连接分组/标签** | 连接多了难管理 | 低 | ConnectionList 加分组折叠、颜色标签、搜索过滤已有可扩展 | | N14 | **连接分组/标签** | 连接多了难管理 | 低 | ConnectionList 加分组折叠、颜色标签 |
| N15 | **TTL 实时倒计时优化** | 修复泄漏 + 加批量设 TTL | 低 | 移到 onMounted;KeyList 批量设 TTL/过期时间 |
| N16 | **主题完整适配** | ReJsonEditor 主题修复 + Monaco 跟随 | 低 | Monaco 编辑器 theme 绑定到 monacoTheme 响应式变量 |
| N17 | **i18n 补全** | 中/日/韩/德文案完整 | 低 | 扫描硬编码文案替换为 `t()` |
### 低优先级 ### 低优先级需求
| # | 需求 | 用户价值 | 复杂度 | 实现思路 | | # | 需求 | 用户价值 | 复杂度 | 实现思路 |
|---|------|---------|--------|---------| |---|------|---------|--------|---------|
@@ -171,50 +192,22 @@
| N22 | **快捷键体系完善** | 当前仅 5 个 | 低 | 加 Ctrl+F 搜索、Ctrl+1~9 切 tab、Ctrl+L 聚焦 CLI | | N22 | **快捷键体系完善** | 当前仅 5 个 | 低 | 加 Ctrl+F 搜索、Ctrl+1~9 切 tab、Ctrl+L 聚焦 CLI |
| N23 | **测试体系** | 当前无测试 | 高 | Vitest 渲染进程单元测试;主进程 Redis 模块用 ioredis-mock | | N23 | **测试体系** | 当前无测试 | 高 | Vitest 渲染进程单元测试;主进程 Redis 模块用 ioredis-mock |
| N24 | **CI/CD** | 自动化构建发布 | 中 | GitHub Actions:lint+typecheck+build 三平台 | | N24 | **CI/CD** | 自动化构建发布 | 中 | GitHub Actions:lint+typecheck+build 三平台 |
| N25 | **TypeScript 严格化** | 类型安全 | 中 | 逐步消除 `any`,preload d.ts 精确化 |
| N26 | **错误上报** | 收集崩溃信息 | 低 | 主进程 crashReporter + 渲染进程 errorHandler | | N26 | **错误上报** | 收集崩溃信息 | 低 | 主进程 crashReporter + 渲染进程 errorHandler |
--- ---
## 四、修复路线图建议 ## 三、路线图建议
``` ```
立即(P0): [已完成] N1 凭据加密 -> N2 资源管理 -> N6 命令白名单 -> P0#2/5/6 第一阶段(高优先级): N4 虚拟滚动 -> N5 Stream 完整化 -> N3 CLI 事务体验
本周(P1): N3 事务修复 -> P1 定时器/监听器泄漏 -> N5 Stream ACK -> N16 主题 第二阶段(中优先级): N7 Cluster -> N9 导入导出 -> N11 大Key扫描 -> N13 PubSub视图
本月(P2): N4 虚拟滚动 -> N7 Cluster -> N9 导入导出 -> N11 大Key扫描 -> N13 PubSub视图 第三阶段(中优先级): N8 ACL -> N10 Function -> N12 Latency -> N14 连接分组
季度(P3): N8 ACL -> N10 Function -> N23 测试 -> N25 严格化 -> N24 CI 第四阶段(低优先级): N23 测试 -> N24 CI/CD -> N22 快捷键 -> N18-N21/N26
``` ```
--- ### 架构改进建议(伴随功能开发渐进推进)
## 五、关键数据 1. **资源管理**:开发 N5/N13 时顺手引入 `useDisposable` composable,逐步迁移现有定时器/监听器
2. **错误处理**:开发 N9 时引入 `safeInvoke` 封装,统一 IPC 错误提示
- **审查范围**:主进程 10 文件、渲染进程 ~40 文件、IPC 65 通道 3. **类型安全**:开发 N7/N8 时消除 `connection.ts``as any`,定义完整的 Redis 操作类型
- **发现问题**:54 个(P0×6, P1×12, P2×17, P3×19) 4. **性能**:N4 虚拟滚动是独立的高价值任务,建议优先单独开发
- **已修复**:P0×6 + P1×11 + P2×14 + P3×9 = **全部 54 个问题已处理** (2026-07-12)
- **安全问题**:6 个(P0 全部已修复)
- **死代码**:6 处
- **可开发需求**:26 项(高优先级 6,中 11,低 9)
### 修复记录 (2026-07-12)
| 缺陷 | 修复内容 | 涉及文件 |
|------|---------|---------|
| P0#1 凭据明文 | storage:saveConnection 加密敏感字段;getConnections 读取时解密 | `ipc-handlers.ts` |
| P0#2 命令注入 | customFormat 白名单(xxd/jq/python3/python/php/column) | `format.ts` |
| P0#3 无命令白名单 | BLOCKED_COMMANDS 拦截 FLUSHALL/SHUTDOWN/DEBUG;新增 executeUnsafe | `ipc-handlers.ts`, `preload/index.ts`, `preload/index.d.ts`, `CliView.vue`, `StatusView.vue` |
| P0#4 退出无清理 | app.on('will-quit') 调 disconnectAll + stopAllPubSubClients | `index.ts`, `pubsub.ts` |
| P0#5 超时竞态 | 3处 setTimeout 保存 timer ID,ready/error 路径 clearTimeout | `connection.ts` |
| P0#6 safeStorage 回退 | encrypt/decrypt 在 safeStorage 不可用时抛出错误 | `credential.ts` |
| P1#15 突变副作用 | saveConnection 创建副本而非修改原对象(随 P0#1 修复) | `ipc-handlers.ts` |
| P1#8 TTL 定时器泄漏 | setInterval 移入 onMounted,onUnmounted 中清理 | `KeyDetail.vue` |
| P1#9 IPC 监听器泄漏 | preload onSubscribeMessage/onMonitorMessage 返回清理函数,CliView onUnmounted 调用 | `preload/index.ts`, `preload/index.d.ts`, `CliView.vue` |
| P1#10 PubSub sender 失效 | 添加 sender.isDestroyed() 检查 + destroyed 事件自动清理 | `pubsub.ts` |
| P1#11 Monitor 未处理 rejection | 添加 .catch() + isDestroyed 检查 | `pubsub.ts` |
| P1#12 SSH error 监听器过晚 | server.on('error') 移到 server.listen() 之前 | `connection.ts` |
| P1#13 loadKeyData 竞态 | 引入 loadKeyVersion 版本号守卫,丢弃过时响应 | `stores/key.ts` |
| P1#14 LREM 删错项 | 改为 LSET 哨兵值 + LREM 按索引删除 | `ListEditor.vue` |
| P1#16 reorderConnections 崩溃 | 移除非空断言,添加 null 守卫 + filter | `ipc-handlers.ts` |
| P1#17 Trim 对话框无确认 | 添加 Cancel/Confirm 按钮调用 trimStream() | `StreamEditor.vue` |
| P1#18 双重扫描 | 移除 KeyBrowser watch 的 { immediate: true } | `KeyBrowser.vue` |
| P1#7 MULTI/EXEC(误报) | 调查确认:Redis 服务器在 MULTI 后自动排队,当前实现正确 | 无需修改 |