Skip to content

Conversation

@daeun-han
Copy link
Member

@daeun-han daeun-han commented Jan 2, 2026

📌 PR 제목

ex) [refactor] 좋아요 API 성능 최적화 및 유저 식별 방식 변경


✨ 요약 설명

좋아요 저장 및 취소 API의 유저 식별 방식을 인증 헤더 기반으로 변경하고, 쿼리 실행 횟수를 최적화하여 서버 부하를 줄였습니다.


🧾 변경 사항

  • 좋아요 취소 로직 최적화: exists 호출 후 delete하던 2단계 로직을 제거하고, @Modifying 쿼리의 반환값(affected rows)을 활용해 1단계로 통합 (DB 네트워크 오버헤드 50% 절감).
  • 유저 식별 방식 변경: 파라미터로 명시적으로 받던 userId를 제거하고, 전역 리졸버(@userid)를 통한 인증 헤더 기반 식별로 변경.
  • Swagger 명세 최적화: 인증 헤더로 처리되는 userId 파라미터가 명세서에 노출되지 않도록 @parameter(hidden = true) 적용.

📂 PR 타입

  • 기능 추가
  • 버그 수정
  • 리팩토링
  • 문서 수정
  • 기타 (직접 작성: )

🧪 테스트

  • Postman으로 API 호출 확인
  • 로컬 실행 결과 화면 캡처 포함

✅ 체크리스트

  • 깃 & 코드 컨벤션을 지켰는가?
  • Swagger/문서화는 최신 상태인가?
  • 기능 변경 시 영향 받는 모듈을 확인했는가?

💬 리뷰어에게 전달할 말

좋아요 api 관련하여 인증 헤더로 유저를 식별하는 점을 적용하였습니다.
또한, 좋아요 취소 시 exists 쿼리 없이 곧바로 삭제를 시도하고, 결과값이 0인 경우 예외를 던지도록 설계하여 쿼리 횟수를 최적화했습니다. 이를 위해 SpringDataPostLikeRepository의 반환 타입을 void에서 int로 변경했습니다.
사실 현재 규모에서 쿼리 1회를 줄이는 것이 오버엔지니어링일까 우려됐지만, 빈번한 인터랙션이 발생하는 기능 특성상 성능과 동시성을 함께 고려해보고 싶어 이 방식을 채택해보았습니다. 팀의 컨벤션에 비해 과한 접근은 아닌지 의견 주시면 감사하겠습니다!


🔗 관련 이슈

아래 이슈번호 에 번호를 적으면 풀리퀘스트 머지 완료 시 자동으로 해당 이슈가 닫힙니다.

Summary by CodeRabbit

릴리스 노트

  • 개선 사항
    • 게시물 좋아요/좋아요 취소 기능의 내부 성능 최적화를 진행했습니다.
    • API 문서 정리를 통해 더 명확한 인터페이스를 제공합니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 2, 2026

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.

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

Walkthrough

좋아요 API의 userId 파라미터 처리 방식을 리팩터링했습니다. 컨트롤러에서 @NotNull 검증을 @Parameter(hidden = true) OpenAPI 주석으로 대체하고, 저장소 계층의 삭제 메서드 반환 타입을 void에서 int로 변경하여 삭제 결과를 활용한 에러 처리로 개선했습니다.

Changes

Cohort / File(s) 요약
컨트롤러 파라미터 주석 개선
src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java
userId 파라미터에서 @NotNull 제거 후 @Parameter(hidden = true) 추가, userId.longValue() 호출 제거하고 직접 userId 사용, jakarta.validation.constraints.NotNull 임포트 제거 및 io.swagger.v3.oas.annotations.Parameter 임포트 추가
서비스 계층 에러 처리 로직 최적화
src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostLikeService.java
cancelLike 메서드에서 존재 확인 후 삭제하는 2단계 과정을 삭제 결과 반환으로 통합, 삭제 결과가 0인 경우 LIKE_NOT_FOUND 예외 발생
저장소 인터페이스 반환 타입 변경
src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java
deleteByUserIdAndPostId 메서드 반환 타입을 void에서 int로 변경하여 영향받은 행 개수 전달
저장소 구현체 반환 타입 변경
src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java
deleteByUserIdAndPostId 메서드 구현을 void 호출에서 int 반환으로 변경, Spring Data JPA 쿼리 결과 반환
Spring Data JPA 쿼리 반환 타입 변경
src/main/java/org/sopt/pawkey/backendapi/domain/post/infra/persistence/repository/SpringDataPostLikeRepository.java
deleteByUserIdAndPostIdQuery 메서드 반환 타입을 void에서 int로 변경

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🔨 Refactor

Suggested reviewers

  • dltnals317
  • bingle625

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 (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 변경 사항의 핵심을 명확하게 전달하고 있으며, 성능 최적화와 유저 식별 방식 변경이라는 주요 변경사항을 정확히 요약하고 있습니다.
Description check ✅ Passed PR 설명이 제공된 템플릿의 주요 섹션(요약 설명, 변경 사항, PR 타입, 테스트, 체크리스트, 리뷰어 메시지, 관련 이슈)을 모두 충실히 작성했으며, 변경 사항의 기술적 세부사항과 의도를 명확하게 설명하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 변경사항이 #193 이슈의 요구사항을 충족합니다. Controller 수정(유저 파라미터 제거 및 인증 헤더 기반 식별)이 완벽하게 구현되었으며, 추가로 쿼리 성능 최적화도 적용되었습니다.
Out of Scope Changes check ✅ Passed 모든 코드 변경사항이 #193 이슈의 범위 내에 있습니다. Controller의 유저 식별 방식 변경, 관련 Repository와 Service 계층의 필요한 조정, 그리고 Swagger 명세 최적화가 모두 이슈 목표 달성을 위한 범위 내 변경입니다.

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.

@daeun-han
Copy link
Member Author

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Jan 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@daeun-han daeun-han self-assigned this Jan 2, 2026
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: 0

🧹 Nitpick comments (1)
src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java (1)

30-32: LGTM! @Modifying 쿼리의 반환 타입 변경이 올바릅니다.

JPQL DELETE 쿼리에서 int 반환 타입을 사용하여 영향받은 행 수를 정확히 받아올 수 있습니다.

선택적 최적화: @Modifying 옵션 고려

동일 트랜잭션 내에서 삭제 전 다른 변경 작업이 있을 경우, flushAutomatically = true 옵션을 추가하면 더 안전합니다:

-@Modifying
+@Modifying(flushAutomatically = true)
 @Query("DELETE FROM PostLikeEntity pl WHERE pl.user.userId = :userId AND pl.post.postId = :postId")
 int deleteByUserIdAndPostIdQuery(@Param("userId") Long userId, @Param("postId") Long postId);

현재는 단순 삭제 연산이므로 기본값으로도 충분하지만, 향후 복잡한 트랜잭션 시나리오에서 예기치 않은 동작을 방지할 수 있습니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 621d851 and f6ab16a.

📒 Files selected for processing (5)
  • src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java
  • src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostLikeService.java
  • src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java
  • src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java
  • src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: daeun-han
Repo: PAW-KEY/PAWKEY-Backend PR: 55
File: src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserLikedPostQueryFacade.java:55-55
Timestamp: 2025-07-13T11:54:29.024Z
Learning: 좋아요한 게시물 목록을 조회하는 API에서 isLiked 필드를 true로 하드코딩하는 것은 성능상 합리적입니다. PostLikeEntity 리스트가 이미 좋아요를 누른 게시물들만 포함하므로 별도 쿼리로 좋아요 상태를 확인하는 것은 중복이고 비효율적입니다.
🔇 Additional comments (5)
src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java (1)

15-15: LGTM! 성능 최적화를 위한 반환 타입 변경이 적절합니다.

삭제된 행 수를 반환하도록 변경하여 호출부에서 exists 체크 없이 바로 삭제 결과를 확인할 수 있게 되었습니다. 이를 통해 쿼리 실행 횟수를 절반으로 줄일 수 있습니다.

src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java (1)

30-31: LGTM! 인터페이스 시그니처에 맞춰 올바르게 구현되었습니다.

JPA Repository의 반환값을 그대로 전달하여 삭제된 행 수를 상위 레이어에서 활용할 수 있도록 했습니다.

src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java (2)

36-41: LGTM! 보안성이 크게 개선되었습니다.

JWT 기반 인증으로 userId를 추출하고 @Parameter(hidden = true)를 사용하여 Swagger 문서에서 숨기는 방식은:

  • 클라이언트가 임의로 userId를 조작하는 것을 방지합니다.
  • API 문서가 실제 사용 방식과 정확히 일치합니다.
  • 인증된 사용자만 자신의 좋아요를 저장할 수 있도록 보장합니다.

53-59: LGTM! like 메서드와 일관되게 보안이 개선되었습니다.

좋아요 취소 API도 동일한 방식으로 JWT 기반 인증을 사용하여 사용자 식별의 일관성과 보안성을 확보했습니다.

src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostLikeService.java (1)

35-39: 훌륭한 성능 최적화입니다! 동시성 안전성도 함께 개선되었습니다.

exists + delete 패턴을 제거하고 delete 결과값으로 판단하는 방식으로 변경하여:

  • 쿼리 실행 횟수를 절반으로 감소시켰습니다.
  • TOCTOU(time-of-check to time-of-use) 문제를 해결하여 동시성 안전성이 향상되었습니다.

트랜잭션 관리도 문제없습니다. PostLikeFacade에서 @Transactional 어노테이션으로 트랜잭션 경계가 관리되고 있으며, Spring의 기본 전파 방식(PROPAGATION_REQUIRED)에 의해 PostLikeService의 cancelLike() 메서드는 Facade의 트랜잭션 컨텍스트 내에서 실행됩니다. 따라서 @Modifying 쿼리도 정상적으로 동작합니다.

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] 좋아요 저장 및 취소 API

2 participants