Skip to content

Conversation

@minwoo1999
Copy link
Member

@minwoo1999 minwoo1999 commented Jul 31, 2025

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

  • 독서기록 상세 조회 API 추가 (GET /detail/{readingRecordId})
  • ReadingRecordService에 상세 조회 로직 추가
  • ReadingRecordDomainServicefindReadingRecordById() 메서드 구현
  • 독서기록 VO에 도서 정보(썸네일, 제목, 출판사) 필드 추가
  • ReadingRecordNotFoundException, ReadingRecordErrorCode 정의 및 예외 처리 적용

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

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

기능 설명 미리보기

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트

  • VO 확장으로 인해 기존 응답 포맷 변경 가능성 있으므로 프론트엔드 영향 여부 확인 부탁드립니다.

Summary by CodeRabbit

  • 신규 기능
    • 특정 독서 기록의 상세 정보를 조회할 수 있는 API 엔드포인트가 추가되었습니다.
    • 독서 기록이 존재하지 않을 경우, 관련 오류 메시지가 제공됩니다.

@minwoo1999 minwoo1999 requested a review from move-hoon July 31, 2025 15:49
@minwoo1999 minwoo1999 self-assigned this Jul 31, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 31, 2025

📝 Walkthrough

Walkthrough

독서기록 상세 조회 기능이 도입되었습니다. 컨트롤러, API 인터페이스, 서비스, 유스케이스, 도메인 서비스에 상세 조회 메서드가 추가되었으며, 관련 예외 및 에러 코드도 신설되었습니다. 새로운 GET 엔드포인트(/detail/{readingRecordId})가 추가되어 인증된 사용자가 특정 독서기록의 상세 정보를 조회할 수 있습니다.

Changes

Cohort / File(s) Change Summary
ReadingRecord 상세 조회 API 엔드포인트 추가
apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordController.kt, apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt
/detail/{readingRecordId} 경로의 GET 엔드포인트 및 관련 API 문서, 메서드 시그니처 추가
서비스/유스케이스 계층 상세 조회 기능
apis/src/main/kotlin/org/yapp/apis/readingrecord/service/ReadingRecordService.kt, apis/src/main/kotlin/org/yapp/apis/readingrecord/usecase/ReadingRecordUseCase.kt
상세 조회 메서드 추가, 존재하지 않을 시 예외 처리, 사용자 및 소유권 검증 로직 포함
도메인 서비스 상세 조회 로직
domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt
ID로 독서기록 조회, 관련 태그/유저북 정보 조합 후 VO 반환 메서드 추가
예외 및 에러 코드 정의
apis/src/main/kotlin/org/yapp/apis/readingrecord/exception/ReadingRecordErrorCode.kt, apis/src/main/kotlin/org/yapp/apis/readingrecord/exception/ReadingRecordNotFoundException.kt
독서기록 미존재 에러코드, 예외 클래스 신설 및 메시지 정의

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant UseCase
    participant Service
    participant DomainService
    participant Repository

    Client->>Controller: GET /detail/{readingRecordId}
    Controller->>UseCase: getReadingRecordDetail(userId, readingRecordId)
    UseCase->>Service: getReadingRecordDetail(userId, readingRecordId)
    Service->>DomainService: findReadingRecordById(readingRecordId)
    DomainService->>Repository: findById(readingRecordId)
    DomainService->>Repository: findTagsByReadingRecordId
    DomainService->>Repository: findUserBookById
    DomainService-->>Service: ReadingRecordInfoVO
    Service->>Service: validateUserBookExists(userId, userBookId)
    Service-->>UseCase: ReadingRecordResponse
    UseCase-->>Controller: ReadingRecordResponse
    Controller-->>Client: 200 OK + ReadingRecordResponse
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
독서기록상세조회 기능 개발 (#67)

Assessment against linked issues: Out-of-scope changes

(해당 사항 없음)

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.


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3332358 and 0090c28.

📒 Files selected for processing (1)
  • domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt (1 hunks)
🔇 Additional comments (1)
domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt (1)

62-66: 새로운 조회 메서드 구현이 깔끔합니다.

findReadingRecordById 메서드의 구현이 잘 되어있습니다. 조기 반환 패턴을 사용한 null 처리와 헬퍼 메서드로의 위임을 통한 관심사 분리가 적절합니다.

✨ 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-201-feature/#67

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.

@minwoo1999 minwoo1999 changed the title Book 201 feature/#67 feat 독서기록상세조회 기능을 개발합니다 Jul 31, 2025
@minwoo1999 minwoo1999 changed the title feat 독서기록상세조회 기능을 개발합니다 feat: 독서기록상세조회 기능을 개발합니다 Jul 31, 2025
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: 4

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0ee57fc and ecca676.

📒 Files selected for processing (7)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordController.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/exception/ReadingRecordErrorCode.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/exception/ReadingRecordNotFoundException.kt (1 hunks)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/service/ReadingRecordService.kt (2 hunks)
  • apis/src/main/kotlin/org/yapp/apis/readingrecord/usecase/ReadingRecordUseCase.kt (1 hunks)
  • domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-validation
🔇 Additional comments (6)
domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt (1)

69-69: UserBook 조회 시 예외 처리 필요성 검토

domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt:69

  • 현재 userBookRepository.findById(readingRecord.userBookId.value) 호출 결과를 userBook?.title 등으로 null-safe하게 처리하고 있는데,
    비즈니스 로직 상 해당 UserBook이 항상 존재해야 한다면 null 반환 시 예외를 던지거나 별도의 처리(flow)를 명시적으로 구현하는 것이 좋습니다.
  • 예를 들어,
    • 존재하지 않을 때 UserBookNotFoundException 등을 던지거나
    findByIdAndUserId 또는 userBookService.validateUserBookExists(userId, userBookId) 호출로 소유권(유효성) 검증 로직을 추가하는 방안을 검토해주세요.
apis/src/main/kotlin/org/yapp/apis/readingrecord/exception/ReadingRecordNotFoundException.kt (1)

1-8: 잘 구현된 예외 클래스입니다.

CommonException을 상속받아 일관된 예외 처리 패턴을 따르고 있으며, 타입 안전한 에러 코드와 선택적 메시지를 지원하는 깔끔한 구현입니다.

apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordController.kt (1)

44-54: REST API 엔드포인트가 잘 구현되었습니다.

Spring Security의 @AuthenticationPrincipal을 통한 사용자 인증, 적절한 HTTP 메서드 사용, 그리고 Use Case로의 위임이 올바르게 구현되어 있습니다. REST 규칙을 잘 따르고 있습니다.

apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt (1)

63-85: OpenAPI 문서화가 훌륭하게 작성되었습니다.

API 명세가 완전하고 명확하며, 한국어 설명과 적절한 HTTP 응답 코드가 잘 정의되어 있습니다. 기존 코드베이스의 패턴을 일관되게 따르고 있습니다.

apis/src/main/kotlin/org/yapp/apis/readingrecord/service/ReadingRecordService.kt (1)

9-10: 새로운 예외 처리를 위한 import 추가가 적절합니다.

독서 기록 상세 조회 기능을 위한 예외 클래스들이 올바르게 import되었습니다.

apis/src/main/kotlin/org/yapp/apis/readingrecord/exception/ReadingRecordErrorCode.kt (1)

1-16: 독서 기록 에러 코드 구현이 우수합니다.

새로운 ReadingRecordErrorCode enum 클래스가 잘 구현되었습니다:

  • BaseErrorCode 인터페이스를 올바르게 구현
  • HTTP 상태 코드(404)가 적절함
  • 에러 코드 네이밍 규칙("READING_RECORD_001")을 준수
  • 한국어 에러 메시지가 사용자 친화적
  • Kotlin enum 모범 사례를 따름

)
]
)
@GetMapping("/detail/{readingRecordId}")
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

