pm-log.md 5.1 KB

PM Decision Log


2026-03-18 — Cloud Upload v1

Request: Add ability to upload local audio files from MixBoard to chad-music cloud library Decision: Approved — Option C (immediate rescan + background beets cron) Appetite: Small-Medium (1 server endpoint + nginx config + cron, 1 client service + UI) Scope: Single file upload via raw PUT, synchronous rescan, background beets enrichment. No dedup, no multi-file, no drag-and-drop. Handed to: @builder (pending) Key tradeoffs: Dropped dedup (beets handles implicitly), dropped multi-file, chose raw PUT over multipart (Woo memory risk), chose background beets over synchronous (avoids subprocess blocking + sudo on upload path). Enikesha needs to review/merge server PR. Deliberation: 3 models — Codex (scope), Gemini (challenge), Claude (requirements). All agreed on cutting dedup and multi-file. Gemini proposed skipping beets entirely; compromise was Option C.


2026-03-18 — Cloud Download for Export v1

Request: Download cloud tracks so they can be included in DAW export sessions (Audition, Bitwig, REAPER etc.) Decision: Approved Appetite: Small (~3-4 files changed, 1 new service, no new dependencies, no model schema changes) Scope: Export-scoped download only. DownloadService downloads cloud tracks to temp dir during export, then cleans up. Pre-flight confirmation dialog, partial-failure policy (export what you can, report missing). No standalone download UI, no persistent cache, no offline mode. Handed to: @builder Key tradeoffs: Chose export-scoped temp dir over persistent ~/Library/Caches/ cache (Codex + Gemini agreed). Chose partial-failure over all-or-nothing export (Claude recommended). Deferred standalone download feature to separate brief. No Track model schema changes — cache path is deterministic, no need to persist it. Deliberation: 3 models — Codex (scope), Gemini (challenge), Claude (requirements). Claude flagged critical prerequisite: ChadTrack→Track materialization — verified in code that Track.fromCloud() creates SwiftData @Model when adding to playlist. All three agreed on bounded concurrency (3-4), auth headers always, and export-scoped cleanup.


2026-03-18 — Offline Download v1

Request: Download cloud tracks for offline use — at song, album, and playlist level (like Spotify/Apple Music) Decision: Approved Appetite: Medium (~5-6 files changed, new model fields, playback routing change, UI components) Scope: Persistent downloads to Application Support. Track/album/playlist level. New model fields (localCachePath + downloadState enum). Playback routing changes from isCloud to hasPlayableLocalFile. AudioEngine for downloaded files with AVPlayer fallback for unsupported formats. Inline download indicators, album/playlist header buttons, context menu download/remove actions. Handed to: @builder Key tradeoffs: Chose Option C (separate localCachePath) over changing hasLocalFile predicate (protects export pipeline + all existing consumers). Application Support over Caches (user expectation of persistence). Included album+playlist batch in v1 (low incremental cost — DownloadService.downloadBatch exists). Deferred auto-download toggles, resumable downloads, OGG transcoding, storage management UI. AVPlayer fallback for OGG instead of wiring stb_vorbis into AudioEngine. Deliberation: 3 models + Designer. All 3 models converged on Option C, Application Support, explicit downloadState enum. Designer chose Direction A (inline icon buttons). Codex wanted track-only v1 — overruled since batch infra exists.


2026-03-18 — Track State Badge Unification (fast-lane)

Request: Track download state not visually clear — need distinct indicators for all 5 track states (local, cloud, downloading, downloaded, uploading) Decision: Approved (fast-lane, designer consulted) Appetite: Small (icon + color changes in 3 existing files) Scope: Changed downloaded icon from checkmark.circle.fill (.secondary) to arrow.down.circle.fill (.green). Cloud badge uses accent blue. Added orange arrow.up.circle.fill for uploading tracks (matched against UploadService state, no model changes). Local = no badge. Handed to: @builder (complete) Key tradeoffs: Kept download action in existing inline position (not artwork overlay). Upload badge is display-only check against UploadService filename — no new model field.


2026-03-18 — Album Covers for Cloud Tracks (backlog)

Request: Fetch and display album artwork for cloud tracks — either from Chad Music server (cover field exists in API) or external source (MusicBrainz, etc.) Decision: Backlog — not shaped yet Priority: Low — cosmetic enhancement, cloud browsing works without it


2026-03-18 — Live Radio / Synchronized Playback (backlog)

Request: Live radio / shared playlist mode — one person DJs (switches tracks), playback is synchronized for all listeners in real time. "Spinning mixes for everyone." (from Enikesha) Decision: Backlog — not shaped yet Priority: Low — cool feature but requires significant backend work (WebSocket/SSE sync, multi-client streaming). Phase 4+ territory.