Skip to content

Feat/order status update event#35

Merged
ginsengcandy merged 16 commits into
devfrom
feat/orderStatusUpdateEvent
May 9, 2026
Merged

Feat/order status update event#35
ginsengcandy merged 16 commits into
devfrom
feat/orderStatusUpdateEvent

Conversation

@ginsengcandy
Copy link
Copy Markdown
Contributor

@ginsengcandy ginsengcandy commented May 6, 2026

개요

주문 상태 변경 이벤트 발행 및 알림 서버에 전송
RedisAutoConfiguration 오버라이딩하여 테스트 코드 실패 해결

작업 내용

기술적 고려사항

주문 조회 시 주문자(buyer)를 fetch join하여 알림 서버에서는 별도 조회 없이 바로 발송할 수 있도록 함

참고사항

Closes #

체크리스트

  • 로컬 환경에서 정상 동작 확인
  • 관련 문서를 업데이트
  • 모든 테스트가 통과
  • 불필요한 console.log, 주석을 제거
  • 코드 self-review를 완료

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 주문 상태 업데이트 이벤트가 관리자 정보 대신 구매자 정보를 올바르게 추적하도록 개선했습니다.
    • 주문 조회 시 구매자 관계 데이터를 함께 로드하여 데이터 일관성을 강화했습니다.
  • Chores

    • CI 워크플로우에 Redis 서비스 컨테이너 지원을 추가했습니다.
    • 테스트 인프라를 Docker 컨테이너 기반으로 개선하여 테스트 환경 안정성을 높였습니다.

Walkthrough

PR은 주문 상태 업데이트 이벤트를 adminId에서 buyerId로 전환하고, 이를 위해 저장소에 buyer를 즉시 로드하는 메서드를 추가하고 서비스와 이벤트 리스너를 수정합니다. CI에 Redis 서비스가 추가되고 테스트 구성과 테스트 코드(Testcontainers, Redisson mock, 테스트 YAML)가 업데이트됩니다.

변경사항

주문 상태 업데이트 이벤트 흐름 리팩토링

레이어 / 파일(s) 요약
이벤트 & DTO 스키마
src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEvent.java, src/main/java/com/example/allinmarket/domain/order/event/dto/OrderStatusUpdateEventRequest.java
OrderStatusUpdateEventOrderStatusUpdateEventRequest 레코드가 adminId 대신 buyerId: Long을 포함하도록 변경됩니다.
저장소 강화
src/main/java/com/example/allinmarket/domain/order/repository/OrderRepository.java
새로운 findByIdWithBuyer(Long orderId) 메서드가 JPQL JOIN FETCH로 buyer 관계를 즉시 로드합니다.
서비스 구현
src/main/java/com/example/allinmarket/admin/order/service/AdminOrderService.java
updateStatusfindByIdWithBuyer를 사용하여 order를 로드하고 order.getBuyer().getId()로부터 OrderStatusUpdateEvent를 게시합니다.
이벤트 리스너 & 통합
src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEventListener.java
리스너가 event.buyerId()를 사용하여 요청을 구성하고 복수 엔드포인트 /internal/notifications/orders로 게시하며 에러 로깅을 업데이트합니다.
CI/CD & 테스트 인프라
.github/workflows/ci.yml, src/test/resources/application-test.yml, src/test/java/com/example/allinmarket/common/config/TestRedisConfig.java
GitHub CI의 test 잡이 Redis 7 서비스 컨테이너를 프로비저닝하고, 테스트 설정에서 bean 정의 오버라이딩을 허용하며 Redis 리포지토리를 비활성화하고 RedissonClient mock 빈을 추가합니다.
테스트 케이스 & 업데이트
src/test/java/com/example/allinmarket/admin/order/service/AdminOrderServiceTest.java, src/test/java/com/example/allinmarket/admin/refund/service/AdminRefundOptimisticLockServiceTest.java
AdminOrderServiceTest의 테스트 스텁이 findByIdWithBuyer로 변경되었고, AdminRefundOptimisticLockServiceTest는 Testcontainers MySQL로 마이그레이션되어 per-test UUID 기반 impUid를 사용합니다.

예상되는 코드 리뷰 노력

🎯 3 (보통) | ⏱️ ~25분

관련 가능성 있는 PR

제안된 리뷰어

  • bjw446
  • LeeJun14
  • hyuham1335-stack
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 주문 상태 업데이트 이벤트라는 주요 변경 사항을 명확하게 나타내며 모든 파일 변경과 관련이 있습니다.
Description check ✅ Passed 설명은 이벤트 발행, 알림 서버 전송, RedisAutoConfiguration 오버라이딩 등 변경 사항과 관련된 내용을 포함합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/orderStatusUpdateEvent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/test/java/com/example/allinmarket/admin/order/service/AdminOrderServiceTest.java (1)

174-255: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

상태 변경 테스트에 이벤트 발행 내용 검증을 추가해 주세요.

Line 188-193은 반환값만 확인하고 있어, PR 핵심인 buyerId 기반 이벤트 발행이 깨져도 테스트가 통과할 수 있습니다. 성공 케이스에서 publishEvent payload를 검증하고, 실패 케이스에서는 발행이 없음을 함께 확인하는 편이 안전합니다.

테스트 보강 예시
+import com.example.allinmarket.domain.order.event.OrderStatusUpdateEvent;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;

@@
     void 관리자_주문상태_변경_성공_테스트() {
@@
         OrderDetailResponse result = adminOrderService.updateStatus(adminId, orderId, request);

         // then
         assertNotNull(result);
         assertEquals(orderId, result.orderId());
+        verify(eventPublisher).publishEvent(argThat(event ->
+                event instanceof OrderStatusUpdateEvent e
+                        && e.buyerId().equals(1L)
+                        && e.orderId().equals(orderId)
+                        && e.status() == OrderStatus.SHIPPED
+        ));
     }

@@
     void 관리자_주문상태_변경_관리자없음_실패_테스트() {
@@
         assertEquals(ErrorEnum.ADMIN_NOT_FOUND, exception.getErrorEnum());
+        verifyNoInteractions(eventPublisher);
     }

