Welcome to Adv-sWE-SOME, our incredible project crafted during the Fall 23 COMS W4156 Advanced Software Engineering course. We’ve leveraged the power of Spring Boot to engineer an efficient API service, and paired it with Google Cloud Firestore for a seamless, robust database experience—all readily configured for local development and testing.
Below are third party libraries included in build files.
- Maven: Dependency management
- Spring Boot: Project Framework, support creation of web RESTful APIs.
- Google Cloud Firestore Database: Project database on cloud.
- Spring Cloud GCP: Access and connect to GCP databse.
- Junit 5: Unit Testing.
- Mockito: Service mocking Library for Unit Testing.
- Reactor Test: Aids in effectively testing reactive programming constructs.
- OpenAI API: Used for integrating OpenAI's API to provide health advice.
- Spring Security: Security framework for authentication and authorization.
- Spring WebFlux: For building reactive web applications.
- Lombok:Java library that simplifies coding, reducing boilerplate code.
- Auth0 Spring Security API: Integration of Auth0 with Spring Security for authentication and authorization.
- JSON Web Token: Implementation of JWT for secure token creation and validation.
- Jacoco: Used to generate code coverage report.
Our client application, the Health Portal, offers a vital service to elderly and disabled individuals, providing a user-friendly platform for creating and viewing their health records. This portal enables users to monitor their current health profiles, receive reminders for medication intakes, and obtain personalized health advice based on their medical history and medication details. Furthermore, the portal serves as an invaluable tool for healthcare workers. By obtaining consent, these professionals can access their patients' profiles, allowing them to effectively track and manage the health records of elderly or disabled individuals, thereby facilitating improved healthcare support.
./health_portal
Please refer to ./health_portal/readme.txt
cd health_portal
Download GCP SDK - MacOS
brew install --cask google-cloud-sdk
Initiate and Login to GCP Console and Select Project Adv-sWE-SOME (group-member and teaching staff team are granted access. Login using your lion mail)
access member:
- yq2339@columbia.edu (Team Member)
- fz2356@columbia.edu (Team Member)
- yw3959@columbia.edu (Team Member)
- zz2919@columbia.edu (Team Member)
- zz2978@columbia.edu (Team Member)
- rs4489@columbia.edu (TA)
Please contact yq2339@columbia.edu for access grant.
gcloud init
gcloud auth application-default login
mvn clean install
or
./mvnw clean install
mvn spring-boot:run
or
./mvnw spring-boot:run
mvn test
or
./mvnw test
Implemented with the Maven Checkstyle Plugin to ensure code quality. Configurations and rules are specified in the checkstyle.xml file. Run check style using:
mvn checkstyle:check
Link to Checkstyler report.
Link to API system testing report.
In our project setup, each client would obtain a unique id upon registration. Each client have their own set of users, users from one client cannot login to other clients. See integration tests in:
src/test/java/com/advswesome/advswesome/MultiClientIntegrationTest.java
Note: When login API requires clientId and user credentials (email, password). After user login, user will receive a token and all following access will validate user tokens. This ensure data isolation between clients.
The service is deploy on GCP App Engine, allow multiple client access simultaneously and send corresponding responses only to the appropriate clients.
https://adv-swe-some.uc.r.appspot.com
Also included test in the test suit to check for concurrency request and send corresponding response to appropriate clients, using concurrency profile creation as example:
src/test/java/com/advswesome/advswesome/MultiClientConcurrencyTest.java
CI code location:
.github/workflows/mavenTests.yml
CI is trigger on two events:
- Push to the Main Branch
- Pull Request to the Main Branch
- Checkout Code
- Set up GCP Credentials: we are using gcp firestore and secret manager to store openai-api-key. Setting up GCP credentials using a service account helps CI to build our project.
- Set up JDK 19
- Build Project with Maven (This step will fail for branch coverage < 85%, for details view Branch Coverage section)
- Run Tests with Maven (This step also create branch coverage report, for details view Branch Coverage section)
- Run Style Checker with Maven
CI reports can be views on Github Action interface. We have also attach SonarCloud report under CI.
Link to Report on internal integration tests.
-
Jacoco library was used to generated coverage report for our codebase. Each time
./mvnw test
or./mvnw clean install
is executed, a coverage report will be generated under./target/site/jacoco/jacoco.xml
. -
You can also check the html version of the report by running the index.html file under target/site/index.html
-
A final report was also copied and attached in
reports/coverage-report.xml
.
Verification of 85% branch coverage was ensured. Check was added on build, when branch coverage < 85%, will fail to build.
We have achieve > 85% on our final branch coverage, however a example below provided build check fail case:
SonarCloud Bug Finder and analysis report would be produced with CI for each push or pull request to the main branch. Example:
- Test registering new client with different clientType Validate response (‘clientId’, ‘apiKey’, ‘clientType’) Attempt registration with missing and invalid fields and validate failure response
- Validate successful registration returns ‘usersId’, ‘clientId’, ‘username’, ‘password’, ‘email’, ‘createdAt’, ‘updatedAt’
- Test user login with correct and incorrect credentials
- Ensure login returns a JWT token on success. (NOT SURE)
- Test creating new profile with required fields and optional fields
- Validate response return correct ‘profileId’
- Attempt profile creating with incomplete data and validate failure response
- Test creating new prescription with valid ‘prescriptionId’
- Validate response
- Attempt with duplication ‘prescriptionId’ errors with valid failure response
- Test creating new consents with valid ‘userId’ and ‘profileId’
- Validate the response for success
- Attempt with duplication with valid failure response.
- Testing the health advice get relevant information to the user
Link to Report on external integration tests.
-
POST
- Description: Register a new app/client to use our service
- Input:
- Header:
Content-Type
:application/json
- Body(JSON) Fields:
appName
(String)clientType
("INDIVIDUAL", "ORGANIZATION", "HOSPITAL").
- Header:
- Output:
- On Success:
- Status Code:
200
- JSON with field
clientId
apiKey
appName
clientType
- Status Code:
- On Success:
-
GET
- Description: Get a new client by Id
- Output:
- On Success:
- Status Code:
200
- JSON with field
clientId
apiKey
appName
clientType
- Status Code:
- On Success:
-
POST
- Description: Register a new user
- Input:
- Header:
Content-Type
:application/json
- Body(JSON) Fields:
clientId
(String)username
(String)password
(String)email
(String)createdAt
(Timestamp String)updatedAt
(Timestamp String)
- Header:
- Output:
- On Success:
- Status Code:
200
- JSON with field
userId
clientId
username
password
email
createdAt
updatedAt
- Status Code:
- On Success:
-
POST
- Description: Login a user
- Input:
- Header
Content-Type
:application/json
- Body(JSON) Fields:
clientId
(String)username
(String)password
(String)
- Header
- Output
- On Success:
- Status Code:
200
- JSON with JWT token
- Status Code:
- On Success:
-
POST
- Description: Create a new profile
- Authentication: Bearer JWT token, Owner Only
- Input:
- Header
Content-Type
:application/json
Authorization
: Bearer token
- Body(JSON) Fields:
userId
(String)age
(String)sex
(String)location
(String)physical_fitness
(String)language_preference
(String)medical_history
(List of medical history)- medical history:
{ `disease_name`, `diagnosed_at`, `treatment` }
- medical history:
- Header
- Output:
- On Success:
- Status Code:
200
- JSON with Fields:
profileId
userId
age
sex
location
physical_fitness
language_preference
medical_history
- Status Code:
- On Success:
-
GET
- Description: Get a profile by ID
- Authentication: Required, owner and user with consent only
- Input:
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success:
- Status Code:
200
- JSON with Fields:
profileId
userId
age
sex
location
physical_fitness
language_preference
medical_history
- Status Code:
- On Success:
-
PUT
- Description: Update a profile
- Authentication: Required, owner only
- Input
- Header
Content-Type
:application/json
Authorization
: Bearer token
- Body(JSON) Fields:
userId
(String)age
(String)sex
(String)location
(String)physical_fitness
(String)language_preference
(String)medical_history
(List of medical history)- medical history:
{ `disease_name`, `diagnosed_at`, `treatment` }
- medical history:
- Header
- Output:
- On Success:
- Status Code:
200
- JSON with Fields:
profileId
userId
age
sex
location
physical_fitness
language_preference
medical_history
- Status Code:
- On Success:
-
GET
- Description: Get all profile of this user
- Authentication: Required, owner only
- Input
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success:
- Status Code:
200
- JSON with list of profiles
- Status Code:
- On Success:
-
DELETE
- Description: Delete a profile
- Authentication: Required, owner only
- Input
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success:
- Status Code:
200
- Status Code:
- On Success:
-
POST
- Description: Create a new prescription
- Authentication: Required
- Input
- Header
Content-Type
:application/json
Authorization
: Bearer token
- Body
prescriptionId
(String)profileId
(String)rx_number
(Integer)rx_provider
(String)rx_name
(String)refills
(Integer)quantity
(Integer)
- Header
- Output
- On Success
- Status Code:
201
- JSON with field:
prescriptionId
(String)profileId
(String)rx_number
(Integer)rx_provider
(String)rx_name
(String)refills
(Integer)quantity
(Integer)
- Status Code:
- On Success
-
GET
- Description: Get a prescription by Id
- Authentication: Required, owner only
- Input:
- Header:
Authorization
: Bearer token
- Header:
- Output:
- On Success
- Status Code:
200
- JSON with Fields:
prescriptionId
profileId
rx_number
rx_provider
rx_name
refills
quantity
- Status Code:
- On Error - Not Found
- Status Code:
404
- Status Code:
- On Success
-
PUT
- Description: Update a prescription
- Authentication: Required, owner only
- Input
- Header
Content-Type
:application/json
Authorization
: Bearer token
- Body
prescriptionId
(String)profileId
(String)rx_number
(Integer)rx_provider
(String)rx_name
(String)refills
(Integer)quantity
(Integer)
- Header
- Output
- On Success
- Status Code:
200
- JSON with Fields:
prescriptionId
profileId
rx_number
rx_provider
rx_name
refills
quantity
- Status Code:
- On Error - Not Found
- Status Code:
404
- Status Code:
- On Success
-
DELETE
- Description: Delete a prescription
- Authentication: Required, owner only
- Input:
- Header:
Authorization
: Bearer token
- Header:
- Output:
- On Success
- Status Code:
204
- Status Code:
- On Error - Not Found
- Status Code:
404
- Status Code:
- On Success
-
GET
- Description: Get prescription base on profile id
- Authentication: Required, owner only
- Input:
- Header:
Authorization
: Bearer token
- Header:
- Output
- On Success
- Status Code:
200
- JSON List of Object with Fields:
prescriptionId
profileId
rx_number
rx_provider
rx_name
refills
quantity
- Status Code:
- On Success
-
POST
- Description: Create a new consent
- Authentication: Required
- Input:
- Header
Content-Type
:application/json
Authorization
: Bearer token
- Body
consentId
(String)userId
(String)profileId
(String)permission
(Boolean)updatedAt
(Timestamp String)
- Header
- Output:
- On Success
- Status Code:
201
- Message:
Consent created successfully with ID {consentID}
- Status Code:
- On Duplicated
consentId
:- Status Code:
409
- Message:
Consent with ID {consentId} already exists
- Status Code:
- On Success
-
GET
- Description: Get consent by consentId
- Authentication: Required
- Input:
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success
- Status Code:
200
- JSON with Fields:
consentId
userId
profileId
permission
updatedAt
- Status Code:
- On Error - Not Found
- Status Code:
404
- Status Code:
- On Success
-
PUT
- Description: Update a consent
- Authentication: Required
- Input:
- Header
Content-Type
:application/json
Authorization
: Bearer token
- Body
consentId
(String)userId
(String)profileId
(String)permission
(Boolean)updatedAt
(Timestamp String)
- Header
- Output:
- On Success
- Status Code:
200
- JSON with Fields:
consentId
userId
profileId
permission
updatedAt
- Status Code:
- On Error - Not Found
- Status Code:
404
- Status Code:
- On Success
-
DELETE
- Description: Delete a consent
- Authentication: Required
- Input:
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success
- Status Code:
200
- Status Code:
- On Error - Not Found
- Status Code:
404
- Status Code:
- On Success
-
GET
- Description: Get consent by profile Id
- Authentication: Required
- Input:
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success
- Status Code:
200
- List of JSON Object with Fields:
consentId
userId
profileId
permission
updatedAt
- Status Code:
- On Success
-
GET
- Description: Get consent by user Id
- Authentication: Required
- Input:
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success
- Status Code:
200
- List of JSON Object with Fields:
consentId
userId
profileId
permission
updatedAt
- Status Code:
- On Success
-
GET
- Description: Get health advise based on profile
- Input:
- Header
Authorization
: Bearer token
- Header
- Output:
- On Success
- Status Code:
200
- String containing health advise.
- Status Code:
- On Success