A comprehensive service that can be integrated by clients to manage all aspects related to their entities.
- Build and Run the Service
- About the Client App
- Unit Tests
- Integration Tests
- System Tests
- End-to-End Testing Checklist
- Multiple Simultaneous Client Instances Tests
- Style Checker
- Bug Finder
- API Documentation
- Change In API Implementation From Proposal
- Persistent Data Storage
- Third Party Code References
- Ensure you have Docker installed on your machine.
- Ensure you have Docker Compose installed.
If you haven't already, clone the repository to your local machine.
Navigate to the directory containing the Dockerfile
and run:
docker build -t ems-image .
This will build a Docker image named ems-image
from the Dockerfile
in the current directory.
Navigate to the directory containing the docker-compose.yml
and run:
docker-compose up
Then give it a couple of minutes because MySQL might take a little while to be ready, especially on the first run when it's initializing data.
Then, the service will run on http://localhost:8080/ems
.
- If you encounter port conflicts (e.g., port
8080
is already in use), either stop the service using the port or bind the application to a different port when running the Docker container. - Ensure your Docker daemon is running before executing Docker commands.
- Check application logs in the Docker container for any issues related to the Spring Boot application.
Our client app is an application tailored for pre-K school internal management. It provides a centralized platform for administrators, teachers, and other school roles to collaborate and manage various aspects of the pre-K education experience. Key Features:
-
Announcement board: the announcement board uses CRUD APIs from /announcement in our service. Pre-K school teachers and administrators can post announcements, which will be visible to all Pre-K school employees. The announcement board serves as an effective notification platform.
-
Role management: the authorization of each role can be customized. This functionality uses /role/list, /role/toAddOrUpdateRolePage, /role/delete, and /module/toAddGrantPage. The administrators or other authorized roles are able to manage the authorization of each role in the Pre-K school. They are also able to create/delete/edit each role. This role management functionality helps to manage the scope of roles within Pre-K school.
-
User management: users can be added, edited, or removed by authorized entities. The user management uses CRUD APIs from /user. The administrators or other authorized roles are able to manage all employees within the Pre-K school. This user management functionality provides the flexibility for adding new teachers or employees.
-
User setting: users are able to update their password. This functionality uses /updatePwd from /user in our service After login, individual can change the default password to their choice. This user setting helps Pre-K school individual to customize their password and provides data security.
The users of our app can have comprehensive role management and user management functionalities, while before they may only can communicate using their internal app.
Once you build and run the Service, the client app will run on http://localhost:8080/ems/index
automatically.
You can use our admin account to log in and use our client.
Username: admin
Password: 123456
Our front-end code files are stored under src/main/java/resources
.
You can make appropriate modifications or refactor the entire front-end.
If you want to develop more front-end functions, you can refer to our API Documentation.
./mvnw test -Dcheckstyle.skip=true -Dspotbugs.skip=true
If you want to generate a test coverage report, you can choose the following two commands:
./mvnw clean verify -Dcheckstyle.skip=true -Dspotbugs.skip=true
Clean old build artifacts, run tests, create the package, and install it to the local Maven repository.
./mvnw clean install -Dcheckstyle.skip=true -Dspotbugs.skip=true
Our unit tests have 99.54% code coverage. Codecov report
We employed the Big Bang Integration Testing approach, where the integration of multiple units are tested simultaneously. Then, the entire system is tested as a whole.
In this phase, we focused on two key integration. The first one is the interaction between Controller Layer and Service Layer, which involved mocking the HTTP request and allow the service layer to process. The second one is the interaction between Service Layer and Repository Layer, which involved mocking the database. After these targeted tests, we proceeded to the External Integration Test, where we examined the entire service through RESTful API testing.
Our service has two external components, which are RESTFul API and the MySQL database. Thus, we tested the interaction between the Mapper files and the external MySQL database. Next, we used @RestTemplate to call each API endpoints, where the service is tested as a whole.
Both Internal and External Integration Tests are located in src/test/java
, which will be run automatically during CI. The folder containing external integration tests is excluded for the 'mvn test' build during CI.
Please see details on below API Documentation section.
We use the Runner in Postman to mock multiple clients are sending requests simultaneously.
We performed several API functional and performance tests that may face multiple clients requesting and high concurrency. You can check details here.
Login: http://localhost:8080/ems/user/login
- Functional test (1000 iterations, 0ms delays)
- Setting: View Screenshot
- Result: View Screenshot
- Performance test (100 virtual clients, 1 min test duration)
- Setting: View Screenshot
- Result: View Screenshot
Get all users: http://localhost:8080/ems/user/all
- Functional test (1000 iterations, 0ms delays)
- Setting: View Screenshot
- Result: View Screenshot
- Performance test (100 virtual clients, 1 min test duration)
- Setting: View Screenshot
- Result: View Screenshot
Get all announcements: http://localhost:8080/ems/announcements/all
- Functional test (1000 iterations, 0ms delays)
- Setting: View Screenshot
- Result: View Screenshot
- Performance test (100 virtual clients, 1 min test duration)
- Setting: View Screenshot
- Result: View Screenshot
Please see details in E2E Testing Checklist
To ensure robust performance under high load, we used Apache JMeter for performance testing on key endpoints.
Our focus was on scenarios likely to experience heavy traffic:
- Concurrent User Logins: Tested the system's response to 100 simultaneous user logins View Screenshot
- Bulk Announcement Posting: Assessed system stability with 100 announcements posted concurrently View Screenshot
Alongside Apache JMeter tests, we conducted real-world scenario tests to validate our system's performance and responsiveness:
-
Manual Multi-Instance Testing: Simulated user activities by opening multiple browsers, logging in as different users, and performing actions like posting announcements and adjusting role assignments.
-
Real-Time Responsiveness: Verified that changes made by one user (e.g., role adjustments) were immediately reflected for other users, ensuring real-time data consistency and dynamic interaction.
We use CheckStyle with Sun Checks
./mvnw checkstyle:check
Our checkstyle results are clean. Checkstyle report
We use SpotBugs Bug Detector
./mvnw spotbugs:check
Our Spotbugs results are clean. SpotBugs report
To generate report, run ./mvnw clean compile site
Base URL: http://localhost:8080/ems
- Description: Display the login page.
- Frontend login page: View Screenshot
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
- Description: Display the main page of the service.
- Frontend login page: View Screenshot
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
- Description: Display the welcome pag.
- Frontend login page: View Screenshot
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
Base URL: http://localhost:8080/ems/user
- Description: Authenticate a user.
- Request Params:
userName
(String): The username of the user.userPwd
(String): The password of the user.
- Response:
UserModel
object for valid credentials. - Status Codes:
- 200 OK: Authentication successful.
- 400 BAD REQUEST: If
userName
oruserPwd
is empty, or if credentials are incorrect. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Login success: View Screenshot
- User does not exist: View Screenshot
- Username is empty: View Screenshot
- Incorrect password: View Screenshot
- Empty password: View Screenshot
- Description: Update the password of an authenticated user.
- Request Params:
userId
(Integer): The ID of the user.oldPassword
(String): The current password of the user.newPassword
(String): The new password for the user.repeatPassword
(String): Confirmation of the new password.
- Response: Success message for a valid request.
- Status Codes:
- 200 OK: Password updated successfully.
- 400 BAD REQUEST: If
userId
does not exist,oldPassword
is incorrect, or new passwords do not match/are empty. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Reset password success: View Screenshot
- Record does not exist: View Screenshot
- Original password is empty: View Screenshot
- Incorrect password: View Screenshot
- New password is empty: View Screenshot
- New password is same as old password: View Screenshot
- Repeated password is empty: View Screenshot
- New password and Repeated password is inconsistent: View Screenshot
- Description: Register a new user.
- Request Params:
userName
(String): The username of the user.email
(String): The email of the user.phone
(String): The phone number of the user.
- Request Body:
User
object. - Response: Success message for a valid request.
- Status Codes:
- 200 OK: User added successfully.
- 400 BAD REQUEST: If input parameters are invalid or missing, or if the username already exists.
- 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Add user success: View Screenshot
- Username is empty: View Screenshot
- Email is empty: View Screenshot
- Phone is empty: View Screenshot
- Description: Update an existing user's information.
- Request Params:
id
(Integer): The ID of the user.userName
(String): The username of the user.email
(String): The email of the user.phone
(String): The phone number of the user.
- Request Body:
User
object. - Response: Success message for a valid request.
- Status Codes:
- 200 OK: User updated successfully.
- 400 BAD REQUEST: If the
User
object is invalid, the user does not exist, or if the updated username already exists. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Update records success: View Screenshot
- Update user does not exist: View Screenshot
- Username is empty: View Screenshot
- Username already exists: View Screenshot
- Email is empty: View Screenshot
- Phone is empty: View Screenshot
- Description: Delete one or more users.
- Request Params:
id
(Integer): The ID of the user.
- Request Body: Array of user
ids
. - Response: Success message for a valid request.
- Status Codes:
- 200 OK: Users deleted successfully.
- 400 BAD REQUEST: If the
ids
array is empty or if any of theids
do not correspond to existing users. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Delete users success: View Screenshot
- Delete user does not exist: View Screenshot
- Delete user fail: View Screenshot
- User deleted proof: View Screenshot
- Description: Retrieve a list of users based on provided parameters.
- Request Params:
page
(Integer): The page number. Default: 1pageSize
(Integer): The number of users per page. Default: 10username
(String): The username to filter by. Optionalemail
(String): The email address to filter by. Optional
- Response: Map with user information.
- Status Codes:
- 200 OK: Request successful.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Get all users success: View Screenshot
- Description: Direct to the main user page.
- Response: A string representing the path the main user management page.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
- Description: Direct to the password management page.
- Response: A string representing the path to the password management page.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
- Description: Direct to the page for adding or updating a user.
- Request Params:
roleId
(Integer): The ID of the user to be updated, or null if adding a new user. Optional
- Response: A string representing the path to the view for adding a new user or updating an existing one.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
Base URL: http://localhost:8080/ems/role
- Description: Retrieve all roles associated with a given user ID.
- Request Params:
roleId
(Integer): The role ID used for querying roles. Default: 1
- Response: A list of maps, each representing a role and its information.
- Status Codes:
- 200 OK: Request successful.
- 500 Internal Server Error: The server encountered an error
- Description: Retrieve a list of roles based on provided parameters.
- Request Params:
roleName
(Integer): The name of the role being queried. Default: 1
- Response: Map with user information.
- Status Codes:
- 200 OK: Request successful.
- 500 Internal Server Error: The server encountered an error
- Description: Add a new role into the system.
- Request Params:
roleName
(String): The name of the role.
- Request Body:
Role
object. - Response: Success message for a valid request.
- Status Codes:
- 200 OK: Role added successfully.
- 400 BAD REQUEST: If input parameters are invalid or missing, or if the rolename already exists.
- 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Description: Update an existing role information in the system.
- Request Params:
roleId
(Integer): The ID of the role.roleName
(String): The name of the role.
- Request Body:
Role
object. - Response: Success message for a valid request.
- Status Codes:
- 200 OK: Role updated successfully.
- 400 BAD REQUEST: If the
Role
object is invalid, the roleID does not exist, or if the updated rolename already exists. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Description: Delete a role from the system.
- Request Params:
roleId
(Integer): The ID of the role.
- Request Body: The role id.
- Response: Success message for a valid request.
- Status Codes:
- 200 OK: Role deleted successfully.
- 400 BAD REQUEST: If the
roleId
is empty or if theroleId
does not correspond to existing users. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Description: Grant permissions to a specific role
- Request Params:
roleId
(Integer): The ID of the role.mId
(Integer): ModuleID that is to be granted to the role.
- Request Body: The roleId and Array of module
mId
s. - Response: Success message for a valid request.
- Status Codes:
- 200 OK: Role deleted successfully.
- 400 BAD REQUEST: If the
roleId
is empty or if theroleId
does not correspond to existing users. - 300 CUSTOM CODE: Represents business logic errors.
- 500 Internal Server Error: The server encountered an error
- Description: Direct to the role index page.
- Response: A string representing the path to the role index view.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
- Description: Direct to a page for adding or updating a role.
- Request Params:
roleId
(Integer): The ID of the role to edit, or null for adding a new role.
- Response: A string representing the path to the role index view.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
Base URL: http://localhost:8080/ems/module
- Description: Retrieve all modules based on the given role ID.
- Request Params:
roleId
(Integer): The role ID used for querying modules. Default: 1
- Response: List of TreeModel representing Module Information.
- Status Codes:
- 200 OK: Request successful.
- 500 Internal Server Error: The server encountered an error
- Description: Directs the user to the page for adding grants to a role.
- Request Params:
roleId
(Integer): The ID of the role to add grants to. Default: 1
- Response: The path to the "grant" view under the "role" directory.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
Base URL: http://localhost:8080/ems/announcement
- Description: Add a new shared data entry.
- Request Body:
SharedDataModel
object, with non-nullsubject
andcontent
. - Response: "Shared data added successfully!" for valid input.
- Status Codes:
- 200 OK: Successfully added.
- 400 BAD REQUEST: If the
SharedDataModel
object is null, orsubject
orcontent
is null/empty. - 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Add shared data without content: View Screenshot
- Add shared data without subject: View Screenshot
- Successfully add shared data: View Screenshot
- Add shared data without uid: View Screenshot
- Description: Retrieve a specific shared data entry by its ID.
- Path Variable:
id
- The ID of the shared data entry. - Response:
SharedDataModel
object for valid ID. - Status Codes:
- 200 OK: Successfully retrieved.
- 400 BAD REQUEST: If
id
does not exist. - 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Get shared data success: View Screenshot
- Get not exist shared data: View Screenshot
- Description: Retrieve all shared data entry in the database.
- Response: Map with
SharedDataModel
objects. - Status Codes:
- 200 OK: Successfully retrieved.
- 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Get all shared data success: View Screenshot
- Description: Update a specific shared data entry by its ID.
- Path Variable:
id
- The ID of the shared data entry. - Request Body:
SharedDataModel
object, with non-nulluid
,subject
andcontent
. - Response: "Shared data updated successfully!" for valid input and ID.
- Status Codes:
- 200 OK: Successfully updated.
- 400 BAD REQUEST: If
id
does not exist, or theSharedDataModel
object is null, oruid
is null, orsubject
orcontent
is null/empty. - 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Update with valid ID, userID, subject, and contents: View Screenshot
- Proof of update subject and contents success: View Screenshot
- Update with valid ID, userID, and subject: View Screenshot
- Proof of update subject success: View Screenshot
- Update with valid ID, but no request body: View Screenshot
- Update with valid ID and subject, but no userID: View Screenshot
- Description: Delete a specific shared data entry by its ID.
- Path Variable:
id
- The ID of the shared data entry. - Response: "Shared data deleted successfully!" for valid ID.
- Status Codes:
- 204 NO CONTENT: Successfully deleted.
- 400 BAD REQUEST: If
id
does not exist. - 500 Internal Server Error: The server encountered an error
- Postman API tests:
- Delete with valid ID: View Screenshot
- Proof of delete with valid ID success: View Screenshot
- Description: Direct to the shared space index page.
- Response: A string representing the path to the shared space index view.
- Status Codes:
- 200 OK: Page loaded successfully.
- 404 Not Found: Cannot find the request page.
- 500 Internal Server Error: The server encountered an error
We decided to make the following changes to our API implementation, which are different from our proposal:
-
Add role management:
Role management allows for the definition of roles, each with specific permissions. This is crucial in an entity management system to control who can perform certain actions on entities. For data protection, different roles should have different levels of access to sensitive information. Role management ensures that only authorized individuals can view or modify specific entities, contributing to data security.
-
Remove customizable workflow:
Our entity management system focuses on handling and organizing data related to entities (e.g., information of the entities, roles) and we decided not to add the complexity of managing intricate workflows.
-
Remove multi-language translation:
We found that many browsers on the market support translation functions. For example, Chrome browser supports the use of Google Translate. Therefore, we did not introduce translation functionality into our service and focused more on core management functionality.
Based on the provided docker-compose.yml
, the MySQL database container is set up to ensure data persistence
through Docker volumes. Specifically, the volumes directive under the mysql-db service maps db-data to /var/lib/mysql
,
which is the default location where MySQL stores its data files. By doing so, any data changes made within the database
are stored in this Docker-managed volume, named ems_db-data
. As a result, even if the MySQL container is stopped,
deleted, or recreated, the data remains intact and can be reattached to a new instance of the MySQL container.
This volume-driven approach guarantees the resilience and persistence of data across container lifecycle events, ensuring that our database changes are consistently retained and not ephemeral.
In the course of our comprehensive System-level Testing for the Service, we rigorously executed all CRUD (Create, Read, Update, Delete) operations utilizing Postman as our primary testing interface. For each individual operation, there was a direct and verifiable reflection in the MySQL database. This consistent alignment between the API calls and the resulting database modifications unequivocally confirms the robust interaction and integration of our service layer with the persistent data layer. Our meticulous testing approach ensures that our application not only responds to API requests as expected but also effectively manages the underlying data in a reliable and consistent manner.
We use some third-party code in our frontend scripts under src/main/resources/public
- Purpose: Provides scalable vector icons that can instantly be customized — size, color, drop shadow, and anything that can be done with the power of CSS.
- License: SIL OFL 1.1 for the font, and MIT License for the CSS.
- Website: Font Awesome
- Usage Example: Icons are used in buttons, forms, and as standalone graphics.
- Purpose: A lightweight module for handling DOM manipulation, event handling, and AJAX.
- License: MIT License.
- Documentation: jq-Module GitHub
- Usage Example: Used for creating dynamic content and managing DOM elements efficiently.
- Purpose: A fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, and animation much simpler with an easy-to-use API that works across a multitude of browsers.
- License: MIT License.
- Website: jQuery
- Usage Example: AJAX calls for asynchronous data fetching, and manipulating HTML elements.
- Purpose: A UI framework for building web interfaces, providing a range of components and widgets.
- License: MIT License.
- Website: Layui
- Usage Example: Used for building the UI layout and integrating various UI components like tables, forms, etc.
All the libraries used in this project are under MIT License, except for Font Awesome which is under SIL OFL 1.1 for the font, and MIT License for the CSS. We ensure compliance with these licenses in our use of these libraries.