@@
     void 관리자_주문상태_변경_주문없음_실패_테스트() {
@@
         assertEquals(ErrorEnum.ORDER_NOT_FOUND, exception.getErrorEnum());
+        verifyNoInteractions(eventPublisher);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/example/allinmarket/admin/order/service/AdminOrderServiceTest.java`
around lines 174 - 255, Add assertions that the event publisher's publishEvent
is called with the correct payload in the success test and not called in the
failure tests: in 관리자_주문상태_변경_성공_테스트 after calling
adminOrderService.updateStatus(adminId, orderId, request) verify the mocked
event publisher's publishEvent was invoked once with an event whose payload
contains the expected buyerId (use createOrderMock(orderId)'s buyer id to
compare, e.g. verify(eventPublisher).publishEvent(argThat(event -> /* payload
contains buyerId */))); and in 관리자_주문상태_변경_관리자없음_실패_테스트, 관리자_주문상태_변경_주문없음_실패_테스트
and 관리자_주문상태_변경_불가상태_실패_테스트 verify(eventPublisher, never()).publishEvent(any())
so no event is emitted on failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 76-77: Update the CI env var for connecting to the Redis service:
change SPRING_REDIS_HOST from "redis" to "localhost" (or "127.0.0.1") so the job
running on runs-on: ubuntu-latest can reach the service container; keep
SPRING_REDIS_PORT: 6379 unchanged and ensure any code that reads
SPRING_REDIS_HOST uses the new value.

In
`@src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEventListener.java`:
- Around line 73-75: The catch in OrderStatusUpdateEventListener that swallows
JsonProcessingException should instead propagate the failure so the missing
order-status notification is observable: in the catch for
JsonProcessingException (inside the method handling the event), log the error as
you do but then rethrow a runtime exception (or wrap and throw) so the error
surfaces to the caller/monitoring; update the catch block around the
serialization call that currently logs "주문 상태 변경 이벤트 직렬화 실패..." to both log and
throw (e.g., new IllegalStateException or custom unchecked) preserving the
original exception as the cause.

In
`@src/test/java/com/example/allinmarket/admin/refund/service/AdminRefundOptimisticLockServiceTest.java`:
- Around line 63-66: The MySQL TestContainer declaration using the floating tag
"mysql:8.0" reduces CI reproducibility; update the static MySQLContainer<?>
mysql declaration in AdminRefundOptimisticLockServiceTest to reference a fixed
image tag or digest (e.g., "mysql:8.0.36" or use
DockerImageName.parse("mysql:8.0.36") or a sha256 digest) so the container uses
an immutable image version across runs.

---

Outside diff comments:
In
`@src/test/java/com/example/allinmarket/admin/order/service/AdminOrderServiceTest.java`:
- Around line 174-255: Add assertions that the event publisher's publishEvent is
called with the correct payload in the success test and not called in the
failure tests: in 관리자_주문상태_변경_성공_테스트 after calling
adminOrderService.updateStatus(adminId, orderId, request) verify the mocked
event publisher's publishEvent was invoked once with an event whose payload
contains the expected buyerId (use createOrderMock(orderId)'s buyer id to
compare, e.g. verify(eventPublisher).publishEvent(argThat(event -> /* payload
contains buyerId */))); and in 관리자_주문상태_변경_관리자없음_실패_테스트, 관리자_주문상태_변경_주문없음_실패_테스트
and 관리자_주문상태_변경_불가상태_실패_테스트 verify(eventPublisher, never()).publishEvent(any())
so no event is emitted on failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b88c0f3d-7de0-4b6f-8a06-b1306f2db574

📥 Commits

Reviewing files that changed from the base of the PR and between a08e4c6 and 5219348.

📒 Files selected for processing (10)
  • .github/workflows/ci.yml
  • src/main/java/com/example/allinmarket/admin/order/service/AdminOrderService.java
  • src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEvent.java
  • src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEventListener.java
  • src/main/java/com/example/allinmarket/domain/order/event/dto/OrderStatusUpdateEventRequest.java
  • src/main/java/com/example/allinmarket/domain/order/repository/OrderRepository.java
  • src/test/java/com/example/allinmarket/admin/order/service/AdminOrderServiceTest.java
  • src/test/java/com/example/allinmarket/admin/refund/service/AdminRefundOptimisticLockServiceTest.java
  • src/test/java/com/example/allinmarket/common/config/TestRedisConfig.java
  • src/test/resources/application-test.yml
📜 Review details
🧰 Additional context used
🪛 Checkov (3.2.526)
src/test/resources/application-test.yml

[low] 24-25: Base64 High Entropy String

(CKV_SECRET_6)

.github/workflows/ci.yml

[low] 75-76: Base64 High Entropy String

(CKV_SECRET_6)

🪛 PMD (7.24.0)
src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEventListener.java

[Low] 71-71: Too many arguments, expected 3 arguments but found 4 (InvalidLogMessageFormat)

(Error Prone)


[Low] 74-74: Too many arguments, expected 2 arguments but found 3 (InvalidLogMessageFormat)

(Error Prone)

🔇 Additional comments (8)
src/main/java/com/example/allinmarket/domain/order/repository/OrderRepository.java (1)

22-26: findByIdWithBuyer fetch join 적용이 적절합니다.

Line 22-26 쿼리로 buyer를 함께 로딩해 이벤트 발행 시 추가 조회를 피한 점이 좋습니다.

src/main/java/com/example/allinmarket/domain/order/event/OrderStatusUpdateEvent.java (1)

6-9: 이벤트 계약 변경(buyerId)이 일관됩니다.

Line 6-9 변경이 상태 변경 이벤트의 실제 수신자 식별자 기준과 잘 맞습니다.

src/main/java/com/example/allinmarket/domain/order/event/dto/OrderStatusUpdateEventRequest.java (1)

6-8: 요청 DTO 필드 변경이 이벤트 스키마와 맞습니다.

Line 6 기준 buyerId 전환으로 발행/전송 데이터 모델이 정렬되었습니다.

src/main/java/com/example/allinmarket/admin/order/service/AdminOrderService.java (1)

42-47: 주문 조회 방식과 이벤트 payload 전환이 일관됩니다.

Line 42, Line 47에서 findByIdWithBuyer + buyerId 발행 흐름으로 맞춘 점이 좋습니다.

src/test/java/com/example/allinmarket/common/config/TestRedisConfig.java (1)

23-26: RedissonClient 목 빈 추가 방향이 적절합니다.

테스트 컨텍스트에서 Redisson 의존성을 안전하게 대체해, 통합 테스트 기동 안정성에 도움이 됩니다.

.github/workflows/ci.yml (1)

40-49: Redis 서비스 컨테이너/헬스체크 구성은 좋습니다.

테스트 단계에서 인프라 의존성을 명시적으로 준비하는 방향이 CI 신뢰성을 높입니다.

src/test/resources/application-test.yml (1)

2-7: 테스트 프로필에서의 Redis 관련 비활성화/오버라이딩 설정이 일관적입니다.

테스트 컨텍스트 충돌을 줄이려는 이번 PR 목적과 맞는 구성입니다.

src/test/java/com/example/allinmarket/admin/refund/service/AdminRefundOptimisticLockServiceTest.java (1)

110-110: impUid를 테스트마다 유니크하게 만든 변경은 충돌 방지에 유효합니다.

결제 식별자 중복으로 인한 간헐적 테스트 실패 가능성을 잘 줄였습니다.

Also applies to: 126-127, 406-407

Comment thread .github/workflows/ci.yml Outdated
@ginsengcandy ginsengcandy merged commit 54e93ee into dev May 9, 2026
2 of 3 checks passed
@ginsengcandy ginsengcandy deleted the feat/orderStatusUpdateEvent branch May 9, 2026 10:50
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.

4 participants