This coding challenge is about a betting game for the soon-to-be happening European Championship 2024, which takes place in Germany beginning at the 14th of June 2024. The goal is to create a simple application that allows you and your friends to bet on the outcome of the games and to display the current standings of the participants.
Link: https://www.youtube.com/watch?v=qluAdJPu7o0&ab_channel=LeonLiang
This repository is a mono repository combining both client- and serverside services.
- client holds the Next.js frontend for end users and administrators.
- server holds the Go Echo backend.
- docker holds the Dockerfiles for all third party services:
- Keycloak as an open source identity and access management solution.
- Postgresql as an open source object-relational database solution.
- Kafka as an open-source distributed event streaming platform.
- Redis for managing task queues.
- Install & run Docker Desktop
- Install Task
- Copy
client/.env.local.exampletoclient/.env.local - Copy
server/.env.exampletoserver/.env - Run
task up - The frontend is available at http://localhost:3000. The backend is available at http://localhost:8000. The backend documentation is available at http://localhost:8000/swagger/index.html
- (Optionally) Run
task seedto seed the database with sample data
Use the following credentials to authenticate Swagger UI:
| OAuth2Implicit | |
|---|---|
| client_id | webclient |
Log in to the admin account using the details below:
| Username | Password |
|---|---|
| admin | 123 |
Example account created with task seed:
| Username | Password |
|---|---|
| leon.liang | 123 |
In order to implement real-time updates, I have decided to opt for a hybrid between websockets and polling. The websocket connection merely notifies the client that the scores have been updated, upon which the client's cache is invalidated. This prompts the client to re fetch the leaderboard standings from the server.
Additionally, to deal with the limitations of websockets, queries are refetched every 4 min as a contingency to ensure that the data is up to date.
The following steps have been taken to ensure the scalability of the system to millions of users:
-
In order to prevent polling the database for changes, and causing unnecessary load as we scale up the number of our server instances, I have decided to use Apache Kafka as a distributed queue to propagate changes to the scores across all server instances. These server instances would notify the client over a websocket that the scores have been updated, prompting them to re fetch the updated leaderboard, as shown in the diagram below:
-
Furthermore, I have bypassed the ORM for queries that could potentially yield a large number of results, opting instead to write raw SQL to take advantage of database-level optimizations.
-
I also make use of workers to process potentially time intensive jobs, which are backed by Redis. For example, to recalculate the scores of all users in the background, the workers divide the total amount of users between themselves and, once completed, notify all server instances over Kafka, prompting the clients to re fetch the leaderboard.
-
The leaderboard only fetches the users that are being displayed. When paginating, the additional users are fetched from the server and dynamically rendered into the current leaderboard.
- Due to time constraints, I was unable to write unit tests for server-side services.

