Skip to content

feat: 독서 기록 등록 API 연동 및 완료 화면 UI 구현#82

Merged
seoyoon513 merged 17 commits intodevelopfrom
BOOK-168-feature/#70
Jul 30, 2025
Merged

feat: 독서 기록 등록 API 연동 및 완료 화면 UI 구현#82
seoyoon513 merged 17 commits intodevelopfrom
BOOK-168-feature/#70

Conversation

@seoyoon513
Copy link
Copy Markdown
Contributor

@seoyoon513 seoyoon513 commented Jul 30, 2025

🔗 관련 이슈

📙 작업 설명

  • 독서 기록 등록 API 연동
  • 기록 상세 화면 UI 개발

🧪 테스트 내역

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

📸 스크린샷 또는 시연 영상

Reed_._.mp4

💬 추가 설명 or 리뷰 포인트

  • 앞으로 남은 API(홈, 도서상세, 기록상세)와의 연계성을 고려해서 먼저 PR 올립니다! 숫자 외 입력 제한, 포커스 등 UI 처리 작업은 별도 이슈 생성하여 진행하겠습니다.
  • 도서 상세 화면은 feature:detail의 book 패키지 내에서 작업하시면 됩니다. 도서 상세에서도 사용할 EmotionTag enum class 만들었습니다. 감정 씨앗 관련 그래픽 추가되면 graphic에 resId값 넣을 예정입니다

Summary by CodeRabbit

  • 신규 기능

    • 독서 기록 상세 화면 및 UI가 추가되어 기록의 인용문, 감상평, 감정 태그 등을 확인할 수 있습니다.
    • 감정 태그 선택, 기록 저장 확인 다이얼로그, 감정 태그별 색상 및 라벨이 적용되었습니다.
    • 기록 등록 시 토스트 알림 및 저장 완료 안내 다이얼로그가 제공됩니다.
    • 기록 등록 기능이 사용자별 도서 ID와 연동되어 기록을 서버에 저장할 수 있습니다.
  • UI 개선

    • 감정 태그, 인용문, 감상평 입력 등 기록 등록 플로우가 개선되었습니다.
    • 기록 등록 화면에서 ‘다음’ 버튼 활성화 조건이 명확히 표시됩니다.
    • 다이얼로그 헤더 커스텀 기능 및 UI 컴포넌트(QuoteBox, ReviewBox) 추가로 시각적 완성도가 높아졌습니다.
  • 내비게이션

    • 도서 등록 성공 시 해당 도서의 기록 작성 화면으로 바로 이동하며, 사용자별 도서 ID가 전달됩니다.
    • 기록 등록 및 상세 화면 진입 시 사용자별 도서 ID가 포함되어 정확한 데이터 연동이 가능합니다.
  • 문서화 및 리소스

    • 기록 상세 및 기록 저장 관련 한글 문자열 리소스가 추가되었습니다.
  • 버그 수정 및 기타

    • 패키지 구조 정리 및 내부 코드 리팩터링이 일부 반영되었습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 30, 2025

"""

Walkthrough

독서 기록 등록 기능을 위한 API 연동과 기록 완료 화면 UI가 추가 및 개선되었습니다. 데이터 모델, 네트워크 요청/응답, 저장소 인터페이스, 구현체, DI 바인딩, UI 상태 및 이벤트, 감정 태그 디자인 시스템, 화면 이동, 완료 다이얼로그 등 관련 코드가 신규 추가 및 확장되었습니다.

Changes

Cohort / File(s) Change Summary
Record 등록 데이터 모델 및 네트워크 구조
core/model/RecordRegisterModel.kt, core/network/request/RecordRegisterRequest.kt, core/network/response/RecordRegisterResponse.kt
독서 기록 등록을 위한 데이터 모델, 네트워크 요청/응답 데이터 클래스 신설
RecordRepository 및 구현
core/data/api/repository/RecordRepository.kt, core/data/impl/repository/DefaultRecordRepository.kt, core/data/impl/mapper/ResponseToModel.kt, core/data/impl/di/RepositoryModule.kt
RecordRepository 인터페이스, 구현체, 매퍼, DI 바인딩 신규 추가
ReedService API 확장
core/network/service/ReedService.kt
독서 기록 등록 API 엔드포인트 메서드 추가
감정 태그 디자인 시스템
core/designsystem/EmotionTag.kt, core/designsystem/theme/Color.kt
감정 태그 enum 및 관련 색상 상수 추가
Record 등록 UI 상태 및 이벤트
feature/record/register/RecordRegisterUiState.kt, feature/record/register/RecordRegisterPresenter.kt, feature/record/register/HandleRecordRegisterSideEffects.kt
감정 태그, 완료 다이얼로그, 사이드 이펙트 등 상태 및 이벤트 확장, 사이드 이펙트 처리 함수 추가
Record 등록 UI 및 감정 선택
feature/record/register/RecordRegisterUi.kt, feature/record/step/EmotionStep.kt
감정 태그 기반 UI, 완료 다이얼로그, 감정 선택 UI 개선
Record 등록 완료 다이얼로그 문자열
feature/record/res/values/strings.xml
기록 완료 다이얼로그 관련 문자열 리소스 추가
RecordScreen 파라미터화 및 화면 이동
feature/screens/Screens.kt, feature/home/HomePresenter.kt, feature/search/SearchPresenter.kt
RecordScreen이 userBookId 파라미터를 받도록 변경, 관련 화면 이동 코드 수정
상세 리뷰 화면 신규 추가
feature/detail/review/ReviewDetailPresenter.kt, feature/detail/review/ReviewDetailUi.kt, feature/detail/review/ReviewDetailUiState.kt, feature/detail/review/HandleReviewDetailSideEffect.kt, feature/detail/review/component/QuoteBox.kt, feature/detail/review/component/ReviewBox.kt, feature/detail/res/values/strings.xml, feature/screens/Screens.kt
리뷰 상세 화면, 상태, 사이드 이펙트, 컴포넌트, 문자열 등 신규 추가
BookDetail 관련 패키지 경로 변경
feature/detail/book/BookDetailPresenter.kt, feature/detail/book/BookDetailSideEffect.kt, feature/detail/book/BookDetailUi.kt, feature/detail/book/BookDetailUiState.kt
BookDetail 관련 파일 패키지 경로 변경 (코드 로직 변화 없음)
ReedDialog 확장
core/ui/component/ReedDialog.kt
headerContent 파라미터 추가, 미리보기 description 값 변경

Sequence Diagram(s)

sequenceDiagram
    participant UI
    participant Presenter
    participant Repository
    participant ReedService
    participant Network

    UI->>Presenter: OnRecordRegister(event)
    Presenter->>Repository: postRecord(userBookId, pageNumber, quote, emotionTags, review)
    Repository->>ReedService: postRecord(userBookId, RecordRegisterRequest)
    ReedService->>Network: POST /api/v1/reading-records/{userBookId}
    Network-->>ReedService: RecordRegisterResponse
    ReedService-->>Repository: RecordRegisterResponse
    Repository-->>Presenter: Result<RecordRegisterModel>
    Presenter->>UI: Show Record Saved Dialog or Toast
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
독서 기록 등록 API 연동 (#70)
기록 완료 화면 UI 개발 (#70)

Assessment against linked issues: Out-of-scope changes

해당 변경사항 중 명확하게 범위를 벗어난 기능적 코드 변경은 발견되지 않았습니다.

Possibly related PRs

Poem

🐇
기록이 저장됐어요, 토끼가 깡총!
감정 태그 골라서, 마음을 담아
새 API로 기록을 쏙—
완료 다이얼로그가 반갑게 뿅!
리뷰도 상세하게, 화면이 번쩍
북잇의 발전, 토끼가 응원해요!
📚✨
"""

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 UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 442b83e and f700241.

