Skip to content

✨Feat: Like 도메인 캐시 적용(isLiked & likeCount)#42

Merged
imjuyongp merged 3 commits intodevelopfrom
feat/redis
Feb 3, 2026
Merged

✨Feat: Like 도메인 캐시 적용(isLiked & likeCount)#42
imjuyongp merged 3 commits intodevelopfrom
feat/redis

Conversation

@angoroa
Copy link
Copy Markdown
Member

@angoroa angoroa commented Feb 3, 2026

#️⃣ Issue Number

  • closed #

📝 요약(Summary)

•	Like 도메인 Redis 캐시 적용
•	isLiked : 사용자별 좋아요 여부 조회 캐시 적용
•	likeCount : 게시글/댓글 좋아요 수 조회 캐시 적용
•	인증 과정에서 반복 호출되는 UserDetailsService.loadUserByUsername()에 캐시를 적용하여

로그인/인증 시 불필요한 DB 조회를 줄였습니다.
• 로컬 개발 환경 구성을 위해 docker-compose.local.yml 설정을 추가했습니다.

🛠️ PR 유형

어떤 변경 사항이 있나요?

  • 새로운 기능 추가
  • 버그 수정
  • CSS 등 사용자 UI 디자인 변경
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • [ x 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📸스크린샷 (선택)

💬 공유사항 to 리뷰어

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

Summary by CodeRabbit

릴리스 노트

  • 성능 개선

    • 좋아요 기능의 응답 속도를 개선하기 위해 캐싱 시스템을 추가했습니다.
    • 사용자 인증 과정의 성능을 향상시켰습니다.
  • Chores

    • 로컬 개발 환경 구성을 업데이트했습니다.

@angoroa angoroa self-assigned this Feb 3, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 3, 2026

개요

이 PR은 Redis 캐싱을 좋아요 관련 작업 및 사용자 인증에 추가하고, PostgreSQL과 Redis 서비스를 위한 로컬 Docker Compose 구성을 제공합니다.

변경 사항

응집단(Cohort) / 파일(들) 요약
Docker 구성
.gitignore, docker/docker-compose.local.yml
로컬 개발 환경용 docker-compose.local.yml을 추적하도록 .gitignore 수정. postgis 데이터베이스와 Redis 서비스가 포함된 Docker Compose 파일 추가(포트 매핑, 헬스체크, 환경변수 포함).
Redis 캐시 구성
src/main/java/com/be/sportizebe/global/config/RedisCacheConfig.java
likeStatus(15초 TTL, Boolean 직렬화기) 및 likeCount(30초 TTL, Long 직렬화기)에 대한 새로운 캐시 항목 추가.
캐싱 적용
src/main/java/com/be/sportizebe/domain/like/service/LikeServiceImpl.java, src/main/java/com/be/sportizebe/global/security/CustomUserDetailService.java
toggleLike, isLiked, getLikeCount에 @Cacheable@CacheEvict 어노테이션 추가. loadUserByUsername에 사용자 상세정보 캐싱 추가. toggleLike 내부에서 저장소에서 직접 개수 조회로 변경.

예상 코드 리뷰 노력

🎯 3 (Moderate) | ⏱️ ~20분

관련 가능성 있는 PR

시 🐰

캐시의 마법으로 번개처럼 빠르게,
좋아요가 춤을 추네요!
Redis의 손길로 부드럽게,
Docker와 함께 춤을 추며,
우리는 더욱 강해졌어요! ⚡💾

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 설명하고 있습니다. Like 도메인에 Redis 캐시를 적용했으며, isLiked와 likeCount를 구체적으로 언급하고 있습니다.

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

✨ 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/redis

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

Caution

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

⚠️ Outside diff range comments (1)
src/main/java/com/be/sportizebe/global/security/CustomUserDetailService.java (1)

17-23: ⚠️ Potential issue | 🟠 Major

userDetails 캐시 무효화 전략이 필요합니다.

UserDetails를 캐시하면서 사용자 정보 수정 시 캐시가 무효화되지 않아 이전 데이터로 계속 인증됩니다. 특히 uploadProfileImage() 메서드가 User 엔티티를 수정하지만 캐시 정제 없이 진행되므로, RedisCacheConfig에서 userDetails에 대한 명시적 TTL 설정과 사용자 변경 흐름에서 @CacheEvict(cacheNames = "userDetails", key = "#username")을 추가해야 합니다.

🤖 Fix all issues with AI agents
In `@src/main/java/com/be/sportizebe/domain/like/service/LikeServiceImpl.java`:
- Around line 56-57: The cache key in isLiked currently uses "#user.id" which
throws an NPE when `@AuthenticationPrincipal` User user is null for
unauthenticated calls (seen from getPostLikeStatus/getCommentLikeStatus); update
the `@Cacheable` key expression on isLiked to be null-safe (for example use a
ternary or null-check like "#user == null ? 'ANON' : `#user.id` + ':' +
`#targetType` + ':' + `#targetId`" or use SpEL null-safe operators) so that
unauthenticated requests produce a stable key instead of causing an exception.
🧹 Nitpick comments (3)
docker/docker-compose.local.yml (3)

1-1: version 키는 Docker Compose V2에서 더 이상 사용되지 않습니다.

Docker Compose V2(Compose Specification)부터 version 키는 obsolete로 처리됩니다. 제거해도 무방하며, 유지해도 동작에는 영향이 없습니다.

♻️ 제안된 수정
-version: "3.9"
-
 services:

35-36: Redis healthcheck에서 비밀번호 경고가 발생할 수 있습니다.

-a password 옵션을 명령줄에 직접 전달하면 Redis가 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe 경고를 출력합니다. REDISCLI_AUTH 환경 변수를 사용하면 이 경고를 피할 수 있습니다.

♻️ 경고 방지를 위한 제안
     healthcheck:
-      test: [ "CMD", "redis-cli", "-a", "password", "PING" ]
+      test: [ "CMD-SHELL", "REDISCLI_AUTH=password redis-cli PING" ]
       interval: 10s
       timeout: 3s
       retries: 5

15-16: 포트가 모든 인터페이스에 바인딩됩니다.

현재 포트 매핑이 0.0.0.0(모든 네트워크 인터페이스)에 바인딩됩니다. 로컬 개발 환경에서 외부 네트워크 노출을 방지하려면 127.0.0.1로 제한하는 것을 고려해 주세요.

🔒️ 로컬호스트 전용 바인딩 제안
     ports:
-      - "5432:5432"
+      - "127.0.0.1:5432:5432"
     ports:
-      - "6379:6379"
+      - "127.0.0.1:6379:6379"

Also applies to: 30-31

Comment on lines +56 to 57
@Cacheable(cacheNames = "likeStatus", key = "#user.id + ':' + #targetType + ':' + #targetId")
public boolean isLiked(User user, LikeTargetType targetType, Long targetId) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cd /repo && find . -name "LikeServiceImpl.java" -type f

Repository: Sportize/be

Length of output: 110


🏁 Script executed:

cd /repo && find . -name "*LikeController*.java" -type f 2>/dev/null || find . -name "*Like*Controller*.java" -type f 2>/dev/null | head -20

Repository: Sportize/be

Length of output: 204


🏁 Script executed:

cd /repo && head -80 src/main/java/com/be/sportizebe/domain/like/service/LikeServiceImpl.java

Repository: Sportize/be

Length of output: 110


🏁 Script executed:

head -80 src/main/java/com/be/sportizebe/domain/like/service/LikeServiceImpl.java

Repository: Sportize/be

Length of output: 2534


🏁 Script executed:

cat src/main/java/com/be/sportizebe/domain/like/controller/LikeController.java

Repository: Sportize/be

Length of output: 3197


🏁 Script executed:

grep -n "isLiked" src/main/java/com/be/sportizebe/domain/like/service/LikeServiceImpl.java

Repository: Sportize/be

Length of output: 137


비로그인 접근 시 SpEL NPE 위험이 실제로 발생할 수 있습니다.

getPostLikeStatusgetCommentLikeStatus 엔드포인트에서 @AuthenticationPrincipal User user는 인증이 없을 때 null을 주입합니다(required=true 미설정). 인증 없이 이 엔드포인트들에 접근 가능하므로, isLiked 메서드의 캐시 키 표현식 #user.id에서 NPE가 발생합니다.

null-safe 처리를 추가해 주세요:

💡 null-safe 처리 예시
-  `@Cacheable`(cacheNames = "likeStatus", key = "#user.id + ':' + `#targetType` + ':' + `#targetId`")
+  `@Cacheable`(
+      cacheNames = "likeStatus",
+      key = "#user.id + ':' + `#targetType` + ':' + `#targetId`",
+      condition = "#user != null"
+  )
   public boolean isLiked(User user, LikeTargetType targetType, Long targetId) {
+    if (user == null) {
+      return false;
+    }
     return likeRepository.existsByUserAndTargetTypeAndTargetId(user, targetType, targetId);
   }
🤖 Prompt for AI Agents
In `@src/main/java/com/be/sportizebe/domain/like/service/LikeServiceImpl.java`
around lines 56 - 57, The cache key in isLiked currently uses "#user.id" which
throws an NPE when `@AuthenticationPrincipal` User user is null for
unauthenticated calls (seen from getPostLikeStatus/getCommentLikeStatus); update
the `@Cacheable` key expression on isLiked to be null-safe (for example use a
ternary or null-check like "#user == null ? 'ANON' : `#user.id` + ':' +
`#targetType` + ':' + `#targetId`" or use SpEL null-safe operators) so that
unauthenticated requests produce a stable key instead of causing an exception.

@imjuyongp imjuyongp merged commit 8abe2af into develop Feb 3, 2026
1 check passed
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.

2 participants