- About
- Requirements
- Project Setup
- Project Structure
- Run the Client App
- Usage
- Troubleshooting
- What I did not do
A case study for Lights On Heights. An auction chat application where users can join rooms, chat, and bid on auctions.
The API uses .NET, SignalR, RabbitMQ & MassTransit. The database used is Postgres. The repo includes a simple client application used to access the chat interface. The client was built with TypeScript, Express and Bun.
If you are interested in reading the code, I suggest reading on Vertical Slice Architecture first. However, you can also choose to dive in straight away. First, take a look at the configuration in Program.cs. After that, follow requests from any controller to their end. That should give you a good understanding of the application.
Also read BehindTheScenes.md
Ideally, you would need to have Bun installed to use the client application. You can install it here. If you don't have Bun, you can use npm & node.
To the run the API, you will need to have Docker installed.
To get started with this project, follow these steps:
Clone the repository to your local machine:
git clone https://github.com/henrychris/AuctionApp.git
Navigate to the project directory:
cd AuctionApp
-
Navigate to the client directory
cd client
-
Install dependencies
bun install
OR
npm install
-
Run the client application
bun start
OR
npm run node-run
-
You can access the client application at http://localhost:3000
-
Setup the appsettings.json file
A settings file was shared with you. Copy its contents and paste them into appsettings.json located in AuctionApp/src/AuctionApp.Host.
-
Navigate to the project root.
cd ..
-
Spin up the Docker containers
docker compose up
-
You can access the Swagger API documentation at http://localhost:5000/swagger/index.html
The project uses a mix of Vertical Slice Architecture and Clean Architecture. Concerns are separated into class libraries and features are grouped together.
- Application
- Features: the core functionality. Requests sent from controllers and their handlers.
- Contracts: interfaces to be implemented in the Infrastructure layer.
- Extensions: type, object or class extensions.
- Common
- Domain
- Entities
- Base: holds a base entity used by domain models
- Hub: holds entities used in SignalR hubs.
- Notifications: holds entities used for sending emails
- Enums
- ServiceErrors: errors are standardised in this project. They are defined here.
- Settings: classes that are used to fetch settings defined in configuration.
- Entities
- Infrastructure
- Middleware
- Data
- Hubs: holds the SignalR hubs.
- Filters
- Services: implementations of the contracts from the Application layer.
- Host
- Configuration: application configuration and setup.
- Controllers
- Templates: html templates used for emails.
- Program.cs
- Tests
- Application: contains the features. A feature consists of its requests, responses,validators and handlers.
- Common: a set of files shared across all modules.
- Domain: contains core domain entities, constants, enums and business logic.
- Infrastructure: contains external concerns like a database or external APIs. Any interfaces defined in the application layer (or other inner layers), should be implemented here.
- Host: The entry point. This layer configures and starts the application.
Some things have been setup to let you test the essential functions.
There are two users seeded into the DB
- Email: [email protected]. Role: Admin.
- Email: [email protected]. Role: User.
The password is 'testPassword123@' for both users.
The admin user can be used to:
- create, update, get and delete auctions.
- create and open rooms.
- start and end auctions in bidding rooms.
The regular user can:
- join and leave rooms.
- bid on auctions and send messages while in a room.
- view rooms with open auctions to join.
On loading the client, you will be greeted with a login page. If you want to receive an email on conclusion of an auction, I suggest that you choose register and provide a real email.
After login/registration, you will see a page with a list of rooms. There's only one room available, which is the one seeded into the database. You can join the room to place bids and chat.
Note: At this point, you might want to open a private or incognito window and login as a different user. With the other user, you can join the same auction room and chat/bid against one another.
When you have placed a sufficient amount of bids, you can end the auction. This means:
- all users will be kicked from the room
- the room will be closed and users will be unable to rejoin.
- the highest bidder will receive an invoice - if they provided a valid email address.
To end the auction, send a POST request on the route api/rooms/biddingRoom1/end
. Here, biddingRoom1 is the id of the default auction room.
-
If you forget to add appsettings before running the application, it will fail to start. Run
docker compose --build auctionapp.host
to rebuild the host image. -
Sometimes the RabbitMQ service starts slower than the others, this is normal. The API will retry until it connects to RabbitMQ.
I built the client app with basic HTML, CSS and TypeScript (transpiled to JS). As such, I didn't add toasts or notifications for error messages. However, all error messages are readable. By monitoring the browser console, you can check if anything went wrong.
You'll notice that on leaving a room and rejoining, any previous messages will be lost. I did not persist messages as the aim was to demonstrate a chat application, not to build WhatsApp.
To scale when using SignalR, developers use Redis to store info on connections or groups, instead of storing that info in memory (like I did in this application). When the Redis cluster is distributed, users would still be able to access their groups despite being connected to different servers, as each server can query Redis.
For testing websockets connections, chat, etc. This would take a lot of time to setup. I did not have the time.
You can access the Postman Collection here.