Skip to content

Specimen / Fullstack web app2024

Retro Player.

A personal music library in the browser: upload your MP3s once, then log in from any device to play, rename or delete them. React on the front, an Express API behind it, Google Drive for the files and PostgreSQL for the data.

  • React
  • Express
  • PostgreSQL
  • Google Drive API
  • Supabase
  • Vite
  • React Router
  • Multer
  • Render
> View the code (opens in a new tab)
Context
Final project, Fullstack Development course at CEI
My role
Solo, from interface to database and deployment
Timeline
June – July 2024 (about 4 weeks)
Platforms
Web app + REST API
The Retro Player library: a dark screen with a floating player card showing “Just Live – Original” at 0:00 of 6:59 with loop, previous, pause, next and shuffle buttons, over a canvas of white dots joined by thin lines. Below, a purple upload bar and a list of six songs, each with edit and delete buttons.
The library: the player floats over a live canvas, the user's songs are listed below.

The challenge

The brief for my Fullstack course's final project was a full CRUD application (create, read, update, delete) built with a front-end framework. I chose React.

I wanted to build something I would actually use: my own music library in the browser. Upload my MP3s once, then log in from any device and play, rename or delete them.

That meant three things I had never done before: build an audio player from scratch, work with the Google Drive API, and find somewhere free to keep large audio files that a web app could stream back.

From play button to database

  1. Step 01 / 05

    Start with the player

    The player was the riskiest part, so I built it first, with a few local MP3s and no backend at all. Playback runs on a single browser audio element kept in React state, so changing track swaps the source instead of creating a new player.

    Within a week it had play and pause, previous and next, loop and shuffle, autoplay of the next song, a time readout, and a custom seek bar that shows how much of the song has played and how much has already downloaded.

    Close-up of the player card: the song title and time, a purple progress bar with a round handle, and five round buttons for loop, previous, pause, next and shuffle.
    The player card: seek bar with played and buffered ranges, and the five controls.
  2. Step 02 / 05

    Find a home for the audio

    Audio files are too big for a free database, so I researched where to put them and chose Google Drive, reached through a service account. On a user's first upload, the API creates a folder just for them and stores every song there.

    Browsers can't play a Drive file directly from another site, so I added a small proxy endpoint: the player asks my API for a song, and the API streams it from Drive with the right headers. The database only stores that proxy link.

  3. Step 03 / 05

    Build the API

    The backend is a Node.js and Express REST API with 8 endpoints for login, the track list, upload, edit, delete and the audio proxy. Uploads arrive as a multipart form handled by Multer, in memory, so nothing is written to the server's disk.

    Before saving, the API reads the song's ID3 tags, so title and artist fill themselves in. Deleting a song removes it from both Drive and the database, so the two never drift apart.

    System diagram. A React app in the browser fetches from an Express server hosted on Render. The server sends files to Google Drive and queries PostgreSQL on Supabase; audio streams back from Drive through the server to the browser. Below, five steps: upload, read tags, store, index, play.
    How a song travels: from the upload form to Drive and the database, and back to the player.
  4. Step 04 / 05

    Make it someone's library

    On the front end, React Router separates the login screen from the library, and a React Context shares who is logged in across the app. The API keeps a session per user, so each person only loads their own songs.

    Each row in the library can be played with a click, edited in place (title and artist become two inputs and a save button) or deleted. The list updates right away, without reloading the page.

    The login screen: the title RETRO PLAYER above a dark card with a username field filled in with Max_steel, a password field and a purple log in button.
    Login: one card, nothing else on screen.
    The song list with the first row in edit mode: it turns purple and shows two text inputs, “Just Live – Original” and “Betoko”, with a save button on the right.
    Editing a song in place: title and artist become inputs, the edit button becomes save.
  5. Step 05 / 05

    Ship it and keep it running

    The API was deployed to Render and connected to a cloud PostgreSQL database over SSL. Both repositories are commented throughout and have a README that explains setup, environment variables and every endpoint.

    The database has since moved to Supabase, whose free tier keeps the project online at no cost. Because the API talks plain PostgreSQL, the move only meant new connection settings.

    Halfway through the project my laptop died. Everything was already on GitHub, so I cloned the repositories on another machine and carried on the same day.

If I built it today

Retro Player was my first complete fullstack app, and I'm proud of it. Looking back with more experience, this is what I would change first:

  • PasswordsHash them with bcrypt, or hand sign-in to Supabase Auth, instead of comparing them as stored.
  • Access controlCheck the session on every request, so a user can only read or change their own songs.
  • File storageMove the audio to Supabase Storage with short-lived signed links, which removes the Drive proxy.
  • Database connectionsShare one connection pool across requests instead of opening a connection per query.
  • ConfigurationRead the API address and the session secret from environment variables, not from the code.

None of these change what the app does. They change how safely it would run with real users, which is the difference between a class project and a product.

The result

A working fullstack product, built solo in four weeks: from the play button down to the database, and still online today.

8REST endpoints
Login, library, upload, edit, delete and the audio proxy.
2Repositories
A React front end and an Express API, both documented.
~4Weeks
From an empty repository to a deployed app.
0Lines lost
My laptop crashed mid-project; Git and GitHub had everything.

Need a web app built end to end, from the database to the play button? Let's talk.

Next specimen / Virtual exhibition2024Humanimalidad