Skip to content

Conversation

@DongChyeon
Copy link
Member

@DongChyeon DongChyeon commented Sep 15, 2025

Related issue 🛠

closed #253

어떤 변경사항이 있었나요?

  • 🐞 BugFix Something isn't working
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (Junit, etc.)

CheckPoint ✅

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • PR 컨벤션에 맞게 작성했습니다. (필수)
  • merge할 브랜치의 위치를 확인해 주세요(main❌/develop⭕) (필수)
  • Approve된 PR은 assigner가 머지하고, 수정 요청이 온 경우 수정 후 다시 push를 합니다. (필수)
  • BugFix의 경우, 버그의 원인을 파악하였습니다. (선택)

Work Description ✏️

  • 앱 업데이트 안내를 위한 UpdateBottomSheet 추가
    • 하루에 1번만 노출
    • 다시 보지 않기 클릭 시 다음 업데이트 전까지 UpdateBottomSheet 노출하지 않음
  • 서버에서 공지 이미지를 받아 표시하도록 구현

Uncompleted Tasks 😅

  • N/A

To Reviewers 📢

Summary by CodeRabbit

  • New Features

    • 홈 화면에 업데이트 안내 바텀시트가 추가되었습니다(배너 이미지 포함).
    • “다시 보지 않기” 선택 시 해당 버전에서는 안내가 더 이상 표시되지 않습니다.
    • 같은 날 이미 본 경우 당일에는 안내가 자동으로 숨겨집니다.
    • “닫기”와 “다시 보지 않기” 버튼으로 간편히 제어할 수 있습니다.
  • Improvements

    • 배너 이미지 로딩 라이브러리 업데이트로 이미지 표시 안정성 향상.
    • 네트워크 상태 확인으로 연결 상태에 따라 안내 노출을 제어합니다.

@coderabbitai
Copy link

coderabbitai bot commented Sep 15, 2025

Walkthrough

앱 버전 주입 모듈을 추가하고 DataStore–로컬–레포–도메인 계층에 업데이트 공지 상태(다시 보지 않을 버전 / 마지막 노출일) 플로우 및 기록 API를 추가했다. 홈 화면에 업데이트 공지 바텀시트를 구현하고 ViewModel에서 노출 여부를 계산·기록하며 사용자 액션을 처리한다. Coil 의존성 버전도 업그레이드했다.

Changes

