# Cloud Music Streaming — iOS Port Spec

## Overview
Port the Chad Music cloud streaming feature from macOS MixBoard to iOS MixBoard. Users connect to a self-hosted Chad Music REST API server (Tailnet) to browse and stream their cloud music library. Cloud tracks can be mixed into the same playlists as local tracks.

## Architecture

### New Files (5)
| File | Location | Purpose |
|------|----------|---------|
| ChadMusic.swift | Models/ | API response models (ChadCategory, ChadAlbum, ChadTrack, ChadStats, ChadCategoryType) |
| ChadMusicAPIClient.swift | Services/ | HTTP client — Bearer auth, URL composition, JSON decoding |
| StreamingPlayer.swift | Services/ | AVPlayer-based streaming (separate from AVAudioEngine) |
| KeychainService.swift | Services/ | Keychain wrapper for API key storage |
| CloudBrowserView.swift | Views/ | Browse categories → albums → tracks with play/add-to-playlist |

### Modified Files (6)
| File | Changes |
|------|---------|
| Track.swift | Add `isCloud`, `cloudStreamPath`, `cloudTrackId` + `fromCloud()` factory |
| PlayerViewModel.swift | Add StreamingPlayer, dual-source routing, cloud transport |
| SettingsView.swift | Add "Chad Music" section (URL, API key, test connection) |
| ContentView.swift | Add cloud browser sheet trigger |
| MiniPlayerView.swift | Buffering indicator, cloud icon |
| MixBoardApp.swift | Bump DB reset to dbResetV7 |

### How It Works
1. User enters server URL + API key in Settings → Chad Music
2. CloudBrowserView fetches categories/albums/tracks from the API
3. Tapping a cloud track → PlayerViewModel routes to StreamingPlayer (AVPlayer)
4. "Add to Playlist" creates a Track with `isCloud=true` in SwiftData
5. Playing a cloud Track from a playlist → PlayerViewModel detects `isCloud`, builds stream URL, uses StreamingPlayer
6. All transport controls (play/pause/seek/skip/next/prev) route based on `isCloudPlayback` flag

### Navigation Pattern
CloudBrowserView is presented as a **sheet** from a toolbar button in PlaylistListView — consistent with the existing Library/Settings sheet pattern.

### DB Migration
Nuclear reset approach (existing pattern): bump `dbResetV6` → `dbResetV7` to force schema recreation with new Track fields.
