feat(phase1): architecture skeleton

- Electron 33 main process with frameless window, IPC, win-state persistence
- Preload with contextBridge typed API (window, theme, dialog)
- Vue 3 + Pinia + Element Plus + Vue Router renderer
- Dark/light dual theme via CSS custom properties
- TitleBar with window controls + theme toggle
- StatusBar placeholder
- Design spec document
This commit is contained in:
2026-07-04 17:21:00 +08:00
parent 3e06def637
commit 7e5d61c099
20 changed files with 8338 additions and 2 deletions
@@ -0,0 +1,233 @@
# 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