
Context
This started as a group capstone project for CODE University of Applied Sciences, assessed across several software engineering modules over one semester. I built and owned every part of it alone.
Spotify's API requires an approved production app with a live backend to get real OAuth access. That wasn't realistic for a graded assessment on a semester timeline, so the constraint from day one was: build a real frontend against a simulated backend, not a live service.
What I did
The frontend is split into three layers: Component, Hook, and Service, connected through a single apiFetch function. Hooks own data fetching (TanStack Query) and app state (Zustand); components stay dumb. That separation is what let me test each layer on its own terms: unit tests for hook logic, MSW for the network boundary, Playwright for what a user actually sees.
MSW (Mock Service Worker) started as a way to develop without hitting Spotify's real API. Once it was clear a live backend wasn't going to happen, I kept MSW running in the deployed build itself, using localStorage as the backing store. That turned a development workaround into the actual demo layer, and it's the reason the live site behaves like a working app even though there's no server behind it.
The clearest example of building for maintainability over just shipping something: five ranked-list views (top tracks, top artists, top albums, and so on) started as five near-identical components. I refactored them into one generic RankedList component, using TypeScript's structural typing so each data type just needs to match the right shape, with no shared base class or interface required.
Outcome
What's live at unwrap.rocks is a full single-page app: demo login, dashboard, customisable stats, all backed by MSW mocks rather than a real Spotify connection. There's a documentation site, a CI pipeline (lint, type check, tests) on GitHub Actions, and a test suite across unit, integration, and end-to-end levels.
This was a university assessment, not a shipped product. I never built or connected a real backend, so no real user's Spotify data has ever passed through it. If I picked it back up, the first thing I'd do is replace the mock layer with a real OAuth backend, then break up the Settings page, which grew into the one component doing too much, and close the accessibility and test-coverage gaps I flagged during assessment prep.