Skip to content

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Customer Route Integration

Java Spring Boot Apache Camel Spring Security MySQL ActiveMQ Artemis Docker Maven

A Spring Boot integration that ingests customer messages, routes them by loyalty tier (gold / silver / base), and forwards them to the correct outgoing ActiveMQ queue — while logging a personalized discount message for each customer. Tier discount rates are backed by a MySQL database and exposed through a secured REST API, with every create/update tracked via an event-driven audit trail.


✨ Features

  • Dual ingestion — accepts incoming customer messages either as files dropped into an messages/inbox/ folder, or as messages on the CUSTOMER.IN ActiveMQ queue.
  • Tier-based routing — routes each message to an outgoing queue based on the customer's tier.
  • Console logging — prints a personalized discount message per processed customer.
  • Configurable discounts (bonus) — gold/silver discount rates are stored in a database instead of being hardcoded.
  • REST API (bonus) — manage tiers and discount rates over HTTP.
  • Basic authentication — write operations on the API require authenticated users.
  • Event-driven audit log (bonus) — every tier creation/update is recorded as a domain event, including which user made the change.

🚀 Getting Started

Prerequisites

  • Java 21+
  • Docker Desktop
  • Maven (or use the included wrapper ./mvnw)

1. Start infrastructure (MySQL + Artemis)

Make sure Docker Desktop is running before you continue — otherwise docker compose will fail with a connection error.

  docker compose up -d

This starts two containers:

Service Container Ports Purpose
mysql db 3306 Stores tiers/discount rates
artemis message_route 8161 (web console), 61616 (broker) ActiveMQ Artemis message broker

The username and password for both MySQL and Artemis is demo. If you wish to customize these, create a .env file in the project root — just remember to also update the corresponding Spring Boot environment variables (spring.datasource.* and spring.artemis.* in application.properties) to match.

2. Run the application

  ./mvnw spring-boot:run

The application starts on http://localhost:8080 by default.

3. Send a message

Via file:

  1. Open the messages/inbox folder in your project.
  2. Create a new file inside it. The file name doesn't matter, but it must end with the .json extension.
  3. Paste in a message, e.g.:
   {
     "customer": "bolag 1",
     "tier": "gold"
   }
  1. Save the file (Ctrl+S) — this is what triggers the message to be picked up and processed.

Via Artemis:

  1. Open the web console at http://localhost:8161.
  2. Log in with your ARTEMIS_USER / ARTEMIS_PASSWORD.
  3. Send a JSON message to the CUSTOMER.IN queue.

4. Explore the tier API

View all tiers — since GET /api/tiers is public, just open it directly in your web browser: http://localhost:8080/api/tiers. This shows a JSON list of all existing tiers and their current discount rates.

Create or update a tierPOST /api/tiers and PATCH /api/tiers/{level} require authentication, so a browser alone isn't enough. Use a tool like Insomnia (or Postman) instead:

  1. Create a new request in Insomnia, set the method to POST or PATCH.
  2. Set the URL, e.g. http://localhost:8080/api/tiers (POST) or http://localhost:8080/api/tiers/gold (PATCH).
  3. Under Auth, choose Basic Auth and log in with one of the users defined in SecurityConfig (see Authentication below), e.g. anna / ninja123.
  4. Set the body to JSON:
    • For POST (creating a new tier), include both fields:
     {
       "level": "bronze",
       "discountPercentage": 5
     }
  • For PATCH (updating an existing tier's discount), only discountPercentage is needed:
     {
       "discountPercentage": 35
     }
  1. Send the request.

📨 Message Format

Incoming messages (from either messages/inbox/ or CUSTOMER.IN) are JSON with the following shape:

{
  "customer": "bolag 1",
  "tier": "gold"
}

The tier field is optional. If it's missing, the customer is treated as a base customer:

{
  "customer": "bolag 3"
}

Console output per tier

Tier Message
gold Thank you <customer> for being a gold-customer. Your discount is 30%
silver Thank you <customer> for being a silver-customer. Your discount is 10%!
base Thank you <customer> for being a base-customer. Your discount is 0%

<customer> is replaced with the value of the customer field from the incoming message (e.g. bolag 1).


🏗️ Architecture

The project follows a domain-driven, event-based design:

  • The tier package is organized around the domain (domain, application, infrastructure, web) rather than technical layers alone, keeping business logic decoupled from persistence and transport concerns.
  • Changes to tiers (creation, discount updates) are modeled as domain events (TierCreatedEvent, DiscountUpdatedEvent), which are picked up asynchronously by TierEventListener to build an audit trail — rather than writing audit logic directly into the service layer.
  • Message ingestion and routing (messages package) is handled via Apache Camel (CamelRouteBuilder), which reads from both the messages/inbox folder and the CUSTOMER.IN queue and routes to the correct outgoing queue based on tier.

🔌 REST API

Base path: /api/tiers

Method Endpoint Auth required Description
GET /api/tiers No List all tiers and their current discount rates
POST /api/tiers Yes (Basic Auth) Create a new tier (e.g. bronze) with a discount rate
PATCH /api/tiers/{level} Yes (Basic Auth) Update the discount rate for an existing tier

See Getting Started → Explore the tier API for step-by-step instructions on testing these endpoints.


🔐 Authentication

The API uses HTTP Basic Auth backed by an in-memory user store (SecurityConfig). GET /api/tiers is public; POST and PATCH require authentication.

Local test users:

Username Password
anna ninja123
emilia agent007
filippa bananer4

These are hardcoded for local development/demo purposes only — do not ship these credentials to a real environment.


📝 Audit Log (event-driven)

Every tier mutation publishes a domain event (TierCreatedEvent, DiscountUpdatedEvent), which TierEventListener picks up and persists as a TierEvent — recording:

  • the tier level
  • the event type (TIER_CREATED / DISCOUNT_UPDATED)
  • a JSON payload with the relevant details (new discount, or old vs. new discount)
  • the username of the authenticated user who made the change (read from SecurityContextHolder)

This gives full traceability of who changed what and when, without coupling the write path directly to persistence logic.


🛠️ Tech Stack

  • Java / Spring Boot
  • Apache Camel (message ingestion & tier-based routing)
  • Spring Security (HTTP Basic Auth)
  • Spring Data JPA (tier persistence)
  • Apache ActiveMQ Artemis (message broker, run via Docker)
  • MySQL (tier/discount persistence, run via Docker)
  • Docker Compose (local infrastructure)
  • Lombok
  • Jackson (tools.jackson / ObjectMapper for event payload serialization)

📌 Assignment Summary

This project was built based on the following requirements:

  1. Ingest customer messages via file (messages/inbox/) or ActiveMQ (CUSTOMER.IN).
  2. Route messages to CUSTOMER.GOLD.OUT, CUSTOMER.SILVER.OUT, or CUSTOMER.BASE.OUT based on tier.
  3. Log a personalized discount message per processed message.
  4. (Bonus) Store discount rates in a database (via Docker).
  5. (Bonus) Expose a REST API to GET/update discount rates and add new tiers.
  6. (Extra, self-initiated) Secure write endpoints with Basic Auth and track all tier changes via an event-driven audit log.

About

Routes messages to different queues based on customer-tier. Information about tiers are saved in database and can be accessed/updated through a REST-API.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages