LumaMusic

LumaMusic Technical Architecture

Status: Phase 1 baseline. Implementation details are validated during scaffolding and technical spikes.

Architecture overview

LumaMusic uses a TypeScript React Native client. Audius is the first remote music source. Provider-specific logic stays behind a music-source adapter so additional licensed providers can be added without rewriting screens or the player UI.

Data flow:

Proposed stack

Concern Initial choice Notes
Mobile app React Native + Expo Android and iOS
Language TypeScript Strict mode
Navigation Expo Router File-based routes
Audius integration Audius REST API Read-only endpoints; official SDK can be added if OAuth or write actions are needed
Server-state cache TanStack Query Search, trending, artist and playlist data
Client/player state Zustand Queue, playback UI, preferences
Persistence AsyncStorage Favourites and recent history; SQLite can be added for larger libraries
Audio expo-audio ~57.0.5 Native playback, background audio config, and lock-screen metadata
Testing GitHub Actions checks Dependency validation, TypeScript, and Android/iOS bundle exports; unit tests are a follow-up task
Builds EAS Build / Expo development builds Native modules require development builds

Initial package versions are pinned in package.json. CI and physical-device checks must validate the dependency set. Expo Go is not the target runtime for native audio testing.

Music-source adapter

Screens and domain logic must not call Audius endpoints directly.

Conceptual interface:

export interface MusicSource {
  searchTracks(query: string, page?: number): Promise<TrackPage>;
  searchArtists(query: string, page?: number): Promise<ArtistPage>;
  getTrendingTracks(options?: BrowseOptions): Promise<TrackPage>;
  getArtistTracks(artistId: string, page?: number): Promise<TrackPage>;
  getPlaylist(playlistId: string): Promise<Playlist>;
  getPlaylistTracks(playlistId: string, page?: number): Promise<TrackPage>;
  getPlayableStream(track: Track): Promise<PlayableStream>;
}

The Audius adapter will:

Domain models

Track

Artist

Playlist

QueueItem

State ownership

Audio engine decision

The initial audio engine is expo-audio ~57.0.5. Its config plugin is enabled for background playback and configures the required Android foreground service and iOS audio background mode. Real-device testing is still required before calling background playback production-ready.

The proof of concept must demonstrate on real Android and iOS devices:

  1. Background playback after app is backgrounded.
  2. Lock-screen / notification metadata and controls.
  3. Play, pause, seek, next, and previous.
  4. Audio focus and interruption handling.
  5. Bluetooth / headset controls.
  6. Queue continuity and recovery from stream errors.
  7. Compatibility with the chosen Expo SDK and development-build workflow.

Do not mark the audio experience production-ready until this test passes.

Audius API and credential handling

Current official Audius documentation describes:

Implementation rules:

Official references:

Playback lifecycle

The player is a single app-level service, not a component-local audio instance.

  1. UI dispatches a play request with a domain Track.
  2. Playback service asks the relevant MusicSource for an authorized stream.
  3. Audio adapter loads the stream and reports status events.
  4. Zustand receives normalized playback state.
  5. Mini-player, Now Playing, queue, and OS media controls render from the same state.
  6. On failure, service reports a typed error and follows an explicit queue policy.

Queue policy:

Network and failure handling

Security, privacy, and rights

Testing strategy

Unit tests:

Integration tests:

Device QA:

Phase gates