This portfolio is a personal project I work on during my free time. Whenever I learn new skills, I enjoy applying them by adding improvements, creating a historical record of my progress. It showcases the backend functionality of an e-commerce system.
This project consists of two Spring Boot microservices for an e-commerce platform:
- ecommerce-api-service: Exposes REST endpoints to handle product-related requests (GET and POST). It does not directly process business logic but publishes messages to Kafka topics (
product-requestsfor product request andproduct-createsfor product creations). - ecommerce-notification-service: Consumes messages from Kafka topics, processes the requests by interacting with a PostgreSQL database, and sends email notifications to users with the result of their requests. Emails are sent in the user's preferred language (i18n supported languages: Spanish, English, and German). The system uses Apache Kafka for asynchronous communication between microservices and is deployed using Docker Compose.
graph TD
User([User])
subgraph "E-Commerce System (Docker Compose)"
API["ecommerce-api-service (REST API)"]
Notification["ecommerce-notification-service (Worker)"]
Kafka[("Apache Kafka (Event Bus)")]
Postgres[("PostgreSQL (Database)")]
end
SMTP["SMTP Server (Gmail)"]
User -->|POST/GET /product| API
API -->|Publish Message| Kafka
Kafka -->|Consume Message| Notification
Notification -->|Read/Write Data| Postgres
Notification -->|Send Email| SMTP
- Languages & Frameworks: Java 21, Spring Boot 3.5.0 (Data, Kafka, Web), Hibernate, JPA
- Modern Features: Java Records (for DTOs), Virtual Threads (for scalability)
- Architecture & Design: DDD, REST APIs, SOLID, Clean Code
- Database & Migrations: PostgreSQL, Flyway
- DevOps & Infrastructure: Docker, Docker Compose, Git
- Testing & Quality: JUnit, Mockito, SonarQube
classDiagram
class ProductController {
-KafkaProductPublisher publisher
-MessageSource messageSource
+getProduct(ProductRequestDTO, Locale) ResponseEntity
+addProduct(ProductCreateRequestDTO, Locale) ResponseEntity
}
class KafkaProductPublisher {
-KafkaTemplate requestKafkaTemplate
-KafkaTemplate createKafkaTemplate
+publishProductRequest(ProductKafkaDTO)
+publishProductCreate(ProductKafkaCreateDTO)
}
class ProductRequestDTO {
<<record>>
+Long id
+String name
+String email
}
class ProductCreateRequestDTO {
<<record>>
+ProductData product
+String notifyEmail
}
class ProductKafkaDTO {
<<record>>
+String name
+String email
+Long productId
+String language
}
class ProductKafkaCreateDTO {
<<record>>
+ProductData product
+String notifyEmail
+String language
}
ProductController --> KafkaProductPublisher : uses
ProductController ..> ProductRequestDTO : handles
ProductController ..> ProductCreateRequestDTO : handles
KafkaProductPublisher ..> ProductKafkaDTO : sends
KafkaProductPublisher ..> ProductKafkaCreateDTO : sends
ProductController: Main logic entry point. Handles REST POST/GET requests, validates them, and routes to the corresponding Kafka topicKafkaProductPublisher: Publishes messages to Kafka topicsKafkaProducerConfig: Kafka producer configurationInternationalizationConfig: i18n configuration (language setup)ProductExceptionHandler: Handles API-level exceptions gracefullyProductCreateRequestDTO: User request to create a productProductRequestDTO: User request to retrieve a productProductKafkaCreateDTO: Kafka message for creating a productProductKafkaDTO: Kafka message for querying a product
classDiagram
class ProductKafkaListener {
-ProductService productService
-EmailNotifier emailNotifier
-ProductDetailsFormatter formatter
+consumeGetProduct(ProductKafkaDTO)
+consumeCreateProduct(ProductKafkaCreateDTO)
}
class ProductService {
-ProductRepository repository
-ProductMapper mapper
+getProductResponseById(Long) ProductResponseDTO
+saveProduct(ProductData) Long
}
class ProductRepository {
<<interface>>
+findById(Long)
+save(Product)
}
class EmailNotifier {
-JavaMailSender mailSender
+send(String, String, String)
}
class ProductDetailsFormatter {
-MessageSource messageSource
+formatProductFoundMessage(ProductResponseDTO, Locale) String
+formatFailedMessage(String) String
+formatProductAddedMessage(Long, Locale) String
}
class Product {
<<Entity>>
+Long id
+String name
+BigDecimal price
+Integer quantity
+String description
+BigDecimal rating
}
ProductKafkaListener --> ProductService : delegates to
ProductKafkaListener --> EmailNotifier : sends via
ProductKafkaListener --> ProductDetailsFormatter : formats with
ProductService --> ProductRepository : persists via
ProductService --> ProductMapper : maps with
ProductRepository --> Product : manages
ProductKafkaListener: Main logic. Consume from Kafka topics, processes product create/query, sends emailsProductDetailsFormatter: Formats user-facing messagesKafkaConsumerConfig: Kafka topic-to-DTO configInternationalizationConfig: i18n setup (supports EN, ES, DE)ProductService: Main product logicProductMapper: Maps between DTOs and entitiesProductRepository: DB access via Spring DataEmailNotifier: Sends emails via JavaMailSenderProduct: DB entityProductResponseDTO: Response to userProductKafkaCreateDTO: Create product messageProductKafkaDTO: Product query message
To test the application, you can use Postman, cURL, or a web browser (for GET requests). When testing, you'll receive an email response based on the request type:
- Product Query (GET): Retrieves a product by ID and sends details via email
- Product Creation (POST): Creates a product and sends confirmation with its ID
The system supports internationalized email responses. Use the Accept-Language HTTP header to specify the language (supported values: en, es, de).
Accept-Language: es
You can test with a simple URL in the browser:
http://localhost:8080/service/query/product?id=2&name=Adrian&email=adrianamaroquero@gmail.com
Example using curl:
curl -X POST [http://localhost:8080/products](http://localhost:8080/products) 
-H "Content-Type: application/json" 
-H "Accept-Language: en" 
-d '{
"product": {
"name": "Cotton T-shirt",
"price": 25.99,
"description": "Unisex T-shirt made of 100% organic cotton",
"quantity": 100,
"rating": 4.5
},
"notifyEmail": "[customer@email.com](mailto:customer@email.com)"
}'
Start all necessary services with Docker Compose:
docker-compose up
This will launch:
ecommerce-api-serviceecommerce-notification-serviceApache KafkaPostgreSQL
You can also import and run tests using this Postman collection:
Ecommerce.collection.postman_collection.json

