iOS MVP — The "Review & Approve" Loop (native SwiftUI)
Active spec. Governed by
00-ROADMAP.md. Last updated 2026-05-31. Target: iOS 26, native Swift / SwiftUI, Liquid Glass design language.
1. Why this wedge
The hardest part of music collaboration to do well on a phone is giving and closing feedback — listening on the go, dropping a comment at the exact second, and approving (or sending back) a version. It's mobile-native, it's the moment people talk about in conversations, and Sonnance's backend already supports ~80% of it. So the MVP is the consumption/feedback side, not creation.
Primary persona: the reviewer — artist, manager, or A&R — who receives work and must react. Job to be done: "When I get a new version, I want to listen and respond from my phone in under a minute, so the project keeps moving."
2. Screen flow (SwiftUI)
Sign in (Apple / Google / email)
└─▶ Home: Recent + Shared tracks ── push notification deep-links here ──┐
└─▶ Track detail: versions list, status │
└─▶ Player: waveform scrub, tap-to-comment @timestamp │
├─ Comments thread (replies, sections, resolve) │
└─ Approve / Request changes ───────────────────────┘
└─▶ Open share link (logged-out or guest) ─▶ Player (review as guest)3. Capability → live endpoint mapping
Routes verified against ctrl-audio-back/src/modules/**/*.controller.ts on 2026-05-31.
| MVP capability | Existing endpoint(s) | Gap to build |
|---|---|---|
| Sign in | POST /user/login, Google OAuth, POST /user/auth/apple, POST /user/refresh-token | ✅ |
| Recent tracks | GET /track/recent-access · mark: POST /track/recent-access/:trackId | — |
| Shared-with-me | GET /collaboration/recents, GET /collaboration/collaborator/tracks | — |
| Track + versions | GET /track/:id (audio[], audioFinal) | — |
| Waveform playback | signed blobUrl on the File (Azure supports HTTP Range) | GET /track/:id/stream (optional) |
| Comments (read) | GET /comment/file/:id | — |
| Comment @timestamp | POST /comment/track/:trackId/file/:fileId | — |
| Replies | POST /comment/:id/responses | — |
| Sections (markers) | GET /section/file/:fileId | — |
| Approve / request changes | track.releaseStatus fields exist | state-transition endpoint |
| Open share link (guest) | GET /link/:linkId → POST /collaboration/:linkId/add-user | — |
| Notifications (in-app) | GET /notification, SSE GET /notification/count | APNs push + POST /notifications/register-device |
Backend MVP surface: complete. approval endpoint ✅ · Apple Sign In ✅ · refresh tokens ✅ · APNs push ✅ (plug APNS_* env to deliver). iOS design system + screen retrofits: complete. DesignSystem/ (Theme/Typography/Tokens/Surfaces/Components/Portals) ✅ · SignInWithAppleView/RecentsView/TrackDetailView retrofitted ✅ · Lexend bundled ✅ (PPMonumentExtended .otf still needs manual Xcode drag-to-target). iOS player slice: complete. PlayerView (AVPlayer, scrub, version selector, silent-switch-safe) ✅ · PlayerBar (glass, .safeAreaInset) ✅ · Waveform (sine-bar, accent fill) ✅ · TrackPortalContent extracted ✅. (Aggregate /mobile/dashboard, /track/:id/stream, cursor pagination are optimizations, not blockers.)
Done (branch feat/track-release-approval): PATCH /track/:id/release-status (approve / request changes) · POST /user/auth/apple (native Sign in with Apple → app JWT) · POST /user/refresh-token (+ refreshToken on all auth responses; existing token unchanged, so web/NextAuth unaffected) · POST /notification/register-device + an APNs sender auto-fired from every createNotification (best-effort, no-op until APNS_* env set).
4. Liquid Glass design language (shared with web)
iOS 26's Liquid Glass is the primary aesthetic; the web app converges toward it (doc 20).
- Materials: lean on system glass —
.regularMaterial/.thinMaterial,glassEffect/.glassBackgroundEffect, and the iOS 26 toolbar/tab-bar glass. Don't fake it with manual blurs; use native materials so it stays correct in light/dark and with reduced-transparency. - Depth & hierarchy: floating glass surfaces over content; the player and approve/request bar are the focal glass elements. Content (waveform, artwork) supplies the color that the glass refracts.
- Motion: spring-based, content-driven; comment pins animate onto the waveform at their timestamp.
- Typography & color: Dynamic Type throughout; semantic colors so dark mode is automatic. Map the web's CSS color tokens (
globals.css) to iOS semantic colors so both clients share one palette. - Accessibility: honor Reduce Transparency / Reduce Motion / Increase Contrast — glass degrades to solid surfaces gracefully.
A shared token table (color, radius, spacing, type scale) should live here once the first SwiftUI screens exist, and be mirrored into
ctrl-audio-front/src/app/globals.cssduring the parity phase.
5. Client tech notes
- Project setup (decided 2026-05-31):
ctrl-audio-iosis a native Xcode project created in Xcode (App · SwiftUI · min iOS 26 · bundle idcom.sonnance.app· capabilities Sign in with Apple + Push Notifications). Agent guidance + conventions live inctrl-audio-ios/CLAUDE.md; setup steps in itsREADME.md. The auth/push surface it targets is complete. - Architecture: SwiftUI + async/await, a thin
APIClient(URLSession),Observableview models. - Auth: Sign in with Apple via
ASAuthorization→ POST theidentityToken(+fullNameon first sign-in) to the livePOST /user/auth/apple(tokenaud=APPLE_CLIENT_ID=com.sonnance.app); store the returned app JWT (and refresh token, once added) in Keychain; Face ID / Touch ID gate on launch. - Audio:
AVPlayerstreaming the signed CDN URL with Range; waveform pre-rendered or sampled client-side. - Push: APNs device token registered after login; notification payload carries
pointerId/type(mirror the existingnotificationschema, incl. the newTRACK_RELEASE_STATUS_UPDATEevent) to deep-link straight to the track/comment. - Offline (later): cache recents + downloaded audio; queue comments/approvals to sync on reconnect (see
13-MOBILE-CONSIDERATIONS.mddelta-sync patterns). - Repo conventions: add
ctrl-audio-ios/CLAUDE.md; sameorigin→GitHub,azuremirror convention as the other repos.
6. Explicitly out of scope for the iOS MVP
Creating spaces/projects, uploading/managing large files & attachments, billing/subscription flows, full search, trash management, analytics dashboards. These remain on web for now and arrive on iOS in the parity / creation phases (00-ROADMAP.md §7).