Skip to content

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 configuration

Desktop 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 definitions

Backend 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 command
import { invoke } from '@tauri-apps/api/core';
// Reading settings
const settings = await invoke<Settings>('read_settings');
// Saving an AI key
await invoke('save_ai_api_key', {
provider: 'openai',
apiKey: 'sk-...'
});
// Starting OAuth flow
await 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 event
use 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 events
import { 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 hook
interface 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 commands
const settings = await readSettings(); // invoke('read_settings')
// And saved on change
await writeSettings(newSettings); // invoke('write_settings', { settings })

Key Technologies

Tauri 2.0

Tauri provides the native shell for the application:

FeatureDescription
WebviewSystem webview renders React UI (WebView2/WebKit)
IPCType-safe communication between frontend/backend
Pluginsfs, opener plugins for system integration
SecurityCapability-based permission system

React 18

Frontend uses modern React patterns:

PatternUsage
Functional ComponentsAll components are functions with hooks
CSS VariablesTheming via CSS custom properties
Concurrent FeaturesuseTransition for non-blocking updates

Rust

Backend handles secure operations:

ModulePurpose
keyringSecure credential storage
reqwestHTTP client for OAuth
axumOAuth callback server
serdeJSON serialization

Build Process

Development

Terminal window
pnpm desktop:dev

This starts:

  1. Vite dev server with HMR (Hot Module Replacement)
  2. Tauri development window
  3. Rust compilation in debug mode

Production

Terminal window
pnpm desktop:build

Build outputs:

  1. Optimized React bundle (Vite)
  2. Platform-specific installer (Tauri)
  3. 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

ComponentTargetActual
React bundle (gzipped)< 200KB~150KB
Rust binary< 10MB~8MB
Total download< 15MB~10MB

Runtime Performance

MetricTargetNotes
Memory usage< 50MBRust backend is lightweight
CPU idle< 1%Efficient polling intervals
Startup time< 1sNative app, no Electron overhead
API polling1-5sAdjusts based on playback state

Optimization Techniques

  1. Lazy loading: AI DJ view loads on demand
  2. Polling optimization: Faster polling when playing, slower when paused
  3. Image caching: Album art cached in memory
  4. Minimal re-renders: Component memoization where needed