Cohort / File(s) Summary
DI: App 버전 주입
app/src/main/java/com/yapp/orbit/di/AppVersionModule.kt
Hilt 모듈 추가. @Named("appVersion")으로 BuildConfig.VERSION_NAME@Singleton 제공.
DataStore: 업데이트 공지 키·플로우·헬퍼
core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt
포춘 날짜를 epoch-day(Long)로 전환(기존 문자열 제거). 업데이트 공지 관련 키 2종 추가, 플로우 2종(updateNoticeDontShowVersionFlow, updateNoticeLastShownDateEpochFlow) 및 기록 함수 2종(markUpdateNoticeDontShow, markUpdateNoticeShownToday) 추가.
로컬 데이터소스 확장
data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt, data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt
업데이트 공지 플로우 2종 및 기록 메서드 2종 추가(구현은 UserPreferences에 위임).
레포지토리 · 도메인 계층 확장
domain/src/main/java/com/yapp/domain/repository/UserInfoRepository.kt, data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt
레포 인터페이스/구현에 공지 플로우 2종과 기록 메서드 2종 추가(로컬 데이터소스 위임).
포춘 날짜 리프터(전체 전환)
data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt, data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt, data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt, domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt, feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt
포춘 날짜 타입/이름을 String→epoch Long으로 변경(fortuneDateFlowfortuneDateEpochFlow) 및 관련 비교 로직을 ISO 문자열에서 epoch-day(Long) 비교로 전환. 일부 툴팁/알람 플로우 추가.
Home UI: 바텀시트·상태·액션 추가
feature/home/src/main/java/com/yapp/home/HomeContract.kt, feature/home/src/main/java/com/yapp/home/HomeScreen.kt, feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt, feature/home/src/main/res/values/strings.xml
상태에 isUpdateNoticeVisible 추가. 액션 OnClickDontShowAgain, HideUpdateNotice 추가. 업데이트 공지 바텀시트 컴포저블과 문자열 리소스 추가.
Home ViewModel: 노출 계산·액션 처리·네트워크 체크
feature/home/src/main/java/com/yapp/home/HomeViewModel.kt
생성자에 @Named("appVersion")@ApplicationContext 주입 추가. 업데이트 공지 노출 여부 계산(저장된 버전 비교, 당일 노출 체크, 온라인 여부), 노출 기록 및 사용자 액션(다시 보지 않기/닫기) 처리 로직 추가.
UI 라이브러리·리소스·매니페스트
feature/home/build.gradle.kts, gradle/libs.versions.toml, app/src/main/AndroidManifest.xml, feature/home/src/main/AndroidManifest.xml
coil-compose 의존성 추가 및 Coil 버전 2.4.0→2.7.0 업그레이드. ACCESS_NETWORK_STATE 권한이 앱 및 feature manifest에 추가/중복 선언.
미션 뷰모델: 포춘 기반 네비게이션 변경
feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt
REAL 모드에서 포춘 오픈 조건 변경: 생성 상태 또는 성공 상태면서 '미확인 포춘'인 경우에만 포춘으로 이동하도록 로직 수정. FortuneRepositoryhasUnseenFortuneFlow 추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant HomeScreen
  participant HomeViewModel
  participant UserInfoRepository
  participant UserLocalDataSource as LocalDS
  participant DataStore
  participant AppVersion as AppVersion

  HomeScreen->>HomeViewModel: 초기 로드
  HomeViewModel->>AppVersion: 주입된 appVersion 사용
  HomeViewModel->>UserInfoRepository: updateNoticeDontShowVersionFlow 구독
  UserInfoRepository->>LocalDS: 구독 위임
  LocalDS->>DataStore: 읽기
  DataStore-->>HomeViewModel: 저장된 dontShowVersion

  HomeViewModel->>UserInfoRepository: updateNoticeLastShownDateEpochFlow 구독
  UserInfoRepository->>LocalDS: 구독 위임
  LocalDS->>DataStore: 읽기
  DataStore-->>HomeViewModel: 저장된 lastShownDateEpoch

  note over HomeViewModel: shouldShow = (savedVersion != appVersion) && (lastShownEpoch != todayEpoch) && isOnline

  alt shouldShow == true
    HomeViewModel->>UserInfoRepository: markUpdateNoticeShownToday()
    UserInfoRepository->>LocalDS: 위임
    LocalDS->>DataStore: 오늘 epoch 저장
    HomeViewModel-->>HomeScreen: isUpdateNoticeVisible = true
  else
    HomeViewModel-->>HomeScreen: isUpdateNoticeVisible = false
  end

  rect rgba(220,240,255,0.6)
  User->>HomeScreen: 바텀시트 상호작용
  HomeScreen->>HomeViewModel: OnClickDontShowAgain
  HomeViewModel->>UserInfoRepository: markUpdateNoticeDontShow(appVersion)
  UserInfoRepository->>LocalDS: 위임
  LocalDS->>DataStore: dontShowVersion = appVersion 저장
  HomeViewModel-->>HomeScreen: isUpdateNoticeVisible = false
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • MoonsuKang

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning PR에는 업데이트 공지 기능과 직접 관련이 적은 대규모 변경들이 포함되어 있습니다: fortune 날짜 표현을 ISO 문자열에서 epoch-day(Long)로 전환하는 리팩터가 core/datastore, data 레이어, domain 인터페이스, MissionViewModel, AlarmSnoozeTimerViewModel 등 여러 모듈에 걸쳐 이루어졌고 MissionViewModel의 내비게이션 로직 변경 및 FortuneRepository에 hasUnseenFortuneFlow 추가도 포함되어 있습니다. 이러한 변경은 본 이슈(#253)의 목적(업데이트 공지 바텀시트)과 성격이 달라 리뷰 범위를 크게 확대하고 잠재적 리그레션 위험을 높입니다. 또한 app/feature manifests에 ACCESS_NETWORK_STATE 권한이 중복 선언된 점도 별도 정리가 필요합니다. 해결 방안으로 fortune 관련 대규모 리팩터와 Mission 관련 로직 변경은 별도 PR로 분리하거나 이 PR 본문에 변경 사유·영향 범위·테스트(단위/통합) 결과를 명확히 기재하여 검증을 요청하십시오. AndroidManifest의 중복 권한은 제거하고, 범위를 분리할 수 없다면 최소한 변경 의도와 롤백 계획을 PR 본문에 포함해 리스크를 낮춰 주세요. 범위 분리가 완료되면 업데이트 공지 관련 변경만 남긴 후 재검토를 요청하는 것을 권장합니다.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 제목 "[FEAT] 업데이트 공지 바텀시트"는 PR의 핵심 변경사항(업데이트 공지 바텀시트 추가)을 간결하고 명확하게 요약하고 있으며 불필요한 파일 목록이나 이모지 없이 읽기 쉽습니다. PR 목적(업데이트 공지 노출 기능)과 일치하므로 동료가 히스토리를 스캔할 때도 주요 변경을 바로 이해할 수 있습니다. 따라서 제목 체크 기준을 충족합니다.
Linked Issues Check ✅ Passed 링크된 이슈 [#253]의 체크리스트(업데이트 공지 바텀시트 구현, 마지막으로 본 날짜 DataStore 저장, '다시 보지 않기'로 버전명 저장)는 코드 변경으로 충족됩니다: UpdateNoticeBottomSheet 및 문자열/Coil 의존성 추가, UserPreferences에 UPDATE_NOTICE_* 키와 흐름 및 markUpdateNotice... API 추가, 그리고 UserPreferences→LocalDataSource→Repository→domain 인터페이스로의 흐름·함수 연결이 일관되게 구현되어 있습니다. HomeViewModel에서 하루 1회 노출 및 '다시 보지 않기' 동작을 처리하는 로직도 포함되어 있어 요구사항을 만족합니다.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#253-update-notice-bottom-sheet

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@DongChyeon
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Sep 15, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Nitpick comments (15)
feature/home/src/main/res/values/strings.xml (1)

128-129: 문구 추가 OK + 배너 접근성 보완 제안

TalkBack을 위해 배너 이미지의 contentDescription 문자열을 추가해 두는 것을 권장합니다.

     <string name="update_notice_bottom_sheet_dont_show_again">다시 보지 않기</string>
     <string name="update_notice_bottom_sheet_close">닫기</string>
+    <string name="update_notice_banner_content_description">업데이트 안내 배너</string>
app/src/main/java/com/yapp/orbit/di/AppVersionModule.kt (1)

11-18: @nAmed 대신 @qualifier 사용 고려

문자 키 충돌을 피하려면 커스텀 Qualifier로 교체하는 편이 안전합니다. 현재 구현도 기능상 문제는 없습니다.

-    @Named("appVersion")
-    fun provideAppVersion(): String = BuildConfig.VERSION_NAME
+    @AppVersion
+    fun provideAppVersion(): String = BuildConfig.VERSION_NAME

추가: Qualifier 정의

import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AppVersion
feature/home/src/main/java/com/yapp/home/HomeContract.kt (1)

62-63: 액션 네이밍 소폭 제안

의도 중심으로 OnClickDontShowAgainMarkDontShowAgain 같은 이름을 고려하면 뷰와의 결합도가 더 낮아집니다. 선택 사항입니다.

core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (2)

119-128: 관찰 플로우 구성 적절

catch(emptyPreferences) + distinctUntilChanged() 패턴 좋습니다. 사용 측에서 null 처리만 유의하면 됩니다. 필요 시 편의 플로우도 고려해 보세요(예: wasShownToday: Flow<Boolean>).


208-218: Clock 주입 권장 — today() 의존성 결정론화
LocalDate.now()를 직접 호출하는 private fun today()는 단위 테스트와 DST/타임존 시나리오에서 비결정적입니다. core/common/di/ClockModule이 이미 있으므로 UserPreferences 등에서 Clock(또는 TimeProvider)을 생성자 주입하고 LocalDate.now(clock).format(...)으로 변경해 고정된 Clock으로 테스트할 수 있게 만드세요.
대상 예: core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (today() 정의·사용), data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt, feature/home/src/main/java/com/yapp/home/HomeViewModel.kt

data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt (1)

9-10: 날짜 포맷 계약 명시 필요.

...LastShownDateFlow: Flow<String?>의 포맷(예: ISO-8601 yyyy-MM-dd)을 KDoc로 명시하거나, 차라리 LocalDate/epochDays(Int)로 저장하는 편이 안전합니다(파싱/로케일 이슈 회피).

저장소 전반에서 동일 포맷을 사용 중인지 확인 부탁드립니다.

feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (5)

68-74: 플레이스홀더/에러 처리 및 접근성 보강.

네트워크 실패/지연 시 공백이 됩니다. 또한 배너가 정보 전달을 포함한다면 contentDescription이 필요합니다.

다음 수정을 제안합니다.

+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.ColorPainter
...
-                AsyncImage(
-                    model = imageUrl,
-                    contentDescription = null,
+                AsyncImage(
+                    model = imageUrl,
+                    placeholder = ColorPainter(Color(0xFFEDEDED)),
+                    error = ColorPainter(Color(0xFFEDEDED)),
+                    contentDescription = stringResource(id = R.string.update_notice_bottom_sheet_banner_cd),
                     contentScale = ContentScale.Crop,
                     modifier = Modifier
                         .fillMaxWidth()
                         .aspectRatio(1.0f),
                 )

리소스 문자열(update_notice_bottom_sheet_banner_cd) 추가가 필요합니다.


35-39: 배경 탭 닫기 리플 억제.

전면 오버레이 클릭 시 전체 화면 리플이 번쩍일 수 있습니다. 상호작용 흔적이 불필요하므로 indication 제거 권장.

+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.runtime.remember
...
     Box(
         modifier = Modifier
             .fillMaxSize()
-            .clickable(onClick = onClose),
+            .clickable(
+                onClick = onClose,
+                indication = null,
+                interactionSource = remember { MutableInteractionSource() },
+            ),

41-56: 중복된 shape 지정 정리.

background(shape=..) + clip(shape=..)가 중복입니다. 하나만으로도 모서리 라운딩은 충분합니다(이미지 영역은 아래에서 별도 clip이 없으므로 background 뒤에 clip만 유지).

-                .background(
-                    color = OrbitTheme.colors.gray_900,
-                    shape = RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp),
-                )
-                .clip(RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp)),
+                .clip(RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp))
+                .background(OrbitTheme.colors.gray_900),

88-100: 액션 영역 접근성: 최소 터치 타겟/역할(Role) 지정.

현재 세로 패딩만으로는 48dp 최소 터치 타겟을 항상 보장하지 못할 수 있고, 스크린리더에 버튼 역할이 명확히 전달되지 않습니다.

+import androidx.compose.ui.semantics.Role
...
     Box(
         modifier = Modifier
             .weight(1f)
-            .clickable(onClick = onDontShowAgain)
-            .padding(vertical = 14.dp),
+            .clickable(role = Role.Button, onClick = onDontShowAgain)
+            .heightIn(min = 48.dp)
+            .padding(vertical = 14.dp),
...
     Box(
         modifier = Modifier
             .weight(1f)
-            .clickable(onClick = onClose)
-            .padding(vertical = 14.dp),
+            .clickable(role = Role.Button, onClick = onClose)
+            .heightIn(min = 48.dp)
+            .padding(vertical = 14.dp),

또는 Material3 TextButton 사용을 고려해주세요.

Also applies to: 102-114


68-74: 배너 비율 고정(1:1) 재검토.

서버 배너가 16:9 등 다른 비율일 수 있습니다. 고정 비율 대신 원본 비율 유지(aspectRatio 제거) 또는 서버/메타데이터로 비율을 주입하는 방식을 검토해주세요.

feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (4)

374-393: “오늘 한 번만 노출” 표시에 대한 기록 타이밍 확인 필요.

계산 시점에 곧바로 markUpdateBottomSheetShownToday()를 호출하여 “실제 노출” 전에 기록됩니다. 화면 전환/프로세스 종료 등으로 실노출이 없었더라도 당일 재노출이 차단될 수 있습니다. 실제 표시 시점(시트가 Compose 트리에 진입하거나 첫 프레임 그려질 때)으로 기록을 이동하는 것을 권장합니다.

UI에서 시트가 실제로 표시됨을 신호하는 이벤트를 추가해 그 시점에 기록할지 논의 부탁드립니다.


382-382: 디버그 로그 가드.

릴리스 빌드에서 불필요한 버전/날짜 로그가 남습니다. if (BuildConfig.DEBUG) 가드 또는 로그 제거를 권장합니다.

-import android.util.Log
+import android.util.Log
+import com.yapp.orbit.BuildConfig
...
-Log.d("HomeViewModel", "App Version: $appVersion, Don't Show Version: $dontShowVersion, Last Shown Date: $lastShownDate, Today: $today")
+if (BuildConfig.DEBUG) {
+    Log.d("HomeViewModel", "App Version: $appVersion, Don't Show Version: $dontShowVersion, Last Shown Date: $lastShownDate, Today: $today")
+}

374-393: 반응형 계산으로 단순화 가능(선택).

두 플로우를 combine하여 shouldShow를 State로 유지하면 설정 변경(예: 설정 초기화)에도 자연스럽게 반영됩니다. 현재 1회 스냅샷(firstOrNull)은 요구사항상 문제는 없으나, UX 관점에서 개선 여지가 있습니다.


374-403: 단위 테스트 추가 제안.

다음 시나리오에 대한 VM 단위 테스트를 제안합니다:

  • dontShowVersion == appVersion → 미노출
  • lastShownDate == today → 미노출
  • 둘 다 조건 불충족 → 노출 및 “오늘 보여줌” 기록

원하시면 테스트 스캐폴딩을 생성해드릴게요.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c0c8a9 and 5957794.

📒 Files selected for processing (13)
  • app/src/main/java/com/yapp/orbit/di/AppVersionModule.kt (1 hunks)
  • core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (3 hunks)
  • data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt (1 hunks)
  • data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt (2 hunks)
  • data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt (1 hunks)
  • domain/src/main/java/com/yapp/domain/repository/UserInfoRepository.kt (1 hunks)
  • feature/home/build.gradle.kts (1 hunks)
  • feature/home/src/main/java/com/yapp/home/HomeContract.kt (2 hunks)
  • feature/home/src/main/java/com/yapp/home/HomeScreen.kt (2 hunks)
  • feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (5 hunks)
  • feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (1 hunks)
  • feature/home/src/main/res/values/strings.xml (1 hunks)
  • gradle/libs.versions.toml (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: Continuous Deployment
🔇 Additional comments (10)
gradle/libs.versions.toml (1)

53-53: Coil 2.7.0 업그레이드 LGTM

Compose(1.7.6)/Kotlin(2.0.0)/AGP(8.7.x) 조합과도 무리 없어 보입니다. 릴리스 브랜치라 이미지 로딩 회귀만 한 번 QA 체크 부탁드립니다.

feature/home/build.gradle.kts (1)

22-22: Coil Compose 의존성 추가 적합

AsyncImage 사용 위해 필요한 최소 의존성만 추가되어 좋습니다. 배너가 GIF일 가능성이 있으면 libs.coil.gif 추가만 검토해 주세요.

feature/home/src/main/java/com/yapp/home/HomeContract.kt (1)

21-21: 상태 필드 추가 적절

UI 토글을 위한 isUpdateNoticeVisible 추가 방향 좋습니다.

core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (1)

41-43: DataStore 키 추가 OK

네이밍 일관성 유지되어 좋습니다. 마이그레이션 이슈도 없어 보입니다.

feature/home/src/main/java/com/yapp/home/HomeScreen.kt (2)

78-78: 필요한 컴포넌트 임포트 OK


250-259: 바텀시트 표출 위치/와이어링 OK + 중첩 시트 상호작용 확인 요청

AlarmListBottomSheet 위에 모달로 올라오는 구조로 보이며 액션 바인딩도 적절합니다. 백프레스/외부 탭 dismiss 시 HideUpdateNotice가 호출되는지 한 번만 확인 부탁드립니다(이중 시트 제스처 충돌 방지).

data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt (1)

14-15: 위임 구조 깔끔합니다.

UserPreferences로의 위임이 일관되고 사이드이펙트가 없습니다. LGTM.

UserPreferences.clearUserData()가 새 키들까지 초기화하는지 한 번만 확인 부탁드립니다.

Also applies to: 29-35

data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt (1)

20-21: 위임/노출 일관성 좋습니다.

로컬 데이터소스와 1:1 위임으로 유지보수 용이합니다. 별도 이슈 없습니다.

Also applies to: 26-27

feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (2)

35-35: 앱 버전 주입 👍

@Named("appVersion") 주입으로 테스트 용이성이 좋아졌습니다.


396-398: “다시 보지 않기” 처리 OK

현재 버전으로 명확히 고정 저장하고 즉시 숨기는 흐름이 요구사항에 부합합니다.

@DongChyeon
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Sep 15, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
domain/src/main/java/com/yapp/domain/repository/UserInfoRepository.kt (1)

11-12: 업데이트 공지 관련 도메인 인터페이스 추가

업데이트 공지 기능을 위한 새로운 Flow와 메서드들이 적절히 추가되었습니다. epoch 기반 날짜 사용으로 타임존 독립적인 구현이 가능합니다.

feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (1)

47-48: 배너 URL이 버전에 고정되어 운영 유연성 부족

현재 구현은 앱 버전에 따라 고정된 URL 패턴을 사용합니다. PR 설명에는 "서버에서 공지 이미지를 받아 표시"한다고 되어 있으나, 실제로는 클라이언트에서 버전 기반으로 URL을 생성하고 있습니다. 이는 다음과 같은 문제를 야기할 수 있습니다:

  • 배너 이미지 변경 시 서버 파일 교체만으로는 불가능
  • A/B 테스트나 긴급 공지 변경이 어려움
  • 버전별로 이미지 경로가 고정되어 유연성 부족

서버 API나 Remote Config를 통해 동적으로 이미지 URL을 받아오는 방식으로 개선을 권장합니다.

🧹 Nitpick comments (7)
app/src/main/AndroidManifest.xml (1)

14-14: 중복된 권한 선언 제거 필요

ACCESS_NETWORK_STATE 권한이 Line 5와 Line 14에 중복으로 선언되어 있습니다. Line 14의 중복 선언을 제거해주세요.

     <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (3)

378-400: 업데이트 공지 노출 로직 — 예외 내성 보강 제안

DataStore 쓰기 실패 시 크래시/중단 방지를 위해 기록 부분을 runCatching으로 감싸면 안전합니다. 또한 최초 1회만 호출되므로 네트워크가 회복돼도 노출되지 않습니다(의도된 동작인지 확인 필요).

다음 정도로 보강을 권합니다.

         val shouldShow = when {
             dontShowVersion != null && dontShowVersion == appVersion -> false
             lastShownDate != null && lastShownDate == today -> false
             else -> true
         }

-        if (shouldShow) userInfoRepository.markUpdateNoticeShownToday()
+        if (shouldShow) {
+            runCatching { userInfoRepository.markUpdateNoticeShownToday() }
+                .onFailure { e -> Log.w("HomeViewModel", "Failed to mark update notice shown", e) }
+        }

         reduce { state.copy(isUpdateNoticeVisible = shouldShow) }

네트워크 재시도 필요 시, Connectivity 상태를 Flow로 노출해 재구독 트리거를 거는 방식을 고려해주세요.


402-405: '다시 보지 않기' 처리 — LGTM, 실패 처리만 보완 권장

기록 후 즉시 숨김 처리 흐름은 적절합니다. 동일하게 runCatching으로 예외 로깅을 추가하면 더 안전합니다.

- userInfoRepository.markUpdateNoticeDontShow(appVersion)
+ runCatching { userInfoRepository.markUpdateNoticeDontShow(appVersion) }
+   .onFailure { e -> Log.w("HomeViewModel", "Failed to mark dont-show version", e) }

457-464: 온라인 판별 방식 개선 여지

단발성 체크만으로는 재연결 시점 반영이 어렵습니다. 필요하다면 ConnectivityManager.registerDefaultNetworkCallback 기반 Flow로 상태를 스트림화하는 유틸로 추출을 권장합니다.

domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt (1)

9-9: KDoc 제안: 'epoch day' 기준 명시

Long 값이 UTC/로컬 기준 epoch‑day인지 인터페이스에 주석을 추가하면 오용을 줄일 수 있습니다.

feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt (1)

137-157: 미션 완료 후 내비게이션 조건 — LGTM, 가독성 소폭 개선 제안

조건식은 의도대로 보입니다. 불변식 추출로 읽기성만 다듬으면 좋습니다.

- val shouldOpenFortune = (
-     fortuneCreateStatus is FortuneCreateStatus.Creating ||
-         fortuneCreateStatus is FortuneCreateStatus.Success && hasUnseenFortune
- )
+ val creating = fortuneCreateStatus is FortuneCreateStatus.Creating
+ val successAndUnseen = fortuneCreateStatus is FortuneCreateStatus.Success && hasUnseenFortune
+ val shouldOpenFortune = creating || successAndUnseen
data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt (1)

36-36: Clock 주입으로 테스트/타임존 안정성 확보

LocalDate.now() 대신 Clock을 주입해 결정적·테스트 가능한 시간을 사용하세요.

-    private fun todayEpoch(): Long = LocalDate.now().toEpochDay()
+    private fun todayEpoch(): Long = LocalDate.now(clock).toEpochDay()

추가 변경(파일 외): 생성자와 import에 Clock을 포함하고 Hilt 모듈에서 @Provides fun provideClock(): Clock = Clock.systemDefaultZone()를 제공하세요.

import java.time.Clock

class FortuneLocalDataSourceImpl @Inject constructor(
    private val userPreferences: UserPreferences,
    private val clock: Clock,
) : FortuneLocalDataSource { ... }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5957794 and de737d4.

⛔ Files ignored due to path filters (1)
  • project.dot.png is excluded by !**/*.png
📒 Files selected for processing (15)
  • app/src/main/AndroidManifest.xml (1 hunks)
  • core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (7 hunks)
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt (1 hunks)
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt (2 hunks)
  • data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt (1 hunks)
  • data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt (2 hunks)
  • data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt (1 hunks)
  • data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt (1 hunks)
  • domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt (1 hunks)
  • domain/src/main/java/com/yapp/domain/repository/UserInfoRepository.kt (1 hunks)
  • feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt (1 hunks)
  • feature/home/src/main/AndroidManifest.xml (1 hunks)
  • feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (10 hunks)
  • feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (1 hunks)
  • feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • data/src/main/java/com/yapp/data/repositoryimpl/UserInfoRepositoryImpl.kt
  • data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSource.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-14T15:32:44.064Z
Learnt from: DongChyeon
PR: YAPP-Github/Orbit-Android#252
File: domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt:16-17
Timestamp: 2025-09-14T15:32:44.064Z
Learning: Fortune creation requests have at least a 1-minute gap between them in the Orbit Android app, making atomic guards for race condition prevention unnecessary in the fortune creation flow.

Applied to files:

  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt
  • core/datastore/src/main/java/com/yapp/datastore/UserPreferences.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: Continuous Deployment
🔇 Additional comments (18)
feature/home/src/main/AndroidManifest.xml (1)

3-3: 네트워크 상태 체크 권한 추가 확인

업데이트 공지 바텀시트의 온라인 상태 체크를 위한 권한 추가가 적절합니다.

data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt (1)

8-8: 날짜 표현 타입 변경 확인

fortuneDateFlowfortuneDateEpochFlow로 변경하여 Long? 타입의 epoch day를 사용하도록 개선되었습니다. 타임존 이슈를 방지하고 날짜 비교를 단순화하는 좋은 변경입니다.

feature/home/src/main/java/com/yapp/home/component/bottomsheet/UpdateNoticeBottomSheet.kt (3)

33-45: 버전 정보 획득 시 예외 처리 적절

resolveVersionName 함수에서 버전 정보를 안전하게 가져오고, 실패 시 빈 문자열을 반환하는 처리가 잘 되어 있습니다.


58-61: Preview 모드와 런타임 분기 처리 적절

LocalInspectionMode를 활용하여 프리뷰와 실제 런타임을 구분하고, 각각 적절한 버전명과 이미지 URL을 설정하는 처리가 잘 되어 있습니다.


79-96: 프리뷰와 실제 이미지 렌더링 분기 처리 적절

프리뷰 모드에서는 흰색 박스를, 실제 런타임에서는 AsyncImage로 배너를 표시하는 분기 처리가 깔끔합니다.

core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (5)

29-29: Fortune 날짜를 epoch day로 변경하여 타임존 문제 해결

FORTUNE_DATE에서 FORTUNE_DATE_EPOCH로 변경하여 Long 타입의 epoch day를 사용하는 것은 타임존 독립적이고 날짜 비교가 간단해지는 좋은 개선입니다.


40-41: 업데이트 공지 관련 새로운 preference key 추가

업데이트 공지 기능을 위한 UPDATE_NOTICE_DONT_SHOW_VERSIONUPDATE_NOTICE_LAST_SHOWN_DATE_EPOCH 키가 적절히 추가되었습니다. epoch 기반 날짜 사용으로 일관성을 유지하고 있습니다.


44-44: todayEpoch 헬퍼 함수로 날짜 처리 일관성 확보

LocalDate.now().toEpochDay()를 사용하는 private 헬퍼 함수로 오늘 날짜를 epoch day로 변환하는 로직을 중앙화한 것이 좋습니다.


194-201: 업데이트 공지 관련 마킹 함수 구현 적절

markUpdateNoticeDontShowmarkUpdateNoticeShownToday 함수가 DataStore에 적절히 값을 저장하도록 구현되었습니다. 특히 markUpdateNoticeShownToday에서 현재 날짜를 epoch day로 저장하는 것이 일관성 있습니다.


148-161: Fortune 생성 시 날짜 기반 중복 체크 로직 개선

markFortuneCreated에서 epoch day 기반으로 오늘의 새로운 fortune인지 확인하고, 필요시 SEEN과 TOOLTIP_SHOWN을 초기화하는 로직이 잘 구현되었습니다. 이전에 학습한 내용대로 fortune 생성 요청 간 최소 1분의 간격이 있어 race condition 방지를 위한 atomic guard는 불필요합니다.

data/src/main/java/com/yapp/data/local/datasource/UserLocalDataSourceImpl.kt (2)

14-15: 위임 구조 적절 — API 추가 LGTM

DataStore의 Flow를 그대로 노출하는 위임이 명확합니다. 네이밍(…EpochFlow)도 다른 모듈과 일관적입니다.


29-35: clearUserData가 업데이트 공지 키들을 초기화함 — 확인됨
core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt의 clearUserData()가 dataStore.edit { it.clear() }를 호출하므로 updateNoticeDontShowVersion 및 updateNoticeLastShownDateEpoch 키가 삭제됩니다.

feature/home/src/main/java/com/yapp/home/HomeViewModel.kt (2)

343-346: Epoch‑day 전환 일관성 확인 — LGTM

LocalDate.now().toEpochDay()와 fortuneDateEpochFlow 비교로 전환이 잘 반영되었습니다. 관련 의존 모듈도 동일 기준(로컬 타임존)인지 유지해주세요.

Also applies to: 356-356, 359-359


38-40: appVersion DI 제공자 확인 — 테스트 바인딩 미확인

app/src/main/java/com/yapp/orbit/di/AppVersionModule.kt 에서 @nAmed("appVersion") 제공자(provideAppVersion() = BuildConfig.VERSION_NAME)를 확인했습니다. 레포지토리의 test/androidTest 소스에서 해당 바인딩을 대체하거나 @bindvalue로 주입하는 코드(@TestInstallIn / @UninstallModules / @bindvalue 등)는 발견되지 않았습니다. 테스트 환경에서 바인딩 필요 시 @TestInstallIn으로 대체하거나 테스트별로 @UninstallModules + 테스트 모듈 또는 @bindvalue를 추가해 주세요.

feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt (1)

47-49: Epoch‑day 마이그레이션 반영 — LGTM

단순 치환 정확합니다. 로컬 타임존 기준 비교도 홈 모듈과 일관적입니다.

data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt (1)

18-18: 데이터 소스 매핑 업데이트 — LGTM

fortuneDateEpochFlow 위임이 올바르게 반영되었습니다.

domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt (1)

9-13: 해결: Public API 변경(브레이킹) 검증 완료 — 호출부/구현부 모두 갱신됨

domain에 추가된 fortuneDateEpochFlow/hasUnseenFortuneFlow가 core/datastore(UserPreferences), data/local(FortuneLocalDataSourceImpl), data/repositoryimpl(FortuneRepositoryImpl) 및 소비처(HomeViewModel, AlarmSnoozeTimerViewModel, MissionViewModel, AlarmInteractionActivityReceiver)에서 모두 반영되어 기존 참조(fortuneDateFlow)는 없습니다.

data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt (1)

15-15: epoch 기반 전환 LGTM — 레거시 fortuneDateFlow 사용처 없음 확인

레포 전체 검색 결과 'fortuneDateFlow'는 발견되지 않았고, 관련 참조는 모두 'fortuneDateEpochFlow'로 통일되어 있습니다. 주요 파일: domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt, data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt, data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt, core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt, feature/home/src/main/java/com/yapp/home/HomeViewModel.kt, feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt.

@DongChyeon DongChyeon merged commit a58c58d into release/1.1.3 Sep 15, 2025
2 checks passed
This was referenced Sep 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants