# 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
