# JellyTau Software Architecture

This document describes the current architecture of JellyTau, a cross-platform Jellyfin client built with Tauri, SvelteKit, and Rust.

Last Updated: 2026-06-20

## Architecture Overview

JellyTau uses a client-server architecture: business logic lives in a comprehensive Rust backend, while a UI-rich Svelte frontend handles presentation and interaction.

### Architecture Principles

- Business Logic in Rust: Core logic — playback, repository, sync, downloads, connectivity — lives in Rust for performance, reliability, and type safety.
- Presentation in Svelte: The frontend (~20.5k non-test lines) owns UI, layout, navigation, and interaction state and invokes Rust commands. It is intentionally UI-heavy, not a thin wrapper. Largest pieces: components + routes (~14.6k lines), stores (~3.4k), api/services/utils (~2.4k); `VideoPlayer.svelte` alone is ~1.6k lines.
- Events + Polling hybrid: Rust emits events the frontend listens to, and the UI also polls status on short intervals in a few hot spots (e.g. queue status in `library/+layout.svelte`, playback progress in `VideoPlayer.svelte`).
- Unified player boundary: UI components control playback only through the frontend facade `src/lib/player/index.ts` (`playerController`), never by calling `commands.player*` directly. Webview-rendered HTML5 video reports its state back into Rust via `src/lib/player/html5Adapter.ts` and the `player_report_*` commands, so the `PlayerController` stays the single source of truth in both native (MPV/ExoPlayer) and HTML5 modes (see 05-platform-backends.md).
- Handle-Based Resources: UUID handles for stateful Rust objects.
- Cache-First: Parallel queries with intelligent fallback.
- Single source of truth for reachability: Server reachability is derived from the outcome of real repository traffic, not a side-channel poller. The `OnlineRepository` reports each server result to the `ConnectivityMonitor` (classified via `RepoError`), which applies a time-window debounce before declaring the server offline and recovers instantly on the first success. The standalone `/System/Info/Public` probe runs only while offline, as a recovery detector for idle sessions.
- Poison-tolerant locking: Shared `std::sync` state is accessed via the `MutexSafe`/`RwLockSafe` helpers in `utils/lock.rs`, which recover a poisoned lock instead of cascading a panic across the player.
- Graceful backend init: If a native player backend (MPV/ExoPlayer) fails to initialize, the app falls back to a no-op backend and emits a `backend-init-failed` event rather than crashing.

    flowchart TB
        subgraph Frontend["Svelte Frontend"]
            subgraph Stores["Stores (Thin Wrappers)"]
                auth["auth"]
                player["player"]
                queue["queue"]
                library["library"]
                connectivity["connectivity"]
                playbackMode["playbackMode"]
            end
            subgraph Components
                playerComp["player/"]
                libraryComp["library/"]
                Search["Search"]
            end
            subgraph Routes
                routeLibrary["/library"]
                routePlayer["/player"]
                routeRoot["/"]
            end
            subgraph API["API Layer (Thin Client)"]
                RepositoryClient["RepositoryClient<br/>(Handle-based)"]
                JellyfinClient["JellyfinClient<br/>(Helper)"]
            end
        end

        Frontend -->|"Tauri IPC (invoke)"| Backend

        subgraph Backend["Rust Backend (Business Logic)"]
            subgraph Commands["Tauri Commands (90+)"]
                PlayerCmds["player.rs"]
                RepoCmds["repository.rs (27)"]
                PlaybackModeCmds["playback_mode.rs (5)"]
                StorageCmds["storage.rs"]
                ConnectivityCmds["connectivity.rs (7)"]
            end

            subgraph Core["Core Modules"]
                MediaSessionManager["MediaSessionManager<br/>(Audio/Movie/TvShow/Idle)"]

                PlayerController["PlayerController<br/>+ PlayerBackend<br/>+ QueueManager"]

                Repository["Repository Layer<br/>HybridRepository (cache-first)<br/>OnlineRepository (HTTP)<br/>OfflineRepository (SQLite)"]

                PlaybackModeManager["PlaybackModeManager<br/>(Local/Remote/Idle)"]

                ConnectivityMonitor["ConnectivityMonitor<br/>(Adaptive polling)"]

                HttpClient["HttpClient<br/>(Exponential backoff retry)"]
            end

            subgraph Storage["Storage Layer"]
                DatabaseService["DatabaseService<br/>(Async trait)"]
                SQLite["SQLite Database<br/>(13 tables)"]
            end

            Commands --> Core
            Core --> Storage
            Repository --> HttpClient
            Repository --> DatabaseService
            Repository -->|"reports server outcome<br/>(success / RepoError)"| ConnectivityMonitor
        end

