Skip to content

Conversation

@minwoo1999
Copy link
Member

@minwoo1999 minwoo1999 commented Jul 30, 2025

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)

  • 🐞 Bugfix (버그 수정)

  • 🔧 Refactor (코드 리팩토링)

  • ⚙️ Chore (환경 설정)

  • 📝 Docs (문서 작성 및 수정)

  • ✅ Test (기능 테스트)

  • 🎨 style (코드 스타일 수정)

📙 작업 내역

  • 도서 동적 검색 시 userIdtitle을 조건으로 사용함에 따라, (userId, title) 복합 B-Tree 인덱스를 추가했습니다.

  • 이를 통해 전체 테이블 스캔을 방지하고, 특정 사용자의 도서 내에서만 LIKE 검색을 수행하여 1차적으로 성능을 개선합니다.

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인

  • 엣지 케이스 테스트 완료

  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

기능 | 미리보기 | 기능 | 미리보기 -- | -- | -- | -- 기능 설명 |   | 기능 설명 |  
Sheets로 내보내기

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다

  • PR 제목이 컨벤션에 맞습니다

  • 관련 이슈 번호를 작성했습니다

  • 기능이 정상적으로 작동합니다

  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

  • MVP 1차 마감 기한을 고려하여, 우선 B-Tree 인덱싱을 통해 1차적으로 검색 성능을 개선했습니다.

  • 현재 LIKE '%...%' 검색 방식은 인덱스의 모든 이점을 활용하지 못하는 한계가 명확합니다.

  • 따라서 MVP 이후, Full-Text Search(FTS)를 도입하여 검색 기능을 근본적으로 개선할 예정입니다. 이 PR은 그 전 단계의 개선 사항으로 이해해주시면 감사하겠습니다.

  • 리뷰어님께서는 코드 리뷰와 함께, UserBookEntity에 추가된 @Index 설정이 DB 스키마에 정상적으로 반영되었는지 확인 부탁드립니다.

Summary by CodeRabbit

  • 신규 기능

    • 내 서재 도서 목록 조회 시, 책 제목으로도 필터링할 수 있는 옵션이 추가되었습니다.
  • 문서

    • 독서 기록 목록 조회 API의 응답 스키마 설명이 실제 반환 형식(페이지네이션 리스트)과 일치하도록 수정되었습니다.
  • 성능 개선

    • 도서 제목 및 사용자+도서 제목에 대한 데이터베이스 인덱스가 추가되어, 제목 검색 시 조회 속도가 향상됩니다.

@coderabbitai
Copy link

coderabbitai bot commented Jul 30, 2025

📝 Walkthrough

Walkthrough

도서관(내서재)에서 도서 제목으로 검색할 수 있도록, title 파라미터가 컨트롤러, API, 서비스, 유스케이스, 도메인 서비스, 레포지토리 계층까지 추가되었습니다. 또한, 인덱스 최적화와 API 문서의 응답 스키마 일부가 수정되었습니다.

Changes

Cohort / File(s) Change Summary
BookController 및 API
apis/src/main/kotlin/org/yapp/apis/book/controller/BookController.kt,
apis/src/main/kotlin/org/yapp/apis/book/controller/BookControllerApi.kt
getUserLibraryBooks 메서드에 title(nullable) 파라미터 추가 및 API 문서 설명 보완
Book UseCase 및 서비스 계층
apis/src/main/kotlin/org/yapp/apis/book/usecase/BookUseCase.kt,
apis/src/main/kotlin/org/yapp/apis/book/service/UserBookService.kt
유저 도서 목록 조회 메서드에 title 파라미터 추가 및 전달 로직 반영
도메인 서비스 및 레포지토리 인터페이스
domain/src/main/kotlin/org/yapp/domain/userbook/UserBookDomainService.kt,
domain/src/main/kotlin/org/yapp/domain/userbook/UserBookRepository.kt
동적 조건 도서 조회 메서드에 title 파라미터 추가
인프라 레포지토리 및 구현체
infra/src/main/kotlin/org/yapp/infra/userbook/repository/JpaUserBookQuerydslRepository.kt,
infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/JpaUserBookQuerydslRepositoryImpl.kt,
infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/UserBookRepositoryImpl.kt
Querydsl 및 JPA 레포지토리 계층에 title 파라미터 추가, 쿼리 조건에 제목 필터 동적 적용
DB 인덱스 최적화
infra/src/main/kotlin/org/yapp/infra/userbook/entity/UserBookEntity.kt
title, user_id+title 인덱스 추가를 위한 @table 어노테이션 수정
API 문서 응답 스키마
apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt
독서기록 목록 조회 응답 스키마를 단일 객체에서 Page로 수정 (문서상 변경)

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant BookController
    participant BookUseCase
    participant UserBookService
    participant UserBookDomainService
    participant UserBookRepository

    Client->>BookController: GET /user/library?title=xxx
    BookController->>BookUseCase: getUserLibraryBooks(..., title, ...)
    BookUseCase->>UserBookService: findUserBooksByDynamicConditionWithStatusCounts(..., title, ...)
    UserBookService->>UserBookDomainService: findUserBooksByDynamicCondition(..., title, ...)
    UserBookDomainService->>UserBookRepository: findUserBooksByDynamicCondition(..., title, ...)
    UserBookRepository-->>UserBookDomainService: Page<UserBook>
    UserBookDomainService-->>UserBookService: Page<UserBookInfoVO>
    UserBookService-->>BookUseCase: UserBookPageResponse
    BookUseCase-->>BookController: UserBookPageResponse
    BookController-->>Client: 200 OK (UserBookPageResponse)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
