Π£ΡΠ΅Π±Π½ΡΠΉ ΠΏΡΠΎΠ΅ΠΊΡ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΡ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ Π΅Π΄Ρ Π½Π° Π±Π°Π·Π΅ Spring Boot. Π Π΅Π°Π»ΠΈΠ·ΡΠ΅Ρ ΠΏΠΎΠ»Π½ΡΠΉ ΡΠΈΠΊΠ» ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π·Π°ΠΊΠ°Π·Π°: ΠΎΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ Π΄ΠΎ Π½Π°Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΊΡΡΡΠ΅ΡΠ°. Π‘Π΅ΡΠ²ΠΈΡΡ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΡΡΡ ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎ ΡΠ΅ΡΠ΅Π· HTTP ΠΈ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎ ΡΠ΅ΡΠ΅Π· Apache Kafka.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β HTTP
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β order-service :8080 β
β - Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°ΠΊΠ°Π·ΠΎΠ² β
β - ΠΠ½ΠΈΡΠΈΠ°ΡΠΈΡ ΠΎΠΏΠ»Π°ΡΡ β
β - ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΡΠ°ΡΡΡΠ° Π·Π°ΠΊΠ°Π·Π° β
βββββ¬βββββββββββββββ¬ββββββββββββββββ¬ββββββ
β HTTP β Kafka β Kafka
β β orders.events β delivery.events
βΌ βΌ βΌ
βββββββββββββ ββββββββββββββββββββββββββββββββββββ
β payment β β delivery-service :8082 β
β service β β - ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΊΡΡΡΠ΅ΡΠ° β
β :8081 β β - ΠΡΠΏΡΠ°Π²ΠΊΠ° ΡΠΎΠ±ΡΡΠΈΡ ΠΎ Π½Π°Π·Π½Π°ΡΠ΅Π½ΠΈΠΈ β
βββββββββββββ ββββββββββββββββββββββββββββββββββββ
| Π‘Π΅ΡΠ²ΠΈΡ | ΠΠΎΡΡ | ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ |
|---|---|---|
order-service |
8080 | Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π·Π°ΠΊΠ°Π·Π°ΠΌΠΈ, ΠΎΡΠΊΠ΅ΡΡΡΠ°ΡΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠ° |
payment-service |
8081 | ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΏΠ»Π°ΡΠ΅ΠΆΠ΅ΠΉ |
delivery-service |
8082 | ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΊΡΡΡΠ΅ΡΠ°, ΠΎΡΠΏΡΠ°Π²ΠΊΠ° ΡΠΎΠ±ΡΡΠΈΠΉ ΠΎ Π΄ΠΎΡΡΠ°Π²ΠΊΠ΅ |
- Java 17
- Spring Boot 3.5
- Spring Data JPA β ΡΠ°Π±ΠΎΡΠ° Ρ ΠΠ
- Spring Kafka β Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΡΠΉ ΠΎΠ±ΠΌΠ΅Π½ ΡΠΎΠ±ΡΡΠΈΡΠΌΠΈ
- Spring Web / HttpExchange β ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠ΅ ΠΌΠ΅ΠΆΡΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅
- PostgreSQL 16 β Ρ ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½ΡΡ
- Apache Kafka (Confluent 8.1) β Π±ΡΠΎΠΊΠ΅Ρ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ
- Lombok / MapStruct β ΡΠΌΠ΅Π½ΡΡΠ΅Π½ΠΈΠ΅ Π±ΠΎΠΉΠ»Π΅ΡΠΏΠ»Π΅ΠΉΡΠ°
- Docker Compose β Π»ΠΎΠΊΠ°Π»ΡΠ½Π°Ρ ΠΈΠ½ΡΡΠ°ΡΡΡΡΠΊΡΡΡΠ°
- Gradle (Kotlin DSL) β ΡΠ±ΠΎΡΠΊΠ°, ΠΌΠ½ΠΎΠ³ΠΎΠΌΠΎΠ΄ΡΠ»ΡΠ½ΡΠΉ ΠΏΡΠΎΠ΅ΠΊΡ
deliveryService/
βββ common-libs/ # ΠΠ±ΡΠΈΠ΅ DTO ΠΈ Kafka-ΡΠΎΠ±ΡΡΠΈΡ (OrderPaidEvent, DeliveryAssignedEvent ΠΈ Π΄Ρ.)
βββ order-service/ # Π‘Π΅ΡΠ²ΠΈΡ Π·Π°ΠΊΠ°Π·ΠΎΠ²
βββ payment-service/ # Π‘Π΅ΡΠ²ΠΈΡ ΠΏΠ»Π°ΡΠ΅ΠΆΠ΅ΠΉ
βββ delivery-service/ # Π‘Π΅ΡΠ²ΠΈΡ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ
βββ docker-compose.yaml # PostgreSQL + Kafka
βββ settings.gradle.kts # ΠΠ½ΠΎΠ³ΠΎΠΌΠΎΠ΄ΡΠ»ΡΠ½Π°Ρ ΡΠ±ΠΎΡΠΊΠ°
| Π’ΠΎΠΏΠΈΠΊ | ΠΡΠΎΠ΄ΡΡΠ΅Ρ | ΠΠΎΠ½ΡΡΠΌΠ΅Ρ | Π‘ΠΎΠ±ΡΡΠΈΠ΅ |
|---|---|---|---|
orders.events |
order-service | delivery-service | OrderPaidEvent |
delivery.events |
delivery-service | order-service | DeliveryAssignedEvent |
1. POST /api/orders β ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°ΠΊΠ°Π·Π° (ΡΡΠ°ΡΡΡ: PENDING_PAYMENT)
2. POST /api/orders/{id}/pay β ΠΎΠΏΠ»Π°ΡΠ° Π·Π°ΠΊΠ°Π·Π° ΡΠ΅ΡΠ΅Π· payment-service
3. order-service β Kafka (orders.events) β delivery-service
4. delivery-service Π½Π°Π·Π½Π°ΡΠ°Π΅Ρ ΡΠ»ΡΡΠ°ΠΉΠ½ΠΎΠ³ΠΎ ΠΊΡΡΡΠ΅ΡΠ° ΠΈ ETA
5. delivery-service β Kafka (delivery.events) β order-service
6. order-service ΠΎΠ±Π½ΠΎΠ²Π»ΡΠ΅Ρ Π·Π°ΠΊΠ°Π· (ΡΡΠ°ΡΡΡ: DELIVERY_ASSIGNED)
7. GET /api/orders/{id} β ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΈΡΠΎΠ³ΠΎΠ²ΠΎΠ³ΠΎ ΡΡΠ°ΡΡΡΠ° Π·Π°ΠΊΠ°Π·Π°
| Π‘ΡΠ°ΡΡΡ | ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ |
|---|---|
PENDING_PAYMENT |
ΠΠ°ΠΊΠ°Π· ΡΠΎΠ·Π΄Π°Π½, ΠΎΠΆΠΈΠ΄Π°Π΅Ρ ΠΎΠΏΠ»Π°ΡΡ |
PAID |
ΠΠΏΠ»Π°ΡΠ° ΠΏΡΠΎΡΠ»Π° ΡΡΠΏΠ΅ΡΠ½ΠΎ |
PAYMENT_FAILED |
ΠΠΏΠ»Π°ΡΠ° ΠΎΡΠΊΠ»ΠΎΠ½Π΅Π½Π° |
DELIVERY_ASSIGNED |
ΠΡΡΡΠ΅Ρ Π½Π°Π·Π½Π°ΡΠ΅Π½ |
DELIVERED |
ΠΠ°ΠΊΠ°Π· Π΄ΠΎΡΡΠ°Π²Π»Π΅Π½ |
| ΠΠ΅ΡΠΎΠ΄ | Π Π΅Π·ΡΠ»ΡΡΠ°Ρ |
|---|---|
CARD |
ΠΡΠ΅Π³Π΄Π° ΡΡΠΏΠ΅ΡΠ½ΠΎ |
YANDEX_SPLIT |
ΠΡΠ΅Π³Π΄Π° ΡΡΠΏΠ΅ΡΠ½ΠΎ |
QR |
ΠΡΠ΅Π³Π΄Π° ΠΎΡΠΊΠ»ΠΎΠ½ΡΠ΅ΡΡΡ |
- JDK 17+
- Docker Desktop
- Gradle (ΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉ
./gradlew)
docker compose up -d./gradlew buildΠΠ°ΠΏΡΡΠΊΠ°ΠΉ ΠΊΠ°ΠΆΠ΄ΡΠΉ ΡΠ΅ΡΠ²ΠΈΡ ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎ ΠΈΠ· ΠΊΠΎΡΠ½Ρ ΠΏΡΠΎΠ΅ΠΊΡΠ° (ΡΠ΅ΡΠ΅Π· IntelliJ IDEA ΠΈΠ»ΠΈ CLI):
./gradlew :order-service:bootRun
./gradlew :payment-service:bootRun
./gradlew :delivery-service:bootRunPOST http://localhost:8080/api/orders
Content-Type: application/json
{
"customerId": 1,
"address": "ΡΠ». ΠΡΡΠΊΠΈΠ½Π°, Π΄. 10",
"items": [
{ "itemId": 101, "quantity": 2, "name": "ΠΡΡΠ³Π΅Ρ" },
{ "itemId": 102, "quantity": 1, "name": "ΠΠ°ΡΡΠΎΡΠΊΠ° ΡΡΠΈ" }
]
}POST http://localhost:8080/api/orders/{id}/pay
Content-Type: application/json
{
"paymentMethod": "CARD"
}GET http://localhost:8080/api/orders/{id}PostgreSQL:
docker exec -it <postgres-container> psql -U postgres -d orders -c \
"DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO postgres;"Kafka:
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --delete --topic orders.events
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --delete --topic delivery.events
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --create --topic orders.events --partitions 1 --replication-factor 1
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --create --topic delivery.events --partitions 1 --replication-factor 1A study project implementing a microservice-based food delivery system built with Spring Boot. It covers the full order lifecycle: from creation to courier assignment. Services communicate synchronously over HTTP and asynchronously through Apache Kafka.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β HTTP
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β order-service :8080 β
β - Create orders β
β - Initiate payments β
β - Update order status β
βββββ¬βββββββββββββββ¬ββββββββββββββββ¬ββββββ
β HTTP β Kafka β Kafka
β β orders.events β delivery.events
βΌ βΌ βΌ
βββββββββββββ ββββββββββββββββββββββββββββββββββββ
β payment β β delivery-service :8082 β
β service β β - Assign courier β
β :8081 β β - Publish delivery event β
βββββββββββββ ββββββββββββββββββββββββββββββββββββ
| Service | Port | Responsibility |
|---|---|---|
order-service |
8080 | Order management, process orchestration |
payment-service |
8081 | Payment processing |
delivery-service |
8082 | Courier assignment, delivery event publishing |
- Java 17
- Spring Boot 3.5
- Spring Data JPA β database access
- Spring Kafka β asynchronous event-driven communication
- Spring Web / HttpExchange β synchronous inter-service HTTP calls
- PostgreSQL 16 β persistent storage
- Apache Kafka (Confluent 8.1) β message broker
- Lombok / MapStruct β boilerplate reduction
- Docker Compose β local infrastructure
- Gradle (Kotlin DSL) β build system, multi-module project
deliveryService/
βββ common-libs/ # Shared DTOs and Kafka events (OrderPaidEvent, DeliveryAssignedEvent, etc.)
βββ order-service/ # Order service
βββ payment-service/ # Payment service
βββ delivery-service/ # Delivery service
βββ docker-compose.yaml # PostgreSQL + Kafka
βββ settings.gradle.kts # Multi-module build definition
| Topic | Producer | Consumer | Event |
|---|---|---|---|
orders.events |
order-service | delivery-service | OrderPaidEvent |
delivery.events |
delivery-service | order-service | DeliveryAssignedEvent |
1. POST /api/orders β create order (status: PENDING_PAYMENT)
2. POST /api/orders/{id}/pay β pay via payment-service over HTTP
3. order-service β Kafka (orders.events) β delivery-service
4. delivery-service assigns a random courier and ETA
5. delivery-service β Kafka (delivery.events) β order-service
6. order-service updates the order (status: DELIVERY_ASSIGNED)
7. GET /api/orders/{id} β fetch final order state
| Status | Description |
|---|---|
PENDING_PAYMENT |
Order created, awaiting payment |
PAID |
Payment successful |
PAYMENT_FAILED |
Payment declined |
DELIVERY_ASSIGNED |
Courier assigned |
DELIVERED |
Order delivered |
| Method | Result |
|---|---|
CARD |
Always succeeds |
YANDEX_SPLIT |
Always succeeds |
QR |
Always fails |
- JDK 17+
- Docker Desktop
- Gradle (or use the
./gradlewwrapper)
docker compose up -d./gradlew buildStart each service separately from the project root (via IntelliJ IDEA or CLI):
./gradlew :order-service:bootRun
./gradlew :payment-service:bootRun
./gradlew :delivery-service:bootRunPOST http://localhost:8080/api/orders
Content-Type: application/json
{
"customerId": 1,
"address": "123 Main St",
"items": [
{ "itemId": 101, "quantity": 2, "name": "Burger" },
{ "itemId": 102, "quantity": 1, "name": "French Fries" }
]
}POST http://localhost:8080/api/orders/{id}/pay
Content-Type: application/json
{
"paymentMethod": "CARD"
}GET http://localhost:8080/api/orders/{id}PostgreSQL:
docker exec -it <postgres-container> psql -U postgres -d orders -c \
"DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO postgres;"Kafka:
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --delete --topic orders.events
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --delete --topic delivery.events
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --create --topic orders.events --partitions 1 --replication-factor 1
docker exec -it <kafka-container> kafka-topics --bootstrap-server localhost:9092 --create --topic delivery.events --partitions 1 --replication-factor 1