Skip to content

feat: decouple fulfillment email side-effects via domain events#34

Open
tkahng wants to merge 3 commits into
mainfrom
feat/event-driven-fulfillment
Open

feat: decouple fulfillment email side-effects via domain events#34
tkahng wants to merge 3 commits into
mainfrom
feat/event-driven-fulfillment

Conversation

@tkahng

@tkahng tkahng commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds FulfillmentShippedEvent and FulfillmentDeliveredEvent domain event records
  • Adds FulfillmentEmailEventListener — handles both events with @TransactionalEventListener(AFTER_COMMIT) + @Async("emailExecutor"), matching the existing OrderEmailEventListener pattern
  • Refactors FulfillmentService to publish events instead of calling EmailService directly, removing the EmailService dependency from that service entirely

Motivation

FulfillmentService.update() was calling emailService.sendShippingNotification() and emailService.sendOrderDelivered() inline inside a @Transactional method. This meant:

  • Email was sent on the request thread, blocking the HTTP response
  • If the transaction rolled back after the email call, a spurious notification would already have been sent
  • FulfillmentService was tightly coupled to EmailService

Publishing events after commit (same pattern already used for OrderConfirmedEvent / OrderCancelledEvent) fixes all three issues.

Changes

File Change
fulfillment/event/FulfillmentShippedEvent.java New record
fulfillment/event/FulfillmentDeliveredEvent.java New record
fulfillment/event/FulfillmentEmailEventListener.java New listener
fulfillment/service/FulfillmentService.java Remove EmailService; inject ApplicationEventPublisher; replace private email methods with event publishing
fulfillment/event/FulfillmentEmailEventListenerTest.java 4 unit tests — delegation and exception safety for both events

Test plan

  • ./mvnw test -Dtest="FulfillmentEmailEventListenerTest" — 4 tests pass
  • ./mvnw test — full suite still green
  • Confirm FulfillmentService no longer imports EmailService: grep -r "EmailService" src/main/java/io/k2dv/garden/fulfillment/

tkahng added 3 commits May 30, 2026 00:02
FulfillmentShippedEvent and FulfillmentDeliveredEvent records replace
direct EmailService calls in FulfillmentService. FulfillmentEmailEventListener
handles delivery after transaction commit (@TransactionalEventListener +
@async), matching the existing OrderEmailEventListener pattern.
…alls

FulfillmentServiceIT and NotificationPreferenceGateIT were verifying
emailService mock calls that now fire asynchronously after transaction
commit. Switched to asserting on FulfillmentShippedEvent /
FulfillmentDeliveredEvent via @RecordApplicationEvents, matching the
existing pattern used for OrderConfirmedEvent / OrderCancelledEvent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant