Skip to content

Comments

feat(rank): 사용자 삭제됐을때, 랭킹에서도 삭제되도록 수정#273

Merged
huhdy32 merged 5 commits intodevelopfrom
feat/rank
Nov 13, 2025
Merged

feat(rank): 사용자 삭제됐을때, 랭킹에서도 삭제되도록 수정#273
huhdy32 merged 5 commits intodevelopfrom
feat/rank

Conversation

@huhdy32
Copy link
Collaborator

@huhdy32 huhdy32 commented Nov 13, 2025

  • 결과적 일관성

Summary by CodeRabbit

  • New Features
    • Member deletion now publishes removal events so all services are notified.
    • Deleting a member automatically removes associated solver records, preventing orphaned data.
    • Cleanup workflow synchronizes member removal across dependent services to improve data consistency and integrity.

@huhdy32 huhdy32 self-assigned this Nov 13, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 13, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds an event-driven member-deletion flow: a MemberDeletedEventPayload type is introduced and published by MemberDeleteService via the outbox; a consumer listener consumes the mathrank-member-removed event and calls a new SolverDeleteService to remove any Solver records for the deleted member.

Changes

Cohort / File(s) Summary
Event Payload Definition
app/consumer/mathrank-rank-consumer-monolith/src/main/java/kr/co/mathrank/app/consumer/rank/EventPayloads.java
Added public nested record MemberDeletedEventPayload(Long memberId, String memberName) implementing EventPayload.
Event Publishing (auth domain)
domain/mathrank-auth-domain/src/main/java/kr/co/mathrank/domain/auth/service/MemberDeleteService.java
Injected TransactionalOutboxPublisher; after expiring tokens, publishes mathrank-member-removed with MemberDeletedEventPayload derived from deleted member.
Event Consumer & Solver deletion
app/consumer/mathrank-rank-consumer-monolith/src/main/java/kr/co/mathrank/app/consumer/rank/SolvedRankEventMonolithListener.java, domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java
Added consumeMemberRemovedEvent(MonolithEvent) to handle mathrank-member-removed events (parses payload and calls solverDeleteService.delete(memberId)). Added SolverDeleteService with @Service and @Transactional delete(Long memberId) that looks up solver by memberId and deletes it if present; logs if not found (does not throw).

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant MemberDeleteService
    participant Outbox as TransactionalOutboxPublisher
    participant Broker as Event Broker
    participant Listener as SolvedRankEventMonolithListener
    participant SolverDeleteService

    Client->>MemberDeleteService: Delete member
    activate MemberDeleteService
    MemberDeleteService->>MemberDeleteService: Expire tokens
    MemberDeleteService->>Outbox: Publish "mathrank-member-removed"\n(MemberDeletedEventPayload)
    deactivate MemberDeleteService
    activate Outbox
    Outbox->>Broker: Emit event
    deactivate Outbox

    Broker->>Listener: Deliver "mathrank-member-removed"
    activate Listener
    Listener->>SolverDeleteService: delete(memberId)
    activate SolverDeleteService
    SolverDeleteService->>SolverDeleteService: findByMemberId(memberId)
    alt Solver found
        SolverDeleteService->>SolverDeleteService: delete solver\nlog deletion
    else Solver not found
        SolverDeleteService->>SolverDeleteService: log info (no-op)
    end
    deactivate SolverDeleteService
    deactivate Listener
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify transactional boundaries around outbox publish in MemberDeleteService
  • Confirm event topic/name and payload shape match consumer expectation
  • Review SolverDeleteService validation, repository usage, and logging (ensure no unintended exceptions)
  • Check listener deserialization and error handling for malformed/unknown payloads

Possibly related PRs

Poem

🐰 I hopped a note into the stream,
A member gone, a tidy beam,
Outbox sent, the broker hummed,
Solvers cleared where once they bum,
Tiny paws, tidy code — all clean! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding member deletion synchronization to the ranking system through event-driven architecture.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/rank

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @huhdy32, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 사용자가 삭제될 때 랭킹 시스템에서도 해당 사용자의 랭킹 정보가 함께 삭제되도록 구현하여 데이터의 결과적 일관성을 보장합니다. 이를 위해 회원 삭제 시 이벤트를 발행하고, 랭킹 서비스에서 해당 이벤트를 수신하여 관련 랭킹 데이터를 처리하는 이벤트 기반 방식을 도입했습니다.

Highlights

  • 회원 삭제 이벤트 페이로드 추가: 회원 삭제 시 발생할 이벤트의 페이로드(MemberDeletedEventPayload)를 정의했습니다.
  • 회원 삭제 이벤트 발행 로직 구현: MemberDeleteService에서 회원이 삭제될 때 mathrank-member-removed 이벤트를 발행하도록 추가했습니다.
  • 랭킹 솔버 삭제 서비스 도입: SolverDeleteService를 새로 추가하여 특정 memberId에 해당하는 랭킹 솔버 데이터를 삭제하는 로직을 구현했습니다.
  • 회원 삭제 이벤트 수신 및 처리: SolvedRankEventMonolithListenermathrank-member-removed 이벤트를 수신하고, 해당 이벤트의 memberId를 사용하여 SolverDeleteService를 통해 랭킹 솔버를 삭제하는 리스너를 추가했습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@huhdy32 huhdy32 changed the title feat(rank): 사용자 삭제됐을때, 랭킹에서 함께 삭제되도록 구현 feat(rank): 사용자 삭제됐을때, 랭킹에서도 삭제되도록 수정 Nov 13, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

