Skip to content

[feat] 콘텐츠 찜(북마크) 수 조회 api 구현#609

Merged
eunseongu merged 2 commits intodevelopfrom
feature/#608
Feb 24, 2026
Merged

[feat] 콘텐츠 찜(북마크) 수 조회 api 구현#609
eunseongu merged 2 commits intodevelopfrom
feature/#608

Conversation

@seaniiio
Copy link
Member

@seaniiio seaniiio commented Feb 23, 2026

Issues

✔️ Check-list

  • : Label을 지정해 주세요.
  • : Merge할 브랜치를 확인해 주세요.

🗒️ Work Description

📷 Screenshot

📚 Reference

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 북마크된 콘텐츠의 개수를 조회할 수 있는 새로운 API 엔드포인트 추가
    • 사용자가 자신의 북마크 통계를 확인할 수 있도록 개선
    • 새 기능에 대한 테스트 커버리지 추가

@seaniiio seaniiio self-assigned this Feb 23, 2026
@seaniiio seaniiio added 🤙🏽 메이 우아한 테크코스 7기 백엔드 메이 💻 BackEnd 백엔드얌 📝 feat labels Feb 23, 2026
@github-actions github-actions bot requested a review from eunseongu February 23, 2026 10:48
@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Walkthrough

사용자 계정의 북마크된 콘텐츠 개수를 조회하는 새로운 API 엔드포인트를 추가합니다. 컨트롤러, 서비스, 저장소 계층과 DTO를 신규 생성하고 통합 테스트를 추가합니다.

Changes

코호트 / 파일 요약
컨트롤러 계층
backend/turip-app/src/main/java/turip/favorite/controller/FavoriteContentController.java
GET /api/v1/bookmarks/count 엔드포인트 추가. 인증된 계정의 북마크된 콘텐츠 개수를 반환하며, Swagger/OpenAPI 어노테이션 포함.
응답 DTO
backend/turip-app/src/main/java/turip/favorite/controller/dto/response/FavoriteContentCountResponse.java
개수 필드를 포함하는 새로운 레코드 클래스 생성. 정적 팩토리 메서드 from() 제공.
서비스 계층
backend/turip-app/src/main/java/turip/favorite/service/FavoriteContentService.java
저장소 메서드를 호출하여 개수를 조회하고 응답 DTO로 감싸는 countByAccount() 메서드 추가.
저장소 계층
backend/turip-app/src/main/java/turip/favorite/repository/FavoriteContentRepository.java
주어진 계정의 북마크된 콘텐츠 개수를 반환하는 countByAccount() 쿼리 메서드 추가.
테스트
backend/turip-app/src/test/java/turip/favorite/api/FavoriteContentApiTest.java
북마크 개수 조회 엔드포인트의 동작을 검증하는 ReadBookmarkCount 테스트 클래스 추가. 3개의 북마크 생성 후 올바른 개수 반환 확인.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as FavoriteContentController
    participant Service as FavoriteContentService
    participant Repository as FavoriteContentRepository
    participant DB as Database

    Client->>Controller: GET /api/v1/bookmarks/count
    activate Controller
    Controller->>Service: countByAccount(account)
    activate Service
    Service->>Repository: countByAccount(account)
    activate Repository
    Repository->>DB: COUNT favorite_content WHERE account_id = ?
    activate DB
    DB-->>Repository: count: int
    deactivate DB
    deactivate Repository
    Service->>Service: FavoriteContentCountResponse.from(count)
    deactivate Service
    Controller-->>Client: ResponseEntity<FavoriteContentCountResponse> (200 OK)
    deactivate Controller
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 분

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항인 콘텐츠 찜(북마크) 수 조회 API 구현을 명확하고 간결하게 설명하고 있습니다.
Description check ✅ Passed PR 설명이 필수 템플릿 구조를 따르고 있으나, Work Description과 Screenshot 섹션이 비어있어 세부 구현 정보가 부족합니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #608 이슈의 요구사항인 '콘텐츠 찜(북마크) 수 조회 API 구현'을 충족하고 있습니다.
Out of Scope Changes check ✅ Passed PR의 모든 변경사항이 API 엔드포인트, DTO, 서비스, 레포지토리, 테스트 구현으로 이루어져 있으며 #608의 범위 내에 있습니다.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/#608

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

@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.

🧹 Nitpick comments (4)
backend/turip-app/src/test/java/turip/favorite/api/FavoriteContentApiTest.java (2)

348-384: 북마크가 0개일 때 count: 0을 반환하는 엣지 케이스 테스트가 없습니다.

현재 테스트는 3개 북마크의 정상 경로만 검증하며, 계정에 북마크가 없을 때 count: 0이 정상 반환되는지 확인하는 테스트가 없습니다. 초기 상태 검증에 유용합니다.

✅ 추가 테스트 예시
`@DisplayName`("북마크가 없을 때 200 OK와 count 0을 반환한다")
`@Test`
void readBookmarkCount_empty() {
    // given
    Long accountId = testDataHelper.insertAccount();
    jdbcTemplate.update("INSERT INTO guest (account_id, device_fid) VALUES (?, 'testDeviceFid')", accountId);

    // when & then
    RestAssured.given().port(port)
            .header("device-fid", "testDeviceFid")
            .when().get("/api/v1/bookmarks/count")
            .then()
            .statusCode(200)
            .body("count", is(0));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@backend/turip-app/src/test/java/turip/favorite/api/FavoriteContentApiTest.java`
around lines 348 - 384, Add an edge-case test in the ReadBookmarkCount nested
class to verify zero bookmarks returns count:0; create a new test method (e.g.,
readBookmarkCount_empty) that inserts an account and guest row (using
testDataHelper.insertAccount() and the same guest insert), does not insert any
favorite_content rows, then calls GET /api/v1/bookmarks/count with the same
"device-fid" header and asserts statusCode 200 and body "count" is 0; place it
alongside readBookmarkCount1 so it runs as part of the same test suite.

354-354: 테스트 메서드 이름에서 불필요한 숫자 접미사 1 제거를 권장합니다.

기존 테스트 메서드들(readMyFavoriteContents_success, removeFavorite 등)은 숫자 접미사를 사용하지 않습니다. readBookmarkCount1readBookmarkCount_success로 변경하는 것이 일관성 있습니다.

♻️ 제안 수정
-        void readBookmarkCount1() {
+        void readBookmarkCount_success() {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@backend/turip-app/src/test/java/turip/favorite/api/FavoriteContentApiTest.java`
at line 354, Rename the test method readBookmarkCount1 to
readBookmarkCount_success to match existing naming convention; update the method
declaration in FavoriteContentApiTest (readBookmarkCount1) and any
references/calls or annotations that mention the old name (e.g., `@Test`,
`@DisplayName` or reflective references) so the test still runs and compiles, and
run the tests to verify no further references remain.
backend/turip-app/src/main/java/turip/favorite/service/FavoriteContentService.java (1)

68-71: 읽기 전용 트랜잭션 어노테이션 추가를 권장합니다.

countByAccount()는 순수 조회 메서드이므로 @Transactional(readOnly = true)를 추가하면 불필요한 dirty checking을 방지하고 DB 드라이버 레벨 최적화 힌트를 활성화할 수 있습니다. 동일 서비스의 findMyFavoriteContentsexistsByAccount도 같은 이유로 추가를 고려해 볼 수 있습니다.

♻️ 제안 수정
+    `@Transactional`(readOnly = true)
     public FavoriteContentCountResponse countByAccount(Account account) {
         int count = favoriteContentRepository.countByAccount(account);
         return FavoriteContentCountResponse.from(count);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@backend/turip-app/src/main/java/turip/favorite/service/FavoriteContentService.java`
around lines 68 - 71, Add read-only transaction annotations to the read-only
methods in FavoriteContentService: annotate countByAccount(Account),
findMyFavoriteContents(...), and existsByAccount(...) with
`@Transactional`(readOnly = true) on their method declarations (or at class level
with explicit overrides if needed) to prevent unnecessary dirty checking and
enable DB-level read optimizations; ensure you import
org.springframework.transaction.annotation.Transactional and only apply it to
methods that perform pure reads.
backend/turip-app/src/main/java/turip/favorite/repository/FavoriteContentRepository.java (1)

59-59: countBy 파생 쿼리의 반환 타입은 관례적으로 long입니다.

Spring Data JPA의 countBy 파생 쿼리는 내부적으로 Long을 반환하며, 공식 문서에서도 countBy 메서드의 반환 타입을 long으로 정의합니다. int를 사용하면 Spring Data가 묵시적 축소 변환을 수행하며, 실용적으로는 대부분의 경우 문제가 없지만 표준 규칙에서 벗어나며 충분히 큰 숫자의 경우 오버플로우 위험이 있습니다.

♻️ 제안 수정
-    int countByAccount(Account account);
+    long countByAccount(Account account);

이에 맞춰 FavoriteContentCountResponsecount 필드 타입과 FavoriteContentService.countByAccount() 메서드의 지역 변수 타입도 함께 long으로 변경이 필요합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@backend/turip-app/src/main/java/turip/favorite/repository/FavoriteContentRepository.java`
at line 59, The repository method
FavoriteContentRepository.countByAccount(Account account) currently returns int;
change its return type to long to match Spring Data JPA conventions and avoid
overflow, then update the FavoriteContentCountResponse DTO's count field from
int to long and adjust the local variable type(s) in
FavoriteContentService.countByAccount() accordingly so the service uses long
throughout (update any mappings/constructors that set the DTO.count).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@backend/turip-app/src/main/java/turip/favorite/repository/FavoriteContentRepository.java`:
- Line 59: The repository method
FavoriteContentRepository.countByAccount(Account account) currently returns int;
change its return type to long to match Spring Data JPA conventions and avoid
overflow, then update the FavoriteContentCountResponse DTO's count field from
int to long and adjust the local variable type(s) in
FavoriteContentService.countByAccount() accordingly so the service uses long
throughout (update any mappings/constructors that set the DTO.count).

In
`@backend/turip-app/src/main/java/turip/favorite/service/FavoriteContentService.java`:
- Around line 68-71: Add read-only transaction annotations to the read-only
methods in FavoriteContentService: annotate countByAccount(Account),
findMyFavoriteContents(...), and existsByAccount(...) with
`@Transactional`(readOnly = true) on their method declarations (or at class level
with explicit overrides if needed) to prevent unnecessary dirty checking and
enable DB-level read optimizations; ensure you import
org.springframework.transaction.annotation.Transactional and only apply it to
methods that perform pure reads.

In
`@backend/turip-app/src/test/java/turip/favorite/api/FavoriteContentApiTest.java`:
- Around line 348-384: Add an edge-case test in the ReadBookmarkCount nested
class to verify zero bookmarks returns count:0; create a new test method (e.g.,
readBookmarkCount_empty) that inserts an account and guest row (using
testDataHelper.insertAccount() and the same guest insert), does not insert any
favorite_content rows, then calls GET /api/v1/bookmarks/count with the same
"device-fid" header and asserts statusCode 200 and body "count" is 0; place it
alongside readBookmarkCount1 so it runs as part of the same test suite.
- Line 354: Rename the test method readBookmarkCount1 to
readBookmarkCount_success to match existing naming convention; update the method
declaration in FavoriteContentApiTest (readBookmarkCount1) and any
references/calls or annotations that mention the old name (e.g., `@Test`,
`@DisplayName` or reflective references) so the test still runs and compiles, and
run the tests to verify no further references remain.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ecaf670 and e88ed39.

📒 Files selected for processing (5)
  • backend/turip-app/src/main/java/turip/favorite/controller/FavoriteContentController.java
  • backend/turip-app/src/main/java/turip/favorite/controller/dto/response/FavoriteContentCountResponse.java
  • backend/turip-app/src/main/java/turip/favorite/repository/FavoriteContentRepository.java
  • backend/turip-app/src/main/java/turip/favorite/service/FavoriteContentService.java
  • backend/turip-app/src/test/java/turip/favorite/api/FavoriteContentApiTest.java

Copy link
Contributor

@eunseongu eunseongu left a comment

Choose a reason for hiding this comment

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

빠른 구현 굿!! 감사함다!!!!

@eunseongu eunseongu merged commit 04ae955 into develop Feb 24, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 BackEnd 백엔드얌 📝 feat 🤙🏽 메이 우아한 테크코스 7기 백엔드 메이

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[feat] 콘텐츠 찜(북마크) 수 조회 api 구현

2 participants