# Architecture

This document provides comprehensive information about the MPV.Rocks Installer system architecture, package organization, and design patterns.

## Table of Contents

- [Package Organization](#package-organization)
- [Key Packages](#key-packages)
- [Design Patterns](#design-patterns)
- [Data Flow](#data-flow)
- [Component Interaction](#component-interaction)

---

## Package Organization

```
mpv-manager/
├── cmd/
│   ├── mpv-manager/          # Main application (web/TUI/CLI entry)
│   ├── generate-info/         # Release JSON generator
│   └── gen-checksums/        # BLAKE3 checksum generator
├── pkg/
│   ├── platform/             # Platform detection (reusable)
│   │   ├── platform.go       # Detect(), OS/arch/distro checks
│   │   ├── cpu.go           # CPU feature detection (x86-64-v levels)
│   │   ├── cpu_other.go     # CPU detection helpers (non-Windows)
│   │   ├── cpu_windows.go   # CPU detection (Windows)
│   │   ├── elevation.go     # Effective UID / elevation checks
│   │   ├── gpu.go           # GPU detection, 37-entry codec database, HWA options
│   │   ├── gpu_darwin.go    # GPU detection (macOS)
│   │   ├── gpu_darwin_cgo.go # VideoToolbox codec detection (CGO)
│   │   ├── gpu_notdarwin.go # GPU detection (Windows/Linux)
│   │   └── linux.go         # Linux distro/package detection
│   │
│   ├── constants/            # Single source of truth
│   │   ├── constants.go      # Method IDs, paths, commands, permissions
│   │   └── paths.go        # Config paths, backup utilities
│   │
│   ├── config/             # App configuration
│   │   ├── config.go       # Load/Save (mutex-guarded, atomic, corrupt quarantine)
│   │   ├── editor.go       # mpv.conf value get/set
│   │   └── validation.go   # Config value validation
│   │
│   ├── version/            # Version management
│   │   ├── version.go       # Version identity, selection, downloads, legacy swap tests
│   │   ├── release.go       # Signed manifest fetch/decode/trust validation
│   │   ├── release_trust.go # Persistent anti-replay, key epochs, revocation
│   │   ├── transaction.go   # Lock, durable journal, helper, relaunch, rollback/recovery
│   │   ├── update_outcome.go # Detached-helper terminal result handoff
│   │   └── updates.go      # Update detection for managed apps
│   │
│   ├── releasemanifest/    # Shared signed release/component schema
│   │   └── manifest.go      # Validation, Ed25519 sign/verify, asset selection
│   │
│   ├── log/                # Logging infrastructure
│   │   └── logger.go       # Thread-safe logging to file
│   │
│   ├── installer/          # Installation logic
│   │   ├── installer.go     # Base installer and ReleaseInfo types
│   │   ├── installer_archive.go # Native archive preflight, private staging, inventory policy
│   │   ├── file_transaction.go # Transactional overlays/path and regular-file replacement
│   │   ├── transaction_journal.go # Crash-durable installer/UI journals and startup recovery
│   │   ├── common.go       # Shared utilities (backup, restore, paths)
│   │   ├── common_handler.go # Shared InstallationHandler implementation
│   │   ├── common_handler_{linux,windows,darwin}.go # Platform hooks
│   │   ├── command_runner.go # Command execution, sudo via keyring
│   │   ├── config_preservation.go # Automatic config backups
│   │   ├── detection.go    # Installation/package manager detection
│   │   ├── download.go     # Download and extract helper
│   │   ├── interfaces.go   # InstallationHandler interfaces
│   │   ├── package_manager.go # Package manager abstraction (apt/dnf/pacman/zypper/...)
│   │   ├── windows.go      # Windows-specific installation
│   │   ├── windows_shortcuts.go # Shortcut creation
│   │   ├── linux.go        # Linux-specific installation
│   │   ├── linux_package.go # Linux package manager installs (incl. zypper)
│   │   ├── macos.go        # macOS-specific installation
│   │   └── macos_appbundle.go # .app bundle installation
│   │
│   ├── locale/             # Language preferences data
│   │   ├── locale.go       # 123+ languages with regions
│   │   ├── selection.go    # Language filtering and selection
│   │   ├── flag_map.go     # Language code to flag emoji mapping
│   │   └── selection_test.go # Shared selection behavior
│   │
│   ├── hotkeys/            # Hotkey presets and shortcut browser
│   │   ├── hotkeys.go      # 120-shortcut database, categories, search
│   │   └── inputconf.go    # input.conf parse/write, presets, backups
│   │
│   ├── keyring/            # System keyring for sudo password
│   │   ├── keyring.go      # Native stores: Secret Service, Keychain, Credential Manager
│   │   └── check.go        # Bounded, read-only availability diagnostics
│   │
│   ├── modernzconf/        # ModernZ config parser/editor and managed defaults
│   ├── uoscconf/           # uOSC config parser/editor
│   ├── uiconfig/           # Active-UI discovery, compatibility audit, migrations
│   │
│   ├── web/                # Web UI server and API
│   │   ├── server.go       # HTTP server, routes, templates, pages
│   │   ├── api.go          # REST API endpoints, modal system
│   │   ├── middleware.go   # Auth token, security headers, rate limiting
│   │   ├── models.go       # Page data and API models
│   │   ├── jobs.go         # Background job manager (install/update/uninstall)
│   │   ├── sse.go          # Server-Sent Events streaming
│   │   ├── validation.go   # API input validation
│   │   ├── locale.go       # Cached locale data and display helpers
│   │   └── package_version.go   # Shared package-query hooks for the Web collector
│   │
│   └── tui/               # Terminal UI (Bubbletea)
│       ├── models.go       # Core constants and Model struct
│       ├── models_types.go # Message types and list items
│       ├── models_init.go  # Constructor and setters
│       ├── models_messages.go # tea.Cmd wrappers
│       ├── models_update.go # Update() method
│       ├── models_views.go  # All View methods
│       ├── ui_select.go     # Reusable select component
│       ├── language_preferences.go # Language preference feature
│       ├── language_adapter.go   # Language data adapter
│       ├── hwaccel_config.go     # Hardware acceleration config
│       └── hotkeys.go            # Hotkey presets and shortcut browser
│
├── internal/
│   ├── assets/             # Embedded files (mpv.conf, hotkey presets, locales.json)
│   └── webassets/          # Embedded Web UI templates and static files
├── Makefile                # Build automation
└── go.mod                  # Go module definition
```

---

## Key Packages

### pkg/platform

**Purpose:** Platform detection and hardware information gathering

**Key Functions:**
- `Detect()` - Main entry point for platform detection
- `GetOS()` - Returns OS type (Windows, Linux, Darwin)
- `GetArch()` - Returns system architecture
- `GetDistro()` - Returns Linux distribution
- `GetDistroFamily()` - Returns distro family (debian, rhel, arch, etc.)
- `GetCPUInfo()` - Returns CPU details (model, features, cores)
- `GetGPU()` - Returns GPU information (model, vendor, VRAM)
- `DetectCodecs()` - Detects supported video codecs (AV1, HEVC, VP9, etc.)

**Platform-Specific Detection:**
- **Linux:** aggregate glxinfo, vulkaninfo, and lspci enumeration; sysfs DRM fallback with PCI-ID database/vendor resolution
- **Windows:** wmic, PowerShell GPU commands
- **macOS:** system_profiler, CGO-based VideoToolbox API
- External commands use independent per-probe contexts, fixed output caps, and bounded process-pipe cleanup; fallbacks never reuse an expired context
- GPU model parsing removes only trailing probe annotations, preserving names
  such as `Radeon(TM) 780M`; per-adapter brands and database codec matches are
  combined so a display-attached adapter cannot hide another GPU

### pkg/constants

**Purpose:** Single source of truth for all constant values

**Key Categories:**
- **Config Keys:** MPV configuration keys (alang, slang, hwdec, vo, scale)
- **Method IDs:** Installation method identifiers
- **HTTP Constants:** Content types, methods, status codes
- **Log Prefixes:** API, SSE, Installer prefixes
- **Modal Types:** Shutdown, update, uninstall, reset, etc.
- **Query Parameters:** API query parameter names
- **Status Values:** Success, failure, shutdown messages

**Example Constants:**
```go
const (
    ConfigKeyAudioLanguage    = "alang"
    ConfigKeySubtitleLanguage = "slang"
    ConfigKeyHardwareDecoder  = "hwdec"
    ConfigKeyVideoOutput      = "vo"
    ConfigKeyScaleFilter      = "scale"
    ConfigKeyDitherAlgorithm  = "dither-depth-convert"
    
    ContentTypeJSON = "application/json"
    ContentTypeHTML = "text/html"
    
    LogPrefixAPI = "[API]"
    LogPrefixSSE = "[SSE]"
)
```

### pkg/config

**Purpose:** Configuration management for installed apps and settings

**Key Functions:**
- `Load()` - Loads configuration from file
- `Save()` - Saves configuration to file
- `GetConfigValue()` - Reads MPV config value (alang, slang, hwdec, etc.)
- `SetConfigValue()` - Writes MPV config value with backup
- `GetInstalledApps()` - Returns list of installed applications
- `AddInstalledApp()` - Adds app to installed apps list
- `RemoveInstalledApp()` - Removes app from installed apps list
- `GetInstallPath()` - Returns installation directory

Manager-config mutations are rendered into isolated snapshots, atomically
persisted, and published to readers only after success. Non-absence load/read
errors retain the last known-good snapshot and block mutation until a later
load succeeds. Every manager-config read/modify/write rebases on the latest
on-disk snapshot while holding one stable cross-process advisory lock, so Web,
TUI, CLI, and concurrent manager processes cannot overwrite unrelated fields.
Manager-data reset requires a unique durable recovery copy.

**Config Locations:**
- **Windows:** `<effective install path>/portable_config/` (including a configured custom path)
- **Linux/macOS:** `~/.config/mpv/`
- **Backups:** `conf_backups/` subdirectory

`mpv.conf` reset, recommended-config install, language updates, and restore use
same-directory staged atomic replacement. Multi-field Config and language API
requests validate the whole request, edit one fresh snapshot, and publish one
atomic file replacement. Existing live configs remain at their primary
pathname while a unique durable recovery snapshot is created;
backup/preservation failures abort before mutation. Restore and delete accept
only flat, regular backup files and perform the final operation through an
`os.Root` rooted at the validated `conf_backups` directory, preventing an
intermediate symlink from redirecting access outside the config tree.

`mpv.conf`, `input.conf`, and script-option parsing share the quote-aware
`internal/confline` comment lexer, so `#` inside quoted values or commands is
not truncated. Script-option rewrites preserve UTF-8 BOMs, CRLF/LF style,
permissions, and Unix ownership; symlink and non-regular destinations are
rejected before replacement.

### pkg/uiconfig

**Purpose:** Shared active-controller discovery, compatibility inspection, and persistent UI config migrations used by
both Web and TUI modes.

**Key Functions:**
- `DetectInstalledUI()` - Resolves ModernZ, uOSC, or no supported controller from on-disk evidence and manager metadata
- `Inspect()` - Reports invalid curated values and any pending versioned migration without rewriting user files
- `ResolveMigration()` - Applies or dismisses an actionable migration and persists the decision only after success

ModernZ migration apply holds the cross-process script-config lock across the
script and manager-state updates. A strict, size-bounded intent journal stores
the exact prior `modernz.conf` and the digest of the proposed result. Recovery
restores the prior content only when the file still matches that result, or
recognizes an already completed restoration. Later edits and ambiguous legacy
intent are retained for reconciliation. A manager-committed change is retained
before the journal is durably retired.

ModernZ and uOSC parsing/editing remain in `pkg/modernzconf` and `pkg/uoscconf`. Installer component updates stage
new assets, preserve the live UI config byte for byte, create a durable pre-update backup, and retain the verified
clean template under `.mpv-manager/ui-baselines/` for future provenance-aware merges.

### pkg/releasemanifest and pkg/version

**Purpose:** Authenticated release discovery, version management, and
transactional portable self-update.

**Key Functions:**
- `GetCurrentVersion()` - Returns current installer version
- `CheckForUpdate()` - Compares versions, returns update availability
- `PrepareSelfUpdateFromCheck()` - Requires an opaque verified-manifest selection, takes the user-wide transaction lock, journals intent, downloads once, verifies, and stages all configured targets
- `PreparedSelfUpdate.LaunchUpdateHelper()` - Hands the post-exit transaction to the copied helper
- `RunUpdateHelper()` - Applies/reverifies targets, relaunches when requested, and commits or rolls back
- `RecoverSelfUpdateTransactions()` - Cleans safe pre-journal orphans, restores interrupted work, and revalidates committed targets without disturbing an active helper
- `GetBinaryIdentity()` - Returns the product, component, version, platform, and build identity used for post-swap validation

`pkg/releasemanifest.Manifest` is the only release schema used by the generator,
installer, and updater. Schema v2 signs canonical component metadata with
Ed25519 and includes exact asset size/hash, platform/architecture, installation
scope, update strategy, expected identity, key ID, channel, and minimum updater
version. Legacy top-level fields remain for the v1.2-to-v1.3 bootstrap.

Unattended release generation consumes a reviewed, tag-bound
`pkg/releaseprovenance` lock and pipeline-local manager build artifacts. It
cannot query upstream “latest” APIs. The application pipeline emits an unsigned
candidate and authenticates to a separately pinned signer with a short-lived
GitLab OIDC assertion; tagged application code never receives the private key.

**Features:**
- Automatic update checking on startup
- Structured progress shared by Web jobs and the TUI
- Three-attempt downloads with bounded linear backoff
- Signed size and BLAKE3 verification
- Authenticated size/BLAKE3 verification immediately before every candidate
  identity execution, plus exact pre/post-swap binary identity verification
- A user-wide cross-process lock covering primary and secondary targets,
  intent-before-staging journaling, durable helper handoff, and startup recovery
- Highest-accepted stable release state, build-time freshness floor, key validity
  epochs/revocation, and replay/rollback/equivocation rejection
- Durable detached-helper outcomes reconciled into shared Web/TUI task history;
  Web handoff is not represented as final success
- Transactional primary/secondary installation commit and rollback
- Never-absent target replacement: hard-link backup plus atomic rename on Unix,
  and write-through replacement over the existing path on Windows
- Original target size/hash/identity evidence is journaled; rollback verifies
  backups before use and restored bytes before execution. If an interrupted
  restoration consumed its backup, replay accepts only the authenticated
  original size/hash/identity at the live target.
- A committed update durably records its terminal outcome and finalization
  before removing rollback backups. Finalized journals defer helper cleanup
  without retaining authority to undo a later manual executable replacement.
  Outcome/finalization publication failure retains recovery evidence.
- Recovery journals use schema 2 and HMAC-SHA256 authentication with a random
  per-user key outside executable-adjacent transaction folders. Verification
  never creates a missing key. Journal, target, backup, and ancestor ownership
  and permissions are checked before executing recovery artifacts. Legacy
  unauthenticated journals or missing original evidence require manual recovery.
  This protects against planted files and other users, not a process already
  able to read the current user's private key.
- TUI relaunch keeps the initiating terminal descriptors and acknowledges
  health only after Bubble Tea initializes the terminal and renders its first frame

### pkg/installer

**Purpose:** Cross-platform installation logic

**Key Interfaces:**
- `InstallationHandler` - Interface for platform-specific installers
- `WindowsInstaller` - Windows implementation
- `LinuxInstaller` - Linux implementation
- `MacOSInstaller` - macOS implementation

**Key Functions:**
- `Install()` - Main installation entry point
- `Uninstall()` - Uninstallation logic
- `InstallMPVConfigWithOutput()` - Installs MPV configuration with streaming output
- `RestoreConfigWithOutput()` - Restores configuration backup
- `SetupFileAssociationsWithOutput()` - Directs Windows users to the OS-owned Default apps settings
- `RemoveFileAssociationsWithOutput()` - Directs Windows users to remove defaults through Windows Settings
- `CreateInstallerShortcutWithOutput()` - Creates desktop/menu shortcuts

Windows portable payloads use `.mpv-manager-owned.json` as transactional,
exact-file ownership proof. Installation refuses populated unowned trees;
uninstall removes only manifest-owned files and empty payload directories.
Mutable install-tree association scripts are never elevated or executed.

ZIP, tar, gzip, xz, and 7z payloads are parsed natively. ZIP/tar/7z receive a
complete entry-count, expanded-size, path-portability, type, collision, and
file-as-parent preflight before any output is created. Extraction occurs under
a private sibling stage; the staged tree is revalidated and committed through
the same overlay transaction used by platform installers. uOSC additionally
requires its reviewed `scripts/uosc.lua`, `scripts/uosc/`, `fonts/uosc/`, and
`script-opts/uosc.conf` inventory and rejects unrelated paths.

Overlay, whole-path, regular-file, and managed-UI mutations take a
cross-process destination-parent lock and persist intent before moving or
removing live data. Schema-2 journals authenticate intent with HMAC-SHA256 and
a private per-user key in the manager config directory. Authoritative journals
live in the protected `.mpv-manager-installer-recovery` config subdirectory,
with filenames bound to the sibling backup identity. Recovery verifies that
private inventory, the authenticated journal, exact requested destination and
private backup ownership before touching live paths. Journals found beside
applications are retained for manual reconciliation even when their MAC is
valid: a shared application parent must not enable replay of retired intent.
Missing keys, unauthenticated legacy intent and ambiguous evidence remain on
disk for manual reconciliation. A durable commit marker is written only after
affected files and directories are synced; committed cleanup can safely resume
after a crash.
Recovery validates every required backup before removing any live target and
copies originals back without consuming the backups. A durable `rolled-back`
marker precedes cleanup, so recovery can repeat after interruption. Missing or
unsafe backups preserve all live files and the journal for manual reconciliation.

Windows FFmpeg component updates copy into a destination-adjacent staging
file, fsync and BLAKE3-compare the copy, validate its matching AMD64/ARM64 PE
structure, and retain the prior executable until post-swap validation and manager-config
version persistence succeed. Any failure restores the old executable; an
unrestorable backup is retained at a reported recovery path. macOS IINA
installation mounts the verified DMG beneath an owned root and binds bundle
validation, copy, and detach to the exact device/mount pair returned by
`hdiutil -plist`. Cleanup is registered before attachment and uses a separate
bounded context, including attachment errors or cancellation after a mount
appears. Cleanup failure retains the owned staging evidence. FFmpeg component
downloads and extraction use a unique private scratch directory and remove only
that owned directory.

Compressed-tar preflight checks cancellation before parsing and between reads;
entry and aggregate size budgets are enforced at each header before traversing
its body. Extraction retains the complete inventory and private staging checks.
Flatpak remote discovery uses the operation context and bounded output before
the commit guard.

Install discovery publishes identity-scoped `found`, `not-found`, or `unknown`
observations. Synchronization keys records by canonical method plus path,
preserves all same-method installations, and never removes durable state after
a missing tool, timeout, permission error, or incomplete scan. Linux package
queries have fixed time/output bounds and `LC_ALL=C`; Windows discovery checks
filesystem/registry metadata without executing candidate `mpv.exe` files.
MPC-QT waits for the elevated installer, propagates its exit status, then
requires a real `mpc-qt.exe` in documented or uninstall-registry locations
before reporting completion.

**Command Runner:**
- `StartStreamingCommand()` - Starts command with SSE event streaming
- Output streamed via channels for real-time TUI display
- Support for stdout and stderr streaming

TUI install, update, uninstall, configuration, UI-change, and manager-update
operations own one cancellable context from launch through worker shutdown.
Escape requests cancellation and returns to the menu only after the worker has
stopped; Ctrl+C follows the same join path before Bubble Tea quits. One channel
reader drains output/progress/prepared streams before publishing the terminal
result, so a ready completion cannot race with or discard trailing output.
All detached operation entry points use the same panic-to-result boundary;
panics are logged with a stack and returned through the ordinary terminal
result instead of bypassing Bubble Tea's terminal restoration. Command runners
created for TUI work disable interactive sudo prompts: root execution and
bounded keyring-backed authentication remain supported, while a missing
credential returns an actionable error rather than competing for the raw
terminal.

Subprocess output is terminal-sanitized before rendering and shared job-history
persistence. The live view retains a bounded recent-line buffer, coalesces
expensive viewport reflow, and supports arrow/Page/Home/End plus mouse-wheel
scrolling; reaching End/bottom resumes automatic following. Every list and
viewport is reflowed with positive dimensions on resize. Release information
is fetched once after the first frame, then reused for installer and manager
update state; failure leaves an explicit offline state and blocks only methods
that require manifest assets.

### pkg/web

**Purpose:** Web UI server and API endpoints

**Key Components:**
- **Server** - HTTP server with templates and static assets
- **API Handlers** - RESTful API endpoints for config, install, uninstall, updates
- **SSE** - Server-Sent Events for real-time output streaming
- **Package Detection** - Detects package manager versions (apt, flatpak, snap, brew)

**API Endpoints:**
- `GET /api/` - Server information
- `POST /api/install` - Install MPV client
- `POST /api/uninstall` - Uninstall app
- `POST /api/config/apply` - Apply configuration settings
- `GET /api/languages/load` - Load language preferences
- `POST /api/languages/save` - Save language preferences
- `GET /api/check-updates` - Check for updates
- `POST /api/modal` - Get modal configuration
- `POST /api/shutdown` - Shutdown server

**Features:**
- Embedded templates and static assets
- Input validation on all endpoints
- SSE streaming for installation output
- Modal system for confirmations
- App card widgets for consistent styling

Web startup binds the validated loopback listener synchronously before it
publishes `Server.Addr`, prints the startup banner, or opens a browser. A
dedicated start mutex permits exactly one server publication, and graceful
shutdown reads the published server under the same synchronization boundary.

Background mutations use worker-owned terminal transitions. A cancellation
request moves a job to `cancelling`, cancels its context, and retains every
resource lease until the worker acknowledges `cancelled`; it never archives a
terminal result while side effects may still be running. Workers atomically
enter a commit boundary before irreversible work, after which cancellation is
rejected with a conflict rather than misreported.

Jobs lease normalized resources (manager state, MPV config/UI, install target,
app identity, and package-manager database) in deterministic order. Direct
config, hotkey, language, UI-config, migration, and settings mutations use the
same coordinator, so unlike method IDs cannot overlap on shared trees. A
physical commit followed by tracking-persistence failure ends as `partial`
with reconciliation guidance; Web/TUI history never labels it successful.
The shared `job-history.json` store also holds a cross-process file lock across
each complete read/modify/write cycle, publishes through unique fsynced
temporary files, and durably quarantines malformed history rather than
silently discarding it.

Each SSE connection has a bounded queue where output/progress may be dropped
under pressure but status/terminal events displace older entries. Every global
connection begins with an authoritative active-plus-recent snapshot, allowing
the browser to reconcile a terminal transition missed while disconnected.
Server shutdown closes the broadcaster and root shutdown channel before the
bounded HTTP shutdown, so persistent streams drain instead of forcing a
timeout/error exit.

Frontend autosave ownership is explicit: UI-setting mutations are serialized
per option key and only the newest intent may update visible state. Regional
language fetches use a monotonic owner plus a request-local abort controller;
an older completion or `finally` block cannot replace data or clear the newer
controller.

### pkg/locale

**Purpose:** Language and regional data management

The Web page and TUI share `LocaleEntry`/`RegionEntry` data. `SearchLanguages`
filters language and regional options; `GetMajorLanguages` returns the common
language list; `GetMajorRegionalVariants` sorts regions by major status and
population. `FindByLanguageCode` and `FindByLocale` resolve canonical entries.
The Web uses the embedded languages controller for interactive selection and
`pkg/web/locale.go` for display helpers. The TUI adapts shared search results to
its regional list. No parallel Web `LanguageOption` compatibility layer remains.

Languages use one canonical selectable code: ISO 639-1 when available and the
stored ISO 639-2/3 code otherwise. Embedded-data integrity tests require every
common code to resolve, regional locale IDs to be unique and prefix-consistent,
and regional metadata to be complete.

### pkg/tui

**Purpose:** Terminal User Interface (Bubbletea)

**Key Components:**
- **Model** - Main state container
- **Views** - View rendering functions
- **Messages** - Tea message types and commands
- **Update Handlers** - State transition logic

**Views:**
- `mainMenuView` - Main menu display
- `platformInfoView` - System information display
- `appsView` - MPV Player Apps selection
- `updatesView` - Updates menu display
- `hwaOptionsView` - Hardware acceleration options
- `configOptionsView` - Configuration options
- `languagePrefsView` - Language preferences interface

**State Machine:**
```go
const (
    StateMainMenu State = iota
    StatePlatformInfo
    StateApps
    StateUpdates
    StateConfigOptions
    StateHWAOptions
    StateLanguagePrefs
    StateInstalling
    StateFileAssociationsMenu
    StateRestoreConfig
    // ... more states
)
```

---

## Design Patterns

### InstallationHandler Interface

Platform-specific installers implement a common interface:

```go
type InstallationHandler interface {
    Install(methodID string, installPath string) (*InstallationResult, error)
    Uninstall(appName string, installPath string) error
    InstallMPVConfigWithOutput(config string, outputChan chan<- string) error
    SetupFileAssociationsWithOutput(installPath string, outputChan chan<- string) error
    RemoveFileAssociationsWithOutput(installPath string, outputChan chan<- string) error
    CreateInstallerShortcutWithOutput(installPath string, appName string, outputChan chan<- string) error
}
```

**Benefits:**
- Consistent API across platforms
- Easy to add new platforms
- Type-safe implementations
- Testable interfaces

### Command Output Streaming

Commands are executed with output streaming to TUI:

```go
func StartStreamingCommand(cmd *exec.Cmd, outputChan chan<- string) error {
    stdout, err := cmd.StdoutPipe()
    stderr, err := cmd.StderrPipe()
    // Stream lines to outputChan
    go streamOutput(stdout, outputChan)
    go streamOutput(stderr, outputChan)
    return cmd.Start()
}
```

**Benefits:**
- Real-time output display
- No buffering
- Separate stdout/stderr
- Non-blocking

### SSE Event Streaming

Server-Sent Events for real-time installation updates:

```go
func (s *Server) handleInstallSSE(w http.ResponseWriter, r *http.Request) {
    // Set SSE headers
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")

    // Create event channel
    eventChan := make(chan SSEEvent)

    // Stream events
    for event := range eventChan {
        fmt.Fprintf(w, "event: %s\n", event.Type)
        fmt.Fprintf(w, "data: %s\n\n", event.Data)
        flusher.Flush()
    }
}
```

**Event Types:**
- `start` - Installation started
- `stdout` - Standard output line
- `stderr` - Error output line
- `success` - Installation completed successfully
- `error` - Installation failed
- `done` - Installation finished

### Input Validation

Comprehensive validation on all API endpoints:

```go
func ValidateConfigValue(key, value string) error
func ValidateMethodID(methodID string) error
func ValidateAppName(appName string) error
func ValidateAppType(appType string) error
func ValidateLanguageCode(code string) error
func ValidateHWAValue(method string) error
func ValidateInstallMethod(methodID string, isWindows, isDarwin, isLinux bool) error
```

**Benefits:**
- Prevents invalid data
- Clear error messages
- Platform-specific validation
- Type-safe validation

### Retry Pattern

Bounded retry logic with increasing delays:

```go
func saveWithRetry(maxRetries int) error {
    delays := []time.Duration{1*time.Second, 2*time.Second, 3*time.Second}
    var errors []string

    for attempt := 0; attempt < maxRetries; attempt++ {
        if attempt > 0 {
            time.Sleep(delays[attempt-1])
        }

        err := performOperation()
        if err == nil {
            return nil // Success
        }

        errors = append(errors, err.Error())
    }

    return fmt.Errorf("failed after %d attempts: %s", maxRetries, strings.Join(errors, "; "))
}
```

**Benefits:**
- Handles transient failures
- Bounded increasing backoff
- Accumulated error tracking
- Clear error messages

### Web Auth Middleware

All `/api/*` routes are guarded by `authMiddleware` (`pkg/web/middleware.go`):

```go
func (s *Server) authMiddleware(next http.Handler) http.Handler
```

- A random 32-byte token is generated per server start (`generateAuthToken`)
- Page/static GET responses (re)set it as an `HttpOnly`, `SameSite=Strict` cookie (`mpv_manager_token`)
- API requests must present the matching cookie (constant-time compare)
- Loopback binds enforce a local Host header (DNS rebinding protection); a present Origin header must match `scheme://Host`
- OPTIONS requests are rejected; mutating handlers enforce POST/DELETE-only methods
- A sliding-window rate limiter (5 attempts / 60 s) protects `/api/keyring/auth`

**Benefits:**
- Blocks cross-site requests to the local server (CSRF, DNS rebinding)
- No user-facing login flow; scripts opt in by reading the cookie
- Fails closed: no valid cookie, no API access

---

## Data Flow

### Installation Flow

```
User selects app and method
    ↓
Validate method ID and platform compatibility
    ↓
Get install path from config or user input
    ↓
Create platform-specific InstallationHandler
    ↓
Install(methodID, installPath)
    ↓
Streaming command execution with SSE events
    ↓
Output displayed in TUI/Web UI
    ↓
InstallationResult with success/error
    ↓
Add to installed_apps config if success
    ↓
Return to menu
```

### Configuration Flow

```
User opens language preferences
    ↓
Load from mpv.conf (GetConfigValue)
    ↓
Display current selections
    ↓
User modifies selections
    ↓
Click "Save" button
    ↓
Validate language codes
    ↓
Save with retry logic (SetConfigValue)
    ↓
Backup created on first write
    ↓
mpv.conf updated
    ↓
Success message displayed
```

### Update Check Flow

```
App startup / User clicks "Check for Updates"
    ↓
GetCurrentVersion()
    ↓
GetLatestVersion() from release server
    ↓
Compare versions
    ↓
If new version available:
    ├─ Display update notification
    └─ Add to Updates menu
    ↓
If user clicks "Update Installer":
    ├─ DownloadFileWithProgress() with progress tracking
    ├─ BLAKE3 verification
    ├─ Replace binary
    └─ Update PATH and quit
```

---

## Component Interaction

### TUI and Web UI

**TUI (Terminal UI):**
- Uses Bubbletea framework
- Direct calls to config, installer, version packages
- Keyboard navigation
- Command output streaming through a single ordered channel reader
- Worker-owned cancellation: Escape/Ctrl+C cancel and join active operations
- UI changes target an explicitly selected stable installed-app ID and update
  only that installation's UI/config metadata
- List filter acceptance is handled before action dispatch, preventing Enter
  from both accepting a filter and activating a destructive action
- Release metadata refresh starts after the first frame and supplies both
  installer assets and manager-update state from one authenticated manifest
- Process/history output is control-sequence sanitized, bounded, scrollable,
  and fully reflowed after terminal resize
- Detached worker panics become ordinary operation failures, and sudo never
  opens an interactive child prompt while Bubble Tea owns raw terminal mode
- PATH installation is a rollback-capable transaction: Unix installs one
  idempotent marked shell block plus `mpv-manager`/`mpv-install` command files;
  Windows installs `.exe` command copies and edits the current-user Environment
  `Path`. Physical state is restored if any filesystem, registry, or manager
  config persistence step fails.

**CLI:**
- Subcommands and `--mode` cannot conflict, trailing positionals are rejected,
  and mode-specific flags fail with exit status 2 instead of being ignored.
- `--path` is accepted only for Windows portable MPV methods that consume the
  destination; package managers, app installers, MPC-QT, and components reject
  it before release download or mutation.
- Successful custom portable installs persist the chosen destination before
  recording installed-app metadata. `--verbose` and `--debug` mirror logs to
  stderr from process startup, including helper paths.

**Web UI:**
- HTTP server with embedded assets
- REST API for config and install operations
- SSE for real-time installation output
- HTML templates with Tailwind CSS styling

**Shared Components:**
- pkg/config - Configuration management
- pkg/constants - Shared constants
- pkg/installer - Installation logic
- pkg/locale - Language data
- pkg/version - Version management

### Cross-Platform Support

**Platform Detection:**
- pkg/platform detects OS, architecture, distribution
- Platform-specific installers selected at runtime
- Hardware-acceleration methods filtered by platform

**Hardware Detection:**
- GPU detection with codec support
- CPU feature detection with complete x86-64 baseline verification and NEON
- Platform-specific detection methods (vainfo, wmic, system_profiler)

The optimized player build requires the complete detected x86-64-v3 or v4
baseline; an AVX2-only or unknown observation selects the conservative build.
CPU-only component selection avoids repeating GPU discovery, and macOS model
inference reuses the GPU model already obtained by platform detection.

### Configuration Management

**MPV Configuration:**
- Single source of truth in ~/.config/mpv/mpv.conf
- Backup creation before writes
- ConfigPreservationHandler pattern for automatic backups
- Language preferences with retry logic

**Installer Configuration:**
- Installed apps tracked in config file
- Install path saved per app
- Version tracking for updates

---

## Code Conventions

### File Organization

**Package Size:**
- Keep packages focused and single-purpose
- Split large files when exceeding 500 lines
- Related functionality grouped together

**Naming Conventions:**
- Package names: lowercase, single word (platform, config, installer)
- Interface names: Descriptive + "Handler" suffix (InstallationHandler)
- Struct names: Descriptive (InstallationResult, ReleaseInfo)
- Functions: PascalCase for exported (GetInstallPath, ValidateConfigValue)

### Code Style

- Follow Go conventions (`go fmt ./...`)
- Use meaningful variable names
- Add comments for public APIs
- Keep functions focused and small
- Prefer composition over inheritance

### Error Handling

- Always return errors, never panic
- Provide context with errors (fmt.Errorf)
- Use sentinel errors for known conditions
- Log errors with stack traces when useful

---

## Testing Considerations

### Unit Testing

- Test functions in isolation
- Mock external dependencies (HTTP, file system)
- Test error paths and edge cases
- Maintain 80%+ test coverage

### Integration Testing

- Test package interactions
- Test platform-specific code on target platforms
- Test installation/uninstallation flows
- Test configuration persistence

### Manual Testing

- Test on all supported platforms (Windows, Linux, macOS)
- Test with various hardware configurations
- Test error recovery and retry logic
- User acceptance testing

---

## Performance Considerations

### Startup Performance

- Lazy loading of platform-specific data
- Cached platform detection results
- Parallel HTTP requests where possible

### Runtime Performance

- Streaming output for immediate display
- Minimal memory allocations
- Efficient string operations
- Goroutine pool for concurrent operations

### Build Time

- Minimal dependencies
- Fast compilation with Go toolchain
- Cross-compilation support for all platforms

---

## Security Considerations

### Input Validation

- Validate all user inputs
- Sanitize file paths
- Validate method IDs against whitelist
- Platform compatibility checks

### File Operations

- Use atomic writes for config files
- Create backups before modifications
- Validate file permissions
- Secure temporary file handling

### Web API Access Control

- Per-start auth token gates all `/api/*` routes (see Web Auth Middleware)
- Host/Origin header checks on loopback binds
- POST/DELETE-only mutating endpoints
- Rate limiting on sensitive endpoints (`/api/keyring/auth`)
- Security headers on all responses (nosniff, DENY framing, XSS protection, referrer policy)

### Network Operations

- Validate HTTPS certificates
- Validate download checksums (BLAKE3; self-update fails closed when no hash is available)
- Rate limiting for API calls
- Timeout on network operations

---

## Future Enhancements

### Architecture Improvements

1. **Plugin System:** Add extensibility for third-party installers
2. **Multi-Language UI:** Full internationalization support
3. **Modular UI Components:** Reusable UI widgets library
4. **Event Bus:** Decoupled component communication

### Platform Support

1. **BSD Support:** Add FreeBSD, OpenBSD support
2. **Native signing gates:** Execute and verify Authenticode and Apple signing/notarization evidence for the exact release artifacts
3. **Embedded Linux:** Support for embedded distros

### Performance Improvements

1. **Lazy Loading:** On-demand asset loading
2. **Caching:** Persistent cache for API responses
3. **Streaming:** Progressive loading for large operations
4. **Parallelism:** Increased concurrent operations

## Operation and persistence boundaries

`Model.Run` owns the Bubble Tea program and retains pending worker reads.
Process cancellation enters the same cancellation/commit lifecycle as keyboard
shutdown. A terminal input or rendering error still drains owned output and
terminal results and persists operation history before returning. Command-line
update checks and preparation inherit the process context and check cancellation
before helper handoff. Ordinary Windows TUI startup never replaces the installed
manager executable.

Windows custom configuration publication commits a full candidate plus intent
at the default locator before writing the custom file. The intent records the
prior custom-file digest. Load/reload/update finish interrupted publication under
the manager lock; a mismatched intervening edit leaves both files and the intent
for reconciliation. Locator publication failure is returned before the custom
file or in-memory candidate is accepted.

Independent ModernZ/uOSC downloads are prepared before Windows payload or Linux
package/Flatpak/Homebrew commit. A post-commit setup failure has an explicit
partial result in the Web/TUI history. Windows updates resolve UI selection from
the selected method/path record. Shortcut requests carry the stable app ID and
lease that app and its installation path.

Application-bundle recovery permits only relative links that resolve inside the
same bundle. It preflights every backup before removing live files and uses
`ditto` on macOS to preserve links, extended attributes and resource forks.
Other installer trees retain their stricter no-link policy.

Scaling migration, row saves and resets share a per-key browser queue. The
migration compares the last persisted value under the script-option lock, keeps
later edits visible, and rejects an intervening external edit. Installer test
doubles are compiled only in tests; package command construction has one active
implementation per supported installation path.

## Native discovery and installation destinations

macOS discovery reads mpv/IINA bundle metadata from `/Applications` without
launching player code. Version refresh now invokes discovery on macOS as well
as Windows/Linux. Externally detected apps remain unmanaged until explicitly
imported.

The Web app collects all platform install methods before filtering against
installed identities. Windows portable methods are hidden only for the selected
destination, so another existing MPV does not prevent a new custom install.
The Settings config path refreshes after destination save/reset. Linux/macOS
Settings explain the package-manager or `/Applications` destinations instead of
offering an unused binary-location input. Arbitrary executable selection on
those platforms remains outside this setting.

MPV git-describe commit suffixes are normalized for player update checks so a
build after a release tag is not treated as a prerelease of that tag. Manager
release SemVer comparison and signed-manifest freshness are unchanged.

Linux credential dispatch recognizes existing OS authorization through a bounded
noninteractive sudo check. The worker still invokes `sudo -n`, so expiration or
a narrower command policy fails without opening a terminal prompt. Stored
keyring validation remains the fallback when OS authorization is unavailable.

macOS MPV bundle installation stages UI prerequisites before replacing the
bundle, then commits UI/configuration after successful replacement. A permission
failure therefore leaves live configuration untouched; setup failures after
bundle replacement use the existing explicit partial-install outcome.

Mac bundle reinstall preserves an existing `mpv.conf` instead of reapplying the
recommended template. The installer checks for the file before UI preparation
can create a fresh stub; only a fresh install receives platform defaults.
Selected UI setup still makes its explicit OSC changes.

Package-backed installed-app records use the same executable or Flatpak launch
identity as discovery. A successful discovery can reconcile one known legacy
package-manager placeholder while preserving ownership and UI choices; multiple
possible locations and concurrently changed records remain untouched.

Package, Homebrew and Windows portable reinstalls retain an existing complete
mpv.conf, including profiles, comments and permissions. Windows checks the
selected installation's portable_config path before committing player files.
Platform defaults apply to fresh configs;
explicitly selected player UI setup still owns its OSC setting.

On a fresh MPV install, platform defaults are committed before the prepared UI
transaction reads the live config and applies its OSC choice. UI downloads still
finish before package or bundle commit begins.