이번 PR은 사용자 삭제 시 이벤트 기반으로 랭킹 정보를 함께 삭제하도록 구현하여 서비스 간의 정합성을 맞추는 좋은 변경입니다. 코드 리뷰 결과, 몇 가지 개선점을 발견했습니다. 첫째, 이벤트 페이로드 객체가 중복으로 정의되어 있어 이를 공통 모듈로 통합하는 것이 필요합니다. 둘째, 이벤트 소비자의 멱등성을 보장하여 반복적인 이벤트 처리에도 시스템이 안정적으로 동작하도록 개선할 필요가 있습니다. 셋째, 이벤트 페이로드에 사용되지 않는 필드가 포함되어 있어 제거를 고려해볼 수 있습니다. 마지막으로, 트랜잭션 내에서 외부 시스템 호출 순서를 조정하여 데이터 정합성을 더 견고하게 만들 수 있습니다. 자세한 내용은 각 코드 라인에 남긴 코멘트를 참고해주세요.

Copy link

@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

♻️ Duplicate comments (1)
app/consumer/mathrank-rank-consumer-monolith/src/main/java/kr/co/mathrank/app/consumer/rank/EventPayloads.java (1)

33-37: LGTM - This is the shared event payload definition.

This record correctly defines the payload structure for member deletion events. The code duplication with the inner record in MemberDeleteService.java has been flagged in the review of that file.

🧹 Nitpick comments (1)
domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java (1)

23-23: Remove unnecessary @Valid annotation on Long parameter.

The @Valid annotation is used to trigger validation on bean properties. Since Long is a simple wrapper type with no nested constraints, @Valid has no effect here. Keep @NotNull but remove @Valid for clarity.

-	public void delete(@NotNull @Valid final Long memberId) {
+	public void delete(@NotNull final Long memberId) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a96213 and d560e2b.

📒 Files selected for processing (4)
  • app/consumer/mathrank-rank-consumer-monolith/src/main/java/kr/co/mathrank/app/consumer/rank/EventPayloads.java (1 hunks)
  • app/consumer/mathrank-rank-consumer-monolith/src/main/java/kr/co/mathrank/app/consumer/rank/SolvedRankEventMonolithListener.java (3 hunks)
  • domain/mathrank-auth-domain/src/main/java/kr/co/mathrank/domain/auth/service/MemberDeleteService.java (4 hunks)
  • domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java (1)
domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/exception/CannotFoundSolverException.java (1)
  • CannotFoundSolverException (3-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (1)
domain/mathrank-auth-domain/src/main/java/kr/co/mathrank/domain/auth/service/MemberDeleteService.java (1)

42-42: Event publishing looks good for eventual consistency.

The outbox-based event publishing after token expiration ensures atomicity. If the event fails to publish, the entire transaction will roll back, maintaining consistency.

Copy link

@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: 1

🧹 Nitpick comments (1)
domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java (1)

21-21: Consider removing unnecessary @Valid annotation.

The @Valid annotation is typically used for complex objects with nested validation constraints. For a simple Long parameter, @NotNull is sufficient. The @Valid annotation adds unnecessary overhead without providing additional validation.

Apply this diff if you'd like to simplify:

-	public void delete(@NotNull @Valid final Long memberId) {
+	public void delete(@NotNull final Long memberId) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d560e2b and 048884d.

📒 Files selected for processing (1)
  • domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (2)
domain/mathrank-rank-domain/src/main/java/kr/co/mathrank/domain/rank/service/SolverDeleteService.java (2)

20-29: LGTM! Idempotent implementation correctly addresses event-driven concerns.

The current implementation properly handles the idempotency requirement for event-driven architectures. Using ifPresentOrElse ensures that if the same deletion event is processed multiple times (due to at-least-once delivery guarantees), the operation succeeds silently without throwing exceptions. This prevents poison messages in the message queue.


22-22: The original review comment is incorrect and should be disregarded.

The current code correctly uses findByMemberId(memberId). The Solver entity has id as its primary key (auto-generated), and memberId as a separate unique field. Using findById(memberId) would be wrong because it would attempt to use memberId as the primary key, causing lookups to fail. The findByMemberId method is explicitly defined in SolverRepository and is the appropriate way to look up solvers by member ID.

Likely an incorrect or invalid review comment.

@huhdy32 huhdy32 merged commit 569d473 into develop Nov 13, 2025
2 checks passed
@huhdy32 huhdy32 deleted the feat/rank branch November 13, 2025 05:03
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