ProductCommandService.java
package com.dmasone.identity.catalog.application;
import com.dmasone.identity.catalog.domain.Product;
import com.dmasone.identity.catalog.domain.ProductNotFoundException;
import com.dmasone.identity.catalog.infrastructure.persistence.ProductJpaEntity;
import com.dmasone.identity.catalog.infrastructure.persistence.ProductJpaRepository;
import com.dmasone.identity.catalog.infrastructure.persistence.ProductMapper;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Write-side catalog service. It is intentionally narrow: other modules can
* reserve stock, but cannot update catalog rows or bypass the domain rule.
*/
@Service
public class ProductCommandService implements StockReservationService {
private final ProductJpaRepository productRepository;
public ProductCommandService(ProductJpaRepository productRepository) {
this.productRepository = productRepository;
}
@Override
@Transactional
@CacheEvict(cacheNames = {"catalogProducts", "catalogProduct"}, allEntries = true)
public void reserveStock(Long productId, int quantity) {
ProductJpaEntity entity = productRepository.findByIdForUpdate(productId)
.orElseThrow(() -> new ProductNotFoundException(productId));
Product product = ProductMapper.toDomain(entity);
product.reserve(quantity);
entity.apply(product);
}
}