Skip to content

[Refactor] 산 좋아요 토글 처리로 통일#247

Open
pooreumjung wants to merge 2 commits into
developfrom
refactor/#233-like-toggle
Open

[Refactor] 산 좋아요 토글 처리로 통일#247
pooreumjung wants to merge 2 commits into
developfrom
refactor/#233-like-toggle

Conversation

@pooreumjung

Copy link
Copy Markdown
Member

🧾 요약

  • MountainLikeService의 좋아요/취소 분리 API를 CourseLike, PostLike와 동일한 토글 방식으로 통일

🔗 이슈

✨ 변경 내용

  • MountainLikeService: likeMountain / unlikeMountain → 단일 toggleMountainLike로 교체
  • MountainLikeService: LikeConflictHandler 적용으로 동시성 예외 처리 방식 통일
  • MountainController: DELETE /{mountainId}/like 제거, POST /{mountainId}/like가 toggle 응답 반환하도록 변경
  • MountainLikeToggleResponse DTO 추가 (liked: boolean)
  • ErrorStatus: MOUNTAIN_LIKE_ALREADY_EXISTS, MOUNTAIN_LIKE_NOT_FOUND 제거
  • SuccessStatus: MOUNTAIN_LIKE_SUCCESS / MOUNTAIN_UNLIKE_SUCCESSMOUNTAIN_LIKE_TOGGLE_SUCCESS로 통합
  • MountainLikeServiceTest 추가 (토글, 취소, 동시 중복 요청 케이스)

✅ 확인

  • 빌드 OK
  • 테스트 OK

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 90b35e73-8540-4867-a193-273ffacce2bd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#233-like-toggle

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.

@pooreumjung pooreumjung self-assigned this Jun 25, 2026
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, 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!

This pull request refactors the mountain liking functionality by consolidating the existing separate 'like' and 'unlike' API operations into a single toggle mechanism. This change simplifies the API surface, improves consistency across the application, and enhances reliability by incorporating concurrency handling for like operations. The update also includes necessary DTOs, status code updates, and robust unit testing to ensure the new toggle logic behaves correctly under various conditions.

Highlights

  • API Refactoring: Replaced separate 'like' and 'unlike' endpoints with a single 'toggle' endpoint for mountain likes, aligning with existing patterns in the project.
  • Concurrency Handling: Integrated 'LikeConflictHandler' into the service layer to robustly manage concurrent like requests.
  • Response Standardization: Introduced 'MountainLikeToggleResponse' DTO and unified success status codes to streamline client-side handling.
  • Testing: Added comprehensive unit tests in 'MountainLikeServiceTest' covering toggle logic, deletion, and concurrent request scenarios.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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 the 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 counterproductive. 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.

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.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

이번 풀요청은 기존의 산 좋아요 등록 및 취소 API를 하나의 토글 API로 통합하고 동시성 요청 발생 시 중복 생성을 방지하기 위해 LikeConflictHandler를 도입하였습니다. 리뷰어는 JPA의 지연 쓰기 특성으로 인해 save 호출 시 동시성 예외가 즉시 감지되지 않는 문제를 지적하며 이를 해결하기 위해 saveAndFlush를 사용하도록 제안했습니다. 또한 이에 맞춰 테스트 코드의 모킹 및 검증 로직도 saveAndFlush를 바라보도록 수정할 것을 권장했습니다.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +60 to +65
private boolean createMountainLike(User user, Mountain mountain) {
return LikeConflictHandler.handleConcurrentCreate(
() -> mountainLikeRepository.save(MountainLike.create(user, mountain)),
() -> log.warn("MountainLike 동시 요청 감지: mountainId={}, userId={}", mountain.getId(), user.getId())
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

JPA의 save() 메서드는 트랜잭션이 커밋되거나 플러시되기 전까지 실제 DB에 INSERT 쿼리를 보내지 않고 영속성 컨텍스트에 지연 저장(Write-behind)합니다. 이로 인해 LikeConflictHandler.handleConcurrentCreate 내부의 try-catch 블록이 실행되는 시점에는 DataIntegrityViolationException이 발생하지 않으며, 메서드가 종료된 후 트랜잭션 커밋 시점에 예외가 발생하여 결국 에러 응답이 클라이언트에 반환됩니다.

동시성 요청 시 예외를 정상적으로 감지하고 처리할 수 있도록 save() 대신 saveAndFlush()를 사용해 즉시 DB에 반영하도록 수정해야 합니다.

Suggested change
private boolean createMountainLike(User user, Mountain mountain) {
return LikeConflictHandler.handleConcurrentCreate(
() -> mountainLikeRepository.save(MountainLike.create(user, mountain)),
() -> log.warn("MountainLike 동시 요청 감지: mountainId={}, userId={}", mountain.getId(), user.getId())
);
}
private boolean createMountainLike(User user, Mountain mountain) {
return LikeConflictHandler.handleConcurrentCreate(
() -> mountainLikeRepository.saveAndFlush(MountainLike.create(user, mountain)),
() -> log.warn("MountainLike 동시 요청 감지: mountainId={}, userId={}", mountain.getId(), user.getId())
);
}

MountainLikeToggleResponse response = mountainLikeService.toggleMountainLike(1L, 10L);

assertThat(response.liked()).isTrue();
verify(mountainLikeRepository).save(any(MountainLike.class));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

MountainLikeService에서 saveAndFlush()를 사용하도록 변경함에 따라, 테스트 코드의 검증(verify) 메서드도 saveAndFlush를 검증하도록 수정해야 합니다.

Suggested change
verify(mountainLikeRepository).save(any(MountainLike.class));
verify(mountainLikeRepository).saveAndFlush(any(MountainLike.class));

Comment on lines +81 to +82
when(mountainLikeRepository.save(any(MountainLike.class)))
.thenThrow(new DataIntegrityViolationException("duplicate"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

MountainLikeService에서 saveAndFlush()를 사용하도록 변경함에 따라, 테스트 코드의 모킹(when) 메서드도 saveAndFlush를 모킹하도록 수정해야 합니다.

Suggested change
when(mountainLikeRepository.save(any(MountainLike.class)))
.thenThrow(new DataIntegrityViolationException("duplicate"));
when(mountainLikeRepository.saveAndFlush(any(MountainLike.class)))
.thenThrow(new DataIntegrityViolationException("duplicate"));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor] Like 토글 로직 중복 및 예외 처리 불일치

1 participant