diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eca6e8f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+# What we are doing here ?
+
+ - Hexagonal (Clean) Architecture -> Port & Adapter Style
+
+ - Domain Driven Desing (DDD)
+
+ - SAGA Pattern : process & rollback ( compensating transactions )
+
+ - Outbox Pattern : Pulling Outbox Table With Scheduler , Saga Status
+
+ - Cover Failure Scerinarios :
+
+ - Ensure idempotency using outbox table in each service
+
+ - Prevent concurrency issues with optimistic looks & DB constaints
+
+ - Kepp updating saga and order status for each operation
+
+ - CQRS Pattern : Materialized view & Event Sourcing
+
+ - Relational Database : for ACID and distributed transactional
+
+ - Kafka Messaging Systems for CQRS desing and Microservices Communication
+
+ - Kubernetes And GKE ( Google Kubernetes Engine )
\ No newline at end of file
diff --git a/common/common-domain/src/main/java/com/food/order/domain/exception/DomainException.java b/common/common-domain/src/main/java/com/food/order/domain/exception/DomainException.java
new file mode 100644
index 0000000..b7b34dc
--- /dev/null
+++ b/common/common-domain/src/main/java/com/food/order/domain/exception/DomainException.java
@@ -0,0 +1,12 @@
+package com.food.order.domain.exception;
+
+public class DomainException extends RuntimeException {
+
+ public DomainException(String message) {
+ super(message);
+ }
+
+ public DomainException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/common/common-domain/src/main/java/com/food/order/domain/valueobject/Money.java b/common/common-domain/src/main/java/com/food/order/domain/valueobject/Money.java
index 6da812d..a6b5a5d 100644
--- a/common/common-domain/src/main/java/com/food/order/domain/valueobject/Money.java
+++ b/common/common-domain/src/main/java/com/food/order/domain/valueobject/Money.java
@@ -8,6 +8,8 @@ public class Money {
private final BigDecimal amount;
+ public static final Money ZERO = new Money(BigDecimal.ZERO);
+
public Money(BigDecimal amount) {
this.amount = amount;
}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java
new file mode 100644
index 0000000..626e8cd
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java
@@ -0,0 +1,7 @@
+package com.food.order.system.domain.entity;
+
+import com.food.order.domain.entity.AggregateRoot;
+import com.food.order.domain.valueobject.CustomerId;
+
+public class Customer extends AggregateRoot {
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java
new file mode 100644
index 0000000..509eced
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java
@@ -0,0 +1,225 @@
+package com.food.order.system.domain.entity;
+
+import com.food.order.domain.entity.AggregateRoot;
+import com.food.order.domain.valueobject.*;
+import com.food.order.system.domain.exception.OrderDomainException;
+import com.food.order.system.domain.valueobject.OrderItemId;
+import com.food.order.system.domain.valueobject.StreetAddress;
+import com.food.order.system.domain.valueobject.TrackingId;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+public class Order extends AggregateRoot {
+
+ private final CustomerId customerId;
+ private final RestaurantId restaurantId;
+ private final StreetAddress deliveryAddress;
+ private final Money price;
+ private final List items;
+
+ private TrackingId trackingId;
+ private OrderStatus status;
+ private List failureMessages;
+
+ public void initializeOrder(){
+ setId(new OrderId(UUID.randomUUID()));
+ trackingId = new TrackingId(UUID.randomUUID());
+ status = OrderStatus.PENDING;
+ initializeOrderItems();
+ }
+
+ public void pay(){
+ if(!Objects.equals(status, OrderStatus.PENDING))
+ throw new OrderDomainException("Order status is not pending !");
+ status = OrderStatus.PAID;
+
+ }
+
+ public void approve(){
+ if(!Objects.equals(status, OrderStatus.PAID))
+ throw new OrderDomainException("Order status is not paid !");
+ status = OrderStatus.APPROVED;
+ }
+
+ public void initCancel(List failureMessages){
+ if(!Objects.equals(status, OrderStatus.PAID))
+ throw new OrderDomainException("Order status is not correct for initCancel operation !");
+ status = OrderStatus.CANCELLED;
+ updateFailureMessages(failureMessages);
+ }
+
+ public void cancel(List failureMessages){
+ if(Objects.equals(status, OrderStatus.CANCELLING) || Objects.equals(status, OrderStatus.PENDING))
+ throw new OrderDomainException("Order status is not correct for cancel operation !");
+ status = OrderStatus.CANCELLED;
+ updateFailureMessages(failureMessages);
+ }
+
+ private void updateFailureMessages(List failureMessages) {
+ if (Objects.nonNull(this.failureMessages) && Objects.nonNull(failureMessages)) {
+ this.failureMessages.addAll(failureMessages.stream().filter(Objects::nonNull).toList());
+ } else {
+ this.failureMessages = failureMessages;
+ }
+ }
+
+ public void validateOrder(){
+ validateInitialOrder();
+ validateTotalPrice();
+ validateItemsPrice();
+ }
+
+ private void validateItemsPrice() {
+ Money orderItemsTotal = items
+ .stream()
+ .map(orderItem -> {
+ validateItemPrice(orderItem);
+ return orderItem.getSubTotal();
+ })
+ .reduce(Money.ZERO, Money::add);
+
+ if(!Objects.equals(orderItemsTotal, price)){
+ throw new OrderDomainException("Order total price is not equal to the sum of order items prices");
+ }
+ }
+
+ private void validateItemPrice(OrderItem orderItem) {
+ if(!orderItem.isPriceValid()){
+ throw new OrderDomainException("Order item price is not valid");
+ }
+ }
+
+ private void validateTotalPrice() {
+ if(Objects.nonNull(price) && !price.isGreaterThanZero()){
+ throw new OrderDomainException("Total price cannot be less than zero");
+ }
+ }
+
+ private void validateInitialOrder() {
+ if (Objects.nonNull(status) && Objects.nonNull(getId()))
+ throw new OrderDomainException("Order is not in correct state to be initialized");
+
+ }
+
+ private void initializeOrderItems() {
+ long itemId = 1;
+ for (OrderItem item : items) {
+ item.initializeOrderItem(super.getId(), new OrderItemId(itemId++));
+ }
+ }
+
+ private Order(Builder builder) {
+ super.setId(builder.orderId);
+ customerId = builder.customerId;
+ restaurantId = builder.restaurantId;
+ deliveryAddress = builder.deliveryAddress;
+ price = builder.price;
+ items = builder.items;
+ trackingId = builder.trackingId;
+ status = builder.status;
+ failureMessages = builder.failureMessages;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public CustomerId getCustomerId() {
+ return customerId;
+ }
+
+ public RestaurantId getRestaurantId() {
+ return restaurantId;
+ }
+
+ public StreetAddress getDeliveryAddress() {
+ return deliveryAddress;
+ }
+
+ public Money getPrice() {
+ return price;
+ }
+
+ public List getItems() {
+ return items;
+ }
+
+ public TrackingId getTrackingId() {
+ return trackingId;
+ }
+
+ public OrderStatus getStatus() {
+ return status;
+ }
+
+ public List getFailureMessages() {
+ return failureMessages;
+ }
+
+
+ public static final class Builder {
+ private OrderId orderId;
+ private CustomerId customerId;
+ private RestaurantId restaurantId;
+ private StreetAddress deliveryAddress;
+ private Money price;
+ private List items;
+ private TrackingId trackingId;
+ private OrderStatus status;
+ private List failureMessages;
+
+ private Builder() {
+ }
+
+ public Builder orderId(OrderId val) {
+ orderId = val;
+ return this;
+ }
+
+ public Builder customerId(CustomerId val) {
+ customerId = val;
+ return this;
+ }
+
+ public Builder restaurantId(RestaurantId val) {
+ restaurantId = val;
+ return this;
+ }
+
+ public Builder deliveryAddress(StreetAddress val) {
+ deliveryAddress = val;
+ return this;
+ }
+
+ public Builder price(Money val) {
+ price = val;
+ return this;
+ }
+
+ public Builder items(List val) {
+ items = val;
+ return this;
+ }
+
+ public Builder trackingId(TrackingId val) {
+ trackingId = val;
+ return this;
+ }
+
+ public Builder status(OrderStatus val) {
+ status = val;
+ return this;
+ }
+
+ public Builder failureMessages(List val) {
+ failureMessages = val;
+ return this;
+ }
+
+ public Order build() {
+ return new Order(this);
+ }
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/OrderItem.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/OrderItem.java
new file mode 100644
index 0000000..50dbd91
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/OrderItem.java
@@ -0,0 +1,101 @@
+package com.food.order.system.domain.entity;
+
+import com.food.order.domain.entity.BaseEntity;
+import com.food.order.domain.valueobject.Money;
+import com.food.order.domain.valueobject.OrderId;
+import com.food.order.system.domain.valueobject.OrderItemId;
+
+public class OrderItem extends BaseEntity {
+
+ private OrderId orderId;
+ private final Product product;
+ private final int quantity;
+ private final Money price;
+ private final Money subTotal;
+
+ void initializeOrderItem(OrderId orderId, OrderItemId orderItemId) {
+ this.orderId = orderId;
+ super.setId(orderItemId);
+ }
+
+ boolean isPriceValid() {
+ return price.isGreaterThanZero() &&
+ price.equals(product.getPrice()) &&
+ price.multiply(quantity).equals(subTotal);
+ }
+
+ private OrderItem(Builder builder) {
+ super.setId(builder.orderItemId);
+ product = builder.product;
+ quantity = builder.quantity;
+ price = builder.price;
+ subTotal = builder.subTotal;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public OrderId getOrderId() {
+ return orderId;
+ }
+
+ public Product getProduct() {
+ return product;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public Money getPrice() {
+ return price;
+ }
+
+ public Money getSubTotal() {
+ return subTotal;
+ }
+
+
+
+
+ public static final class Builder {
+ private OrderItemId orderItemId;
+ private Product product;
+ private int quantity;
+ private Money price;
+ private Money subTotal;
+
+ private Builder() {
+ }
+
+ public Builder orderItemId(OrderItemId val) {
+ orderItemId = val;
+ return this;
+ }
+
+ public Builder product(Product val) {
+ product = val;
+ return this;
+ }
+
+ public Builder quantity(int val) {
+ quantity = val;
+ return this;
+ }
+
+ public Builder price(Money val) {
+ price = val;
+ return this;
+ }
+
+ public Builder subTotal(Money val) {
+ subTotal = val;
+ return this;
+ }
+
+ public OrderItem build() {
+ return new OrderItem(this);
+ }
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Product.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Product.java
new file mode 100644
index 0000000..027513c
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Product.java
@@ -0,0 +1,31 @@
+package com.food.order.system.domain.entity;
+
+import com.food.order.domain.entity.BaseEntity;
+import com.food.order.domain.valueobject.Money;
+import com.food.order.domain.valueobject.ProductId;
+
+public class Product extends BaseEntity {
+ private String name;
+ private Money price;
+
+ public Product(ProductId id, String name, Money price) {
+ super.setId(id);
+ this.name = name;
+ this.price = price;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Money getPrice() {
+ return price;
+ }
+
+ public void updateWithConfirmedNameAndPrice(String name, Money price) {
+
+ this.name = name;
+ this.price = price;
+
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Restaurant.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Restaurant.java
new file mode 100644
index 0000000..5757a9a
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Restaurant.java
@@ -0,0 +1,58 @@
+package com.food.order.system.domain.entity;
+
+import com.food.order.domain.entity.AggregateRoot;
+import com.food.order.domain.valueobject.RestaurantId;
+
+import java.util.List;
+
+public class Restaurant extends AggregateRoot {
+ private final List products;
+ private final boolean isActive;
+
+ private Restaurant(Builder builder) {
+ super.setId(builder.restaurantId);
+ products = builder.products;
+ isActive = builder.isActive;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public List getProducts() {
+ return products;
+ }
+
+ public boolean isActive() {
+ return isActive;
+ }
+
+
+ public static final class Builder {
+ private RestaurantId restaurantId;
+ private List products;
+ private boolean isActive;
+
+ private Builder() {
+ }
+
+ public Builder id(RestaurantId val) {
+ restaurantId = val;
+ return this;
+ }
+
+ public Builder products(List val) {
+ products = val;
+ return this;
+ }
+
+ public Builder isActive(boolean val) {
+ isActive = val;
+ return this;
+ }
+
+ public Restaurant build() {
+ return new Restaurant(this);
+ }
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java
new file mode 100644
index 0000000..6e8f7b5
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java
@@ -0,0 +1,12 @@
+package com.food.order.system.domain.event;
+
+import com.food.order.system.domain.entity.Order;
+
+import java.time.ZonedDateTime;
+
+public class OrderCancelledEvent extends OrderEvent {
+
+ public OrderCancelledEvent(Order order, ZonedDateTime utc) {
+ super(order, utc);
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java
new file mode 100644
index 0000000..620f5c1
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java
@@ -0,0 +1,11 @@
+package com.food.order.system.domain.event;
+
+import com.food.order.system.domain.entity.Order;
+
+import java.time.ZonedDateTime;
+
+public class OrderCreatedEvent extends OrderEvent {
+ public OrderCreatedEvent(Order order, ZonedDateTime createdAt) {
+ super(order, createdAt);
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderEvent.java
new file mode 100644
index 0000000..fe26697
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderEvent.java
@@ -0,0 +1,24 @@
+package com.food.order.system.domain.event;
+
+import com.food.order.domain.event.DomainEvent;
+import com.food.order.system.domain.entity.Order;
+
+import java.time.ZonedDateTime;
+
+public abstract class OrderEvent implements DomainEvent {
+ private final Order order;
+ private final ZonedDateTime createdAt;
+
+ protected OrderEvent(Order order, ZonedDateTime createdAt) {
+ this.order = order;
+ this.createdAt = ZonedDateTime.now();
+ }
+
+ public Order getOrder() {
+ return order;
+ }
+
+ public ZonedDateTime getCreatedAt() {
+ return createdAt;
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java
new file mode 100644
index 0000000..6467567
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java
@@ -0,0 +1,13 @@
+package com.food.order.system.domain.event;
+
+import com.food.order.system.domain.entity.Order;
+
+import java.time.ZonedDateTime;
+
+public class OrderPaidEvent extends OrderEvent {
+
+ public OrderPaidEvent(Order order, ZonedDateTime utc) {
+ super(order, utc);
+ }
+
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/exception/OrderDomainException.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/exception/OrderDomainException.java
new file mode 100644
index 0000000..42d05ba
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/exception/OrderDomainException.java
@@ -0,0 +1,14 @@
+package com.food.order.system.domain.exception;
+
+import com.food.order.domain.exception.DomainException;
+
+public class OrderDomainException extends DomainException {
+
+ public OrderDomainException(String message) {
+ super(message);
+ }
+
+ public OrderDomainException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java
new file mode 100644
index 0000000..6de2853
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java
@@ -0,0 +1,23 @@
+package com.food.order.system.domain.service;
+
+import com.food.order.system.domain.entity.Order;
+import com.food.order.system.domain.entity.Restaurant;
+import com.food.order.system.domain.event.OrderCancelledEvent;
+import com.food.order.system.domain.event.OrderCreatedEvent;
+import com.food.order.system.domain.event.OrderPaidEvent;
+
+import java.util.List;
+
+public interface OrderDomainService {
+
+ OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant);
+
+ OrderPaidEvent payOrder(Order order);
+
+ void approve(Order order);
+
+ OrderCancelledEvent cancelOrderPayment(Order order, List failureMessages);
+
+ void cancelOrder(Order order, List failureMessages);
+
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java
new file mode 100644
index 0000000..901e4fc
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java
@@ -0,0 +1,73 @@
+package com.food.order.system.domain.service.impl;
+
+import com.food.order.system.domain.entity.Order;
+import com.food.order.system.domain.entity.Restaurant;
+import com.food.order.system.domain.event.OrderCancelledEvent;
+import com.food.order.system.domain.event.OrderCreatedEvent;
+import com.food.order.system.domain.event.OrderPaidEvent;
+import com.food.order.system.domain.exception.OrderDomainException;
+import com.food.order.system.domain.service.OrderDomainService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.List;
+
+@Slf4j
+public class OrderDomainServiceImpl implements OrderDomainService {
+
+ private static final String UTC = "UTC";
+
+ @Override
+ public OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant) {
+ validateRestaurant(restaurant);
+ setOrderProductInformation(order,restaurant);
+ order.validateOrder();
+ order.initializeOrder();
+ log.info("Order with id {} initialize successfully", order.getId().getValue());
+ return new OrderCreatedEvent(order, ZonedDateTime.now(ZoneId.of(UTC)));
+ }
+
+ private void setOrderProductInformation(Order order, Restaurant restaurant) {
+ order.getItems()
+ .forEach(orderItem -> restaurant.getProducts().forEach(restaurantProduct -> {
+ var currentProduct = orderItem.getProduct();
+ if(currentProduct.equals(restaurantProduct)){
+ currentProduct.updateWithConfirmedNameAndPrice(restaurantProduct.getName(),restaurantProduct.getPrice());
+ }
+ }));
+ }
+
+ private void validateRestaurant(Restaurant restaurant) {
+ if (Boolean.FALSE.equals(restaurant.isActive())) {
+ throw new OrderDomainException("Restaurant is not active, please try again later. " +
+ "Restaurant id: {} " + restaurant.getId());
+ }
+ }
+
+ @Override
+ public OrderPaidEvent payOrder(Order order) {
+ order.pay();
+ log.info("Order with id {} paid successfully", order.getId().getValue());
+ return new OrderPaidEvent(order, ZonedDateTime.now(ZoneId.of(UTC)));
+ }
+
+ @Override
+ public void approve(Order order) {
+ order.approve();
+ log.info("Order with id {} approved successfully", order.getId().getValue());
+ }
+
+ @Override
+ public OrderCancelledEvent cancelOrderPayment(Order order, List failureMessages) {
+ order.initCancel(failureMessages);
+ log.info("Order with id {} cancelled successfully", order.getId().getValue());
+ return new OrderCancelledEvent(order, ZonedDateTime.now(ZoneId.of(UTC)));
+ }
+
+ @Override
+ public void cancelOrder(Order order, List failureMessages) {
+ order.cancel(failureMessages);
+ log.info("Order with id {} cancelled successfully", order.getId().getValue());
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/OrderItemId.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/OrderItemId.java
new file mode 100644
index 0000000..7a12043
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/OrderItemId.java
@@ -0,0 +1,12 @@
+package com.food.order.system.domain.valueobject;
+
+import com.food.order.domain.valueobject.BaseId;
+
+import java.util.UUID;
+
+public class OrderItemId extends BaseId {
+
+ public OrderItemId(Long id) {
+ super(id);
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/StreetAddress.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/StreetAddress.java
new file mode 100644
index 0000000..6253260
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/StreetAddress.java
@@ -0,0 +1,47 @@
+package com.food.order.system.domain.valueobject;
+
+import java.util.UUID;
+
+
+public class StreetAddress {
+
+ private final UUID id;
+ private final String street;
+ private final String city;
+ private final String postalCode;
+
+ public StreetAddress(UUID id, String street, String city, String postalCode) {
+ this.id = id;
+ this.street = street;
+ this.city = city;
+ this.postalCode = postalCode;
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public String getPostalCode() {
+ return postalCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof StreetAddress that)) return false;
+ return id.equals(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+}
diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/TrackingId.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/TrackingId.java
new file mode 100644
index 0000000..3c94c97
--- /dev/null
+++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/valueobject/TrackingId.java
@@ -0,0 +1,11 @@
+package com.food.order.system.domain.valueobject;
+
+import com.food.order.domain.valueobject.BaseId;
+
+import java.util.UUID;
+
+public class TrackingId extends BaseId {
+ public TrackingId(UUID id) {
+ super(id);
+ }
+}
diff --git a/pom.xml b/pom.xml
index 9de0e1a..fa6d9b9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,19 @@
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+