This is a multi-modules Maven project, aim to address the requirements described for the Customer App.

- RESTFul: naming convention
- Spring: Include Spring Boot, Spring Web, Spring WebFlux, Reactive Hibernate Spring Boot Starter (my library that integrate Hibernate Reactive to Spring Data), Spring Doc, Spring Validation
- Storage: Hibernate/JPA, PostgreSQL (locking), Redis
- Auth: Oauth2/Keycloak
- Migration: Liquibase
- Autoconfig for Reactive-based Liquibase
- Testing: Jmeter
- Designing: UML
- Deployment: docker, docker compose
- Clone the repository
mvn clean installdocker-compose up --build
- Customer app: http://35.209.248.48:8081/swagger-ui/index.html
- Shop app: http://35.209.248.48:8080/v3/webjars/swagger-ui/index.html
The project has 3 modules, each address particular requirements.
-
org.example.common: Contains common things likeDTO, which are used in other modules -
org.example.coffee-shop: This is a small project contains APIs for supporting the main module. I make use of Spring Webflux and Reactive Hibernate Spring Boot Starter , which is created by me, to build up the APIs. Although the Deliverable doesn't require to implement this module, but in my point of view, the coffee-shop should be the place in which we put the logic to, as it serve the business of the shops.AND, BELIEVE ME, YOU NEED TO TAKE A LOOK AT THIS MODULE.
-
org.example.coffee-shop-customer: The main module that solves Part 2 of the requirements. It requires some APIs from theorg.example.coffee-shop.
I. Allows the customer to register with their mobile number, name and regular address (home or work)
Although this requirement is on coffee-shop-customer, but think further, coffee-shop also has to provide User Management/Security feature.
To archive that, I propose using Oauth2, a standard for authorization. One of most popular Oauth2 implementation is Keycloak.
To integrate it to Spring Boot app, we need Spring Security, Spring Oauth2 Resource Server included in Maven/Gradle.
Our apps act as Resource Server, while Keycloak is an Authorization Server. Bellow is how a User is created:
The process of Authorization is quite simple: A Bearer JWT token (generated by Keycloak) have to be supplied on the Header each HTTP request sent to our apps.
The apps will check whether the token is valid or not (by invoking JWKS URI on Keycloak). If the token is invalid, 401 or 403 will be returned.
How it works? Basically, Spring Security will set up a FilterChain to filter incoming HTTP request.
I propose using Google Map APIs to fulfill this requirement. The detail is bellow:
This is the main feature of ours apps. It must work correctly in concurrent situations. We have some options for this case:
- Using
Optimistic Lockingsupported by Hibernate/JPA:
- The table
orderwill have an Integer field annotated by@Version. - Whenever a transaction want to commit an order, the application compares the
entity versionwith thein-DB version. If they do not match, mean there is/are other transaction(s) committed before, so the version get increased. In this case, an Exception will be thrown. If they match, mean is no other transaction committed before. The current transaction will increase the version and do commit.
- Using Redis along with Redisson library:
Since Redis is single threaded, there is no multiple write at a particular timestamp, so concurrent issue is not happened.
We can use Redis List, which is backed by Redisson Queue to store the orders. First in first out!
In the scope of this assessment, I use Option 2. Basically, there is an application.yml
in org.example.coffee-shop where I set the queue id(s). For now there are 2 queues.
orders will be distributed fairly (Round Robin) to the queues (detail HERE).

We could make a table to store the expected waiting time for each item on the menu:
| id | item_id | waiting_time |
|---|---|---|
| 1 | 12 | 5 (minutes) |
| 2 | 13 | 10 (minutes) |
And a table to store the current position of the particular user:
| id | order_id | position | user_id |
|---|---|---|---|
| 51 | 48f2554c-ef29-4d46-a8bd-632eaf8ae03e | 5 | bda05e7d-65c5-4988-b0b3-d70f261227cb |
| 52 | 2051ac86-3ea9-45ae-8a2e-0b427d0ff14b | 6 | bda05e7d-65c5-4988-b0b3-d70f261227cb |
When someone check his/her position, we pull records from two table and orders before the current position of the user (for example, if user has position of 4, we pull order 1, 2, 3). Then we calculate the total waiting time and return them to the user (detail HERE).
When the user want to cancel his/her order, the coffee-shop-customer app will make a http call to the coffee-shop
include order id. Then we can use it to remove everything from the Redis, PostgreSQL