> The `Repository --> ConnectivityMonitor` edge is the source of truth for the offline/online banner: every server request the user actually makes updates reachability. The monitor's own polling is now an offline-only recovery probe (see 07-connectivity.md).

## Detailed Documentation

Each major subsystem is documented in its own file in this directory:

Document | Contents
--- | ---
01 - Rust Backend | Media session state machine, player state machine, playback mode, media items, queue manager, favorites (marking + browsing), player backend trait, player controller, playlist system, domain vocabulary owned by Rust (search scope, library exclusions, streaming quality ladder), background workers (catalog indexer, drains), Tauri commands
02 - Svelte Frontend | Store structure, music library navigation, playback reporting, repository architecture, playback mode system, database service abstraction, component hierarchy, MiniPlayer, sleep timer, auto-play, navigation guard, playlist management UI, library mosaic, series/episode navigation, downloaded browse, safe-area insets, native-video store, logging
03 - Data Flow | Repository query flow (cache-first), locally-indexed search, playback initiation, playback mode transfer, queue navigation, volume control
04 - Type Sync & Threading | Rust/TypeScript type synchronization, Tauri v2 IPC parameter naming convention, thread safety patterns
05 - Platform Backends | Player events system, HTML5 video adapter, MpvBackend (Linux), ExoPlayerBackend (Android) incl. audio settings parity, native video compositing, MediaSession & remote volume, album art caching, backend initialization
06 - Downloads & Offline | Download manager, download worker, smart caching engine, one storage model (cache entries are downloads), offline catalog visibility, download/offline commands, player integration, frontend store, UI components
07 - Connectivity | HTTP client with retry logic, connectivity monitor, network resilience architecture
08 - Database Design | Entity relationships, all table definitions (servers, users, libraries, items, user_data, downloads, media_streams, sync_queue, thumbnails, playlists), key queries, data flow diagrams, storage estimates
09 - Security | Authentication token storage, secure storage module, network security, webview CSP + asset-protocol scope, path confinement and input binding, local data protection

