Skip to content

fix: 약관동의 API 네트워크 에러 핸들링#146

Merged
easyhooon merged 6 commits intodevelopfrom
BOOK-260-fix/#142
Aug 16, 2025
Merged

fix: 약관동의 API 네트워크 에러 핸들링#146
easyhooon merged 6 commits intodevelopfrom
BOOK-260-fix/#142

Conversation

@easyhooon
Copy link
Copy Markdown
Contributor

@easyhooon easyhooon commented Aug 15, 2025

🔗 관련 이슈

📙 작업 설명

  • 스플래시 화면 진입시 네트워크 연결이 없는 경우, 이후 화면으로 이동하지 않고 네트워크 에러 다이얼로그를 노출

🧪 테스트 내역 (선택)

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

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

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

  • 에러 관련해서 중앙 집중화해서 관리하는 방식 넘 잘 구현된 것 같습니다. 기존 프로젝트에도 적용해봐야겠슴다
  • 현재 도서 등록, 기록 플로우에서 토스트랑 다이얼로그가 둘다 뜨는데 다이얼로그만 띄워도될듯합니다. 관련해서 PD분들과 논의 후 제거하면 될 것 같슴다
  • 에러 케이스에 대한 다이얼로그 figma 시안중에 '다시 시도하기'라는 buttonLabel이 있는데 현재 앱에서 쓰는 워딩은 '다시 시도'라 둘중 하나로 결정 후 통일하면 좋을 것 같습니다

Summary by CodeRabbit

  • New Features

    • 오류 다이얼로그 버튼 텍스트가 문자열 리소스를 사용하도록 변경되어 지역화 가능해졌습니다.
    • 인증 실패 시 스플래시에서 오류 다이얼로그를 띄우고 재시도로 흐름을 재시도할 수 있습니다.
  • 데이터/모델

    • 독서 기록 모델에 페이징 메타데이터 및 상세 항목(페이지, 인용문, 후기, 감정 태그, 저자 등) 추가 및 @stable 적용.
    • 일부 모델의 안정성 애노테이션 변경(@stable 제거 포함).
  • Chores

    • 문자열 리소스(confirm) 및 여러 OSS 라이선스 항목 추가, kotlinx-datetime 의존성 항목 제거.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 15, 2025

Warning

Rate limit exceeded

@easyhooon has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 53cd427 and e919ffb.

📒 Files selected for processing (3)
  • feature/record/src/main/kotlin/com/ninecraft/booket/feature/record/register/RecordRegisterUi.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUi.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt (1 hunks)

Walkthrough

에러 다이얼로그 버튼 라벨을 문자열에서 문자열 리소스 ID로 전환하고 기본 리소스(confirm)를 추가했으며, 스플래시에서 약관동의 실패 시 에러 다이얼로그를 띄워 재시도하도록 흐름을 변경했습니다.

Changes

Cohort / File(s) Summary
Error dialog spec update
core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt
ErrorDialogSpec의 버튼 라벨 타입을 String@StringRes Int (buttonLabelResId)로 변경.
Exception handling & dialog posting
core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt
postErrorDialog 시그니처에 @StringRes buttonLabelResId: Int = R.string.confirm 추가 및 ErrorDialogSpec 생성에 리소스 ID 전달로 변경.
String resources
core/common/src/main/res/values/strings.xml
문자열 리소스 confirm("확인") 추가.
Dialog usage (Main)
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt
ReedDialog 확인 버튼을 stringResource(spec.buttonLabelResId)로 가져오도록 변경(관련 import 추가).
Splash retry flow
feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt
약관동의 실패 시 postErrorDialog(..., buttonLabelResId = R.string.retry, action = { checkTermsAgreement() }) 호출하여 재시도 구현.
Model annotation & fields
core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt, core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt
BookUpsertModel@Stable 제거; ReadingRecordModel@Stable 추가 및 필드 확장; ReadingRecordsModel에 페이징 필드(startIndex, itemsPerPage) 추가.
Assets: OSS licenses
feature/settings/src/main/assets/oss_licenses.json
OSS 라이선스 항목 10개 추가.
Dependency manifest
gradle/libs.versions.toml
kotlinx-datetime 항목 제거.
Minor UI reorder
core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt
Scaffold 호출 내 named-argument 순서 변경(동작 영향 없음).
Search event rename
feature/search/.../BookSearchUiState.kt, BookSearchPresenter.kt, BookSearchUi.kt, LibrarySearchUi.kt
OnSearchClick의 프로퍼티명 textquery로 변경 및 호출부 파라미터명 일치화.

