Enregistrement.2026-04-09.164841.mp4
This repository is an educational microservices project that demonstrates:
- A ticket booking workflow implemented with Spring Boot services.
- Event-driven communication with Kafka (producers/consumers, consumer groups, fan-out).
- MySQL persistence with Flyway migrations (single migration owner pattern).
- A Spring Cloud Gateway API Gateway as a single entry point.
- A simple static frontend that talks to the gateway.
- Optional email notification on payment completion (Mailtrap SMTP sandbox).
The core flow is:
- User lists events from Inventory.
- User creates a customer (name/email) in Booking service.
- User posts a booking request to Booking service (via the gateway).
- Booking publishes
booking_event. - Order consumes
booking_event, creates an order, then publishesorder_created_event. - Inventory consumes
order_created_eventand publishesinventory_updated_event. - Payment consumes
order_created_event(fan-out) and publishespayment_completed_eventand can send an email. - Booking consumes
inventory_updated_eventto keep the UI responsive.
An architecture diagram is available in docs/kafka-architecture.md.
project/→ Inventory Service (events/venues, capacity updates, Flyway migrations, docker compose)bookingService/bookingService/→ Booking Service (booking API + customer API + Kafka producer/consumer)Order/Order/→ Order Service (Kafka consumer, creates orders, Kafka producer)paymentService/paymentService/→ Payment Service (Kafka consumer, persists payments, Kafka producer, optional Mailtrap email)apigateway/api-gateway/→ API Gateway (routing + permissive dev CORS)frontend/→ Static UI (index.html,payments.html)docs/→ Documentation and diagramskafka_2.13-3.9.1/→ Kafka distribution (optional local broker)
- Java 17
- Maven Wrapper (
mvnw,mvnw.cmd) - Spring Boot 4.x
- Spring Data JPA
- Spring Cloud Gateway (WebMVC)
- Spring for Apache Kafka
- MySQL 8 (Docker)
- Flyway migrations (owned by Inventory service)
This repository contains a complete event-ticketing backend built with Spring Boot microservices, Kafka event streaming, MySQL persistence, and an API Gateway, plus a lightweight frontend.
It demonstrates a full booking workflow:
- User browses events from Inventory Service.
- User submits booking to Booking Service.
- Booking Service validates capacity and publishes
booking_eventto Kafka. - Order Service consumes the Kafka event, creates an order, and updates inventory capacity.
- Frontend accesses services through API Gateway.
project/→ Inventory Service (catalog, event capacity, Flyway migrations, docker assets)bookingService/bookingService/→ Booking Service (booking API, Kafka producer)Order/Order/→ Order Service (Kafka consumer, order persistence)apigateway/api-gateway/→ API Gateway (routing + CORS)frontend/→ Static UI (index.html)
- Java 17
- Maven Wrapper (
mvnw,mvnw.cmd) - Spring Boot 4.0.5
- Spring Data JPA
- Spring Cloud Gateway MVC (API Gateway)
- Apache Kafka + Zookeeper
- MySQL 8
- Flyway (schema migration in inventory service)
- Lombok
- Tailwind CSS (frontend via CDN)
| Component | Port | Notes |
|---|---|---|
| API Gateway | 8090 | Single entry point for the frontend/Postman |
| Inventory Service | 8080 | Events/venues + capacity updates + Flyway owner |
| Booking Service | 8081 | Customers + booking API + produces booking_event |
| Order Service | 8082 | Consumes booking_event, produces order_created_event |
| Payment Service | 8083 | Consumes order_created_event, produces payment_completed_event |
| Kafka Broker | 9092 | Not started by docker-compose in this repo |
| Kafka UI (Docker) | 8084 | Observability UI for topics/messages |
| MySQL (Docker) | 3307 → 3306 | DB name: ticketing |
booking_eventorder_created_eventinventory_updated_eventpayment_completed_event
Note on “2 consumers on one topic”:
order_created_event is consumed by both Inventory and Payment using different consumer groups. This is intentional fan-out / pub-sub.
- Java 17
- Docker Desktop
- A Kafka broker reachable at
localhost:9092- Option A: start Kafka locally using
kafka_2.13-3.9.1/(recommended for demos) - Option B: use your own Kafka (Docker, Confluent, etc.) and keep
bootstrap-servers=localhost:9092
- Option A: start Kafka locally using
- Optional: Mailtrap account (only if you want to see emails)
- Optional: Postman
From project/:
cd project
docker compose up -dThis starts:
- MySQL on
localhost:3307 - Kafka UI on
http://localhost:8084
If you already have a Kafka broker running on localhost:9092, skip this.
This repo includes Kafka in kafka_2.13-3.9.1/.
One-time (KRaft storage format):
- Open PowerShell in
kafka_2.13-3.9.1/. - (Recommended) Edit
config/kraft/server.propertiesand setlog.dirsto a local folder (example:log.dirs=./kraft-combined-logs). - Run:
cd kafka_2.13-3.9.1
.\bin\windows\kafka-storage.bat random-uuid
.\bin\windows\kafka-storage.bat format -t <PASTE_UUID_HERE> -c .\config\kraft\server.propertiesThen start the broker:
.\bin\windows\kafka-server-start.bat .\config\kraft\server.propertiesStart each service in a separate terminal:
cd project
.\mvnw.cmd spring-boot:runcd bookingService\bookingService
.\mvnw.cmd spring-boot:runcd Order\Order
.\mvnw.cmd spring-boot:runcd paymentService\paymentService
.\mvnw.cmd spring-boot:runcd apigateway\api-gateway
.\mvnw.cmd spring-boot:runOpen these files in a browser:
frontend/index.html(events + booking)frontend/payments.html(payments view)
The frontend calls the API Gateway at http://localhost:8090/api/v1.
All requests go through the gateway (8090).
GET http://localhost:8090/api/v1/inventory/events
POST http://localhost:8090/api/v1/customers
{
"name": "Alice Doe",
"email": "alice@example.com",
"address": "Street 1"
}POST http://localhost:8090/api/v1/booking
| Component | Port | Purpose |
|---|---|---|
| API Gateway | 8090 |
Single entry point + route forwarding |
| Inventory Service | 8080 |
Event and venue inventory APIs |
| Booking Service | 8081 |
Booking creation API + Kafka producer |
| Order Service | 8082 |
Kafka consumer, order persistence, inventory update |
| MySQL (Docker) | 3307 (host) → 3306 (container) |
Primary database |
| Kafka Broker | 9092 |
Kafka for app services (host) |
| Kafka UI | 8084 |
Inspect topics/messages |
| Schema Registry | 8083 |
Kafka schema registry |
| Zookeeper | 2181 |
Kafka dependency |
Frontend (index.html)
|
v
API Gateway (8090)
|-----------------------> Inventory Service (8080) ----> MySQL
|
|-----------------------> Booking Service (8081) -------> MySQL
|
| publish booking_event
v
Kafka (9092)
|
| consume booking_event
v
Order Service (8082) -----------> MySQL
|
| REST call
v
Inventory Service capacity update
Flyway scripts are in project/src/main/resources/db/migration:
V1__init.sql- Creates
venue - Creates
eventwith FK tovenue
- Creates
V2__add_ticket_column_in_event_table.sql- Adds
ticket_pricetoevent
- Adds
V3__create__customer_table.sql- Creates
customer
- Creates
V4__create_order_table.sql- Creates
orderwith FK tocustomerandevent
- Creates
MySQL init script (project/docker/mysql/init.sql) creates database ticketing.
Note: In
project/docker-compose.yml,MYSQL_DATABASEistickiting(typo), while app configs useticketing. The JDBC URL includescreateDatabaseIfNotExist=true, soticketingcan still be created at runtime.
GET /api/v1/inventory/events- List all events with venue and remaining capacity.
GET /api/v1/inventory/venue/{venueId}- Venue details by ID.
GET /api/v1/inventory/event/{eventId}- Event details by ID.
PUT /api/v1/inventory/event/{eventId}/capacity/{capacity}- Decrements remaining capacity by
capacity(used by Order Service).
- Decrements remaining capacity by
POST /api/v1/booking- Creates a booking request.
- Validates customer existence.
- Validates inventory capacity.
- Publishes Kafka event
booking_event. - Returns booking summary.
Request body:
{
"userId": 1,
"eventId": 1,
"ticketCount": 2
}What to expect:
- Order service creates an order in MySQL.
- Inventory updates remaining capacity.
- Payment creates a payment row and publishes
payment_completed_event.
GET http://localhost:8090/api/v1/payments?limit=50
GET http://localhost:8090/api/v1/payments/order/{orderId}
Payment service can send an email when a payment is completed.
- Create a Mailtrap inbox and copy SMTP credentials.
- Start Payment service with environment variables:
$env:MAILTRAP_USERNAME="<your_username>"
$env:MAILTRAP_PASSWORD="<your_password>"
cd paymentService\paymentService
.\mvnw.cmd spring-boot:runConfiguration is in paymentService/paymentService/src/main/resources/application.properties.
Notes:
- Mailtrap Sandbox captures emails in the Mailtrap UI (not a real mailbox).
- If a customer email cannot be resolved, you can set
payment.email.fallback-to.
- Flyway migrations are owned by the Inventory service.
- Migration scripts live in
project/src/main/resources/db/migrationand include payment-related tables/columns. - Payment service runs with Flyway disabled and
spring.jpa.hibernate.ddl-auto=validate.
- Booking works but Kafka listeners show “0 records”: normal when there are no new messages; create a booking to produce events.
- Kafka UI shows no cluster/topics: ensure Kafka is running on
localhost:9092and Docker can reach it (host.docker.internal:9092). - Port conflict on
8083: this repo uses8083for Payment service. Stop anything else using that port. - MySQL connection fails: ensure
docker compose up -dis running and port3307is free.
Per service:
.\mvnw.cmd -DskipTests package"eventId": 2, "ticketCount": 3 }
Response body:
```json
{
"userId": 1,
"eventId": 2,
"ticketCount": 3,
"totalPrice": 150.00
}
No direct REST controller is currently exposed. It works asynchronously as a Kafka consumer:
- listens to topic
booking_eventwith grouporder-service - deserializes message to
BookingEvent - persists order in table
order - calls Inventory Service to reduce available seats
Gateway routes (configured in apigateway/api-gateway/src/main/resources/application.properties):
/api/v1/inventory/**→http://localhost:8080/api/v1/booking/**→http://localhost:8081/api/v1/order/**→http://localhost:8082
CORS is globally enabled with permissive configuration to simplify local frontend usage.
Install the following:
- Java 17
- Docker Desktop
- Maven (optional, wrappers are included)
- (Optional) Postman or similar API client
From project/:
docker compose up -dThis starts MySQL, Zookeeper, Kafka broker, Kafka UI, Schema Registry.
Start each service in a separate terminal.
cd project
./mvnw spring-boot:run(Windows: mvnw.cmd spring-boot:run)
cd bookingService/bookingService
./mvnw spring-boot:run(Windows: mvnw.cmd spring-boot:run)
cd Order/Order
./mvnw spring-boot:run(Windows: mvnw.cmd spring-boot:run)
cd apigateway/api-gateway
./mvnw spring-boot:run(Windows: mvnw.cmd spring-boot:run)
Open frontend/index.html in a browser.
By default it targets:
http://localhost:8090/api/v1
You can override the API base via query parameter:
index.html?api=http://localhost:8090/api/v1
- Call gateway inventory endpoint:
GET http://localhost:8090/api/v1/inventory/events
- Submit booking:
POST http://localhost:8090/api/v1/booking
- Check Kafka UI:
http://localhost:8084
- Validate DB updates:
- New row in
ordertable event.left_capacitydecreased
- New row in
If your DB is empty, insert seed data manually:
USE ticketing;
INSERT INTO venue (name, address, total_capacity)
VALUES
('Olympia Hall', 'Downtown', 1000),
('Open Air Arena', 'North City', 5000);
INSERT INTO event (name, venue_id, total_capacity, left_capacity, ticket_price)
VALUES
('Spring Music Festival', 1, 1000, 1000, 50.00),
('Tech Conference 2026', 2, 5000, 5000, 120.00);
INSERT INTO customer (name, email, address)
VALUES
('Alice Doe', 'alice@example.com', 'Street 1'),
('Bob Smith', 'bob@example.com', 'Street 2');Per service:
./mvnw clean test
./mvnw clean package(Windows: replace with mvnw.cmd ...)
All services use MySQL datasource:
- URL:
jdbc:mysql://localhost:3307/ticketing?createDatabaseIfNotExist=true - Username:
root - Password:
password
Kafka settings:
- Bootstrap server:
localhost:9092 - Producer topic used by booking:
booking_event - Consumer group used by order:
order-service
- There are some naming typos in code and folders (
contolleur,BookingContolleur,tickitingin compose env). The project can still run, but cleanup is recommended. Order Servicehas no REST controller at the moment; it is event-driven.- Ensure all four backend apps are running before testing through the frontend.
- Kafka broker must be available before booking/order interactions.
- Add
READMEper service and a parent aggregator build. - Add Dockerfiles and a unified compose for all apps.
- Add OpenAPI/Swagger for Inventory and Booking APIs.
- Add validation/error handling (
@ControllerAdvice). - Add integration tests for booking → kafka → order → inventory flow.
- Add monitoring (
Actuator, Prometheus, Grafana).
# Infra
cd project
docker compose up -d
# Services (in separate terminals)
cd project && mvnw.cmd spring-boot:run
cd bookingService/bookingService && mvnw.cmd spring-boot:run
cd Order/Order && mvnw.cmd spring-boot:run
cd apigateway/api-gateway && mvnw.cmd spring-boot:runThis project appears to be an educational microservices + Kafka ticketing implementation. Feel free to fork and improve architecture, observability, and production-readiness.