# Architecture This repository is a native macOS 26 SwiftPM internet radio app. The app is split into a small app target and a larger shared core target. ## Top-Level Structure - `Package.swift` Defines: - `BearWaveCore` - `BearWave` - `BearWaveChecks` - `Sources/BearWaveApp` App entrypoint and scene wiring - `Sources/BearWaveCore` Application logic, models, services, stores, views, and resources ## Main Runtime Objects ### `BearWaveApp` File: - [Sources/BearWaveApp/BearWaveApp.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveApp/BearWaveApp.swift) Responsibilities: - create the root `AppModel` - host the main `WindowGroup` - host `MenuBarExtra` - host `Settings` - manage window sizing and mini-player mode - define app commands such as play/pause and `Cmd+M` This file should stay thin. It is scene setup, not business logic. ### `AppModel` File: - [Sources/BearWaveCore/App/AppModel.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/App/AppModel.swift) Responsibilities: - own the major runtime subsystems - coordinate radio, playback, settings, and artwork - restore launch state - route user actions like `play(_:)`, `setVolume(_:)`, and `quit()` Owned objects: - `SettingsStore` - `StationLibrary` - `PlaybackController` - `StationArtworkLoader` - `NowPlayingArtworkResolver` `AppModel` is the top-level coordinator. It should not become a dumping ground for unrelated view logic. ## Domain Store ### `StationLibrary` File: - [Sources/BearWaveCore/Stores/StationLibrary.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Stores/StationLibrary.swift) Responsibilities: - load and store browse pages - manage global search - manage favorites - manage recents - manage manual stations - manage station folders - persist radio-related state Important behaviors: - search is global, not page-local - search results live on a dedicated `Search Results` page - search ranking is stricter than raw Radio Browser substring matching - folders are persisted entities and not just transient UI state ## Playback and Metadata ### `PlaybackController` File: - [Sources/BearWaveCore/Services/PlaybackController.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/PlaybackController.swift) Responsibilities: - own the shared `AVPlayer` - manage playback state transitions - play radio streams - expose explicit playback states - read timed metadata through `AVPlayerItemMetadataOutput` - update `MPNowPlayingInfoCenter` - handle artwork updates Important invariants: - do not collapse playback state to only `isPlaying` - metadata handling must tolerate streams that provide nothing useful ## Network Services ### `RadioBrowserClient` File: - [Sources/BearWaveCore/Services/RadioBrowserClient.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/RadioBrowserClient.swift) Responsibilities: - call Radio Browser endpoints - decode station payloads - provide search support - cache API responses on disk ### Artwork Services Files: - [Sources/BearWaveCore/Services/StationArtworkLoader.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/StationArtworkLoader.swift) - [Sources/BearWaveCore/Services/NowPlayingArtworkResolver.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/NowPlayingArtworkResolver.swift) Responsibilities: - load and cache station favicons - resolve playback artwork for Now Playing - fall back through available artwork sources when metadata is incomplete ## Persistence ### `PersistenceStore` File: - [Sources/BearWaveCore/Stores/PersistenceStore.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Stores/PersistenceStore.swift) Responsibilities: - JSON persistence for: - favorites - manual stations - groups - playback state - manage application support and cache directories - import legacy Linux config files on first run where applicable ## UI Structure Main views: - [Sources/BearWaveCore/Views/ContentView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/ContentView.swift) - [Sources/BearWaveCore/Views/SidebarView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/SidebarView.swift) - [Sources/BearWaveCore/Views/StationListView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/StationListView.swift) - [Sources/BearWaveCore/Views/StationDetailView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/StationDetailView.swift) - [Sources/BearWaveCore/Views/PlayerBarView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/PlayerBarView.swift) - [Sources/BearWaveCore/Views/MiniPlayerView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/MiniPlayerView.swift) - [Sources/BearWaveCore/Views/MenuBarContentView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/MenuBarContentView.swift) - [Sources/BearWaveCore/Views/SettingsView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/SettingsView.swift) High-level behavior: - `ContentView` switches between full app UI and mini-player mode - sidebar chooses radio pages and folders - station list and station detail cover browse, search, favorites, recents, manual stations, and folders - `PlayerBarView` stays focused on radio playback controls ## Data Flow 1. User selects a page or search query 2. `StationLibrary` loads data through `RadioBrowserClient` 3. UI renders visible stations 4. User starts playback 5. `AppModel` records playback and forwards to `PlaybackController` 6. `PlaybackController` updates playback state, metadata, artwork, and Now Playing ## Build and Packaging Notes - The current app bundle is staged by `script/build_and_run.sh` - SwiftPM resource bundles are copied manually into `dist/BearWave.app` - Localization directories are copied manually as part of staging - This is good enough for local development but not yet a polished release pipeline ## Architectural Guardrails - Keep the app native-first for macOS - Keep search global and independently modeled - Keep explicit playback states - Keep `BearWaveApp` thin - Do not move product behavior into ad hoc view code when it belongs in a store or service