FEATURED PROJECT
Playlist Manager
A full-stack web application for organising and managing video playlists from different platforms across the internet.

Overview
Playlists is a project I built to explore full-stack web development and create a practical application around something I use regularly.
The application allows users to save videos from supported platforms into playlists, organise those playlists into collections, and manage their saved content from one place.
I built the frontend, backend API, database structure, authentication, validation, testing, and deployment pipeline.
Features
Create and manage video playlists
Load video link previews
Add videos from YouTube and TikTok
Search across playlists and videos
Reorder videos within playlists
Edit video titles and descriptions
Choose playlist cover images
Secure user authentication and resource ownership
Currently developing
Collections for organising playlists into groups
Search across collections
Upcoming features
Rich text editor for video notes
Instagram support
Technology
The project uses a Next.js frontend and an Express REST API, with PostgreSQL as the primary database and Redis for short-lived data.
Architecture
The frontend is built with Next.js and communicates with a separate Express REST API. TanStack Query is used to manage server state, including fetching, caching, mutations, and loading and error states.
The backend uses Prisma to interact with PostgreSQL. The database models relationships between users, playlists, videos, and collections while using database constraints to enforce relationships and uniqueness.
Redis is used for short-lived data that does not need to be persisted in PostgreSQL. Docker is used during development to run the project's supporting services locally.
Development and testing
The application is maintained across separate development, testing, and production environments. Integration and end-to-end tests use isolated test containers for postgres and redis to prevent test data from affecting other environments.
The development environment uses Dockerised dependencies to keep local development consistent, including services such as PostgreSQL, Redis, and a local mail server. This allows features involving external services such as email to be developed and tested locally without relying on production services.
Responsive Design
I designed the application to adapt across different screen sizes, with layouts, grids, and controls adjusting between mobile devices and large desktop monitors.


API design and type safety
I use Zod to define and validate API schemas in the backend. These schemas are also used to generate the project's OpenAPI documentation, keeping the API specification close to the validation rules used by the application.
The OpenAPI specification is then used to generate TypeScript types for the frontend. This gives the frontend a typed representation of the API contract instead of maintaining request and response types separately.
This approach helps keep the frontend and backend aligned as the API changes, while also providing validation at the API boundary and useful documentation for the available endpoints.
Authentication and security
Authentication uses short-lived access tokens and refresh tokens stored in secure HTTP-only cookies. Refresh tokens are rotated when they are used, with reuse detection to invalidate compromised sessions. Email verification, password reset and user login require two factor authenticated via a code sent to the users email.
API requests also verify that resources belong to the authenticated user before allowing them to be accessed or modified. Input is validated with Zod before it reaches the application logic.
Technical challenges
Authentication sessions
I implemented refresh-token rotation and reuse detection to manage longer-lived sessions while keeping access tokens short-lived.
Video metadata
Adding a video requires retrieving metadata from the supported platform. The backend validates the supplied URL and platform before retrieving the relevant metadata rather than allowing arbitrary remote requests.
Client-side server state
The application has several related pieces of server state, such as playlists and collections. I used TanStack Query to handle caching and mutations while keeping the UI synchronised after changes.
Database design
PostgreSQL is used as the primary database because the application has several connected resources. Users can have multiple playlists, playlists contain videos, and playlists can belong to multiple collections. Prisma is used to model these relationships and provide typed database access from the TypeScript backend.
What I learned
This project gave me experience building a complete application rather than working on an isolated feature. I worked across the frontend, backend, database, authentication, testing, and deployment.
It also gave me a better understanding of how decisions in one part of an application affect the rest of the system, particularly around API design, database relationships, authentication, and client-side state.
The project is still something I continue to improve as I find areas where the design or implementation can be made clearer.