diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 712ab9d..947ef88 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -6,6 +6,11 @@
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index d656404..df316bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,6 +47,12 @@
lombok
true
+
+ com.github.Podzilla
+ podzilla-utils-lib
+ 1.1.11
+
+
@@ -150,7 +156,12 @@
test
-
+
+
+ jitpack.io
+ https://jitpack.io
+
+
diff --git a/src/main/java/cart/CartApplication.java b/src/main/java/cart/CartApplication.java
index 2ef8d6d..abec166 100644
--- a/src/main/java/cart/CartApplication.java
+++ b/src/main/java/cart/CartApplication.java
@@ -2,10 +2,12 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@SpringBootApplication
@EnableMongoRepositories(basePackages = "cart.repository")
+@ComponentScan(basePackages = { "com.podzilla" })
public class CartApplication {
public static void main(final String[] args) {
SpringApplication.run(CartApplication.class, args);
diff --git a/src/main/java/cart/controller/CartController.java b/src/main/java/cart/controller/CartController.java
index 16a3a0c..1cfe7eb 100644
--- a/src/main/java/cart/controller/CartController.java
+++ b/src/main/java/cart/controller/CartController.java
@@ -1,7 +1,5 @@
package cart.controller;
-
-
import cart.model.Cart;
import cart.service.CartService;
import io.swagger.v3.oas.annotations.Operation;
@@ -13,6 +11,9 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
+
+import com.podzilla.mq.events.DeliveryAddress;
+
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.GetMapping;
@@ -22,6 +23,7 @@
import org.springframework.web.bind.annotation.RequestBody;
import cart.model.CartItem;
import io.swagger.v3.oas.annotations.media.Content;
+import org.springframework.web.bind.annotation.RequestHeader;
@RestController
@RequestMapping("/api/carts")
@@ -46,9 +48,11 @@ public class CartController {
description = "Internal server error",
content = @Content)
})
- @PostMapping("/create/{customerId}")
+
+
+ @PostMapping("/create")
public ResponseEntity createCart(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering createCart endpoint"
+ " with customerId:", customerId);
Cart cart = cartService.createCart(customerId);
@@ -63,9 +67,10 @@ public ResponseEntity createCart(
@ApiResponse(responseCode = "404",
description = "Cart not found for this customer")
})
- @GetMapping("/customer/{customerId}")
+
+ @GetMapping("/customer")
public ResponseEntity getCartByCustomerId(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering getCartByCustomerId"
+ " endpoint with customerId:",
customerId);
@@ -81,9 +86,10 @@ public ResponseEntity getCartByCustomerId(
@ApiResponse(responseCode = "404",
description = "Cart not found")
})
- @DeleteMapping("/customer/{customerId}")
+
+ @DeleteMapping("/customer")
public ResponseEntity deleteCart(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering deleteCart end"
+ "point with customerId:", customerId);
cartService.deleteCartByCustomerId(customerId);
@@ -105,7 +111,7 @@ public ResponseEntity deleteCart(
})
@PostMapping("/{customerId}/items")
public ResponseEntity addItemToCart(
- @PathVariable("customerId") final String customerId,
+ @RequestHeader("X-User-Id") final String customerId,
@RequestBody final CartItem cartItem) {
log.debug("Entering addItemToCart"
+ " endpoint with customerId: {},"
@@ -127,7 +133,7 @@ public ResponseEntity addItemToCart(
})
@PatchMapping("/{customerId}/items/{productId}")
public ResponseEntity updateItemQuantity(
- @PathVariable("customerId") final String customerId,
+ @RequestHeader("X-User-Id") final String customerId,
@PathVariable("productId") final String productId,
@RequestParam final int quantity) {
log.debug("Entering updateItemQuantity"
@@ -150,7 +156,7 @@ public ResponseEntity updateItemQuantity(
})
@DeleteMapping("/{customerId}/items/{productId}")
public ResponseEntity removeItemFromCart(
- @PathVariable("customerId") final String customerId,
+ @RequestHeader("X-User-Id") final String customerId,
@PathVariable("productId") final String productId) {
log.debug("Entering removeItemFromCart"
+ " endpoint with customerId:,"
@@ -169,9 +175,10 @@ public ResponseEntity removeItemFromCart(
@ApiResponse(responseCode = "404",
description = "Cart not found")
})
- @DeleteMapping("/{customerId}/clear")
+
+ @DeleteMapping("/clear")
public ResponseEntity clearCart(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering clearCart"
+ " endpoint with customerId:", customerId);
cartService.clearCart(customerId);
@@ -186,9 +193,10 @@ public ResponseEntity clearCart(
@ApiResponse(responseCode = "404",
description = "Cart not found")
})
- @PatchMapping("/{customerId}/archive")
+
+ @PatchMapping("/archive")
public ResponseEntity archiveCart(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering archiveCart"
+ " endpoint with customerId:", customerId);
Cart archivedCart = cartService.archiveCart(customerId);
@@ -203,9 +211,10 @@ public ResponseEntity archiveCart(
@ApiResponse(responseCode = "404",
description = "Archived cart not found")
})
- @PatchMapping("/{customerId}/unarchive")
+ // Replace @PatchMapping("/{customerId}/unarchive")
+ @PatchMapping("/unarchive")
public ResponseEntity unarchiveCart(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering unarchiveCart"
+ " endpoint with customerId:", customerId);
Cart activeCart = cartService.unarchiveCart(customerId);
@@ -222,20 +231,27 @@ public ResponseEntity unarchiveCart(
@ApiResponse(responseCode = "500",
description = "Failed to communicate with Order Service")
})
- @PostMapping("/{customerId}/checkout")
+
+ @PostMapping("/checkout")
public ResponseEntity checkoutCart(
- @PathVariable("customerId") final String customerId) {
- log.debug("Entering checkoutCart"
- + " endpoint with customerId:", customerId);
+ @RequestHeader("X-User-Id") final String customerId,
+ @RequestParam(required = true) final com.podzilla.mq.events.ConfirmationType confirmationType,
+ @RequestParam(required = false) final String signature,
+ @RequestParam(required = true) final Double longitude,
+ @RequestParam(required = true) final Double latitude,
+ @RequestParam(required = true) final DeliveryAddress address
+ ) {
+ log.debug("Entering checkoutCart endpoint with customerId: {}," +
+ " confirmationType: {}, signature: {}",
+ customerId, confirmationType, signature);
try {
- Cart updatedCart = cartService.checkoutCart(customerId);
+ Cart updatedCart = cartService.checkoutCart(customerId, confirmationType,
+ signature, longitude, latitude, address);
log.debug("Cart checked out: {}", updatedCart);
return ResponseEntity.ok(updatedCart);
} catch (Exception ex) {
- log.error("Error during checkout"
- + " for customerId: {}", customerId, ex);
- throw new IllegalCallerException("Error "
- + "communicating with Order Service");
+ log.error("Error during checkout for customerId: {}", customerId, ex);
+ throw new IllegalCallerException("Error communicating with Order Service");
}
}
@@ -248,9 +264,10 @@ public ResponseEntity checkoutCart(
@ApiResponse(responseCode = "404",
description = "Active cart not found")
})
- @PostMapping("/{customerId}/promo/{promoCode}")
+
+ @PostMapping("/promo/{promoCode}")
public ResponseEntity applyPromoCode(
- @PathVariable("customerId") final String customerId,
+ @RequestHeader("X-User-Id") final String customerId,
@PathVariable("promoCode") final String promoCode) {
log.debug("Entering applyPromoCode endpoint with "
+ "customerId: {}, promoCode: {}",
@@ -269,9 +286,10 @@ public ResponseEntity applyPromoCode(
@ApiResponse(responseCode = "404",
description = "Active cart not found")
})
- @DeleteMapping("/{customerId}/promo")
+
+ @DeleteMapping("/promo")
public ResponseEntity removePromoCode(
- @PathVariable("customerId") final String customerId) {
+ @RequestHeader("X-User-Id") final String customerId) {
log.debug("Entering removePromoCode "
+ "endpoint with customerId: {}", customerId);
Cart updatedCart = cartService.removePromoCode(customerId);
diff --git a/src/main/java/cart/model/OrderRequest.java b/src/main/java/cart/model/OrderRequest.java
deleted file mode 100644
index 2823dcf..0000000
--- a/src/main/java/cart/model/OrderRequest.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package cart.model;
-
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class OrderRequest {
- private String eventId;
- private String customerId;
- private String cartId;
- private List items;
- private BigDecimal subTotal;
- private BigDecimal discountAmount;
- private BigDecimal totalPrice;
- private String appliedPromoCode;
-
-}
diff --git a/src/main/java/cart/service/CartService.java b/src/main/java/cart/service/CartService.java
index 15a4413..2945d27 100644
--- a/src/main/java/cart/service/CartService.java
+++ b/src/main/java/cart/service/CartService.java
@@ -3,40 +3,41 @@
import cart.exception.GlobalHandlerException;
import cart.model.Cart;
import cart.model.CartItem;
-import cart.model.OrderRequest;
import cart.model.PromoCode;
import cart.repository.CartRepository;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.amqp.rabbit.core.RabbitTemplate;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
+import com.podzilla.mq.EventPublisher;
+import com.podzilla.mq.EventsConstants;
+import com.podzilla.mq.events.CartCheckedoutEvent;
+import com.podzilla.mq.events.ConfirmationType;
+import com.podzilla.mq.events.DeliveryAddress;
+import com.podzilla.mq.events.OrderItem;
+
import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.UUID;
+import java.util.stream.Collectors;
@Service
@Slf4j
public class CartService {
private final CartRepository cartRepository;
- private final RabbitTemplate rabbitTemplate;
+ private final EventPublisher eventPublisher;
private final PromoCodeService promoCodeService;
- @Value("${rabbitmq.exchange.name}")
- private String exchangeName;
- @Value("${rabbitmq.routing.key.checkout}")
- private String checkoutRoutingKey;
-
public CartService(final CartRepository cartRepository,
- final RabbitTemplate rabbitTemplate,
- final PromoCodeService promoCodeService) {
+ final EventPublisher eventPublisher,
+ final PromoCodeService promoCodeService) {
this.cartRepository = cartRepository;
- this.rabbitTemplate = rabbitTemplate;
+ this.eventPublisher = eventPublisher;
this.promoCodeService = promoCodeService;
}
@@ -250,8 +251,10 @@ private BigDecimal calculateSubTotal(final Cart cart) {
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
- public Cart checkoutCart(final String customerId) {
- log.debug("Entering checkoutCart [RabbitMQ] for customerId: {}", customerId);
+ public Cart checkoutCart(final String customerId, final ConfirmationType confirmationType,
+ final String signature, final Double longitude, final Double latitude, DeliveryAddress address) {
+ log.debug("Entering checkoutCart for customerId: {} with confirmationType: {}",
+ customerId, confirmationType);
Cart cart = getActiveCart(customerId);
recalculateCartTotals(cart);
@@ -261,21 +264,34 @@ public Cart checkoutCart(final String customerId) {
throw new GlobalHandlerException(HttpStatus.BAD_REQUEST, "Cannot checkout an empty cart.");
}
- OrderRequest checkoutEvent = new OrderRequest(
- UUID.randomUUID().toString(),
- customerId,
- cart.getId(),
- new ArrayList<>(cart.getItems()),
- cart.getSubTotal(),
- cart.getDiscountAmount(),
- cart.getTotalPrice(),
- cart.getAppliedPromoCode()
- );
+ if (confirmationType == ConfirmationType.SIGNATURE && (signature == null || signature.trim().isEmpty())) {
+ throw new GlobalHandlerException(HttpStatus.BAD_REQUEST, "Signature is required for SIGNATURE confirmation type");
+ }
+
+ List orderItems = cart.getItems().stream()
+ .map(cartItem -> OrderItem.builder()
+ .productId(cartItem.getProductId())
+ .quantity(cartItem.getQuantity())
+ .pricePerUnit(cartItem.getUnitPrice())
+ .build())
+ .collect(Collectors.toList());
+
+ CartCheckedoutEvent checkoutEvent = CartCheckedoutEvent.builder()
+ .cartId(cart.getId())
+ .customerId(customerId)
+ .items(orderItems)
+ .totalAmount(cart.getTotalPrice())
+ .deliveryAddress(address)
+ .orderLatitude(latitude != null ? latitude : 0.0)
+ .orderLongitude(longitude != null ? longitude : 0.0)
+ .signature(signature)
+ .confirmationType(confirmationType)
+ .build();
try {
- log.debug("Publishing checkout event for cartId: {} with totals: Sub={}, Discount={}, Total={}",
- cart.getId(), cart.getSubTotal(), cart.getDiscountAmount(), cart.getTotalPrice());
- rabbitTemplate.convertAndSend(exchangeName, checkoutRoutingKey, checkoutEvent);
+ log.debug("Publishing checkout event for cartId: {} with totals: Sub={}, Discount={}, Total={}, ConfirmationType={}",
+ cart.getId(), cart.getSubTotal(), cart.getDiscountAmount(), cart.getTotalPrice(), confirmationType);
+ eventPublisher.publishEvent(EventsConstants.ORDER_PLACED, checkoutEvent);
log.info("Checkout event published successfully for cartId: {}. Clearing cart.", cart.getId());
cart.getItems().clear();
diff --git a/src/test/java/service/CartServiceTest.java b/src/test/java/service/CartServiceTest.java
index da519e5..eb9622a 100644
--- a/src/test/java/service/CartServiceTest.java
+++ b/src/test/java/service/CartServiceTest.java
@@ -2,7 +2,6 @@
import cart.exception.GlobalHandlerException;
import cart.model.Cart;
import cart.model.CartItem;
-import cart.model.OrderRequest;
import cart.model.PromoCode;
import cart.repository.CartRepository;
import cart.service.CartService;
@@ -18,6 +17,12 @@
import org.springframework.http.HttpStatus;
import org.springframework.test.util.ReflectionTestUtils;
+import com.podzilla.mq.EventPublisher;
+import com.podzilla.mq.EventsConstants;
+import com.podzilla.mq.events.CartCheckedoutEvent;
+import com.podzilla.mq.events.ConfirmationType;
+import com.podzilla.mq.events.DeliveryAddress;
+
import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
@@ -36,7 +41,7 @@ class CartServiceTest {
private CartRepository cartRepository;
@Mock
- private RabbitTemplate rabbitTemplate;
+ private EventPublisher eventPublisher; // Replace RabbitTemplate with EventPublisher
@Mock
private PromoCodeService promoCodeService;
@@ -51,9 +56,12 @@ class CartServiceTest {
private final String customerId = "cust123";
private final String productId1 = "prod1";
private final String productId2 = "prod2";
+ private final Double latitude = 77.12;
+ private final Double longitude = 77.12;
private final BigDecimal price1 = new BigDecimal("10.50");
private final BigDecimal price2 = new BigDecimal("5.00");
private final String cartId = UUID.randomUUID().toString();
+ private final DeliveryAddress address = new DeliveryAddress("123 Main St", "City", "State", "Country", "12345");
private final String exchangeName = "test.cart.events";
private final String checkoutRoutingKey = "test.order.checkout.initiate";
@@ -81,9 +89,11 @@ void setUp() {
item1Input = new CartItem(productId1, 1, price1);
item2Input = new CartItem(productId2, 2, price2);
- ReflectionTestUtils.setField(cartService, "exchangeName", exchangeName);
- ReflectionTestUtils.setField(cartService, "checkoutRoutingKey", checkoutRoutingKey);
+ // Remove these lines as they're no longer needed
+ // ReflectionTestUtils.setField(cartService, "exchangeName", exchangeName);
+ // ReflectionTestUtils.setField(cartService, "checkoutRoutingKey", checkoutRoutingKey);
+ // Rest of the setup remains the same
lenient().when(cartRepository.save(any(Cart.class))).thenAnswer(invocation -> invocation.getArgument(0));
lenient().when(cartRepository.findByCustomerId(anyString())).thenReturn(Optional.empty());
@@ -335,21 +345,22 @@ void checkoutCart_validCartWithPromo_publishesEventAndClearsCart() {
PromoCode promo = createTestPromoCode("SAVE10", PromoCode.DiscountType.PERCENTAGE, new BigDecimal("10"), null, null, true);
when(promoCodeService.getActivePromoCode("SAVE10")).thenReturn(Optional.of(promo));
- doNothing().when(rabbitTemplate).convertAndSend(anyString(), anyString(), any(OrderRequest.class));
+ doNothing().when(eventPublisher).publishEvent(eq(EventsConstants.ORDER_PLACED), any(CartCheckedoutEvent.class));
- Cart result = cartService.checkoutCart(customerId);
+ Cart result = cartService.checkoutCart(customerId, ConfirmationType.OTP, "", latitude, longitude, address);
- ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(OrderRequest.class);
- verify(rabbitTemplate).convertAndSend(eq(exchangeName), eq(checkoutRoutingKey), eventCaptor.capture());
- OrderRequest publishedEvent = eventCaptor.getValue();
+ ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(CartCheckedoutEvent.class);
+ verify(eventPublisher).publishEvent(eq(EventsConstants.ORDER_PLACED), eventCaptor.capture());
+ CartCheckedoutEvent publishedEvent = eventCaptor.getValue();
assertEquals(customerId, publishedEvent.getCustomerId());
assertEquals(cartId, publishedEvent.getCartId());
assertEquals(1, publishedEvent.getItems().size());
- assertEquals(new BigDecimal("100.00").setScale(2), publishedEvent.getSubTotal());
- assertEquals(new BigDecimal("10.00").setScale(2), publishedEvent.getDiscountAmount());
- assertEquals(new BigDecimal("90.00").setScale(2), publishedEvent.getTotalPrice());
- assertEquals("SAVE10", publishedEvent.getAppliedPromoCode());
+ // assertEquals(new BigDecimal("100.00").setScale(2), publishedEvent().getSubTotal());
+ // assertEquals(new BigDecimal("10.00").setScale(2), publishedEvent.getDiscountAmount());
+ assertEquals(new BigDecimal("90.00").setScale(2), publishedEvent.getTotalAmount());
+ // assertEquals("SAVE10", publishedEvent.getAppliedPromoCode());S
+ assertEquals(ConfirmationType.OTP, publishedEvent.getConfirmationType());
assertTrue(result.getItems().isEmpty());
assertNull(result.getAppliedPromoCode());
@@ -360,16 +371,43 @@ void checkoutCart_validCartWithPromo_publishesEventAndClearsCart() {
verify(cartRepository, times(1)).save(any(Cart.class));
}
+ @Test
+ void checkoutCart_withSignature_publishesEventWithSignature() {
+ cart.getItems().add(new CartItem(productId1, 1, new BigDecimal("100.00")));
+ String signature = "customer_signature_data";
+
+ Cart result = cartService.checkoutCart(customerId, ConfirmationType.SIGNATURE, signature, latitude, longitude, address);
+
+ ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(CartCheckedoutEvent.class);
+ verify(eventPublisher).publishEvent(eq(EventsConstants.ORDER_PLACED), eventCaptor.capture());
+ CartCheckedoutEvent publishedEvent = eventCaptor.getValue();
+
+ assertEquals(ConfirmationType.SIGNATURE, publishedEvent.getConfirmationType());
+ assertEquals(signature, publishedEvent.getSignature());
+ }
+
+ @Test
+ void checkoutCart_signatureTypeWithoutSignature_throwsException() {
+ cart.getItems().add(new CartItem(productId1, 1, new BigDecimal("100.00")));
+
+ GlobalHandlerException ex = assertThrows(GlobalHandlerException.class,
+ () -> cartService.checkoutCart(customerId, ConfirmationType.SIGNATURE, null, latitude, longitude, address));
+
+ assertEquals(HttpStatus.BAD_REQUEST, ex.getStatus());
+ assertEquals("Signature is required for SIGNATURE confirmation type", ex.getMessage());
+verify(eventPublisher, never()).publishEvent(eq(EventsConstants.ORDER_PLACED), any(CartCheckedoutEvent.class));
+ }
+
@Test
void checkoutCart_emptyCart_throwsGlobalHandlerException() {
when(cartRepository.findByCustomerIdAndArchived(customerId, false)).thenReturn(Optional.of(cart));
GlobalHandlerException ex = assertThrows(GlobalHandlerException.class,
- () -> cartService.checkoutCart(customerId));
+ () -> cartService.checkoutCart(customerId, ConfirmationType.OTP, null, latitude, longitude, address));
assertEquals(HttpStatus.BAD_REQUEST, ex.getStatus());
assertEquals("Cannot checkout an empty cart.", ex.getMessage());
- verify(rabbitTemplate, never()).convertAndSend(anyString(), anyString(), any(OrderRequest.class));
+verify(eventPublisher, never()).publishEvent(eq(EventsConstants.ORDER_PLACED), any(CartCheckedoutEvent.class));
}
@Test
@@ -384,11 +422,11 @@ void checkoutCart_rabbitMqFails_throwsRuntimeExceptionAndCartNotCleared() {
cart.setTotalPrice(new BigDecimal(formattedSubTotal));
cart.setDiscountAmount(new BigDecimal(formattedBigZero));
- doThrow(new RuntimeException("RabbitMQ publish error")).when(rabbitTemplate)
- .convertAndSend(eq(exchangeName), eq(checkoutRoutingKey), any(OrderRequest.class));
+ doThrow(new RuntimeException("Event publish error")).when(eventPublisher)
+ .publishEvent(eq(EventsConstants.ORDER_PLACED), any(CartCheckedoutEvent.class));
RuntimeException ex = assertThrows(RuntimeException.class,
- () -> cartService.checkoutCart(customerId));
+ () -> cartService.checkoutCart(customerId, ConfirmationType.QR_CODE, null, latitude, longitude, address));
assertTrue(ex.getMessage().contains("Checkout process failed: Could not publish event."));
verify(cartRepository, never()).save(any(Cart.class));
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index 2fb525b..a2b598e 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -3,10 +3,10 @@ spring.data.mongodb.database=testdb
spring.main.banner-mode= off
spring.main.log-startup-info=false
# RabbitMQ Configuration
-spring.rabbitmq.host=localhost
+spring.rabbitmq.host=rabbitmq
spring.rabbitmq.port=5672
-spring.rabbitmq.username=guest # Use appropriate credentials
-spring.rabbitmq.password=guest # Use appropriate credentials
+spring.rabbitmq.username=guest
+spring.rabbitmq.password=guest
# spring.rabbitmq.virtual-host=/ # Optional
# Custom properties for exchange/routing keys