Tauri 2.0 desktop app. React/TypeScript frontend + Rust backend. Two-language codebase.
- Frontend (
src/): React 18 + TypeScript + Vite + Tailwind CSS 3.4 - Backend (
src-tauri/src/): Rust + rusqlite + argon2 + aes-gcm + secrecy + zeroize
Two Tauri windows (different visual configs):
main: transparent frameless search window (800x600, no decorations)dashboard: normal framed settings window (1200x700, with OS chrome)
npm run tauri dev # Development (runs both Rust + React)
npm run tauri build # Production build
npm run build # Frontend-only: tsc typecheck + vite build
npm run dev # Frontend-only: vite dev server (port 1420, strictPort)No linter or formatter is configured. TypeScript strict: true with noUnusedLocals and noUnusedParameters enforced at build time via tsc.
NEVER pass plaintext API Keys over IPC to the frontend. This is the iron rule.
- Frontend sends only item IDs (
itemId,item_id). - Rust backend performs all encryption/decryption locally.
- IPC commands check vault state (
Unlockedonly) before executing.
The ONE exception: reveal_vault_item_secret intentionally returns plaintext to frontend for the "eye icon" reveal feature. Frontend auto-masks after 10 seconds. Do NOT use this pattern for new commands.
Rust StateManager drives vault state. Frontend receives state via Tauri events:
FirstLaunch → (setup_master_password) → Unlocked
Unlocked → (lock_vault / auto-lock) → Locked (master key zeroized)
Locked → (unlock_vault) → Unlocked (key re-derived)
Events broadcast to ALL windows: vault://unlocked, vault://lock-triggered.
Frontend App.tsx routes by window.label + vaultState:
mainwindow: FirstLaunch→OnboardingView, Locked→UnlockView, Unlocked→SearchPagedashboardwindow: always DashboardPage (but listens for lock events)
- Field is
provider_id(string), NOTprovider. Matches Rust backend snake_case. tagsis a comma-separatedstring, NOT an array.VaultItemMetais the safe type frontend receives (no ciphertext fields).VaultItem(withsecret_cipher,nonce) is Rust-internal only.- The
@/path alias resolves to./src/in bothtsconfig.jsonandvite.config.ts.
- Argon2id: 64 MiB memory, 3 iterations, 4 parallelism → 256-bit key
- AES-256-GCM: Per-record independent 96-bit random Nonce, 128-bit Auth Tag
- Memory safety: Master key wrapped in
Zeroizing<Vec<u8>>, zeroed on lock - Clipboard: Auto-clear timer (configurable: 30s/60s/5min/never), privacy marking
- Metadata key inconsistency: The Rust code reads
saltinvault.rsbut usesmaster_saltinsettings.rschange_master_password. When adding new code, match thesetup_master_passwordconvention which writes as"salt". Thechange_master_passwordpath has a bug reading"master_salt"that won't exist.
- Rust guardian thread polls every 10 seconds, checks
last_activity_timeagainstauto_lock_timeoutfrom DB. - Frontend
useHeartbeathook sends IPCheartbeaton keyboard/mouse events (throttled to 5 seconds). - Timeout value 0 means "never auto-lock".
SQLite database at {app_data_dir}/vault.db. Two tables:
app_metadata(key TEXT PK, value TEXT) - salt, password hash, settingsvault_items- encrypted API keys.secret_cipherandnonceare BLOB encrypted.title,provider_id,tags,favorite,usage_countstored plaintext for search.
Database files (*.db, *.db-shm, *.db-wal) are in .gitignore - never commit them.
- No Shadcn/ui components installed despite README listing it. All components are custom Tailwind.
- Tailwind dark mode via
classstrategy, CSS custom properties (hsl(var(--...))) for theming. - Custom scrollbar styles (
.scrollbar-thin). - Transparent window background:
html,body,#rootall forcedbackground-color: transparent !important- this is REQUIRED for the Tauri frameless window to work correctly. - Glassmorphism effects via
backdrop-blur-2xlandbackdrop-blur-3xl.
react-i18next with inline JSON locale files in src/i18n/locales/. Default language: zh-CN, fallback: en-US. Always add new UI strings to both locale files.
src-tauri/capabilities/default.json lists allowed permissions for windows main and dashboard. When adding new IPC commands that require additional permissions (clipboard, dialog, global-shortcut, shell), update this file AND add the plugin in main.rs.
docs/PRD.md- product requirementsdocs/PROJECT_STRUCTURE.md- module overviewdocs/PHASE*.md- phase completion reports with implementation detailsCHANGELOG.md- detailed feature history