Architecture
Architecture
This document provides a comprehensive overview of MiniFy’s technical architecture, helping developers understand how the different parts of the application work together.
High-Level System Architecture
┌─────────────────────────────────────────────────────────────────────────────┐│ MiniFy System Architecture │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌───────────────────────────────────────────────────────────────────┐ ││ │ MiniFy Monorepo │ ││ │ │ ││ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ ││ │ │ apps/desktop │ │ apps/www │ │ apps/docs │ │ ││ │ │ Tauri + React │ │ Next.js │ │ Starlight │ │ ││ │ │ Desktop App │ │ Website │ │ Documentation │ │ ││ │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ ││ │ │ │ │ │ ││ └────────────┼────────────────────┼────────────────────┼───────────┘ ││ │ │ │ ││ ▼ ▼ ▼ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ Build & Development Tools │ ││ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ ││ │ │ pnpm │ │ Turborepo│ │ Biome │ │ Lefthook │ │ ││ │ │ Workspace│ │ (Tasks) │ │ (Lint) │ │ (Hooks) │ │ ││ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ │└──────────────────────────────────────────────────────────────────────────────┘Monorepo Structure
MiniFy uses a monorepo architecture with pnpm workspaces:
MiniFy/├── apps/│ ├── desktop/ # Tauri + React desktop application│ │ ├── src/ # React frontend code│ │ ├── src-tauri/ # Rust backend code│ │ ├── public/ # Static assets│ │ └── package.json│ ││ ├── www/ # Next.js marketing website│ │ ├── app/ # Next.js App Router pages│ │ ├── components/ # React components│ │ └── package.json│ ││ └── docs/ # Astro Starlight documentation│ ├── src/content/ # MDX documentation files│ └── package.json│├── package.json # Root package with workspace scripts├── pnpm-workspace.yaml # Workspace configuration├── turbo.json # Turborepo task configuration├── biome.json # Code formatting/linting config└── lefthook.yml # Git hooks configurationDesktop Application Architecture
The desktop app is the core of MiniFy, built with Tauri 2.0 (Rust backend) and React (TypeScript frontend).
Component Layers
┌─────────────────────────────────────────────────────────────────────────────┐│ Desktop Application Layers │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌───────────────────────────────────────────────────────────────────────┐ ││ │ Presentation Layer (React) │ ││ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │ ││ │ │ Views │ │ Layouts │ │ Components │ │ Hooks │ │ ││ │ │ • Player │ │ • LayoutA │ │ • Button │ │ • usePlaying │ │ ││ │ │ • Settings │ │ • LayoutB │ │ • Controls │ │ • useTheme │ │ ││ │ │ • AI DJ │ │ • LayoutC │ │ • TrackInfo │ │ • useLayout │ │ ││ │ └─────────────┘ └─────────────┘ └─────────────┘ └──────────────┘ │ ││ └───────────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌───────────────────────────────────────────────────────────────────────┐ ││ │ Service Layer (TypeScript) │ ││ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ ││ │ │ spotifyClient │ │ aiClient │ │ settingLib │ │ ││ │ │ (API Calls) │ │ (AI Provider) │ │ (Config Mgmt) │ │ ││ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ ││ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ ││ │ │ spotifyTools │ │ playerState │ │ themeLoader │ │ ││ │ │ (AI Tools) │ │ (State Store) │ │ (Theme Loading) │ │ ││ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ ││ └───────────────────────────────────────────────────────────────────────┘ ││ │ ││ Tauri IPC │ invoke() / listen() ││ ▼ ││ ┌───────────────────────────────────────────────────────────────────────┐ ││ │ Backend Layer (Rust) │ ││ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ ││ │ │ spotify_auth │ │ ai_keyring │ │ settings │ │ ││ │ │ (OAuth PKCE) │ │ (AI Key Mgmt) │ │ (JSON Config) │ │ ││ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ ││ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ ││ │ │ resize │ │ custom_themes │ │ debug │ │ ││ │ │ (Window Size) │ │ (Theme IO) │ │ (DevTools) │ │ ││ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ ││ └───────────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ┌───────────────────────────────────────────────────────────────────────┐ ││ │ OS Integration Layer │ ││ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ ││ │ │ Keyring │ │ File System │ │ WebView │ │ ││ │ │ (Credentials) │ │ (Settings) │ │ (UI Renderer) │ │ ││ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ ││ └───────────────────────────────────────────────────────────────────────┘ ││ │└──────────────────────────────────────────────────────────────────────────────┘Frontend Structure
apps/desktop/src/├── main.tsx # Application entry point├── vite-env.d.ts # Vite type definitions│├── ui/│ ├── index.tsx # Root React component│ ├── global.css # Global styles with CSS variables│ ├── spotifyClient.ts # Spotify API client│ ││ ├── views/ # Full-page view components│ │ ├── PlayerView.tsx # Main player view│ │ ├── AIDJView.tsx # AI DJ chat interface│ │ ├── SettingsView.tsx # Settings panel│ │ └── ...│ ││ ├── layouts/ # Player layout variations│ │ ├── LayoutA.tsx # Compact horizontal layout│ │ ├── LayoutB.tsx # Standard layout│ │ └── LayoutC.tsx # Expanded layout│ ││ └── components/ # Reusable UI components│ ├── Button.tsx│ ├── TrackControls/│ ├── TrackDataComponent/│ └── LayoutTrackInfo/│├── hooks/ # React hooks│ ├── useCurrentlyPlaying.ts # Playback state hook│ └── useWindowLayout.ts # Layout management hook│├── lib/ # Utility libraries│ ├── aiClient.ts # AI provider client│ ├── playerState.ts # Player state management│ ├── settingLib.ts # Settings utilities│ ├── spotifyTools.ts # AI DJ Spotify tools│ └── trackInfoProps.ts # Track info type definitions│├── loader/ # Data loaders│ └── themeLoader.ts # Theme loading utilities│├── themes/ # Built-in theme definitions│ ├── dark.json│ ├── light.json│ ├── catppuccin.json│ ├── dracula.json│ └── ...│└── config/ # Configuration files └── shortcuts.json # Keyboard shortcut definitionsBackend Structure (Rust)
apps/desktop/src-tauri/├── Cargo.toml # Rust dependencies├── Cargo.lock # Dependency lockfile├── build.rs # Build script├── tauri.conf.json # Tauri configuration│├── src/│ ├── main.rs # Application entry point│ ├── lib.rs # Library entry, command registration│ ││ ├── spotify_auth.rs # Spotify OAuth PKCE implementation│ │ - OAuth flow management│ │ - Token storage/retrieval│ │ - Token refresh logic│ │ - Callback server│ ││ ├── ai_keyring.rs # AI API key management│ │ - Key storage per provider│ │ - Key retrieval│ │ - Provider listing│ ││ ├── settings.rs # Settings management│ │ - Settings file IO│ │ - Default settings│ │ - Settings structure│ ││ ├── resize.rs # Window size management│ │ - Layout-based sizing│ │ - Window constraints│ ││ ├── custom_themes.rs # Custom theme handling│ │ - Theme file IO│ │ - Theme validation│ │ - Theme export│ ││ └── debug.rs # Debug utilities│ - DevTools opening│├── capabilities/ # Tauri capability configs│ └── default.json # Default permissions│└── icons/ # Application icons ├── icon.ico ├── icon.icns └── ...Data Flow Diagrams
Playback State Flow
┌─────────────────────────────────────────────────────────────────────────────┐│ Playback State Flow │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌────────────────┐ ││ │ useCurrently │ Polls every 1-5 seconds ││ │ Playing Hook │ (adjusts based on playback state) ││ └───────┬────────┘ ││ │ ││ ▼ ││ ┌────────────────┐ ┌────────────────┐ ┌────────────────────┐ ││ │ spotifyClient │─────▶│ Spotify API │─────▶│ CurrentlyPlaying │ ││ │ fetchCurrent() │ │ /v1/me/player │ │ Response │ ││ └────────────────┘ └────────────────┘ └─────────┬──────────┘ ││ │ ││ ▼ ││ ┌────────────────────┐ ││ │ State Update │ ││ │ { track, progress,│ ││ │ isPlaying } │ ││ └─────────┬──────────┘ ││ │ ││ ┌──────────────────────────────────┘ ││ ▼ ││ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ ││ │ Layout │ │ Track │ │ Progress │ ││ │ Component │ │ Controls │ │ Bar │ ││ │ (re-render) │ │ (re-render) │ │ (re-render) │ ││ └────────────────┘ └────────────────┘ └────────────────┘ ││ │└──────────────────────────────────────────────────────────────────────────────┘Token Refresh Flow
┌─────────────────────────────────────────────────────────────────────────────┐│ Token Refresh Flow │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ Background Task (Every 5 min) │ ││ │ │ ││ │ ┌─────────────┐ │ ││ │ │ Check token │ │ ││ │ │ expiry time │ │ ││ │ └──────┬──────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────────────────┐ │ ││ │ │ Expires within 5 min? │ │ ││ │ └──────┬──────────────────┘ │ ││ │ │ │ ││ │ No │ Yes │ ││ │ ▼ ▼ │ ││ │ Done ┌─────────────────┐ ┌─────────────────┐ │ ││ │ │ refresh_token() │─────▶│ Spotify Token │ │ ││ │ │ (Rust backend) │ │ Endpoint │ │ ││ │ └─────────────────┘ └────────┬────────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────────┐ │ ││ │ │ New Access Token│ │ ││ │ │ (Maybe new │ │ ││ │ │ refresh token) │ │ ││ │ └────────┬────────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────────┐ │ ││ │ │ Store in │ │ ││ │ │ OS Keyring │ │ ││ │ └─────────────────┘ │ ││ │ │ ││ └──────────────────────────────────────────────────────────────────────┘ ││ │└──────────────────────────────────────────────────────────────────────────────┘Settings Data Flow
┌─────────────────────────────────────────────────────────────────────────────┐│ Settings Data Flow │├─────────────────────────────────────────────────────────────────────────────┤│ ││ React Frontend Rust Backend ││ ────────────── ──────────── ││ ││ ┌────────────────┐ ┌────────────────────┐ ││ │ Settings View │ │ settings.rs │ ││ │ Component │ │ │ ││ └───────┬────────┘ │ Tauri Commands: │ ││ │ │ • read_settings │ ││ │ invoke("read_settings") │ • write_settings │ ││ ├───────────────────────────▶│ • clear_settings │ ││ │ │ │ ││ │◀──────────────────────────│ Returns Settings │ ││ │ Settings JSON │ struct │ ││ │ └─────────┬──────────┘ ││ │ │ ││ ┌───────▼────────┐ │ ││ │ Update local │ ▼ ││ │ React state │ ┌─────────────────────────┐ ││ └───────┬────────┘ │ File System │ ││ │ │ ~/.config/MiniFy/ │ ││ │ User makes changes │ settings.json │ ││ ▼ └─────────────────────────┘ ││ ┌────────────────┐ ││ │ Update state │ ││ │ + invoke │ ││ │ write_settings │ ││ └────────────────┘ ││ │└──────────────────────────────────────────────────────────────────────────────┘Communication Patterns
Frontend → Backend (Tauri Commands)
Commands are synchronous request-response calls:
// Frontend: Invoke a Tauri commandimport { invoke } from '@tauri-apps/api/core';
// Reading settingsconst settings = await invoke<Settings>('read_settings');
// Saving an AI keyawait invoke('save_ai_api_key', { provider: 'openai', apiKey: 'sk-...'});
// Starting OAuth flowawait invoke('start_oauth_flow');// Backend: Define a Tauri command#[tauri::command]pub fn read_settings() -> Settings { // Load and return settings let path = get_settings_path(); // ...}
#[tauri::command]pub async fn save_ai_api_key(provider: String, api_key: String) -> Result<(), String> { // Save key to keyring // ...}Backend → Frontend (Events)
Events are one-way notifications from backend to frontend:
// Backend: Emit an eventuse tauri::Emitter;
#[tauri::command]fn complete_auth(app: tauri::AppHandle) -> Result<(), String> { // After successful auth... app.emit("oauth-success", serde_json::json!({}))?; Ok(())}
// On auth failure...app.emit("oauth-failed", serde_json::json!({ "error": "reason" }))?;// Frontend: Listen for eventsimport { listen } from '@tauri-apps/api/event';
await listen('oauth-success', (event) => { console.log('Auth successful!'); // Update UI state});
await listen('oauth-failed', (event) => { console.error('Auth failed:', event.payload.error); // Show error to user});State Management
MiniFy uses React’s built-in state management with custom hooks:
Player State
// useCurrentlyPlaying hookinterface CurrentlyPlayingState { track: SimplifiedTrack | null; progress_ms: number; duration: number; isPlaying: boolean; loading: boolean; error: string | null;}
function useCurrentlyPlaying() { const [state, setState] = useState<CurrentlyPlayingState>(initialState);
useEffect(() => { const poll = async () => { const data = await fetchCurrentlyPlaying(); setState(/* updated state */); };
const interval = setInterval(poll, pollInterval); return () => clearInterval(interval); }, []);
return state;}Settings State
// Settings are loaded via Tauri commandsconst settings = await readSettings(); // invoke('read_settings')
// And saved on changeawait writeSettings(newSettings); // invoke('write_settings', { settings })Key Technologies
Tauri 2.0
Tauri provides the native shell for the application:
| Feature | Description |
|---|---|
| Webview | System webview renders React UI (WebView2/WebKit) |
| IPC | Type-safe communication between frontend/backend |
| Plugins | fs, opener plugins for system integration |
| Security | Capability-based permission system |
React 18
Frontend uses modern React patterns:
| Pattern | Usage |
|---|---|
| Functional Components | All components are functions with hooks |
| CSS Variables | Theming via CSS custom properties |
| Concurrent Features | useTransition for non-blocking updates |
Rust
Backend handles secure operations:
| Module | Purpose |
|---|---|
| keyring | Secure credential storage |
| reqwest | HTTP client for OAuth |
| axum | OAuth callback server |
| serde | JSON serialization |
Build Process
Development
pnpm desktop:devThis starts:
- Vite dev server with HMR (Hot Module Replacement)
- Tauri development window
- Rust compilation in debug mode
Production
pnpm desktop:buildBuild outputs:
- Optimized React bundle (Vite)
- Platform-specific installer (Tauri)
- Code signing (if configured)
Output locations:
- Windows:
src-tauri/target/release/bundle/msi/*.msi - macOS:
src-tauri/target/release/bundle/dmg/*.dmg - Linux:
src-tauri/target/release/bundle/deb/*.deb
Performance Considerations
Bundle Size
| Component | Target | Actual |
|---|---|---|
| React bundle (gzipped) | < 200KB | ~150KB |
| Rust binary | < 10MB | ~8MB |
| Total download | < 15MB | ~10MB |
Runtime Performance
| Metric | Target | Notes |
|---|---|---|
| Memory usage | < 50MB | Rust backend is lightweight |
| CPU idle | < 1% | Efficient polling intervals |
| Startup time | < 1s | Native app, no Electron overhead |
| API polling | 1-5s | Adjusts based on playback state |
Optimization Techniques
- Lazy loading: AI DJ view loads on demand
- Polling optimization: Faster polling when playing, slower when paused
- Image caching: Album art cached in memory
- Minimal re-renders: Component memoization where needed