내서재에서 도서검색 기능 구현 (#59)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
독서기록 목록 조회 API 응답 스키마 수정 (apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt) 내서재 도서검색 기능과 직접적 관련이 없는 API 문서 변경입니다.

Possibly related PRs

Suggested reviewers

  • hoonyworld

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BOOK-190-feature/#59

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82f0a61 and c8eac5c.

📒 Files selected for processing (11)
  • apis/src/main/kotlin/org/yapp/apis/book/controller/BookController.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/book/controller/BookControllerApi.kt (2 hunks)
  • apis/src/main/kotlin/org/yapp/apis/book/service/UserBookService.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/book/usecase/BookUseCase.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt (1 hunks)
  • domain/src/main/kotlin/org/yapp/domain/userbook/UserBookDomainService.kt (1 hunks)
  • domain/src/main/kotlin/org/yapp/domain/userbook/UserBookRepository.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/userbook/entity/UserBookEntity.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/userbook/repository/JpaUserBookQuerydslRepository.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/JpaUserBookQuerydslRepositoryImpl.kt (3 hunks)
  • infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/UserBookRepositoryImpl.kt (1 hunks)
🔇 Additional comments (16)
apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt (1)

72-72: OpenAPI 문서화 수정이 올바릅니다.

응답 스키마를 ReadingRecordResponse::class에서 Page::class로 변경한 것이 정확합니다. 실제 메서드 시그니처가 ResponseEntity<Page<ReadingRecordResponse>>를 반환하므로, 이 변경으로 OpenAPI 문서와 실제 구현 간의 일관성이 확보되었습니다.

infra/src/main/kotlin/org/yapp/infra/userbook/entity/UserBookEntity.kt (2)

7-7: 적절한 import 추가

jakarta.persistence.Index import가 올바르게 추가되었습니다.


15-21: 효율적인 인덱싱 전략 구현

사용자별 도서 제목 검색을 위한 인덱스 구성이 적절합니다:

  • idx_user_books_title: 제목 기반 검색 최적화
  • idx_user_books_user_id_title: 사용자별 제목 검색에 최적화된 복합 인덱스

복합 인덱스에서 user_id를 먼저 배치한 것은 선택도가 높은 컬럼을 앞에 두는 모범 사례를 따른 것입니다.

domain/src/main/kotlin/org/yapp/domain/userbook/UserBookRepository.kt (1)

20-26: 도메인 인터페이스 올바르게 확장

findUserBooksByDynamicCondition 메서드에 title 파라미터가 적절히 추가되었습니다. nullable 타입으로 선택적 파라미터임을 명확히 하였고, 파라미터 순서도 논리적입니다.

infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/UserBookRepositoryImpl.kt (1)

48-57: 레포지토리 구현체 올바르게 업데이트

도메인 인터페이스의 변경사항이 구현체에 올바르게 반영되었습니다. title 파라미터가 하위 JPA 레포지토리로 적절히 전달되고 있습니다.

apis/src/main/kotlin/org/yapp/apis/book/controller/BookController.kt (2)

66-66: API 파라미터 올바르게 추가

선택적 title 쿼리 파라미터가 적절히 추가되었습니다. required = false 설정으로 하위 호환성을 유지합니다.


70-70: use case로 파라미터 올바르게 전달

title 파라미터가 use case 계층으로 올바르게 전달되고 있습니다.

infra/src/main/kotlin/org/yapp/infra/userbook/repository/JpaUserBookQuerydslRepository.kt (1)

11-17: Querydsl 레포지토리 타이틀 필터링 구현 확인 완료

findUserBooksByDynamicCondition 인터페이스에 title 파라미터가 추가되었으며, 구현체의 titleContains 메서드에서
userBook.title.like("%"+it+"%") 형태로 올바르게 LIKE 쿼리가 적용된 것을 확인했습니다. 추가 조치 없이 머지 가능합니다.

  • infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/JpaUserBookQuerydslRepositoryImpl.kt:
    titleContains 메서드에서 userBook.title.like("%" + it + "%") 사용 확인
apis/src/main/kotlin/org/yapp/apis/book/usecase/BookUseCase.kt (1)

78-83: LGTM! 제목 필터링 파라미터가 올바르게 추가되었습니다.

title 파라미터가 적절하게 nullable String으로 정의되었고, 서비스 레이어로 올바르게 전달되고 있습니다.

domain/src/main/kotlin/org/yapp/domain/userbook/UserBookDomainService.kt (1)

44-47: LGTM! 도메인 서비스에서 제목 필터링이 올바르게 구현되었습니다.

도메인 레이어에서 title 파라미터가 적절하게 추가되었고 레포지토리로 올바르게 전달되고 있습니다.

apis/src/main/kotlin/org/yapp/apis/book/controller/BookControllerApi.kt (2)

120-120: API 문서화가 잘 개선되었습니다.

제목 검색 기능에 대한 설명이 Operation 어노테이션에 명확하게 추가되어 사용자가 이해하기 쉽게 작성되었습니다.


145-145: 파라미터 문서화가 적절합니다.

title 파라미터에 대한 설명이 명확하게 작성되어 API 사용자가 기능을 이해하기 쉽습니다.

infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/JpaUserBookQuerydslRepositoryImpl.kt (2)

28-28: title 파라미터가 올바르게 추가되었습니다.

메서드 시그니처에 title 파라미터가 적절하게 추가되어 다른 레이어와 일관성을 유지하고 있습니다.


35-36: 쿼리 조건이 일관성 있게 적용되었습니다.

메인 쿼리와 카운트 쿼리 모두에 titleContains 조건이 적절하게 적용되어 페이징 결과의 정확성을 보장합니다.

Also applies to: 50-51

apis/src/main/kotlin/org/yapp/apis/book/service/UserBookService.kt (2)

58-61: 서비스 레이어에서 제목 필터링이 올바르게 구현되었습니다.

title 파라미터가 적절하게 추가되었고 도메인 서비스로 올바르게 전달되고 있습니다.


69-72: 상태 카운트와 함께 제목 필터링이 일관성 있게 구현되었습니다.

findUserBooksByDynamicConditionWithStatusCounts 메서드에서도 title 파라미터가 올바르게 전달되어 필터링과 상태 카운트 기능이 함께 작동합니다.

Comment on lines +76 to +80
private fun titleContains(title: String?): BooleanExpression? {
return title?.takeIf { it.isNotBlank() }?.let {
userBook.title.like("%" + it + "%")
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

LIKE 검색 구현이 올바르지만 성능 고려사항이 있습니다.

titleContains 메서드가 적절하게 구현되었고 빈 문자열 처리도 잘 되어 있습니다. 다만 LIKE '%...%' 패턴은 인덱스를 완전히 활용하지 못할 수 있습니다. PR 목표에서 언급한 것처럼 향후 Full-Text Search 구현을 고려해보시기 바랍니다.

 private fun titleContains(title: String?): BooleanExpression? {
     return title?.takeIf { it.isNotBlank() }?.let {
-        userBook.title.like("%" + it + "%")
+        userBook.title.like("%" + it.replace("%", "\\%").replace("_", "\\_") + "%")
     }
 }

추가적으로 특수문자 이스케이핑을 고려해보세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private fun titleContains(title: String?): BooleanExpression? {
return title?.takeIf { it.isNotBlank() }?.let {
userBook.title.like("%" + it + "%")
}
}
private fun titleContains(title: String?): BooleanExpression? {
return title?.takeIf { it.isNotBlank() }?.let {
userBook.title.like(
"%" + it.replace("%", "\\%")
.replace("_", "\\_") + "%"
)
}
}
🤖 Prompt for AI Agents
In
infra/src/main/kotlin/org/yapp/infra/userbook/repository/impl/JpaUserBookQuerydslRepositoryImpl.kt
around lines 76 to 80, the titleContains method uses a LIKE '%...%' pattern
which can degrade performance and does not handle special characters properly.
To fix this, implement escaping for special characters in the input title string
before constructing the LIKE pattern, and consider planning for a future
migration to Full-Text Search for better performance and accuracy.

@minwoo1999 minwoo1999 changed the title Book 190 feature/#59 feat: 내서재에서 도서검색이 가능하도록 기능을 구현 Jul 31, 2025
@minwoo1999 minwoo1999 merged commit 46978d1 into develop Jul 31, 2025
7 of 8 checks passed
@move-hoon move-hoon deleted the BOOK-190-feature/#59 branch August 12, 2025 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-190/feat] 내서재에서 도서검색이 가능하도록 기능을 구현합니다.

2 participants