📒 Files selected for processing (1)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUi.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUi.kt
⏰ 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: ci-build
✨ 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-168-feature/#70

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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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.

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

🔭 Outside diff range comments (1)
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt (1)

35-56: 중복 클릭 시 다중 코루틴 실행 및 중복 요청 위험 – 로딩 상태/동기화 추가 권장
upsertBook이 매 호출마다 새로운 코루틴을 발사합니다. 사용자가 버튼을 여러 번 연달아 눌러도 UI 측에서 막을 로직이 없으므로 동일 API가 중복 호출될 수 있습니다.
isLoading 플래그를 remember { mutableStateOf(false) }로 두고, 요청 전 true → 완료/실패 시 false 로드
• 이벤트 처리부에서 isLoading일 때 클릭 무시 또는 UI 비활성화
• 혹은 Mutex/atomic한 Job 캐싱으로 단일 실행 보장

@@
 var sideEffect by rememberRetained { mutableStateOf<BookDetailSideEffect?>(null) }
+var isLoading by rememberRetained { mutableStateOf(false) }
@@
-fun upsertBook(bookIsbn: String, bookStatus: String) {
-    scope.launch {
+fun upsertBook(bookIsbn: String, bookStatus: String) {
+    if (isLoading) return
+    isLoading = true
+    scope.launch {
         repository.upsertBook(bookIsbn, bookStatus)
             .onSuccess {
                 sideEffect = BookDetailSideEffect.ShowToast("성공")
+                isLoading = false
             }
             .onFailure { exception ->
@@
                 }
+                isLoading = false
             }
     }
 }
🧹 Nitpick comments (10)
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailSideEffect.kt (1)

15-27: RememberedEffect 대신 LaunchedEffect 사용을 고려해 보세요

RememberedEffect(외부 라이브러리)로 side-effect 를 처리하고 있는데, Jetpack Compose 기본 LaunchedEffect를 쓰면
① 의존성(라이브러리)에 덜 묶이고,
key 변경에 따라 코루틴이 재시작되는 Compose 권장 패턴과도 맞습니다.

-import com.skydoves.compose.effects.RememberedEffect
+import androidx.compose.runtime.LaunchedEffect
...
-    RememberedEffect(state.sideEffect) {
+    LaunchedEffect(state.sideEffect) {

기능적 차이는 없지만 내부 의존성을 줄이고 표준 API 로 통일할 수 있습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt (1)

34-71: 문자열 하드코딩 → stringResource로 분리 권장

다국어 지원‧A/B 테스트‧접근성 측면에서 하드코딩된 문자열은 유지 보수에 불리합니다. stringResource를 사용해 리소스로 분리해 주세요.

-        ReedBackTopAppBar(
-            title = "도서 상세 정보",
+        ReedBackTopAppBar(
+            title = stringResource(R.string.book_detail_title),
...
-                    text = "읽기 전",
+                    text = stringResource(R.string.reading_status_before),
...
-                    text = "읽는 중",
+                    text = stringResource(R.string.reading_status_reading),
...
-                    text = "독서 완료",
+                    text = stringResource(R.string.reading_status_completed),

리소스 파일(res/values/strings.xml)에 대응 문자열을 추가하고, 미리보기에서도 LocalContext가 필요 없는 stringResource 호출이 정상 동작합니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt (1)

7-10: sideEffect를 data class 필드에 포함하면 재조합 트리거 가능성

sideEffectdata class의 프로퍼티로 포함되어 있어 equals 비교 시 값이 달라질 때마다 전체 UiState가 변경된 것으로 간주됩니다.
Compose 재구성이 과도하게 일어날 수 있으므로, sideEffect를 별도 MutableSharedFlow로 분리하거나 @IgnoredOnParcel-과 유사한 방식(예: val sideEffect: BookDetailSideEffect? = null, @Transient)으로 equals 대상에서 제외하는 방법을 고려해 보세요.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt (2)

39-40: 토스트 메시지 하드코딩 제거
사용자 노출 문구 "성공"을 코드에 직접 넣으면 다국어 대응 및 테스트가 어렵습니다. string-resources(e.g., R.string.book_upsert_success)로 이동 후 BookDetailSideEffect.ShowToast(stringResource(...)) 형태로 주입해 주세요.


68-78: 상태 문자열 하드코딩 → enum 클래스로 추출 권장
"BEFORE_READING" | "READING" | "COMPLETED" 문자열이 이벤트마다 반복됩니다. 오타 위험과 유지보수성을 위해

enum class BookStatus { BEFORE_READING, READING, COMPLETED }

를 정의하고 upsertBook(screen.isbn, BookStatus.COMPLETED)처럼 넘기면 compile-time 검사가 가능합니다.

core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt (1)

68-73: postRecord API 메서드가 잘 구현되었습니다.

독서 기록 등록을 위한 API 메서드가 적절히 정의되었습니다. Path 파라미터와 Body 파라미터 사용이 올바릅니다.

엔드포인트 경로의 일관성을 확인해보세요. 다른 엔드포인트들은 leading slash 없이 api/v1/...로 시작하는데, 이 메서드는 /api/v1/...로 시작합니다:

-    @POST("/api/v1/reading-records/{userBookId}")
+    @POST("api/v1/reading-records/{userBookId}")
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (1)

103-123: 독서 기록 저장 완료 다이얼로그 구현을 개선할 수 있습니다.

다이얼로그 기능은 잘 구현되었지만, headerContent의 Box 컴포넌트에 하드코딩된 크기와 배경색을 개선할 수 있습니다.

다음과 같이 개선을 고려해보세요:

 headerContent = {
     Box(
         modifier = Modifier
-            .size(132.dp)
-            .background(ReedTheme.colors.contentTertiary),
+            .size(ReedTheme.spacing.spacing32) // 또는 디자인 시스템의 정의된 크기
+            .background(
+                color = ReedTheme.colors.contentTertiary,
+                shape = RoundedCornerShape(ReedTheme.radius.md)
+            ),
     )
 }

또는 향후 실제 그래픽 리소스가 추가될 때까지 placeholder 컴포넌트를 별도로 정의할 수도 있습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/component/ReviewBox.kt (1)

24-72: 컴포넌트 구조는 좋으나 재사용성을 위한 매개변수화를 고려해보세요.

UI 구현 단계에서 더미 데이터를 사용하는 팀의 개발 방식을 이해하지만, 향후 서버 연동 시 편의성을 위해 다음과 같은 매개변수들을 추가하는 것을 고려해보세요:

 @Composable
-fun ReviewBox(modifier: Modifier = Modifier) {
+fun ReviewBox(
+    emotionTag: String,
+    date: String,
+    review: String,
+    modifier: Modifier = Modifier
+) {
     // ...
-    text = "#따뜻함",
+    text = emotionTag,
     // ...
-    text = "2025.06.25",
+    text = date,
     // ...
-    text = "소설가들은 늘 소재를 찾아 떠도는 존재 같지만, 실은 그 반대인 경우가 더 잦다",
+    text = review,

현재 레이아웃과 테마 적용은 잘 되어 있습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailPresenter.kt (1)

25-25: 사용하지 않는 코루틴 스코프를 제거해주세요.

rememberCoroutineScope()가 생성되지만 사용되지 않고 있습니다. 필요하지 않다면 제거하는 것이 좋겠습니다.

-        val scope = rememberCoroutineScope()
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt (1)

74-105: 비동기 레코드 저장 기능이 잘 구현되었습니다.

postRecord 함수가 적절히 구현되어 있으나, 한 가지 개선 사항이 있습니다:

  • Repository 호출 후 성공/실패 처리가 올바르게 구현됨
  • 공통 예외 처리 유틸리티 handleException 사용이 적절함
  • 로그인이 필요한 경우 적절히 LoginScreen으로 리셋함

다만, 레코드 저장 중에 로딩 상태를 표시하는 것을 고려해보세요. 사용자 경험 향상을 위해 저장 중임을 알려주는 UI 피드백이 있으면 좋겠습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4ea63d and 9d0ce07.

📒 Files selected for processing (31)
  • core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/RecordRepository.kt (1 hunks)
  • core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/di/RepositoryModule.kt (2 hunks)
  • core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/mapper/ResponseToModel.kt (3 hunks)
  • core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultRecordRepository.kt (1 hunks)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/EmotionTag.kt (1 hunks)
  • core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt (1 hunks)
  • core/model/src/main/kotlin/com/ninecraft/booket/core/model/RecordRegisterModel.kt (1 hunks)
  • core/network/src/main/kotlin/com/ninecraft/booket/core/network/request/RecordRegisterRequest.kt (1 hunks)
  • core/network/src/main/kotlin/com/ninecraft/booket/core/network/response/RecordRegisterResponse.kt (1 hunks)
  • core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt (2 hunks)
  • core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt (4 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailSideEffect.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailPresenter.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailSideEffect.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUi.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUiState.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/component/QuoteBox.kt (1 hunks)
  • feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/component/ReviewBox.kt (1 hunks)
  • feature/detail/src/main/res/values/strings.xml (1 hunks)
  • feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/HandleRecordRegisterSideEffects.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt (6 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (5 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUiState.kt (1 hunks)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (2 hunks)
  • feature/record/src/main/res/values/strings.xml (1 hunks)
  • feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/Screens.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchPresenter.kt (4 hunks)
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#46
File: feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/component/InfiniteLazyColumn.kt:83-95
Timestamp: 2025-07-14T00:46:03.843Z
Learning: seoyoon513과 팀은 한국어 주석을 선호하며, 한국어 주석을 영어로 번역하라는 제안을 하지 않아야 함
Learnt from: seoyoon513
PR: YAPP-Github/Reed-Android#75
File: feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeUi.kt:0-0
Timestamp: 2025-07-29T06:07:11.727Z
Learning: seoyoon513 팀에서는 UI 구현 단계에서 더미 데이터를 하드코딩하여 화면을 먼저 구현하고, 이후 서버 연동 시점에 실제 데이터로 교체하는 개발 방식을 사용합니다.
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt (2)

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

Learnt from: easyhooon
PR: #77
File: feature/onboarding/src/main/kotlin/com/ninecraft/booket/feature/onboarding/OnboardingUi.kt:73-73
Timestamp: 2025-07-29T07:02:18.885Z
Learning: Kotlin에서 같은 패키지 내의 파일들은 패키지 레벨에 정의된 const val 상수를 import 없이 직접 접근할 수 있습니다. OnboardingPresenter.kt와 OnboardingUi.kt 모두 com.ninecraft.booket.feature.onboarding 패키지에 속해 있어서 ONBOARDING_STEPS_COUNT 상수를 공유할 수 있습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt (3)

Learnt from: easyhooon
PR: #77
File: feature/onboarding/src/main/kotlin/com/ninecraft/booket/feature/onboarding/OnboardingUi.kt:73-73
Timestamp: 2025-07-29T07:02:18.885Z
Learning: Kotlin에서 같은 패키지 내의 파일들은 패키지 레벨에 정의된 const val 상수를 import 없이 직접 접근할 수 있습니다. OnboardingPresenter.kt와 OnboardingUi.kt 모두 com.ninecraft.booket.feature.onboarding 패키지에 속해 있어서 ONBOARDING_STEPS_COUNT 상수를 공유할 수 있습니다.

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegatingNavigator.kt:0-0
Timestamp: 2025-07-16T15:54:19.322Z
Learning: In the Reed-Android project using Circuit architecture, DelegatingNavigator was restored because NavigableCircuitContent can only inject a single navigator, but the dual-navigator architecture (childNavigator for bottom navigation screens, rootNavigator for full-screen screens) requires a delegating component to work within Circuit's constraint.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt (2)

Learnt from: easyhooon
PR: #77
File: feature/onboarding/src/main/kotlin/com/ninecraft/booket/feature/onboarding/OnboardingUi.kt:73-73
Timestamp: 2025-07-29T07:02:18.885Z
Learning: Kotlin에서 같은 패키지 내의 파일들은 패키지 레벨에 정의된 const val 상수를 import 없이 직접 접근할 수 있습니다. OnboardingPresenter.kt와 OnboardingUi.kt 모두 com.ninecraft.booket.feature.onboarding 패키지에 속해 있어서 ONBOARDING_STEPS_COUNT 상수를 공유할 수 있습니다.

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailSideEffect.kt (2)

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

Learnt from: easyhooon
PR: #77
File: feature/onboarding/src/main/kotlin/com/ninecraft/booket/feature/onboarding/OnboardingUi.kt:73-73
Timestamp: 2025-07-29T07:02:18.885Z
Learning: Kotlin에서 같은 패키지 내의 파일들은 패키지 레벨에 정의된 const val 상수를 import 없이 직접 접근할 수 있습니다. OnboardingPresenter.kt와 OnboardingUi.kt 모두 com.ninecraft.booket.feature.onboarding 패키지에 속해 있어서 ONBOARDING_STEPS_COUNT 상수를 공유할 수 있습니다.

core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt (1)

Learnt from: seoyoon513
PR: #35
File: feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/TermsAgreementScreen.kt:127-127
Timestamp: 2025-07-09T01:14:29.836Z
Learning: In the Reed-Android project's TermsAgreementScreen.kt, the OnTermDetailClick event is intentionally passed an empty string for the URL parameter because the actual URLs for terms detail pages haven't been decided yet. This is a temporary implementation that will be updated once the URLs are finalized.

feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchPresenter.kt (1)

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (2)

Learnt from: easyhooon
PR: #77
File: feature/onboarding/src/main/kotlin/com/ninecraft/booket/feature/onboarding/OnboardingUi.kt:73-73
Timestamp: 2025-07-29T07:02:18.885Z
Learning: Kotlin에서 같은 패키지 내의 파일들은 패키지 레벨에 정의된 const val 상수를 import 없이 직접 접근할 수 있습니다. OnboardingPresenter.kt와 OnboardingUi.kt 모두 com.ninecraft.booket.feature.onboarding 패키지에 속해 있어서 ONBOARDING_STEPS_COUNT 상수를 공유할 수 있습니다.

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

core/network/src/main/kotlin/com/ninecraft/booket/core/network/response/RecordRegisterResponse.kt (1)

Learnt from: easyhooon
PR: #46
File: core/network/src/main/kotlin/com/ninecraft/booket/core/network/response/BookSearchResponse.kt:33-44
Timestamp: 2025-07-14T00:51:38.952Z
Learning: The project uses Kotlinx Serialization with JSON configuration that includes ignoreUnknownKeys = true, encodeDefaults = true, isLenient = true, and prettyPrint = true to handle API response parsing robustly, making additional null safety measures less critical if the API consistently provides all expected fields.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt (2)

Learnt from: seoyoon513
PR: #32
File: core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/button/ButtonColorStyle.kt:10-16
Timestamp: 2025-07-08T12:33:01.863Z
Learning: Reed Android 프로젝트에서 KAKAO 버튼 스타일은 디자이너가 pressed 상태 색상을 별도로 정의하지 않았기 때문에 pressed 상태에서도 동일한 Kakao 색상을 사용한다.

Learnt from: seoyoon513
PR: #32
File: core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Theme.kt:15-21
Timestamp: 2025-07-08T03:21:24.693Z
Learning: Reed Android 프로젝트에서는 다크모드/라이트모드 대응 계획이 없고 기본 테마 값만 사용할 예정이다.

feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt (5)

Learnt from: seoyoon513
PR: #35
File: feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/TermsAgreementScreen.kt:127-127
Timestamp: 2025-07-09T01:14:29.836Z
Learning: In the Reed-Android project's TermsAgreementScreen.kt, the OnTermDetailClick event is intentionally passed an empty string for the URL parameter because the actual URLs for terms detail pages haven't been decided yet. This is a temporary implementation that will be updated once the URLs are finalized.

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegatingNavigator.kt:0-0
Timestamp: 2025-07-16T06:08:40.883Z
Learning: In the Reed-Android project, DelegatingNavigator was removed because it caused confusion and added unnecessary complexity. The simplified approach uses childNavigator only within bottom navigation screens and rootNavigator for all other navigation, which is more intuitive and maintainable.

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegateNavigator.kt:0-0
Timestamp: 2025-07-16T16:11:27.044Z
Learning: In the Reed-Android project's DelegateNavigator implementation, the pop(), peek(), and peekBackStack() methods should always use childNavigator without branching logic, as they operate on the currently active navigation stack. Only goTo() and resetRoot() methods need to route between childNavigator and rootNavigator based on screen type.

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegateNavigator.kt:0-0
Timestamp: 2025-07-16T16:11:27.044Z
Learning: In the Reed-Android project's DelegateNavigator implementation, the pop(), peek(), and peekBackStack() methods should always use childNavigator without branching logic, as they operate on the currently active navigation stack. Only goTo() and resetRoot() methods need to route between childNavigator and rootNavigator based on screen type using isMainTabScreen() function.

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegatingNavigator.kt:0-0
Timestamp: 2025-07-16T15:54:19.322Z
Learning: In the Reed-Android project using Circuit architecture, DelegatingNavigator was restored because NavigableCircuitContent can only inject a single navigator, but the dual-navigator architecture (childNavigator for bottom navigation screens, rootNavigator for full-screen screens) requires a delegating component to work within Circuit's constraint.

feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/Screens.kt (1)

Learnt from: seoyoon513
PR: #35
File: feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/TermsAgreementScreen.kt:127-127
Timestamp: 2025-07-09T01:14:29.836Z
Learning: In the Reed-Android project's TermsAgreementScreen.kt, the OnTermDetailClick event is intentionally passed an empty string for the URL parameter because the actual URLs for terms detail pages haven't been decided yet. This is a temporary implementation that will be updated once the URLs are finalized.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt (2)

Learnt from: easyhooon
PR: #55
File: feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchPresenter.kt:44-44
Timestamp: 2025-07-17T18:40:41.210Z
Learning: rememberTextFieldState()는 내부적으로 rememberSaveable(saver = TextFieldState.Saver)를 사용하여 구현되어 있어, 화면 회전이나 프로세스 재시작 시에도 텍스트 상태가 자동으로 보존된다. 따라서 추가적인 rememberRetained 래핑이 불필요하다.

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegatingNavigator.kt:0-0
Timestamp: 2025-07-16T15:54:19.322Z
Learning: In the Reed-Android project using Circuit architecture, DelegatingNavigator was restored because NavigableCircuitContent can only inject a single navigator, but the dual-navigator architecture (childNavigator for bottom navigation screens, rootNavigator for full-screen screens) requires a delegating component to work within Circuit's constraint.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailPresenter.kt (1)

Learnt from: easyhooon
PR: #52
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/screens/DelegatingNavigator.kt:0-0
Timestamp: 2025-07-16T15:54:19.322Z
Learning: In the Reed-Android project using Circuit architecture, DelegatingNavigator was restored because NavigableCircuitContent can only inject a single navigator, but the dual-navigator architecture (childNavigator for bottom navigation screens, rootNavigator for full-screen screens) requires a delegating component to work within Circuit's constraint.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUiState.kt (1)

Learnt from: seoyoon513
PR: #35
File: feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/TermsAgreementScreen.kt:127-127
Timestamp: 2025-07-09T01:14:29.836Z
Learning: In the Reed-Android project's TermsAgreementScreen.kt, the OnTermDetailClick event is intentionally passed an empty string for the URL parameter because the actual URLs for terms detail pages haven't been decided yet. This is a temporary implementation that will be updated once the URLs are finalized.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUi.kt (2)

Learnt from: seoyoon513
PR: #35
File: feature/login/src/main/kotlin/com/ninecraft/booket/feature/login/TermsAgreementScreen.kt:127-127
Timestamp: 2025-07-09T01:14:29.836Z
Learning: In the Reed-Android project's TermsAgreementScreen.kt, the OnTermDetailClick event is intentionally passed an empty string for the URL parameter because the actual URLs for terms detail pages haven't been decided yet. This is a temporary implementation that will be updated once the URLs are finalized.

Learnt from: easyhooon
PR: #61
File: feature/webview/build.gradle.kts:17-21
Timestamp: 2025-07-20T12:34:23.786Z
Learning: Reed-Android 프로젝트에서는 booket.android.feature convention plugin을 사용하여 feature 모듈들의 공통 의존성을 관리한다. 이 plugin은 Circuit, Compose, 그리고 core 모듈들의 의존성을 자동으로 포함하므로, 각 feature 모듈의 build.gradle.kts에서는 특별한 의존성(예: libs.logger, libs.kakao.auth)만 별도로 선언하면 된다.

🧬 Code Graph Analysis (3)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (3)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/HandleRecordRegisterSideEffects.kt (1)
  • HandleRecordRegisterSideEffects (8-23)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (1)
  • EmotionStep (31-70)
core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt (1)
  • ReedDialog (25-109)
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/component/QuoteBox.kt (1)
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Theme.kt (1)
  • ReedTheme (14-21)
feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt (1)
core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (1)
  • handleException (13-40)
⏰ 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: ci-build
🔇 Additional comments (56)
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailSideEffect.kt (1)

1-1: 패키지 경로 변경 확인 완료

feature.detailfeature.detail.book 로 패키지를 정비한 것은 모듈 구조와 일관성을 높여 줍니다. 다른 관련 파일들도 동일하게 이동된 것인지 한 번 더 확인해 주세요.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUi.kt (1)

1-1: 패키지 이동에 따른 의존성 확인 필요

패키지를 feature.detail.book으로 변경하면서 동일 모듈 내 참조(예: HandleBookDetailSideEffects, BookDetailUiState)와 외부 모듈에서의 import가 깨질 수 있습니다. CI 통과 여부를 확인하시고, IDE에서 자동 리팩터링되지 않은 파일이 없는지 한번 더 점검해 주세요.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailUiState.kt (1)

1-1: 패키지 이동 및 참조 업데이트 완료

  • feature/detail/build.gradle.kts의 namespace = "com.ninecraft.booket.feature.detail" 설정은 모듈 루트 패키지로 의도된 값입니다.
  • 모든 Kotlin 파일의 packageimport 구문이 com.ninecraft.booket.feature.detail.book (또는 .review) 로 올바르게 업데이트되었습니다.
  • 이전 패키지명(com.ninecraft.booket.feature.book.detail)을 참조하는 잔여 코드는 발견되지 않았습니다.

추가 수정이 필요 없습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/book/BookDetailPresenter.kt (1)

1-1: 패키지 경로 분리 확인 완료
detail.book 하위로 이동하여 리뷰·기타 상세 화면과 명확히 구분된 점 👍

feature/record/src/main/res/values/strings.xml (1)

36-39: 기록 저장 완료 다이얼로그 문자열 리소스가 잘 추가되었습니다!

네이밍 컨벤션이 일관되고 사용자 친화적인 문구로 작성되어 있습니다.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt (1)

68-76: 감정 태그용 색상 정의가 잘 추가되었습니다!

각 감정별로 텍스트 색상과 배경 색상이 쌍으로 정의되어 있어 일관성 있고 접근성을 고려한 구조입니다.

feature/detail/src/main/res/values/strings.xml (1)

1-6: 독서 기록 상세 화면용 문자열 리소스가 잘 정의되었습니다!

명확한 네이밍 컨벤션과 사용자 친화적인 라벨들로 구성되어 있습니다.

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/mapper/ResponseToModel.kt (2)

12-12: 필요한 import 문이 적절히 추가되었습니다!

RecordRegisterModel과 RecordRegisterResponse 클래스 import가 올바르게 추가되었습니다.

Also applies to: 22-22


140-151: 기록 등록 응답 매퍼 함수가 잘 구현되었습니다!

모든 필드를 명확하게 1:1 매핑하고 있으며, 기존 매퍼 함수들과 일관된 패턴을 따르고 있습니다.

core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedDialog.kt (2)

34-34: headerContent 파라미터 추가가 잘 구현되었습니다.

다이얼로그에 커스텀 헤더 콘텐츠를 추가할 수 있는 기능이 적절히 구현되었습니다. nullable 파라미터 설계와 렌더링 로직이 올바르게 작성되었습니다.

Also applies to: 62-65


119-119: 프리뷰 함수의 description 텍스트 개선이 좋습니다.

"subtext"에서 "description"으로 변경하여 더 명확하고 이해하기 쉬운 프리뷰를 제공합니다.

Also applies to: 132-132

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/di/RepositoryModule.kt (1)

5-5: RecordRepository 바인딩이 올바르게 추가되었습니다.

새로운 독서 기록 저장소가 의존성 주입 모듈에 적절히 추가되었으며, 기존 패턴과 일관성을 유지하고 있습니다.

Also applies to: 9-9, 33-35

feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchPresenter.kt (4)

17-17: RecordScreen import 추가가 적절합니다.

네비게이션을 위한 필수 import가 올바르게 추가되었습니다.


55-55: registeredUserBookId 상태 변수 추가가 적절합니다.

책 등록 후 반환받은 userBookId를 저장하기 위한 상태 변수가 올바르게 추가되었습니다.


103-103: upsertBook 성공 시 userBookId 저장 로직이 잘 구현되었습니다.

책 등록 성공 후 반환받은 userBookId를 상태에 저장하여 이후 네비게이션에서 활용할 수 있도록 구현되었습니다.


187-187: RecordScreen 네비게이션 및 파라미터 전달 확인됨

RecordScreenval userBookId: String 파라미터를 받도록 정의되어 있어
SearchPresenternavigator.goTo(RecordScreen(registeredUserBookId)) 호출이 올바릅니다.
변경사항 승인합니다.

  • RecordScreen 정의:
    feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/Screens.kt:36
core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt (1)

5-5: 필요한 import들이 적절히 추가되었습니다.

독서 기록 등록 API를 위한 필수 import들이 올바르게 추가되었습니다.

Also applies to: 12-12, 19-19

core/network/src/main/kotlin/com/ninecraft/booket/core/network/request/RecordRegisterRequest.kt (1)

6-16: RecordRegisterRequest 데이터 클래스가 잘 구현되었습니다.

독서 기록 등록을 위한 요청 데이터 클래스가 적절히 정의되었습니다. Serializable 어노테이션과 SerialName을 통한 JSON 매핑이 올바르게 구현되었습니다.

core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/EmotionTag.kt (1)

13-18: 감정 태그 enum 구현이 깔끔합니다.

디자인 시스템의 색상 상수를 활용하여 일관성 있게 구현되었고, 한국어 라벨과 함께 UI 속성들이 잘 중앙화되어 있습니다. graphic 필드의 placeholder(0) 값도 향후 리소스 추가 계획을 명확히 나타냅니다.

feature/screens/src/main/kotlin/com/ninecraft/booket/feature/screens/Screens.kt (2)

36-36: RecordScreen 파라미터 추가가 적절합니다.

userBookId 파라미터를 추가하여 화면 상태 관리가 개선되었고, 네비게이션 시 필요한 데이터를 전달할 수 있게 되었습니다.


44-45: 새로운 ReviewDetailScreen 추가가 좋습니다.

@parcelize 어노테이션과 함께 적절히 구현되어 있고, 리뷰 상세 기능을 위한 화면 정의가 명확합니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/HandleRecordRegisterSideEffects.kt (1)

8-23: 사이드 이펙트 핸들링이 올바르게 구현되었습니다.

RememberedEffect를 사용하여 상태 변화를 관찰하고, Toast 메시지를 표시하는 로직이 깔끔하게 분리되어 있습니다. Compose의 사이드 이펙트 패턴을 잘 따르고 있습니다.

core/network/src/main/kotlin/com/ninecraft/booket/core/network/response/RecordRegisterResponse.kt (1)

6-24: 네트워크 응답 모델이 적절하게 구현되었습니다.

@serializable과 @SerialName 어노테이션을 올바르게 사용하여 API 응답을 매핑하고 있고, 모든 필드가 명확하게 정의되어 있습니다. emotionTags를 List으로 처리하는 것도 네트워크 계층에서 적합한 접근입니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (3)

40-40: 사이드 이펙트 처리가 적절한 위치에 추가되었습니다.

컴포저블 시작 부분에서 HandleRecordRegisterSideEffects를 호출하여 토스트 메시지 등의 사이드 이펙트가 올바르게 처리됩니다.


65-65: EmotionStep에 전체 상태 전달이 좋습니다.

EmotionTag enum을 활용한 동적 감정 태그 렌더링을 위해 전체 상태를 전달하는 것이 적절합니다.


82-82: 다음 버튼 활성화 상태 제어가 잘 구현되었습니다.

state.isNextButtonEnabled를 통한 버튼 상태 관리로 사용자 경험이 개선됩니다.

core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/RecordRepository.kt (1)

5-13: 인터페이스 설계가 깔끔합니다.

Repository 패턴을 잘 따르고 있으며, suspend 함수와 Result 타입을 사용하여 비동기 처리와 에러 핸들링을 적절히 고려했습니다. 매개변수 타입들도 도메인에 맞게 잘 정의되어 있습니다.

core/model/src/main/kotlin/com/ninecraft/booket/core/model/RecordRegisterModel.kt (1)

3-12: 모델 클래스 설계가 적절합니다.

독서 기록 등록에 필요한 모든 필드가 잘 정의되어 있고, 기본값 설정으로 초기화 편의성을 제공하고 있습니다. 데이터 타입들도 각 필드의 용도에 맞게 적절히 선택되었습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailSideEffect.kt (1)

8-28: 사이드 이펙트 처리 패턴이 잘 구현되었습니다.

RememberedEffect를 사용하여 상태 변화를 적절히 관찰하고 있으며, 사이드 이펙트 처리 후 초기화하는 패턴도 중복 실행을 방지하는 좋은 접근입니다. UI와 사이드 이펙트 처리의 분리도 깔끔합니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/component/QuoteBox.kt (1)

16-49: 잘 설계된 재사용 가능한 컴포넌트입니다.

매개변수를 통해 적절히 데이터를 받도록 설계되어 있고, 인용문 형식("$quote")과 페이지 번호 형식(${page}p)도 사용자 친화적입니다. 레이아웃 구조와 테마 적용도 일관성 있게 잘 구현되었습니다.

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultRecordRepository.kt (2)

13-21: API 연동 구현이 깔끔하게 되어 있습니다.

Repository 패턴과 에러 핸들링이 적절히 구현되어 있고, 의존성 주입 및 응답 매핑도 올바르게 처리되어 있습니다.


14-14: userBookId 타입 일관성 확인 요청

DefaultRecordRepository.kt에서 userBookId를 String으로 선언하셨습니다.
다른 레이어(Repository 인터페이스, Service/Controller DTO, 외부 API 스펙)에서도 userBookId가 동일하게 String으로 정의되어 있는지 확인해 주세요.

확인해야 할 위치 예시:

  • core/data/api/.../RecordRepository.kt – 메서드 시그니처
  • service 레이어 DTO (RecordDto 등) – userBookId 필드
  • controller 레이어 요청/응답 DTO – userBookId 필드
feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailPresenter.kt (1)

29-43: 이벤트 핸들링 로직이 명확하게 구현되어 있습니다.

Circuit 패턴에 맞는 이벤트 처리와 네비게이션 로직이 잘 구현되어 있습니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/step/EmotionStep.kt (3)

32-35: 상태 기반 접근 방식으로의 리팩토링이 잘 되어 있습니다.

정적 리스트에서 RecordRegisterUiState를 사용하는 방식으로 변경하여 더 유연하고 반응적인 UI가 구현되었습니다.


58-66: 감정 태그 선택 로직이 깔끔하게 구현되어 있습니다.

EmotionTag 열거형을 사용하여 타입 안전성을 보장하고, 선택 상태에 따른 동적 UI 업데이트가 잘 처리되어 있습니다.


73-95: 선택 상태에 따른 UI 피드백이 적절합니다.

선택된 감정에 따라 배경색이 동적으로 변경되고, clickableSingle을 사용하여 중복 클릭을 방지하는 것이 좋습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUiState.kt (2)

7-10: UI 상태 구조가 Circuit 패턴에 맞게 잘 정의되어 있습니다.

사이드 이펙트와 이벤트 싱크를 포함한 상태 관리 구조가 적절하게 설계되었습니다.


12-17: 사이드 이펙트 패턴이 적절하게 구현되어 있습니다.

UUID를 사용한 고유 키 생성으로 사이드 이펙트의 중복 처리를 방지하는 것이 좋은 접근입니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUiState.kt (4)

16-17: EmotionTag 열거형 사용으로 타입 안전성이 향상되었습니다.

selectedEmotionString에서 EmotionTag?로 변경되어 더 엄격한 타입 체크가 가능해졌습니다.


21-25: UI 제어를 위한 상태 플래그들이 적절히 추가되었습니다.

다음 버튼 활성화 상태와 기록 저장 다이얼로그 표시 여부를 관리하는 플래그들이 잘 정의되어 있습니다.


29-35: 사이드 이펙트 패턴이 일관성 있게 구현되어 있습니다.

다른 기능들과 동일한 패턴으로 ShowToast 사이드 이펙트가 구현되어 있어 코드베이스의 일관성이 유지되고 있습니다.


41-41: 감정 선택 이벤트가 타입 안전하게 개선되었습니다.

OnSelectEmotion이 객체에서 EmotionTag 매개변수를 받는 데이터 클래스로 변경되어 더 명확한 이벤트 처리가 가능해졌습니다.

feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterPresenter.kt (9)

11-19: 새로운 의존성 추가가 적절합니다.

RecordRepository, handleException, EmotionTag 등 새로운 기능에 필요한 의존성들이 올바르게 추가되었습니다. 각 import가 실제로 코드에서 사용되고 있어 불필요한 import는 없습니다.


33-35: 생성자 파라미터 변경이 올바릅니다.

RecordScreenuserBookId를 받는 데이터 클래스로 변경된 것과 RecordRepository 의존성 주입이 적절하게 반영되었습니다.


58-65: 새로운 상태 변수들이 적절하게 추가되었습니다.

감정 태그, 선택된 감정, 다음 버튼 활성화 상태, 레코드 저장 다이얼로그 등 새로운 기능에 필요한 상태들이 rememberRetained를 사용해 올바르게 관리되고 있습니다.


107-121: 다음 버튼 활성화 로직이 올바르게 구현되었습니다.

각 단계별로 필요한 조건들을 적절히 체크하고 있습니다:

  • QUOTE: 페이지와 문장이 모두 입력됨
  • EMOTION: 감정이 선택됨
  • IMPRESSION: 감상이 입력됨

158-160: 감정 선택 이벤트 처리가 올바릅니다.

선택된 감정을 상태에 업데이트하는 로직이 간단하고 명확합니다.


198-204: 레코드 저장 호출이 적절하게 구현되었습니다.

  • screen.userBookId 사용이 올바름
  • 페이지 번호의 안전한 변환 (toIntOrNull() ?: 0)
  • 감정 태그를 문자열 리스트로 변환하는 로직이 적절함

209-218: 레코드 저장 완료 다이얼로그 처리가 올바릅니다.

확인 시 ReviewDetailScreen으로 이동하고, 취소 시 이전 화면으로 돌아가는 로직이 사용자 경험에 적합합니다.


222-230: LaunchedEffect 사용이 적절합니다.

필요한 의존성들(currentStep, 텍스트 상태들, selectedEmotion)이 모두 포함되어 상태 변경 시 다음 버튼 활성화 상태가 올바르게 업데이트됩니다.


253-257: Factory 인터페이스 업데이트가 올바릅니다.

RecordScreen 파라미터가 추가되어 새로운 화면 구조에 맞게 업데이트되었습니다.

feature/detail/src/main/kotlin/com/ninecraft/booket/feature/detail/review/ReviewDetailUi.kt (5)

1-36: Import 구성이 적절합니다.

필요한 Compose UI 컴포넌트들과 프로젝트 내부 모듈들이 올바르게 import되어 있으며, Circuit 아키텍처와 디자인 시스템 컴포넌트들이 적절히 포함되어 있습니다.


38-60: Circuit 아키텍처 패턴이 올바르게 적용되었습니다.

@CircuitInject 어노테이션을 사용한 의존성 주입과 사이드 이펙트 처리, 이벤트 처리가 적절하게 구현되어 있습니다. ReedFullScreenReedTopAppBar 사용도 프로젝트의 디자인 시스템을 잘 활용하고 있습니다.


78-126: 더미 데이터 사용이 현재 개발 단계에 적합합니다.

팀의 개발 방식에 따라 UI 구현 단계에서 하드코딩된 데이터("여름은 오래 그곳에 남아", "미쓰이에 마사시", "비채")를 사용하는 것이 적절합니다. 이후 서버 연동 시점에 실제 데이터로 교체될 예정입니다.

NetworkImage에서 빈 URL을 사용하는 것도 현재 단계에서는 적절하며, placeholder 이미지가 올바르게 설정되어 있습니다.


141-149: QuoteBox와 ReviewBox 컴포넌트 사용이 적절합니다.

인용구와 리뷰 내용을 표시하기 위해 전용 컴포넌트들을 사용하는 것이 코드의 재사용성과 일관성 측면에서 좋습니다. 하드코딩된 인용구 데이터도 현재 UI 구현 단계에서는 적절합니다.


154-164: Preview 구현이 올바릅니다.

@ComponentPreview 어노테이션을 사용한 미리보기 구현이 적절하며, 빈 eventSink를 제공하여 미리보기에서 이벤트 처리 오류를 방지하고 있습니다.

}
is HomeUiEvent.OnRecordButtonClick -> {
navigator.goTo(RecordScreen)
navigator.goTo(RecordScreen(""))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

빈 문자열 파라미터 전달을 검증해주세요.

홈 화면에서 기록 화면으로 이동할 때 빈 userBookId를 전달하고 있습니다. 실제 책 정보 없이 기록 화면이 정상 작동하는지 확인이 필요합니다.

다음 스크립트로 RecordScreen에서 빈 문자열 파라미터 처리 방식을 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# RecordScreen에서 userBookId 파라미터 사용 방식 확인
ast-grep --pattern $'data class RecordScreen($$$) : Screen'
echo "---"
rg -A 10 "userBookId.*isEmpty\|userBookId.*isBlank\|userBookId.*\"\""

Length of output: 145


아직 RecordScreen 정의 위치와 userBookId 사용처를 찾지 못했습니다. 아래 스크립트를 실행하여 다시 한 번 재검색해 주세요.


🏁 Script executed:

#!/bin/bash
# RecordScreen 정의 및 userBookId 사용처 재검색
rg -n "data class RecordScreen" -A 3 || true
echo "-----"
rg -n "class RecordScreen" -A 3 || true
echo "-----"
rg -n "object RecordScreen" -A 3 || true
echo "-----"
rg -n "userBookId" -A 3 || true

Length of output: 11139


RecordScreen 호출 시 빈 userBookId 전달 수정 필요

HomePresenter.kt 31행에서

navigator.goTo(RecordScreen(""))

처럼 빈 문자열을 넘기면,
RecordScreen(val userBookId: String)
RecordRegisterPresenter
ReedService.postRecord("/api/v1/reading-records/{userBookId}") 호출 시
경로가 /api/v1/reading-records/로 잘못 구성되어 API 오류가 발생할 수 있습니다.

실제 사용자의 userBookId를 전달하거나, 빈값 전달 시 별도 예외 처리 로직을 추가해주세요.

  • 위치: feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt
    • 31행: navigator.goTo(RecordScreen(""))
🤖 Prompt for AI Agents
In
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt
at line 31, the call navigator.goTo(RecordScreen("")) passes an empty string as
userBookId, causing incorrect API path construction and errors. Fix this by
passing the actual userBookId value when calling RecordScreen, or implement
logic to handle empty userBookId cases explicitly before navigation to avoid API
errors.

var isRecordSavedDialogVisible by rememberRetained { mutableStateOf(false) }
var isNextButtonEnabled by rememberRetained { mutableStateOf(false) }

val ocrNavigator = rememberAnsweringNavigator<OcrScreen.OcrResult>(navigator) { result ->
Copy link
Copy Markdown
Contributor

@easyhooon easyhooon Jul 30, 2025

Choose a reason for hiding this comment

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

오오... rememberAnsweringNavigator 적용했었군요 👍 👍 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

공식문서 보니까 잘 나와있어서 쉽게 적용했습니다 😄

@easyhooon
Copy link
Copy Markdown
Contributor

@seoyoon513 테스트해보면서 바텀시트나 다이얼로그가 닫히기전에 화면이동이 먼저되는 경우를 확인했는데, 관련해서 UX가 별로라 생각이 되면 일단 매직넘버도입도 고려해볼 필요가 있을것같고 정통 해결법은 좀더 고민해봐야할듯하네여

@seoyoon513
Copy link
Copy Markdown
Contributor Author

스트해보면서 바텀시트나 다이얼로그가 닫히기전에 화면이동이 먼저되는 경우를 확인했는데, 관련해서 UX가 별로라 생각이 되면 일단 매직넘버도입도 고려해볼 필요가 있을것같고 정통 해결법은 좀더 고민해봐야할듯하네여

이거 2차 UT 전에는 매직넘버로 긴급 처방하시는건 어떤가요? 확장함수 하나 만들어서 일괄 처리하고 나중에 확장함수로 처리했던 부분 추적해서 수정하면 될 것 같긴 해요

@seoyoon513 seoyoon513 merged commit 5bbac4b into develop Jul 30, 2025
3 checks passed
@seoyoon513 seoyoon513 deleted the BOOK-168-feature/#70 branch July 30, 2025 13:44
@easyhooon
Copy link
Copy Markdown
Contributor

이거 2차 UT 전에는 매직넘버로 긴급 처방하시는건 어떤가요? 확장함수 하나 만들어서 일괄 처리하고 나중에 확장함수로 처리했던 부분 추적해서 수정하면 될 것 같긴 해요

@seoyoon513 좋습니다!

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-168/feat] 독서 기록 등록 API 연동 및 완료 화면 UI 구현

2 participants