API 경로 구조에 대한 제안사항입니다.

현재 /detail/{readingRecordId} 경로는 기능적으로 올바르지만, RESTful 설계 관점에서 /{readingRecordId}만으로도 충분할 수 있습니다. 다른 리소스와의 일관성을 고려해보세요.

-@GetMapping("/detail/{readingRecordId}")
+@GetMapping("/{readingRecordId}")

하지만 기존 /userBookId 엔드포인트와의 충돌을 피하기 위해 현재 구조가 더 명확할 수 있습니다.

📝 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
@GetMapping("/detail/{readingRecordId}")
@GetMapping("/{readingRecordId}")
🤖 Prompt for AI Agents
In
apis/src/main/kotlin/org/yapp/apis/readingrecord/controller/ReadingRecordControllerApi.kt
at line 81, the API endpoint uses the path "/detail/{readingRecordId}" which is
functionally correct but could be simplified to "/{readingRecordId}" for better
RESTful design consistency. Review other endpoints like "/userBookId" to ensure
no conflicts arise, and if safe, rename the mapping to just "/{readingRecordId}"
to align with RESTful conventions and improve path clarity.

Comment on lines +43 to +56
fun getReadingRecordDetail(
userId: UUID,
readingRecordId: UUID
): ReadingRecordResponse {
val readingRecordInfoVO = readingRecordDomainService.findReadingRecordById(readingRecordId)
?: throw ReadingRecordNotFoundException(
ReadingRecordErrorCode.READING_RECORD_NOT_FOUND,
"Reading record not found with id: $readingRecordId"
)

userBookService.validateUserBookExists(userId, readingRecordInfoVO.userBookId.value)

return ReadingRecordResponse.from(readingRecordInfoVO)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

보안 취약점: 인가되지 않은 사용자에게 정보 누출 가능성이 있습니다.

현재 구현에서는 독서 기록 존재 여부를 먼저 확인한 후 사용자 권한을 검증하는데, 이는 권한이 없는 사용자에게도 특정 ID의 독서 기록 존재 여부를 알려줄 수 있습니다.

다음과 같이 수정하여 보안을 강화하는 것을 권장합니다:

 fun getReadingRecordDetail(
     userId: UUID,
     readingRecordId: UUID
 ): ReadingRecordResponse {
     val readingRecordInfoVO = readingRecordDomainService.findReadingRecordById(readingRecordId)
         ?: throw ReadingRecordNotFoundException(
             ReadingRecordErrorCode.READING_RECORD_NOT_FOUND,
             "Reading record not found with id: $readingRecordId"
         )

-    userBookService.validateUserBookExists(userId, readingRecordInfoVO.userBookId.value)
+    // 사용자 권한 검증을 먼저 수행하여 정보 누출 방지
+    try {
+        userBookService.validateUserBookExists(userId, readingRecordInfoVO.userBookId.value)
+    } catch (e: Exception) {
+        // 권한이 없는 경우에도 동일한 예외를 던져 정보 누출 방지
+        throw ReadingRecordNotFoundException(
+            ReadingRecordErrorCode.READING_RECORD_NOT_FOUND,
+            "Reading record not found with id: $readingRecordId"
+        )
+    }

     return ReadingRecordResponse.from(readingRecordInfoVO)
 }
🤖 Prompt for AI Agents
In
apis/src/main/kotlin/org/yapp/apis/readingrecord/service/ReadingRecordService.kt
around lines 43 to 56, the current code checks for the existence of the reading
record before validating user authorization, which can leak information about
the record's existence to unauthorized users. To fix this, first call
userBookService.validateUserBookExists with the userId and userBookId to verify
the user's permission, then retrieve the reading record by ID. This way,
unauthorized users cannot infer the existence of records they shouldn't access.

Comment on lines +45 to +55
fun getReadingRecordDetail(
userId: UUID,
readingRecordId: UUID
): ReadingRecordResponse {
userAuthService.validateUserExists(userId)

return readingRecordService.getReadingRecordDetail(
userId = userId,
readingRecordId = readingRecordId
)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

보안 취약점: 사용자 권한 검증이 누락되었습니다.

현재 구현에서는 사용자 존재 여부만 확인하고 있어, 다른 사용자의 독서기록에 접근할 수 있는 보안 취약점이 있습니다. 독서기록 소유권 검증이 필요합니다.

다음과 같이 수정하여 보안을 강화하세요:

 fun getReadingRecordDetail(
     userId: UUID,
     readingRecordId: UUID
 ): ReadingRecordResponse {
     userAuthService.validateUserExists(userId)
+    
+    // 독서기록 소유권 검증 추가 필요
+    // readingRecordService에서 userId와 readingRecord의 소유자가 일치하는지 확인
 
     return readingRecordService.getReadingRecordDetail(
         userId = userId,
         readingRecordId = readingRecordId
     )
 }

또는 service layer에서 소유권 검증이 이루어지고 있는지 확인해주세요.

📝 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
fun getReadingRecordDetail(
userId: UUID,
readingRecordId: UUID
): ReadingRecordResponse {
userAuthService.validateUserExists(userId)
return readingRecordService.getReadingRecordDetail(
userId = userId,
readingRecordId = readingRecordId
)
}
fun getReadingRecordDetail(
userId: UUID,
readingRecordId: UUID
): ReadingRecordResponse {
userAuthService.validateUserExists(userId)
// 독서기록 소유권 검증 추가 필요
// readingRecordService에서 userId와 readingRecord의 소유자가 일치하는지 확인
return readingRecordService.getReadingRecordDetail(
userId = userId,
readingRecordId = readingRecordId
)
}
🤖 Prompt for AI Agents
In
apis/src/main/kotlin/org/yapp/apis/readingrecord/usecase/ReadingRecordUseCase.kt
between lines 45 and 55, the method getReadingRecordDetail only validates that
the user exists but does not verify if the user owns the requested reading
record, creating a security vulnerability. To fix this, add a check to confirm
that the reading record belongs to the user before returning the detail, either
by adding ownership validation in this use case method or ensuring that the
service layer method getReadingRecordDetail performs this ownership verification
and throws an error if the user is unauthorized.

Comment on lines 62 to 78
fun findReadingRecordById(readingRecordId: UUID): ReadingRecordInfoVO? {
val readingRecord = readingRecordRepository.findById(readingRecordId) ?: return null

val readingRecordTags = readingRecordTagRepository.findByReadingRecordId(readingRecord.id.value)
val tagIds = readingRecordTags.map { it.tagId.value }
val tags = tagRepository.findByIds(tagIds)

val userBook = userBookRepository.findById(readingRecord.userBookId.value)

return ReadingRecordInfoVO.newInstance(
readingRecord = readingRecord,
emotionTags = tags.map { it.name },
bookTitle = userBook?.title,
bookPublisher = userBook?.publisher,
bookCoverImageUrl = userBook?.coverImageUrl
)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

성능 최적화를 위한 쿼리 개선이 필요합니다.

현재 구현에서 여러 개의 개별 데이터베이스 쿼리가 순차적으로 실행되어 N+1 문제가 발생할 수 있습니다. 또한 기존 findReadingRecordsByDynamicCondition 메서드와 유사한 로직이 중복되고 있습니다.

다음과 같은 개선을 제안합니다:

 fun findReadingRecordById(readingRecordId: UUID): ReadingRecordInfoVO? {
     val readingRecord = readingRecordRepository.findById(readingRecordId) ?: return null
 
-    val readingRecordTags = readingRecordTagRepository.findByReadingRecordId(readingRecord.id.value)
-    val tagIds = readingRecordTags.map { it.tagId.value }
-    val tags = tagRepository.findByIds(tagIds)
-
-    val userBook = userBookRepository.findById(readingRecord.userBookId.value)
-
-    return ReadingRecordInfoVO.newInstance(
-        readingRecord = readingRecord,
-        emotionTags = tags.map { it.name },
-        bookTitle = userBook?.title,
-        bookPublisher = userBook?.publisher,
-        bookCoverImageUrl = userBook?.coverImageUrl
-    )
+    return buildReadingRecordInfoVO(readingRecord)
+ }
+
+ private fun buildReadingRecordInfoVO(readingRecord: ReadingRecord): ReadingRecordInfoVO {
+     val readingRecordTags = readingRecordTagRepository.findByReadingRecordId(readingRecord.id.value)
+     val tagIds = readingRecordTags.map { it.tagId.value }
+     val tags = tagRepository.findByIds(tagIds)
+     val userBook = userBookRepository.findById(readingRecord.userBookId.value)
+     
+     return ReadingRecordInfoVO.newInstance(
+         readingRecord = readingRecord,
+         emotionTags = tags.map { it.name },
+         bookTitle = userBook?.title,
+         bookPublisher = userBook?.publisher,
+         bookCoverImageUrl = userBook?.coverImageUrl
+     )
 }
📝 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
fun findReadingRecordById(readingRecordId: UUID): ReadingRecordInfoVO? {
val readingRecord = readingRecordRepository.findById(readingRecordId) ?: return null
val readingRecordTags = readingRecordTagRepository.findByReadingRecordId(readingRecord.id.value)
val tagIds = readingRecordTags.map { it.tagId.value }
val tags = tagRepository.findByIds(tagIds)
val userBook = userBookRepository.findById(readingRecord.userBookId.value)
return ReadingRecordInfoVO.newInstance(
readingRecord = readingRecord,
emotionTags = tags.map { it.name },
bookTitle = userBook?.title,
bookPublisher = userBook?.publisher,
bookCoverImageUrl = userBook?.coverImageUrl
)
}
fun findReadingRecordById(readingRecordId: UUID): ReadingRecordInfoVO? {
val readingRecord = readingRecordRepository.findById(readingRecordId) ?: return null
return buildReadingRecordInfoVO(readingRecord)
}
private fun buildReadingRecordInfoVO(readingRecord: ReadingRecord): ReadingRecordInfoVO {
val readingRecordTags = readingRecordTagRepository.findByReadingRecordId(readingRecord.id.value)
val tagIds = readingRecordTags.map { it.tagId.value }
val tags = tagRepository.findByIds(tagIds)
val userBook = userBookRepository.findById(readingRecord.userBookId.value)
return ReadingRecordInfoVO.newInstance(
readingRecord = readingRecord,
emotionTags = tags.map { it.name },
bookTitle = userBook?.title,
bookPublisher = userBook?.publisher,
bookCoverImageUrl = userBook?.coverImageUrl
)
}
🤖 Prompt for AI Agents
In
domain/src/main/kotlin/org/yapp/domain/readingrecord/ReadingRecordDomainService.kt
around lines 62 to 78, the method findReadingRecordById executes multiple
sequential database queries causing potential N+1 query issues and duplicates
logic similar to findReadingRecordsByDynamicCondition. To fix this, refactor the
method to fetch all necessary data with fewer queries by using joins or batch
fetching strategies, and consolidate overlapping logic with existing methods to
avoid redundancy and improve performance.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Aug 2, 2025

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarQube Cloud

@minwoo1999 minwoo1999 merged commit 2c0ef87 into develop Aug 2, 2025
2 of 3 checks passed
@move-hoon move-hoon deleted the BOOK-201-feature/#67 branch August 12, 2025 06:29
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.

[BOOK-201/feat] 독서기록상세조회 기능을 개발합니다.

2 participants