This is a learning project to create a technical solution for a real-time quiz feature for an English learning application. This feature will allow users to answer questions in real-time, compete with others, and see their scores updated live on a leaderboard.
- Frontend (Client): React.js for building interactive single page app.
- Backend: Express.js with TypeScript for REST APIs and WebSocket-based with Socket.io and Redis adapter for real-time updates.
- Database: PostgreSQL for storing quiz data, Redis for caching and live leaderboard management.
- Cloud Hosting: AWS for scalable infrastructure.
- Frontend (Client):
- Connects to the WebSocket server for real-time updates on the quiz and leaderboard.
- Fetches questions and posts answers through REST APIs.
- WebSockets Server:
- Manages the real-time communication between the users and the backend.
- Updates the leaderboard live as users submit answers.
- Manages quiz state (timers, score, active participants, etc.).
- REST API:
- Handles CRUD operations for quizzes, users, and leaderboard data.
- Fetches the questions for each quiz round from the database.
- Submits the user’s answers to be processed.
- Real-Time Quiz Logic:
- Contain main business logic such as timing, score calculation, and answer validation.
- Updates Redis with the real-time leaderboard and manages active players’ data.
- Redis:
- Used for storing and retrieving the live leaderboard data, reducing the load on the database.
- Keeps track of active participants and their current scores.
- PostgreSQL:
- Stores all persistent data, including questions, answers, users, quiz results, etc.
- User Joins
- The user logs into the app and joins a quiz session.
- The WebSocket connection is established with the server.
- The WebSocket server sends the initial quiz data (e.g., number of questions, current leaderboard) to the user.
- Quiz Starts
- The quiz server sends questions to all connected users simultaneously via WebSocket.
- A timer is managed on both the server and client to sync the quiz round duration.
- User Submits Answer
- The answer is sent to the WebSocket server.
- The WebSocket server places the answer in a Redis queue for async processing.
- Answer Processing
- The backend fetches the user’s answer from the Redis queue to validate and give scores.
- The score is updated in Redis (leaderboard).
- Leaderboard Update
- The live leaderboard is continuously updated to the frontend via WebSocket from Redis.
- Users can see the updated scores and ranks in real-time.
- Quiz Ends
- Final scores are calculated and stored persistently in PostgreSQL.
- The user’s quiz history performance can also be saved for future analytics.
- Frontend:
- React with Vite: For the interactive UI, handling real-time updates with WebSockets.
- WebSocket API: For real-time communication between clients and server.
- Backend:
- Express.js with TypeScript: For handling both REST API and WebSocket communication.
- Socket.io: For low-latency, bidirectional and event-based communication between a client and a server. It adds an abstraction on websockets transport with additional features like reconnection, broadcasting, etc.
- Redis adapter: Used with Socket.io to make use of Redis pub/sub mechanism.
- Redis: To store real-time leaderboard data with high-speed access.
- PostgreSQL: For storing quiz questions, users, and scores.
- Infrastructure:
- Docker and AWS ECR: For containerizing the backend services and managing container images.
- AWS Fargate and Application Load Balancer: Cloud hosting solutions for handling dynamic scaling and load balancing.
- Amazon RDS for PostgreSQL: for auto handling backups, monitoring, and scaling.
- Amazon ElastiCache for Redis: for managing Redis clusters.
The project will use npm workspace
as a monorepo for both backend and frontend apps.
├── README.md
├── apps
│ ├── backend
│ └── frontend
├── assets
│ └── system.png
And for the simplicity of a demo, I only implement a core feature which is Real-time Score Updates: Users' scores should be updated in real-time as they submit answers.
So the frontend will be a simple page built with React to allow user to input userId
and quizId
, click Join Quiz button and see the latest scores.
The action of submitting answer will be done through a POST endpoint /api/submit-answer
to call to the backend to calculate score for user.
// sample payload
{
"quizId": "quiz123",
"userId": "a",
"questionId": "question1",
"answerId": "answer3"
}
- Run
npm install
at rool to install dependencies. - Change directory to
apps/backend
then rundocker compose up --build
to start server and redis. - Change directory to
apps/frontend
then runnpm run dev
to start Vite app. - Open
localhost:5173
on browser > inputuserId
andquizId
to join. Should usequiz123
as quizId because it is hardcoded for testing with scores. - Open Postman to make a POST request to
localhost:3000/api/submit-answer
with the samplepayload above. - Verify scores updated on browser.
Note: Right-click the image and select "Open link in new tab" to view the video.