## File Structure Summary

    src-tauri/src/
    ├── lib.rs                    # Tauri app setup, state initialization
    ├── commands/                 # Tauri command handlers (~245 #[tauri::command] fns)
    │   ├── mod.rs               # Command exports
    │   ├── player/              # Player commands: queue, remote, session, settings, timers
    │   ├── repository.rs        # Repository commands (items, search, favourites, disk usage)
    │   ├── catalog.rs           # Catalog sync + the background index pass
    │   ├── favorites.rs         # Offline favourite drain
    │   ├── library.rs           # Library listing + folder exclusions
    │   ├── playlist.rs          # Playlist commands
    │   ├── playback_mode.rs     # Local/remote transfer
    │   ├── playback_reporting.rs
    │   ├── connectivity.rs      # Connectivity commands
    │   ├── storage/             # Storage & database commands: people, series_prefs, thumbnails
    │   ├── download/            # Download commands: mod, pinning, smart_cache
    │   ├── offline.rs           # Offline commands
    │   ├── device.rs            # Device id / capabilities
    │   ├── sessions.rs          # Remote sessions
    │   ├── sync.rs              # Sync queue commands
    │   └── sync_drain.rs        # Background sync-queue drain
    ├── repository/              # Repository pattern implementation
    │   ├── mod.rs               # MediaRepository trait, handle management
    │   ├── types.rs             # RepoError, Library, MediaItem, etc.
    │   ├── hybrid.rs            # HybridRepository with cache-first racing
    │   ├── online.rs            # OnlineRepository (HTTP API)
    │   └── offline.rs           # OfflineRepository (SQLite queries)
    ├── playback_mode/           # Playback mode manager
    │   └── mod.rs               # PlaybackMode enum, transfer logic
    ├── connectivity/            # Connectivity monitoring
    │   └── mod.rs               # ConnectivityMonitor, adaptive polling
    ├── jellyfin/                # Jellyfin API client
    │   ├── mod.rs               # Module exports
    │   ├── http_client.rs       # HTTP client with retry logic
    │   └── client.rs            # JellyfinClient for API calls
    ├── storage/                 # Database layer
    │   ├── mod.rs               # Database struct, migrations
    │   ├── db_service.rs        # DatabaseService trait (async wrapper)
    │   ├── schema.rs            # Table definitions
    │   └── queries/             # Query modules
    ├── download/                # Download manager module
    │   ├── mod.rs               # DownloadManager, DownloadInfo, DownloadTask
    │   ├── worker.rs            # DownloadWorker, HTTP streaming, retry logic
    │   ├── events.rs            # DownloadEvent enum
    │   └── cache.rs             # SmartCache, CacheConfig, LRU eviction
    └── player/                  # Player subsystem
        ├── mod.rs               # PlayerController
        ├── session.rs           # MediaSessionManager, MediaSessionType
        ├── state.rs             # PlayerState, PlayerEvent
        ├── media.rs             # MediaItem, MediaSource, MediaType
        ├── queue.rs             # QueueManager, RepeatMode
        ├── backend.rs           # PlayerBackend trait, NullBackend
        ├── events.rs            # PlayerStatusEvent, TauriEventEmitter
        ├── mpv/                 # Linux MPV backend
        │   ├── mod.rs           # MpvBackend implementation
        │   └── event_loop.rs    # Dedicated thread for MPV operations
        └── android/             # Android ExoPlayer backend
            └── mod.rs           # ExoPlayerBackend + JNI bindings

    src/lib/
    ├── api/                     # Thin API layer (~200 lines total)
    │   ├── types.ts             # TypeScript type definitions
    │   ├── repository-client.ts # RepositoryClient wrapper (~100 lines)
    │   ├── client.ts            # JellyfinClient (helper for streaming)
    │   └── sessions.ts          # SessionsApi (remote session control)
    ├── player/                  # Unified player boundary (frontend)
    │   ├── index.ts             # playerController facade — the only write-side entry point for playback
    │   └── html5Adapter.ts      # Reports webview <video> DOM events back into Rust (player_report_*)
    ├── services/
    │   ├── playerEvents.ts      # Tauri event listener for player events
    │   └── playbackReporting.ts # Thin wrapper (~50 lines)
    ├── stores/                  # Thin reactive wrappers over Rust commands
    │   ├── index.ts             # Re-exports
    │   ├── auth.ts              # Auth store (calls Rust commands)
    │   ├── player.ts            # Player store
    │   ├── queue.ts             # Queue store
    │   ├── library.ts           # Library store
    │   ├── playbackMode.ts      # Playback mode store (~150 lines)
    │   ├── connectivity.ts      # Connectivity store (~250 lines)
    │   └── downloads.ts         # Downloads store with event listeners
    └── components/
        ├── Search.svelte
        ├── player/              # Player UI components
        ├── playlist/            # Playlist modals (Create, AddTo)
        ├── sessions/            # Remote session control UI
        ├── downloads/           # Download UI components
        └── library/             # Library UI components + PlaylistDetailView

## Key Architecture Changes

What moved to Rust (~3,500 lines of business logic):

1. HTTP Client (338 lines) - Retry logic with exponential backoff
2. Connectivity Monitor (301 lines) - Reachability derived from real repository traffic, time-window debounce, offline-only recovery probe, event emission
3. Repository Pattern (1061 lines) - Cache-first hybrid with parallel racing
4. Database Service - Async wrapper preventing UI freezing
5. Playback Mode (303 lines) - Local/remote transfer coordination

Svelte/TypeScript frontend (~20.5k non-test lines, plus ~9.6k test lines):

- Components + routes (~14.6k lines) — UI and presentation
- Stores (~3.4k lines) — reactive state that invokes Rust commands and listens for events
- api / services / utils (~2.4k lines) — typed clients, event listeners, conversion helpers

The frontend is genuinely UI-heavy; business decisions live in Rust, but the UI owns layout, navigation, and interaction state.

Total Commands: ~245 `#[tauri::command]` functions across 17 command modules (~58k lines of Rust, ~37k non-test lines of TypeScript/Svelte).

> Counts and line totals in this file are periodic snapshots, not gates — the authority is the tree. Regenerate with `grep -rc '#\[tauri::command\]' src-tauri/src` and `wc -l`.