# JRedisDesktop v2 — Design Spec **Date:** 2026-07-04 **Status:** Approved ## 1. Project Identity Fork of [AnotherRedisDesktopManager](https://github.com/qishibo/AnotherRedisDesktopManager). Full rewrite of the legacy Vue 2 + Webpack 4 + Electron 12 codebase (archived in `legacy/`) to Electron 33 + Vue 3 + Vite 6 + TypeScript 5. ## 2. Scope & Phasing ### Phase 1: Architecture Skeleton (Week 1-2) - Electron main process with contextIsolation + preload + contextBridge - Vue 3 SPA with Vue Router + Element Plus + Pinia - electron-vite three-target build pipeline (main/preload/renderer) - Dark/light dual theme system via CSS variables - Window management (min/max/close, win-state persistence) ### Phase 2: Connection Management MVP (Week 2-3) - Standalone Redis connections (host:port + password/ACL) - TLS support (CA/cert/key file reading via main process) - Connection list CRUD with drag-to-reorder - Secure credential storage (electron-store + safeStorage encryption) - SSH tunnel support (single node) ### Phase 3: Key Browser MVP (Week 3-4) - Key list with SCAN-based pagination + tree view (key separator) - String viewer/editor (plain text, JSON formatting) - Hash viewer/editor (field table, pagination, add/edit/delete) - Server INFO status dashboard - Database switching ### Phase 4: Advanced Features (Iterative) - List/Set/Zset/Stream editors - Format viewers (Msgpack, Protobuf, Pickle, Brotli, Gzip, etc.) - Redis CLI terminal - Cluster/Sentinel connections - Slow log, memory analysis, batch delete - i18n (13 languages from legacy) - Monaco JSON editor - Custom shell formatters ## 3. Architecture ### Process Model ``` ┌─────────────────────────────────────────────┐ │ Main Process │ │ ├── Window management │ │ ├── RedisService (ioredis + SSH + TLS) │ │ ├── electron-store (persistence) │ │ ├── safeStorage (credential encryption) │ │ └── IPC handlers (typed channels) │ ├─────────────────────────────────────────────┤ │ Preload (contextBridge) │ │ └── window.electronAPI (typed IPC methods) │ ├─────────────────────────────────────────────┤ │ Renderer (Vue 3 SPA) │ │ ├── Pinia stores (connection, key, app) │ │ ├── Vue Router │ │ ├── Element Plus │ │ └── Composition API components │ └─────────────────────────────────────────────┘ ``` ### Key Architectural Decision: RedisService in Main Process ioredis depends on Node `net`/`tls` modules and cannot run in a contextIsolation renderer. All Redis operations go through typed IPC: ``` Renderer (Pinia action) → IPC invoke → Main (RedisService) → ioredis → Redis ``` IPC latency (~1ms) is negligible vs Redis network latency (1-100ms). High-frequency operations (SCAN) use batch IPC to minimize round trips. ### Renderer Component Tree (MVP) ``` App.vue ├── TitleBar.vue (window controls, connection badge) ├── Sidebar.vue │ ├── ConnectionSearch.vue (filter connections) │ ├── ConnectionList.vue (card list, drag sort) │ │ └── ConnectionCard.vue │ └── NewConnectionBtn.vue ├── MainArea.vue (tab host) │ ├── StatusView.vue (INFO dashboard with stat cards) │ ├── KeyBrowser.vue (key list + tree + detail) │ │ ├── KeyList.vue (SCAN pagination, tree toggle) │ │ └── KeyDetail.vue (type dispatcher) │ │ ├── StringEditor.vue │ │ └── HashEditor.vue │ └── CliView.vue (Phase 4) └── StatusBar.vue (connection status, latency) ``` ### Pinia Stores | Store | Responsibility | |---|---| | `useConnectionStore` | Connections CRUD, active connection, RedisService proxy | | `useKeyStore` | Key list, tree view, selected key, key data cache | | `useAppStore` | Theme (dark/light), settings, i18n locale, UI state | ### IPC Channel Design | Channel | Type | Direction | Purpose | |---|---|---|---| | `redis:connect` | invoke | renderer→main | Create Redis connection, return client ID | | `redis:disconnect` | invoke | renderer→main | Close connection by ID | | `redis:execute` | invoke | renderer→main | Execute Redis command, return result | | `redis:event` | on | main→renderer | Connection events (ready, error, close) | | `storage:get` | invoke | renderer→main | Read from electron-store | | `storage:set` | invoke | renderer→main | Write to electron-store | | `credential:encrypt` | invoke | renderer→main | Encrypt via safeStorage | | `credential:decrypt` | invoke | renderer→main | Decrypt via safeStorage | | `dialog:openFile` | invoke | renderer→main | Open file picker, return file content | | `window:minimize` | send | renderer→main | Minimize window | | `window:maximize` | send | renderer→main | Toggle maximize | | `window:close` | send | renderer→main | Close window | | `theme:set` | send | renderer→main | Set nativeTheme source | | `theme:os-updated` | on | main→renderer | OS theme change notification | ## 4. UI Design ### Visual Style - **Dark theme:** Deep blue-black gradient background, perspective cards with rotateY/X micro-angles, ambient light overlays, glow dot status indicators, multi-tier shadows for depth hierarchy - **Light theme:** Clean white background, soft shadows, purple-blue accent, light frosted glass effects - **Dual theme:** CSS custom properties (`--bg`, `--text`, `--border`, `--accent`, `--shadow`) switch at root level. Follows OS preference by default, manual toggle persisted. ### Layout - Left sidebar (~260px): connection cards with search + new connection button - Right main area: stat cards row + tab bar + content panel - Bottom status bar: connection status + latency + app version - Resizable sidebar (drag handle) ## 5. Data Persistence ### Strategy: Mixed - **electron-store** (main process): Non-sensitive data — connection list, settings, UI preferences - **safeStorage** (main process): Sensitive data — passwords, SSH private keys, TLS certs ### Data Shape ```typescript // electron-store schema interface AppStorage { connections: Connection[]; settings: AppSettings; windowState: { x: number; y: number; width: number; height: number; maximized: boolean }; } interface Connection { id: string; name: string; host: string; port: number; auth: string; // encrypted via safeStorage username: string; // ACL username tls: boolean; tlsCaPath: string; tlsCertPath: string; tlsKeyPath: string; sshEnabled: boolean; sshHost: string; sshPort: number; sshUsername: string; sshPassword: string; // encrypted via safeStorage sshPrivateKeyPath: string; cluster: boolean; sentinelMasterName: string; separator: string; // key tree separator, default ":" order: number; createdAt: number; } interface AppSettings { theme: 'system' | 'dark' | 'light'; locale: string; fontSize: number; scanCount: number; // keys per SCAN page // ... more settings as needed } ``` ## 6. Security Model - **contextIsolation: true** — renderer has zero Node.js/Electron API access - **nodeIntegration: false** — no Node globals in renderer - **contextBridge** — only typed API surface exposed via `window.electronAPI` - **safeStorage** — OS-level encryption for credentials (DPAPI on Windows, Keychain on macOS, libsecret on Linux) - **IPC validation** — all IPC handlers validate input before executing - **No remote module** — all main-process features accessed via IPC ## 7. Compatibility Mitigations | Legacy Pattern | v2 Approach | |---|---| | `redisClient.js` in renderer | RedisService in main, typed IPC proxy | | `fs.readFileSync` for TLS | `dialog:openFile` IPC → main reads file | | `remote.app` sandbox bookmarks | Main process handles file access | | `vue.$bus` / `vue.$message` | mitt EventEmitter + ElMessage composable | | `Vue.prototype.$storage` | `useConnectionStore()` composable | | `Vue.prototype.$util` | Pure functions in `utils/` | | Node `zlib` for decompression | Web `DecompressionStream` + WASM fallback | | `child_process.exec` formatters | IPC → main process spawn (Phase 4) | | `window.localStorage` | electron-store IPC | | Monaco + webpack plugin | ESM Monaco + vite plugin (Phase 4) | ## 8. Build & Dev ```bash npm run dev # electron-vite dev (HMR, renderer on :5173) npm run build # production build → out/ npm start # preview built app npm run build:unpack # build + electron-builder --dir npm run build:win # build + electron-builder --win npm run build:mac # build + electron-builder --mac npm run build:linux # build + electron-builder --linux ``` ## 9. Dependencies ### Runtime - `ioredis` ^5.7.0 — Redis client (main process) - `tunnel-ssh` ^5.x — SSH tunneling (main process) - `electron-store` ^10.x — persistence (main process) ### Dev / Renderer - `electron` ^33.4.0 - `electron-vite` ^3.0.0 - `vue` ^3.5.0 - `vue-router` ^4.5.0 - `pinia` ^2.x - `element-plus` ^2.9.0 - `typescript` ^5.7.0 - `vite` ^6.0.0 - `electron-builder` ^25.1.0