OrderService.java

package com.github.danielemasone.orderevents.application;

import com.github.danielemasone.orderevents.api.dto.CreateOrderRequest;
import com.github.danielemasone.orderevents.api.dto.OrderResponse;
import com.github.danielemasone.orderevents.domain.Order;
import com.github.danielemasone.orderevents.domain.OrderCreatedEvent;
import com.github.danielemasone.orderevents.domain.OrderStatus;
import com.github.danielemasone.orderevents.infrastructure.mapping.OrderMapper;
import com.github.danielemasone.orderevents.infrastructure.persistence.OrderEntity;
import com.github.danielemasone.orderevents.infrastructure.persistence.OrderRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Clock;
import java.util.UUID;

/**
 * Coordinates order creation by persisting the aggregate and publishing the corresponding Kafka event.
 */
@Service
public class OrderService {

    private final OrderRepository orderRepository;
    private final OrderMapper orderMapper;
    private final EventPublisher eventPublisher;
    private final Clock clock;

    public OrderService(OrderRepository orderRepository, OrderMapper orderMapper, EventPublisher eventPublisher, Clock clock) {
        this.orderRepository = orderRepository;
        this.orderMapper = orderMapper;
        this.eventPublisher = eventPublisher;
        this.clock = clock;
    }

    /**
     * Creates an order inside a database transaction, flushes it to PostgreSQL, and then publishes the event.
     * This deliberately keeps the project simple instead of introducing an outbox; the trade-off is that the
     * database write and Kafka write are coordinated by application flow rather than a single atomic resource.
     *
     * @param request validated API request
     * @return persisted order representation
     */
    @Transactional
    public OrderResponse createOrder(CreateOrderRequest request) {
        Order order = new Order(
                UUID.randomUUID(),
                request.customerId(),
                request.amount(),
                OrderStatus.CREATED,
                clock.instant()
        );

        OrderEntity persisted = orderRepository.saveAndFlush(orderMapper.toEntity(order));
        Order createdOrder = orderMapper.toDomain(persisted);
        OrderCreatedEvent event = orderMapper.toCreatedEvent(createdOrder, UUID.randomUUID(), clock.instant());
        eventPublisher.publish(event);
        return orderMapper.toResponse(createdOrder);
    }
}