Solo project

RecordShop

A full-stack record shop application for browsing, searching and managing albums, built with a layered ASP.NET Core Web API, TDD, Entity Framework Core and a Blazor frontend.

  • C#
  • .NET 8
  • ASP.NET Core Web API
  • Blazor
  • Entity Framework Core
  • SQL Server
  • PostgreSQL
  • NUnit
The RecordShop album catalogue page, showing a grid of albums with title, artist and genre

A full-stack application for managing records

I developed RecordShop as my solo project during the Northcoders Enterprise Engineering Bootcamp. My goal was to apply the backend, database, testing and frontend skills I had learned by building a complete full-stack application with a strong focus on backend development.

Users can browse, search, add, update and delete albums through the Blazor frontend. The frontend sends HTTP requests to an ASP.NET Core Web API, which uses Entity Framework Core for data access. I originally developed the application with SQL Server and later migrated the deployed version to PostgreSQL hosted on Neon.

From requirements to implementation

Challenge

Managing responsibilities across the application

The application needed to handle HTTP requests, business logic and database access without placing all of these responsibilities in one class.

Approach

Using a layered backend architecture

I separated the backend into controller, service and repository layers, using dependency injection to connect them. The Blazor frontend communicates with the API through HTTP requests.

Core application capabilities

  • 01

    Browse and view albums

    Browse the complete album catalogue and open an individual album to view its details.

  • 02

    Search for albums

    Find albums by their ID, title or artist using search options provided through the frontend.

  • 03

    Manage the album catalogue

    Add new albums, edit existing album details and remove albums that are no longer required.

  • 04

    Persistence and health monitoring

    Store album data using Entity Framework Core. SQL Server is used for local development so data persists across restarts, since an in-memory option is also available but resets every time the application stops, and PostgreSQL is used for the deployed application. Health checks monitor both the API and its database connection.

Testing backend behaviour with TDD

I used test-driven development for much of the backend, writing tests before implementing the related functionality. NUnit tests cover the controller, service and repository layers, including CRUD operations, search behaviour and HTTP responses. Moq isolates dependencies, while repository tests use an in-memory database and Shouldly keeps assertions readable.

  • NUnit
  • Moq
  • Shouldly

Taking the application from local development to production

I deployed the RecordShop frontend and API to Railway using Docker. To support the live application, I switched the production database provider from SQL Server to PostgreSQL and configured the application to connect to a Neon-hosted database.

I also separated development and production configuration so the application can use the appropriate API and database settings for each environment. The live frontend is available through a custom subdomain of my portfolio domain.

I later added a GitHub Actions pipeline for both the frontend and backend, so every push automatically builds (and, for the backend, runs the test suite) before it reaches production.

  • Docker
  • Railway
  • PostgreSQL
  • Neon
  • GitHub Actions

What I developed through this project

I better understand how a request moves from the Blazor frontend through the controller, service and repository layers to the database. Testing each backend layer helped me learn how to isolate dependencies and verify behaviour, while deploying the application gave me practical experience of configuring an application for a production environment, migrating between database providers and troubleshooting issues that only became apparent outside local development.

An unhandled error has occurred. Reload 🗙