CASE STUDY / MOBILE MEDIA

MusicFy

Prototype complete

From bare React Native to a complete music playback path

A full-stack mobile music app built without Expo. MusicFy uses React Native, React Navigation, Redux and React Query for the mobile experience, while React Native Track Player and RNFS handle cross-screen playback, queues and local audio files.

01 / MOBILE PRODUCT SCOPE

Why design the mobile product around playback?

MusicFy was not just about putting a list of songs on a phone. Starting with a bare React Native setup meant defining boundaries between the player, navigation, authentication, user-generated content and the device file system. The product needed registration, email verification, uploads, playlists, favourites, listening history and follows while keeping playback alive as users moved between screens.

  • Integrate native React Native modules without relying on Expo
  • Keep the player, queue, mini player and system media controls working across screens
  • Separate Redux global state, React Query server state and device file caching
  • Cover authentication, uploads, playlists, favourites, history and follows in one mobile product

02 / PLAYBACK FLOW

How a track moves from the content API to the device

  1. 01

    Authenticate

    The app restores a token from AsyncStorage, calls /auth/is-auth to validate the session, and lets the auth slice select the auth or tab navigator.

  2. 02

    Discover

    Home uses React Query to fetch latest uploads, recommendations, playlists and recently played tracks without coupling server data to navigation state.

  3. 03

    Cache

    Before playback, useAudioController checks the RNFS cache directory. On a miss it starts a background download from the API audio URL before handing the file to the player.

  4. 04

    Queue

    AudioData is mapped into a Track Player queue that owns the current track, previous and next actions, playback rate, progress and artwork.

  5. 05

    Control

    MiniAudioPlayer, AudioPlayer and playbackService share the same Track Player, so screen controls and Android media controls operate on one playback path.

  6. 06

    History

    The playback service listens for progress events and sends audio, progress and date to /history, bringing recently played and listening history back to the server.

03 / ENGINEERING DECISIONS

Mobile decisions visible in the code

  1. 01

    Create a continuous playback boundary with Track Player

    ImplementationInitPlayer configures Track Player capabilities and Android media notifications. useAudioController manages queues and playback operations, while playbackService handles remote play, pause and skip events.

    ValuePlayback no longer belongs to one screen: users can move between Home, Profile and content views while the same playback path continues.

  2. 02

    Separate two kinds of state with Redux and React Query

    ImplementationAuth, player and playlist modal state live in Redux. Latest uploads, recommendations, favourites, history, public profiles and follows are fetched through React Query hooks.

    ValueCross-screen state such as the active track and authentication has a stable home, while server data that changes over time is not copied into the global store.

  3. 03

    Keep device caching in the file system, not a state container

    ImplementationRNFS derives a cache path from the public ID, checks for an existing file and downloads the remote audio on a miss. AsyncStorage is used for the authentication token rather than audio binaries.

    ValueAudio data does not enter Redux or AsyncStorage, reducing memory and serialisation pressure while leaving a clear local boundary for replay.

  4. 04

    Use nested navigators to express the mobile information hierarchy

    ImplementationAuth, Home, Profile and upload flows are composed through AuthNavigator, HomeNavigator, ProfileNavigator and TabNavigator. AppView renders the shared player outside individual screens.

    ValueNavigation follows product areas and the common player is implemented once instead of being rebuilt by each screen.

  5. 05

    Connect user-generated content into a complete product loop

    ImplementationAudioForm combines Yup, native document/image pickers and multipart upload. The Express backend uses Formidable, Cloudinary and MongoDB for audio, artwork, playlists and user relationships.

    ValueThe project is more than a player demo: authentication, creation, media publishing, favourites, history and social relationships form an operable product flow.

  6. 06

    Start recommendations with explainable rules

    ImplementationThe backend extracts categories from a user’s recent history, filters matching audio and uses a scheduled task to generate automatic playlists. The frontend consumes the result through React Query.

    ValueWithout introducing a machine-learning stack, the project establishes an understandable recommendation entry point that can be evaluated with real usage data.

04 / CURRENT BOUNDARIES

A complete prototype still has engineering edges to close

The mobile playback and content flows form a working product skeleton. Download timing, token lifecycle, history writes and backend constraints are the most valuable next improvements.

  1. High priority

    The download helper does not fully await completion

    downLoadFile starts RNFS.downloadFile but does not return or await its promise, while onAudioPress continues into the playback flow. On a cold start or weak network the file may not be ready when Track Player receives it; await, failure fallback and duplicate-download control should be added.

  2. High priority

    JWT lifecycle and mobile storage need strengthening

    The token is stored in AsyncStorage and the server signing path does not visibly define expiry, rotation or bounded device-token cleanup. This is suitable for prototype validation, but not a complete production session-security story.

  3. Medium priority

    Playback writes and the history model need to converge

    playbackService writes /history from progress events, while the history document maintains both last and an embedded all array. Event frequency, idempotency, array growth and offline compensation need a deliberate design before the catalogue grows.

  4. Medium priority

    Media uploads and relationship writes need stronger server constraints

    Formidable file limits, cross-document consistency between favourites and audio likes, transaction boundaries for follows, and access checks for private playlists all have room to converge.

  5. Medium priority

    Localisation, testing and observability are not complete capabilities yet

    The current code does not show an integrated react-i18next layer, Redis/CDN, push notifications or a full test suite. Recommendations are history-and-category rules, not a machine-learning recommendation system.

05 / NEXT ITERATION

What to improve next

  1. 01

    Make audio downloads awaitable, cancellable and retryable, with cache cleanup and concurrent-request deduplication

  2. 02

    Add short-lived JWTs, refresh rotation, revocation and device limits, then evaluate safer credential storage

  3. 03

    Batch or throttle history writes, cap document growth and design offline event compensation

  4. 04

    Add upload limits, unique constraints and MongoDB transactions, with one authorization rule for private content

  5. 05

    Add unit and integration coverage for playback, uploads, auth and recommendations before evaluating Redis, a CDN or push notifications