Github link: https://github.com/AnnaRandeberg/PG3402
The goal of this project is to create a user-friendly learning app designed for middle school students. We've all experienced how reading school textbooks can sometimes feel boring, and it can be difficult to keep track of multiple subjects and curriculum demands. As the curriculum grows more challenging, our aim is to make learning easier and more enjoyable for the next generation.
Our solution is to turn learning into a fun, game-like experience. The app will feature quizzes subjects, with users receiving scores for each quiz. A leaderboard will allow students to compete with classmates, adding a layer of friendly competition that can be a strong motivator. Additionally, users will have access to making flashcards.
This project leverages microservice architecture to provide scalability, maintainability and flexibility for future enhancements. Key components include services for managing quizzes, scores, user authentication and flashcards, with RabbitMQ handling asynchronous communication and Consul ensuring service discovery.
To build the project, navigate to each service directory (pg3402/loginservice
, pg3402/flashcardservice
, pg3402/quizservice
, pg3402/scoreservice
, pg3402/gateway
) and run the following command in the terminal:
mvn clean install
Once all services are built, navigate to the pg3402/docker
folder and run the following commands (ps remember to have Docker Dekstop running in the background):
docker-compose down
docker-compose up --build -d
This will start all services as Docker containers.
- Open Consul to check the status of all services:
http://localhost:8500/ui/dc1/services
Wait until all services are displayed as green in Consul:gateway
loginservice
flashcardservice
scoreservice
quizservice
consul
Each service has an H2 database accessible through the following links:
Service | URL | JDBC URL | Username | Password |
---|---|---|---|---|
Login Service | http://localhost:8084/h2-console | jdbc:h2:file:~/learningapp |
user |
(none) |
Quiz Service | http://localhost:8081/h2-console | jdbc:h2:file:~/learningapp |
user |
(none) |
Flashcard Service | http://localhost:8087/h2-console | jdbc:h2:file:~/learningapp |
user |
(none) |
Score Service | http://localhost:8082/h2-console | jdbc:h2:file:~/learningapp |
user |
(none) |
RabbitMQ is used for asynchronous communication between services.
Access the RabbitMQ Dashboard at:
http://localhost:15672/
Username: guest
Password: guest
The system consists of the following microservices:
- Login Service (Port: 8084)
- Quiz Service (Port: 8081)
- Flashcard Service (Port: 8087)
- Score Service (Port: 8082)
- Gateway (Port: 8080)
Communication types:
- Synchronous communication: REST calls via Gateway.
- Asynchronous communication: RabbitMQ for message passing.
Below is a list of user stories that allow an examiner to assess the functionality developed in the project. These user stories represent key scenarios that demonstrate the features implemented in the application. Can be used on postman.
As a middle school student,
I want to register/login,
So I can take quizzes and access the learning app.
-
Register
Method:POST
URL:http://localhost:8084/api/users/register
Body:{ "email": "kally@gmail.com", "rawPassword": "secret123", "firstName": "Kally", "lastName": "Kai" }
-
Login
Method:POST
URL:http://localhost:8084/api/users/login
Body:{ "email": "kally@gmail.com", "rawPassword": "secret123" }
Description: Users can register and log in using a secure process. Passwords are hashed to ensure data security and prevent plaintext storage in the database.
As a user of the learning app,
I want to link with friends,
So I can see their quiz scores, compare progress, and motivate each other to improve.
-
View All Users
Method:GET
URL:http://localhost:8084/api/users
-
Search for a Specific User
Method:GET
URL:http://localhost:8084/api/users/search/Kally/Kai
Description: Users can view all registered users or search for specific friends using their first and last name. Sensitive information remains protected, as only non-critical data is displayed.
As a middle school student,
I want to take quizzes for various subjects and topics,
So that I can learn different subjects in a more engaging way and track my progress.
-
View All Available Quizzes
Method:GET
URL:http://localhost:8081/quizapi
-
Start a Quiz
Method:POST
URL:http://localhost:8081/quizapi/1/start
Body:{ "email": "kally@gmail.com" }
-
Submit Answer
Method:POST
URL:http://localhost:8081/quizapi/1/answer
Body:{ "email": "kally@gmail.com", "questionId": "1", "answer": "4" }
Description: Students can view available quizzes, search for quizzes by ID, and submit answers. The system provides immediate feedback.
As an admin,
I want to create quizzes,
So that students can take them and test their knowledge.
-
Create Quiz
Method:POST
URL:http://localhost:8081/quizapi
Body:{ "email": "admin@gmail.com", "title": "Science Grade 9", "chapter": "Fungi and Leaves", "subject": "Science", "questions": [ { "questionId": 1, "questionText": "What is a fungus?", "correctAnswer": "A type of fungal structure" } ] }
-
Find Quiz by ID
Method:GET
URL:http://localhost:8081/quizapi/quiz/1
Description: Only users with the admin email (admin@gmail.com
) can create new quizzes. Unauthorized users are denied access.
As a student,
I want to see my quiz scores,
So I can understand my performance and track my progress.
-
View Scores for All Users
Method:GET
URL:http://localhost:8082/scores
-
View Score for a Specific User
Method:POST
URL:http://localhost:8082/scores/email
Body:{ "email": "kally@gmail.com" }
Description: Users can view their quiz scores and compare progress with others.
As a user,
I want to practice for my quizzes using flashcards,
So that I can improve my scores.
-
See Flashcards for a Specific Quiz
Method:GET
URL:http://localhost:8087/flashcards/quiz/1
Description: By integrating with the QuizService, users can fetch flashcards directly tied to quizzes. This promotes seamless interaction between services and demonstrates RESTful communication.
-
Create a Flashcard
Method:POST
URL:http://localhost:8087/flashcards
Body:{ "questionText": "Hva er 5 + 3?", "answer": "8" }
Description: This functionality allows users to create their own flashcards, similar to how they would in real life when studying. It supports personalized learning and adds interactivity to the application.
-
Retrieve All Flashcards
Method:GET
URL:http://localhost:8087/flashcards
Description: Retrieves all existing flashcards created by users.
Our project is well-suited for a microservices architecture because it addresses many challenges while making the system scalable and flexible. A monolithic architecture would not be ideal, as our system is divided into multiple services with a clear separation of responsibilities.
- Scalability: If the QuizService experiences heavy traffic, it can be scaled independently without affecting other services.
- Maintainability: Each service handles a specific functionality, making the code organized and easier to maintain.
- Resilience: Errors in one service do not affect the entire application, improving system robustness.
- Collaboration: With two developers working on this project, microservices allowed us to work on different services simultaneously without interfering with each other or the overall system.
For the database, we initially used Flyway for database migrations, as we had learned it in our backend programming course. However, we encountered numerous issues due to migration file conflicts. To avoid these conflicts and simplify database management, we switched to Spring Boot's built-in database initialization using data.sql
. This approach provided better control and reduced complexity in our project.
-
Synchronous Communication (REST Calls):
- FlashcardService → QuizService: FlashcardService retrieves quiz data from QuizService using
RestTemplate
to make direct HTTP calls. - API Gateway → All Services: The API Gateway forwards incoming REST requests to the appropriate microservices using Spring Cloud Gateway.
- FlashcardService → QuizService: FlashcardService retrieves quiz data from QuizService using
-
Asynchronous Communication (RabbitMQ):
- LoginService → RabbitMQ: When a new user is created, a
UserCreatedEvent
is published to theuser.queue
. - QuizService → RabbitMQ: After a quiz is completed, a
QuizCompleteEvent
is published to thequiz.complete
queue. - ScoreService ← RabbitMQ: ScoreService listens to the
quiz.complete
queue to update user scores accordingly.
- LoginService → RabbitMQ: When a new user is created, a
-
Candidate 81: Responsible for FlashcardService and QuizService.
-
Candidate 70: Responsible for ScoreService and LoginService.
-
Docker and Gateway: Shared responsibilities.
Additionally, we used a lot of pair programming to solve problems, ensuring both of us contributed to all services equally. Each of us took responsibility for 50% of the workload, with a strong emphasis on collaboration to ensure that we were both actively involved in all parts of the project.
- Data Initialization: Spring Boot - data.sql
- Microservice Diagram Creation: Kroki.io
- Project Inspiration: Bogdan Marculescu's Microservices Project