Sequence Diagram(s)

sequenceDiagram
  participant Splash as SplashPresenter
  participant EH as HandleException.postErrorDialog
  participant UI as ErrorDialog
  participant User as User

  Splash->>Splash: checkTermsAgreement()
  alt failure
    Splash->>EH: postErrorDialog(errorScope=Global, exception, buttonLabelResId=R.string.retry, action=retry)
    EH-->>UI: show ErrorDialog(message, button: Retry)
    User->>UI: Tap Retry
    UI-->>Splash: invoke action()
    Splash->>Splash: checkTermsAgreement() (retry)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
스플래시에서 에러 다이얼로그 노출 및 재시도 제공 (#142)

Out-of-scope changes

Code Change Explanation
@Stable 제거 — core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt 모델 어노테이션 변경은 #142의 에러 핸들링/다이얼로그 목표와 관련 없음.
ReadingRecordsModel 확장 및 @Stable 추가 — core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt 레코드 모델 필드 확장과 페이징 필드 추가는 스플래시 네트워크 에러 처리 요구사항과 무관함.
OSS 라이선스 JSON 항목 추가 — feature/settings/src/main/assets/oss_licenses.json 라이선스 메타데이터 추가는 에러 핸들링 개선과 관련 없음.
kotlinx-datetime 제거 — gradle/libs.versions.toml 의존성 제거는 #142의 목적(스플래시 에러 처리)과 관련 없는 빌드/종속성 변경임.

Suggested labels

✨ feat

Poem

깡총깡총, 토끼가 알리네 🥕
버튼은 리소스가 되었고, 창은 다시 뜨네,
실패해도 누르면 재시도, 길은 이어지리 — 깡총! 🐇

✨ 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-260-fix/#142

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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: 2

🔭 Outside diff range comments (1)
core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (1)

133-138: IOException 제외 후 네이밍 검토 필요
isNetworkError()IOException을 포함하면 파일 I/O 등 순수 네트워크 오류가 아닌 예외까지 네트워크 오류로 분류됩니다. 실제로는 Retrofit 호출 등 네트워크 경로에서만 쓰이지만, 공용 확장 함수라는 점을 고려해 범위를 좁히거나 이름을 바꿔 의도를 명확히 하는 것이 좋겠습니다.

수정 제안:

  • core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt
    fun Throwable.isNetworkError()에서 this is IOException 제거
    • 필요하면 SSL 관련 예외(SSLException 등)만 추가
  • (또는) 네이밍을 isIoOrNetworkError()처럼 변경하여 IOException 포함 의도를 드러내기

추가로, 아래 사용 위치에서 변경 영향 범위를 확인해 주세요:

  • core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/component/ReedErrorUi.kt
  • core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (여러 처리 분기)
🧹 Nitpick comments (5)
core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt (1)

5-5: 리소스 ID에 @stringres 어노테이션을 추가해 타입 안정성을 높이세요.

컴파일 타임에 잘못된 리소스 전달을 잡을 수 있습니다.

다음 변경을 권장합니다:

-data class ErrorDialogSpec(
-    val message: String,
-    val buttonLabelResId: Int,
-    val action: () -> Unit,
-)
+data class ErrorDialogSpec(
+    val message: String,
+    @androidx.annotation.StringRes val buttonLabelResId: Int,
+    val action: () -> Unit,
+)

또는 import를 추가해 간결하게 사용할 수 있습니다(파일 상단에 추가):

import androidx.annotation.StringRes
feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt (1)

56-63: 스플래시 네트워크 오류에 다이얼로그로 재시도 유도하는 흐름이 목적에 부합합니다.

이전의 잘못된 로그인 화면 이동을 막고 사용자 주도 재시도를 제공하므로 요구사항과 일치합니다. 두 가지 확인/제안 사항입니다:

  • 전역 에러 스코프 사용 시, 동일 예외가 토스트 등 다른 채널로도 중복 노출되지 않는지 확인해 주세요(중복 노출 이슈 언급됨).
  • 다이얼로그에서 재시도 버튼을 연속 탭하면 요청이 중첩 실행될 수 있습니다. 필요하다면 진행 중 플래그로 추가 탭을 일시 차단하는 방식을 고려해 보세요.
core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (3)

64-69: 네트워크 오류일 때 기본 라벨을 자동으로 ‘재시도’로 스위칭 제안

호출부마다 R.string.retry를 지정하지 않아도, 네트워크 오류인 경우에 한해 기본 라벨(확인) → 재시도 라벨로 자동 전환하면 UX 일관성이 좋아집니다. 기본값은 유지하되 네트워크 케이스만 덮어쓰는 방식입니다.

적용 예시(diff):

 private fun buildDialog(
     scope: ErrorScope,
     exception: Throwable,
     @StringRes buttonLabelResId: Int,
     action: () -> Unit,
 ): ErrorDialogSpec {
     val message = when {
         exception.isNetworkError() -> {
             "네트워크 연결이 불안정합니다.\n인터넷 연결을 확인해주세요"
         }
@@
     }
 
-    return ErrorDialogSpec(message = message, buttonLabelResId = buttonLabelResId, action = action)
+    // 네트워크 오류 + 호출부에서 별도 라벨 지정이 없을 때 기본 라벨을 재시도로 전환
+    val effectiveButtonLabelResId =
+        if (exception.isNetworkError() && buttonLabelResId == R.string.confirm) {
+            R.string.retry
+        } else {
+            buttonLabelResId
+        }
+
+    return ErrorDialogSpec(
+        message = message,
+        buttonLabelResId = effectiveButtonLabelResId,
+        action = action
+    )
 }

Also applies to: 100-100


70-99: 다이얼로그 메시지 하드코딩 → 문자열 리소스 이전 권장

현재 메시지가 하드코딩되어 있어 현지화(i18n), 접근성(A/B 테스트/카피 일관성) 관점에서 관리가 어렵습니다. 버튼 라벨과 동일하게 메시지도 리소스로 관리하는 방향을 권장드립니다. 필요하다면 ErrorDialogSpec을 messageResId 기반으로 확장하는 것도 고려해볼 수 있습니다.


36-38: 네트워크 안내 문구 일관성 정리 제안

handleException의 네트워크 문구(“네트워크 연결을 확인해주세요.”)와 다이얼로그 문구(“네트워크 연결이 불안정합니다.\n인터넷 연결을 확인해주세요”)가 달라 사용자 경험이 다소 파편화될 여지가 있습니다. 문구를 통일하거나, 공통 상수/리소스로 중앙집중화하는 것을 제안드립니다.

Also applies to: 71-73

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c7bdf0f and 3720fca.

📒 Files selected for processing (6)
  • core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt (1 hunks)
  • core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (4 hunks)
  • core/common/src/main/res/values/strings.xml (1 hunks)
  • core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt (1 hunks)
  • feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt (2 hunks)
  • feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt (1)
core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (1)
  • postErrorDialog (48-62)
🔇 Additional comments (7)
core/ui/src/main/kotlin/com/ninecraft/booket/core/ui/ReedScaffold.kt (1)

25-25: 명명된 인자 순서 변경은 무해합니다 (LGTM).

modifier = modifier.keyboardHide() 위치만 변경되었고 Compose Scaffold의 명명 인자 순서는 의미에 영향이 없습니다.

core/common/src/main/res/values/strings.xml (1)

8-8: 확인 기본 문자열 리소스 추가 좋습니다.

전역 다이얼로그의 기본 확인 텍스트로 활용하기 적절합니다.

core/common/src/main/kotlin/com/ninecraft/booket/core/common/constants/ErrorDialogSpec.kt (1)

3-7: 문자열 → 리소스 기반 라벨 전환은 i18n/일관성 측면에서 적절합니다.

buttonLabel에서 buttonLabelResId로의 API 변경은 합리적이며, 다른 모듈의 사용처도 PR 범위 내에서 업데이트된 것으로 보입니다.

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

74-75: 리소스 기반 라벨 적용은 적절합니다 (LGTM).

stringResource(spec.buttonLabelResId)로 전환하여 다국어 대응과 일관성을 확보했습니다.

core/common/src/main/kotlin/com/ninecraft/booket/core/common/utils/HandleException.kt (3)

3-4: 리소스 기반 라벨로 전환: 타입 안전성과 현지화 측면에서 적절합니다

@stringres와 core/common 모듈의 R을 사용해 버튼 라벨을 리소스 ID로 관리하는 방향이 좋습니다. 모듈 간 의존성도 core/common 내 strings.xml 추가로 정합성이 맞습니다.


54-60: 파라미터 전달 경로 정합성 확보: OK

추가된 buttonLabelResId가 빌더까지 그대로 전달되는 흐름 문제 없습니다.


51-53: postErrorDialog 시그니처 확장 일관성 확인 완료

  • 모든 호출부에서 buttonLabelResId를 명시하지 않고 기본값(R.string.confirm) 사용 중 → 추가 수정 불필요
  • ErrorDialogSpec 생성부 정상 적용
  • 구식 필드명(buttonLabel) 잔존 여부 없음

변경사항이 레포 전반에 일관적으로 반영되었습니다. 👍

<string name="book_status_completed">독서 완료</string>
<string name="record_sort_page_ascending">페이지순</string>
<string name="record_sort_recent_register">최신 등록순</string>
<string name="confirm">확인</string>
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

Retry 라벨의 리소스 위치 일관성 확인 및 중앙화 제안

Splash에서 R.string.retry를 사용 중인데, 현재 confirm은 core-common에, retry는 다른 모듈(core-ui 등)에 있을 가능성이 있습니다. 버튼 라벨 리소스는 한 모듈로 중앙화하는 편이 의존성/가시성 측면에서 안정적입니다. 또한 PR 설명에 언급된 문구 통일(“다시 시도하기” vs “다시 시도”)도 함께 확정해 주세요.

다음 스크립트로 retry 리소스의 정의 위치를 확인해 주세요:

필요 시 core-common에 retry를 함께 두는 방향도 고려해 주세요. 예시:

   <string name="record_sort_recent_register">최신 등록순</string>
   <string name="confirm">확인</string>
+  <string name="retry">다시 시도</string>

🏁 Script executed:

#!/bin/bash
# retry 문자열 리소스 정의 위치 검색
rg -n -C1 -g '**/res/values/**/*.xml' '<string\s+name="retry">\s*([^<]+)\s*</string>'

Length of output: 393


Retry 라벨 리소스 중앙화 및 문구 통일 필요

현재 confirm 리소스는 core-common에, retry 리소스는 core-ui에 분리되어 있어 의존성 관리 및 가시성 측면에서 불일치합니다. 또한 사용 중인 버튼 문구가 “다시 시도”인지 “다시 시도하기”인지 프로젝트 전반에서 통일되어야 합니다.

수정 제안:

  • core-common/src/main/res/values/strings.xml에 retry 정의 추가 및 문구 확정
       <string name="confirm">확인</string>
    +  <string name="retry">다시 시도</string>  <!-- 또는 “다시 시도하기”로 통일 -->
  • core-ui/src/main/res/values/strings.xml에서 중복된 <string name="retry">…</string> 제거
  • 프로젝트 전역(코드, 레이아웃, 문서)에서 버튼 문구를 선택한 한 가지 표현으로 일관되게 교체
🤖 Prompt for AI Agents
In core/common/src/main/res/values/strings.xml around line 8, the retry label is
missing from core-common while a duplicate exists in core-ui; add a <string
name="retry"> entry to core-common with the decided wording (choose either "다시
시도" or "다시 시도하기"), remove the duplicated <string name="retry"> from
core-ui/src/main/res/values/strings.xml, and then search/replace across the
project (code, layouts, and docs) to ensure all usages use the chosen single
expression so resources are centralized and wording is consistent.

Comment on lines +9 to 11
import com.ninecraft.booket.core.common.constants.ErrorScope
import com.ninecraft.booket.core.common.utils.postErrorDialog
import com.ninecraft.booket.core.data.api.repository.AuthRepository
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

R 소스 모듈 확인: retry 리소스가 core-ui가 아닌 다른 모듈에 있을 수 있습니다.

현재 import com.ninecraft.booket.core.ui.R을 통해 R.string.retry를 참조합니다. 실제 retry 정의가 core-ui가 아닐 경우, 올바른 모듈의 R로 수정해야 합니다. 또한 confirm은 core-common에 있으므로 버튼 라벨 리소스의 모듈 위치를 통일하는 편이 좋습니다.

아래 스크립트로 retry 정의 위치와 현재 import가 맞는지 점검해 주세요:

Also applies to: 15-15


🏁 Script executed:

#!/bin/bash
# retry 문자열 정의 위치 나열
rg -n -C1 -g '**/res/values/**/*.xml' '<string\s+name="retry">\s*([^<]+)\s*</string>'

# SplashPresenter에서 실제로 어떤 R을 import하는지 출력
fd -t f 'SplashPresenter.kt' -E '.gradle' -E 'build' \
  | xargs -I{} rg -n 'import\s+.*\.R\b' {}

Length of output: 528


아래 스크립트로 confirm 문자열 정의 위치를 확인해 주세요:


🏁 Script executed:

#!/bin/bash
# confirm 문자열 정의 위치 나열
rg -n -C1 -g '**/res/values/**/*.xml' '<string\s+name="confirm">\s*([^<]+)\s*</string>'

Length of output: 342


UI 리소스 모듈 일관성 검토: retry(core-ui) vs confirm(core-common)

  • retry 정의:
    • 위치: core/ui/src/main/res/values/strings.xml:4
    • SplashPresenter의 import(com.ninecraft.booket.core.ui.R)과 일치함
  • confirm 정의:
    • 위치: core/common/src/main/res/values/strings.xml:8
    • 현 코드에서는 core-ui.R을 사용하므로 참조 모듈 불일치 가능성 존재
  • 제안: 버튼 라벨 리소스(retry, confirm)를 동일 모듈에서 관리하도록 조정
    • confirm을 core-ui 모듈로 이동 후 리소스 import 유지
    • 또는 retry를 core-common 모듈로 이동하고 SplashPresenter import를 com.ninecraft.booket.core.common.R로 변경
🤖 Prompt for AI Agents
In feature/splash/src/main/kotlin/com/ninecraft/booket/splash/SplashPresenter.kt
around lines 9 to 11, the presenter imports com.ninecraft.booket.core.ui.R while
string resources used (retry vs confirm) live in different modules (core-ui vs
core-common), causing inconsistent resource resolution; fix by making both
button labels reside in the same module and aligning imports: either move the
"confirm" string into core/ui (res/values/strings.xml) and keep the current
import, or move the "retry" string into core/common and change the import in
this file to com.ninecraft.booket.core.common.R, then update any references and
rebuild to ensure R resolves correctly.

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

🧹 Nitpick comments (4)
core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt (4)

3-3: 불변 데이터 클래스에는 @stable 대신 @immutable 사용 권장

ReadingRecordModel은 모든 프로퍼티가 val이고 외부에서 변하지 않는 불변 타입이라 @immutable가 의도에 더 부합합니다. Compose의 안정성 추론에도 더 명확하게 작동합니다.

아래처럼 import를 교체해 주세요:

-import androidx.compose.runtime.Stable
+import androidx.compose.runtime.Immutable

13-27: ReadingRecordModel의 @stable@immutable로 변경, 상위 모델에도 동일 주석 적용 제안

불변 모델은 @immutable가 더 적합합니다. 또한 상위 ReadingRecordsModel도 동일한 특징(불변)이라 일관성 있게 @immutable를 부여하는 것을 권장합니다.

우선 본 블록의 주석은 아래처럼 교체해 주세요:

-@Stable
+@Immutable

추가로(선택):

  • 상위 모델에도 동일 주석을 부여해 불필요한 재구성을 줄일 수 있습니다.
  • 읽기 전용 List는 Compose에서 완전한 안정 타입으로 간주되지 않습니다. 빈번한 UI 사용이 예상되면, kotlinx.collections.immutable의 ImmutableList로 바꾸는 것도 고려해 주세요.

예시(참고용, 파일 다른 위치 수정 포함):

import androidx.compose.runtime.Immutable
// import kotlinx.collections.immutable.ImmutableList
// import kotlinx.collections.immutable.persistentListOf

@Immutable
data class ReadingRecordsModel(
    val lastPage: Boolean = true,
    val totalResults: Int = 0,
    val startIndex: Int = 0,
    val itemsPerPage: Int = 0,
    // val readingRecords: ImmutableList<ReadingRecordModel> = persistentListOf(),
    val readingRecords: List<ReadingRecordModel> = emptyList(),
)

5-11: 페이지네이션 필드 의미(KDoc) 명시 제안

startIndex가 0/1-base 중 어느 기준인지, lastPage의 정의(“다음 페이지 없음” vs “현재 응답이 마지막 페이지 크기를 채우지 않음”) 등을 KDoc으로 고정하면 사용/매핑 시 혼동을 줄일 수 있습니다.

예시:

/**
 * @param startIndex 서버/클라이언트 기준 인덱스(0-based 권장) 
 * @param itemsPerPage 페이지당 항목 수
 * @param lastPage 더 이상 다음 페이지가 없으면 true
 * @param totalResults 전체 결과 수
 */

21-22: createdAt/updatedAt는 문자열 대신 타입 안전한 시간 타입 권장

문자열 파싱/포매팅 오류를 줄이고 비교/정렬을 안전하게 하려면 java.time.Instant 또는 kotlinx-datetime.Instant 사용을 권장합니다. 매핑은 Data/Remote 계층에서 수행하고, 도메인/모델은 타입 안전성을 유지하는 것이 유지보수에 유리합니다.

변경 예시(Instant 사용 시):

-    val createdAt: String = "",
-    val updatedAt: String = "",
+    val createdAt: java.time.Instant? = null,
+    val updatedAt: java.time.Instant? = null,

또는 kotlinx-datetime 사용 시:

-    val createdAt: String = "",
-    val updatedAt: String = "",
+    val createdAt: kotlinx.datetime.Instant? = null,
+    val updatedAt: kotlinx.datetime.Instant? = null,
📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3720fca and b1645f8.

📒 Files selected for processing (2)
  • core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt (0 hunks)
  • core/model/src/main/kotlin/com/ninecraft/booket/core/model/ReadingRecordsModel.kt (2 hunks)
💤 Files with no reviewable changes (1)
  • core/model/src/main/kotlin/com/ninecraft/booket/core/model/BookUpsertModel.kt

Copy link
Copy Markdown
Contributor

@seoyoon513 seoyoon513 left a comment

Choose a reason for hiding this comment

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

Goood ~ 👍

사용하지 않는 라이브러리 의존성 제거
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: 0

🧹 Nitpick comments (4)
feature/settings/src/main/assets/oss_licenses.json (4)

93-96: 라이선스 표기 일관성: "MIT license" → "MIT License"로 통일 권장

기존 항목들에서 "MIT License" 대소문자 표기를 사용하고 있어, 본 항목도 동일하게 맞추는 편이 좋습니다.

아래 변경 제안:

-        "license": "MIT license",
+        "license": "MIT License",

53-56: 명칭 정확성: "Google Analytics" → "Firebase Analytics"로 명확화 제안

실제 사용 라이브러리가 Firebase의 Analytics SDK라면 "Firebase Analytics" 또는 "Google Analytics for Firebase"로 명시하는 것이 더 정확합니다.

예시 변경:

-        "name": "Google Analytics",
+        "name": "Firebase Analytics",

53-66: 문서 URL 대신 리포지토리 URL 사용 검토(선택)

  • Analytics/Crashlytics는 보통 firebase-android-sdk 리포지토리로 귀속됩니다.
  • Kakao SDK도 GitHub 리포지토리를 링크하면 라이선스 추적이 수월합니다.

서비스 문서 링크가 팀 합의라면 유지해도 무방하나, 라이선스 고지 관점에서는 소스/라이선스 파일이 있는 리포지토리 URL이 더 적합합니다.

예시 변경:

-        "url": "https://firebase.google.com/docs/analytics"
+        "url": "https://github.com/firebase/firebase-android-sdk"
-        "url": "https://firebase.google.com/docs/crashlytics"
+        "url": "https://github.com/firebase/firebase-android-sdk"
-        "url": "https://developers.kakao.com/docs/latest/ko/android/getting-started"
+        "url": "https://github.com/kakao/kakao-android-sdk"

Also applies to: 83-86


68-76: 동일 리포지토리 중복 표기 여부 확인 요청 (System UI Controller / Keyboard State)

두 항목이 같은 리포지토리(ComposeExtensions)를 가리킵니다. 화면 정책에 따라:

  • 모듈별로 개별 표기 유지, 또는
  • 하나의 항목으로 묶어 “ComposeExtensions (System UI Controller, Keyboard State)”처럼 표기

중 어느 쪽이 적합한지 결정해 주세요. 현재 방식도 문제는 없으나, 중복으로 보일 수 있습니다.

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b1645f8 and 12cd888.

📒 Files selected for processing (2)
  • feature/settings/src/main/assets/oss_licenses.json (1 hunks)
  • gradle/libs.versions.toml (0 hunks)
💤 Files with no reviewable changes (1)
  • gradle/libs.versions.toml
🔇 Additional comments (2)
feature/settings/src/main/assets/oss_licenses.json (2)

47-96: 신규 OSS 항목 추가 전반적으로 깔끔합니다

추가된 10개 항목의 포맷(키명, 쉼표 위치, 들여쓰기)과 JSON 구조가 일관적이며, 기존 목록과의 연결(마지막 객체 뒤 쉼표 포함)도 문제 없어 보입니다.


47-96: OSS 라이선스 파일 검증 결과 및 수정 제안

검증 스크립트를 실행한 결과, 다음과 같은 항목이 확인되었습니다:

  • JSON 구문: 정상 (jq로 검사 완료)
  • 중복 URL 발견:
    • https://github.com/taehwandev/ComposeExtensions
      • Compose System UI Controller
      • Compose Keyboard State
      → 동일 리포지토리를 참조하는 것이 의도된 사항인지 확인하고, 필요하다면 설명을 추가하거나 URL을 분리해주세요.
  • 라이선스 표기 불일치:
    • “MIT License”
    • “MIT license”
      → 모두 “MIT License” 로統一 부탁드립니다.

위 외에는 추가 이슈가 없으며, 라이선스 관리의 일관성을 위해 위 두 가지를 반영해주시길 권장드립니다. [optional_refactors_recommended]

@easyhooon
Copy link
Copy Markdown
Contributor Author

@seoyoon513 12cd888 사소한 변경사항이라 여기 PR에 추가했습니다.

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

🧹 Nitpick comments (1)
feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt (1)

161-165: 검색어 트리밍 및 빈 문자열 가드 적절 — 중복 검색 방지 가드 추가 고려

공백 제거 후 빈 문자열 차단으로 불필요한 요청을 방지하는 흐름 적절합니다. 선택 사항으로, 같은 검색어에 대한 연속 검색을 방지하는 가드를 두면 네트워크/CPU 낭비를 더 줄일 수 있습니다.

아래와 같이 마지막 검색어를 보관해 동일 검색어 반복 요청을 차단할 수 있습니다.

-                    val query = event.query.trim()
-                    if (query.isNotEmpty()) {
-                        searchBooks(query = query, startIndex = START_INDEX)
-                    }
+                    val query = event.query.trim()
+                    if (query.isNotEmpty() && query != lastSearchedQuery) {
+                        lastSearchedQuery = query
+                        searchBooks(query = query, startIndex = START_INDEX)
+                    }

위 변경을 위해 상태 정의부에 다음 변수가 필요합니다(파일 상단 상태들과 동일 위치):

// 상태 정의부 인접 위치에 추가
var lastSearchedQuery by rememberRetained { mutableStateOf("") }

참고: 최근검색 아이템 클릭 분기에서도 lastSearchedQuery를 동일하게 갱신하면 일관성이 좋아집니다.

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1401a84 and 53cd427.

📒 Files selected for processing (4)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchPresenter.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUi.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUiState.kt (1 hunks)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/library/LibrarySearchUi.kt
🔇 Additional comments (2)
feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/book/BookSearchUiState.kt (1)

51-51: OnSearchClick 매개변수명 변경 검증 완료 – LGTM
textquery 변경에 따른 named argument 호출부 및 event.text 참조를 전역적으로 확인한 결과 문제가 없음을 확인했습니다.

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

96-98: onSearch 파라미터명 변경 반영 — LGTM

UI에서 query를 그대로 이벤트로 위임하고, 트리밍은 Presenter에서 일괄 처리하므로 책임 분리가 깔끔합니다.

@easyhooon easyhooon merged commit fabd9b2 into develop Aug 16, 2025
2 checks passed
@easyhooon easyhooon deleted the BOOK-260-fix/#142 branch August 16, 2025 08:03
data class ErrorDialogSpec(
val message: String,
val buttonLabel: String,
val buttonLabelResId: Int,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
val buttonLabelResId: Int,
@StringRes val buttonLabelResId: Int,

놓치신 거 같아서 슬쩍 제안드려용

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.

억 붙였다고 생각하고 있었는데 빼먹었군여,, 다음 PR에 어노테이션 추가해야겠슴다...!

@seoyoon513 seoyoon513 changed the title [BOOK-260] feat: 스플래시 화면 네트워크 연결 에러 대응 fix: 약관동의 API 네트워크 에러 핸들링 Aug 17, 2025
@github-actions github-actions Bot added the 🐞 fix Something isn't working label Aug 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 fix Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-260/fix] 약관동의 API 네트워크 에러 핸들링

3 participants