This repo is used to keep diagrams, designs and documentation about the project.
draw.io is used for the designs.
Files are available under the folder /draw.io.
PlantText is used for the sequence diagrams.
Files are available under the folder /plant-text.
The application uses a gateway as entry point and Oauth2 integration. Keycload is the Identity Service responsible to keep users data and provvide the access token to be used on the resource servers.
List of frameworks and tools used on the applications:
- Keycloak
- Spring Cloud Gateway
- Spring Cloud Netflix Eureka
- Spring Security Oauth2
- Prometheus
- Alert Manager
- Slack
- Micrometer
- Grafana Tempo
- Grafana Loki
- Grafana
And below the Design how all the frameworks and tools integrate each other:
What each repository does:
docs (this repository)
: contains documentationdocker-local-setup
: contains docker config to run all the services together on a local environment- Repository: docker-local-setup
insomnia-requests
: contains a backup for the insomnia requests- Repository: insomnia-requests
observability-tools
: contains config for prometheus, alert-manager, grafana, tempo and fluent-bit.- Repository: observability-tools
local-database-config
: contains centralised config for database- Repository: local-database-config
local-kafka-config
: contains centralised config for kafka- Repository: local-kafka-config
service-discovery
: service discovery app (Netflix eureka)- Repository: service-discovery
gateway
: gateway app, the application entrypoint.- Repository: gateway
identity-service
: contains keycloak config (and an application that is not used in the project, but can be used to login and create new users)- Repository: identity-service
- Wiki: here
sales-catalog
: manage products and stock- Repository: sales-catalog
basket-service
: manage the client basket- Repository: basket-service
notification-service
: kafka consumer for notifications, but this has no implementation- Repository: notification-service
The project is an simple e-commerce that manages products and allow customers to buy them. It provides a whole monitoring architecture with Prometheus, Grafana dashboards and logging tracing, also including an alerting system with alert-manager integrated with Slack.
In deep details are provided on the next topics, but a summary on the main features are:
- Sale and customer users are allowed, some features on the application are limited to specific users
- Sale users will register, update, delete, active or deactivate products
- Customers are able to retrieve all the active products and buy them
- Validations are included during product registration, update, delete, on user interation with basket
- A reservation system is implemented to avoid 2 different customers to buy the last product in stock
- On checkout, Kafka messages are created to notify the seller, the customer, and to create a tracking record to delivery the order, but there is no implementation on those features besides reading and logging the message
This is not intended to be a complex or a full e-commerce implementation, so the features below are not included:
- Sending real e-mail/SMS or other type of notifications
notification
repository contains a kafka consumer to consume notifications (kafka message) but it just logs on the console and does not have much implementation
- Tracking system (Delivery)
notification
repository contains a kafka consumer to consume messages when the user checks out a basket, but there is not tracking system implementation for the delivery (shipping, dispatched, delivered, etc), it just logs on the console
- Discount cupom or promotions, or delivery calculation
- Discounts, promotions or delivery calculation are not included on this project during check out
- Multiple currencies (Dolar, Euro, Real, etc)
- There is no support for multiple currencies
- Multi language
- product names or desriptions could have support for more than one language, but it is not set on this project
- Payments
- This project does not implement any payment flow
Users will have 2 different roles:
Sale
: user that is able to register products and see its salesClient
: user that is able to purchase products
p.s
: The users are created directly on keycloak.
For Authentication and Authorization, an Spring OAuth2 is used with Keycloak. The sequence diagram below shows what happen when an unauthenticated user tries to access a specific resource.
- First the user sends a request to the gateway 1.2. Gateway checks a session does not exists and returns a 302 to /oauth2/authorization/keycloak
- Again the gateway returns a 302 but now redirects the request to keycloak login
- Users login successfully and Keycloak redirects the request to the gateway 3.1 Gateway saves the session and user session details on keycloak, including the JWT Access Token (this token is used by the gateway to redirect requests to the final downstreams) 3.2 Returns 302 with a redirect to the initial request
- Request the Gateway again, and now logged in, access successfully the resource
The diagram above is high level about the features and the communications between the services:
- A sales user register/update/delete products
- Products in basket or purchased are not allowed to be deleted
- a field on database
reserved
will increment when a product is reserved in basket - if the product is removed from all basked it will be back to
0
and allowed to be deleted - another flag 'is_sold' will be set to true is a sale is finished with the product, after this, it will be disallowed to be deleted forever (in a real scenario the product would be in the invoice)
- a field on database
- Any product are allowed to be deactivated
- Clients are allowed to list all active products
- When the stock is low or sold out, a notification should be sent to the seller
- Add product (POST /products)
- Role: sale
- Validations:
- name duplication
- price should be positive
- quantity should be zero or positive
- Update product (PATCH /product/{product_id})
- Role: sale
- same validations as to add product
- Increment stock or decrement stock
- Delete product (DELETE /products/{product_id})
- Validations:
- products in basket are not allowed to be deleted
- products purchased are not allowed to be deleted
- Validations:
- Disable product (PUT /products/{product_id}/activate, PUT /products/{product_id}/deactivate)
- List products (GET /products)
- If sales user - list all owned products
- Does not list products from other users
- If client, list all active products in stock
- If sales user - list all owned products
- Get specific product (GET /products/{product_id})
- Same validation on the user type as to return all products
- GET products by ids (GET /products?ids={ids})
- This will be used by basket service to verify if products exist in a single call
- The response when a product does not exist will be an error with details on body
Database: PostgreSQL
- product:
- product_id
- name
- description
- price
- quantity
- reserved
- is_sold
- user_id (sale user)
- Only client users are allowed to interact with basket endpoints
- When a product has its price changed and a product is already on the basket, the previous price will be still used
- A basket will have 15 minutes life (in a real project it would be longer)
- When a basket is created, a Kafka message should be created to be triggered 15 minutes later
- A consumer job will check the basket status, and if it is not closed, it should expire the basket and remove the product as reserved
Endpoints:
-
Create basket (POST /baskets)
- Validations
- Check if user has already an open basket
- Should have at least one product
- Check if products exist on
sales_catalog
- Call
sales_catalog
to reserve the product
- Create a kafka message for basket expiration in 15 minutes
- Validations
-
Add product to the basket (POST /baskets/{basket_id}/products)
- Allow maximun 10 products in the basket
- Call
sales_catalog
and check if product exist - Call
sales_catalog
to reserve the product
-
Update product quantity (PUT /baskets/{basket_id}/products/{products_id})
- Check
sales_catalog
if the product exist - Reserve product on
sales_catalog
- If the update set it to 0, remove the product from the basket
- Basket should have at least 1 product, so need validation
- Check
-
Delete product from basket (DELETE /baskets/{basket_id}/products/{product_id})
- Basket should have at least one product
-
List all baskets (GET /baskets)
-
List by id (GET /baskets/{basket_id})
-
Checkout (POST /baskets/{basket_id}/checkout)
- call
sales_catalog
and update stock/reserved product - update basket status to CLOSED
- create kafka messages for:
- user notification - sale completed
- notification for each sale user about the product(s) sold
- call
-
Kafka consumer
- Consumer message for basket expiration
- If basket is not CLOSED, update status to EXPIRED
- Calls
sales_catalog
and put he product in the stock again
- Calls
Database: PostgreSQL
-
basket:
- basket_id
- user_id (client user)
- total_preview
- status (active, closed, expired)
-
basket_items:
- basket_id
- product_id
- product_price
- Notification service will have the default
/info
,/health
and/metrics
endpoints from actuator - It is a kafka listener
- A message will be listened when a customer closes a basket
- A notification should be sent (fake) to the customer and to the seler