Skip to content

Conversation

@DongChyeon
Copy link
Member

@DongChyeon DongChyeon commented Nov 30, 2025

Related issue 🛠

closed #278

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

  • 🐞 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 ✏️

기존 알람–운세 생성 흐름은

  • DataStore가 “운세 생성 API 호출 상태”를 직접 저장하고
  • WorkManager가 백그라운드에서 운세 생성을 트리거하며
  • ViewModel들은 해당 DataStore에서 상태를 수집해 화면 전환을 제어하는 구조

이 구조는 DataStore와 WorkManager 사이의 비동기 경합, 상태 불일치, 워커 재실행 시의 예외 처리 문제 등 다양한 자잘한 버그를 유발했습니다.

WorkManager를 통한 재시도 로직보다는 실패했을 경우 다음 알람에서 운세를 받아볼 수 있도록 하기로 했습니다.

  • WorkManager 기반 운세 생성 트리거 제거
  • 알람 서비스가 직접 운세 생성 API 호출
  • 생성 중/성공/실패는 FortuneCreationTracker에서 인메모리 브로드캐스트
  • 알람 인앱 리시버 및 화면 로직은 트래커 상태만 구독해 화면 전환 판단
  • FortuneViewModel: DataStore Flow → 트래커 기반 전환
  • MissionViewModel: hasTodayFortune / hasUnseenFortune 두 값만으로 운세 화면 진입 여부 판단

이번 변경으로 DataStore는 다음 정보만 관리합니다:

  • 오늘 운세 ID
  • 날짜
  • 이미지/점수
  • 툴팁 여부

Why

  • 운세 생성 생성 중/성공/실패는 영속화할 성질의 데이터가 아닌 순간 이벤트이므로 인메모리 트래킹이 더 적합함
  • DataStore에 API 호출 상태를 저장하면 경합조건, 중복 호출, 복잡한 복구 시나리오 등이 발생함

Uncompleted Tasks 😅

N/A

To Reviewers 📢

Summary by CodeRabbit

릴리즈 노트

  • 개선 사항

    • 운세 생성 워크플로우를 간소화하여 더 빠르고 직접적인 동작 제공
    • 운세 상태 추적 시스템을 단순화하여 오늘의 운세 확인이 더 효율적
  • 의존성 업데이트

    • Compose 라이브러리를 최신 버전으로 업데이트 (UI 안정성 및 성능 개선)

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

개요

WorkManager 기반 백그라운드 작업 스케줄링을 제거하고 직접 운세 생성 처리로 전환하는 아키텍처 개선. 운세 생성 상태 모델을 단순화하고 새로운 in-memory 추적 시스템을 도입하며, 복잡한 상태 머신 로직을 제거합니다.

변경 사항

코호트 / 파일(들) 변경 요약
빌드 설정 및 의존성 제거
app/build.gradle.kts, build-logic/src/main/java/com/yapp/convention/HiltAndroid.kt, feature/fortune/build.gradle.kts, gradle/libs.versions.toml
AndroidX Work 및 Hilt Worker 관련 모든 의존성 제거 (hilt-worker, androidx-work-runtime, androidx-work-testing, androidx-hilt-compiler). Compose 라이브러리 버전 업데이트 (BOM 2024.11.00 → 2025.02.00, Material3 1.3.1 → 1.4.0, UI 1.7.6 → 1.8.3)
애플리케이션 초기화 변경
app/src/main/AndroidManifest.xml, app/src/main/java/com/yapp/orbit/OrbitApplication.kt
AndroidX Startup InitializationProvider 및 WorkManager 자동 초기화 제거. OrbitApplication에서 Configuration.Provider 인터페이스 구현 제거 및 HiltWorkerFactory 의존성 제거
도메인 계층 - 상태 모델
domain/src/main/java/com/yapp/domain/model/FortuneCreationState.kt, domain/src/main/java/com/yapp/domain/model/FortuneCreateStatus.kt
새로운 FortuneCreationState 봉인 클래스 도입 (Start, Success(fortuneId), Failure). 기존 FortuneCreateStatus 클래스 제거 (Idle, Creating, Success, Failure)
도메인 계층 - 추적 인터페이스 및 저장소
domain/src/main/java/com/yapp/domain/tracker/FortuneCreationTracker.kt, domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt
새로운 FortuneCreationTracker 인터페이스 추가 (state StateFlow, start(), succeed(), fail() 메서드). FortuneRepository에서 fortuneCreateStatusFlow 및 다중 인자 생성 메서드 제거, markFortuneAsCreated(fortuneId), hasTodayFortune(), saveFortuneScore(), markFirstAlarmDismissedToday() 추가
공통 핵심 - 추적 구현 및 DI
core/common/src/main/java/com/yapp/common/tracker/InMemoryFortuneCreationTracker.kt, core/common/src/main/java/com/yapp/common/di/FortuneTrackerModule.kt
새로운 InMemoryFortuneCreationTracker 싱글톤 클래스 구현 (private MutableStateFlow 기반). FortuneTrackerModule Hilt 바인딩 추가
데이터저장소 계층 - 설정 및 데이터소스
core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt, data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt, data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt
FortunePreferences에서 CREATING, FAILED, ATTEMPT_ID, STARTED_AT, EXPIRES_AT 키 제거. isFortuneCreatingFlow, isFortuneFailedFlow 제거. markFortuneCreating(attemptId, lease), markFortuneCreatedIfAttemptMatches(attemptId, fortuneId), markFortuneFailedIfAttemptMatches(attemptId) 제거. markFortuneCreated(fortuneId) 및 hasTodayFortune(): Boolean 추가
저장소 계층
data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt
fortuneCreateStatusFlow 및 다중 인자 생성 메서드 제거. markFortuneAsCreated(fortuneId), hasTodayFortune() 추가
알람 핵심 - 서비스 및 수신자
core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt, core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt
AlarmService에서 PostFortuneTaskScheduler 제거 후 직접 운세 포스팅 로직 추가. FortuneRepository, UserInfoRepository, FortuneCreationTracker 의존성 추가. handleIntent()를 suspend 함수로 변경. AlarmInteractionActivityReceiver에서 FortuneCreationState로 전환하고 FortuneCreationTracker 의존성 추가
알람 스케줄러 제거
core/alarm/src/main/java/com/yapp/alarm/scheduler/PostFortuneTaskScheduler.kt
PostFortuneTaskScheduler 인터페이스 파일 및 enqueueOnceForToday() 메서드 완전 삭제
기능 계층 - 뷰모델
feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt, feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt
FortuneViewModel에서 FortuneCreationState로 전환 및 FortuneCreationTracker.state 관찰. MissionViewModel에서 hasTodayFortune() 및 hasUnseenFortuneFlow 기반의 단순화된 로직 사용
기능 계층 - 워커 및 스케줄러 제거
feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt, feature/fortune/src/main/java/com/yapp/fortune/scheduler/WorkManagerPostFortuneTaskScheduler.kt, feature/fortune/src/main/java/com/yapp/fortune/di/SchedulerModule.kt
WorkManager 기반 PostFortuneWorker 클래스 및 WorkManagerPostFortuneTaskScheduler 구현 완전 삭제. SchedulerModule 및 PostFortuneTaskScheduler 바인딩 제거
테스트
core/datastore/src/test/kotlin/com/yapp/datastore/FortunePreferencesTest.kt
만료 처리, 재시도, 이전 날짜 상태 자동 초기화 등 복잡한 상태 머신 테스트 제거. 새로운 두 가지 테스트 추가: 오늘 운세 생성 시 hasTodayFortune() 참 검증, 다른 날짜의 운세는 hasTodayFortune() 거짓 검증

시퀀스 다이어그램

sequenceDiagram
    participant AlarmService
    participant UserInfoRepository
    participant FortuneRepository
    participant FortuneCreationTracker
    participant FortunePreferences

    Note over AlarmService: 알람 트리거 수신

    rect rgb(200, 220, 255)
    Note over AlarmService,FortunePreferences: 기존: WorkManager 스케줄링 (async)
    AlarmService->>AlarmService: PostFortuneTaskScheduler.enqueueOnceForToday()
    Note over AlarmService: WorkManager가 PostFortuneWorker 실행<br/>(백그라운드 작업)
    end

    rect rgb(200, 255, 220)
    Note over AlarmService,FortunePreferences: 신규: 직접 동기 처리
    
    AlarmService->>FortunePreferences: hasTodayFortune() 확인
    FortunePreferences-->>AlarmService: 오늘 운세 여부 반환
    
    alt 오늘 운세 없음
        AlarmService->>UserInfoRepository: userIdFlow.first()로 userId 조회
        UserInfoRepository-->>AlarmService: userId 반환
        
        AlarmService->>FortuneCreationTracker: start()
        FortuneCreationTracker->>FortuneCreationTracker: state = Start 설정
        
        AlarmService->>FortuneRepository: postFortune(userId)
        FortuneRepository-->>AlarmService: fortune (id, score)
        
        AlarmService->>FortuneRepository: markFortuneAsCreated(fortuneId)
        FortuneRepository->>FortunePreferences: markFortuneCreated(fortuneId)
        
        AlarmService->>FortuneRepository: saveFortuneScore(score)
        
        AlarmService->>FortuneCreationTracker: succeed(fortuneId)
        FortuneCreationTracker->>FortuneCreationTracker: state = Success(fortuneId) 설정
    else 포스팅 실패
        AlarmService->>FortuneCreationTracker: fail()
        FortuneCreationTracker->>FortuneCreationTracker: state = Failure 설정
    end
    end

    Note over AlarmService,FortuneCreationTracker: UI는 FortuneCreationTracker.state<br/>구독으로 상태 반영
Loading

코드 리뷰 예상 소요 시간

🎯 4 (복잡) | ⏱️ ~60분

주의 깊게 검토해야 할 영역

  • AlarmService.handleIntent() 메서드: suspend 함수로 변경되었고, 직접 운세 포스팅 로직 추가. userId 조회 실패 시 처리, 예외 처리 경로, FortuneCreationTracker 상태 전이의 정확성 확인 필요
  • FortunePreferences 단순화: 복잡한 상태 머신 로직이 제거되었으나, 오늘 운세 존재 여부 판단 로직(hasTodayFortune)이 정확하게 작동하는지, 날짜 변경 처리가 올바른지 검증 필요
  • 상태 모델 전환: FortuneCreateStatus → FortuneCreationState로의 전환이 모든 관찰 지점에서 일관성 있게 처리되었는지 (AlarmService, AlarmInteractionActivityReceiver, FortuneViewModel 등)
  • 의존성 그래프: WorkManager 제거로 인한 의존성 제거가 완전한지, 누락된 import나 미사용 의존성이 없는지 확인
  • 동작 흐름 변경의 영향: 기존 백그라운드 재시도 로직(exponential backoff)에서 직접 동기 호출로 전환됨에 따른 오류 처리 및 복원력의 변화 이해 필요

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Compose 라이브러리 버전 업데이트(bom, navigation, material3, ui)는 운세 생성 버그 수정과 직접적 관련이 없는 범위 외 변경사항입니다. Compose 버전 업데이트를 별도 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
Title check ✅ Passed 제목은 주요 변경사항인 '오늘의 운세 생성 실패 시 다음날까지 계속 실패하는 문제 해결'을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed WorkManager 제거, 직접 API 호출 구현, FortuneCreationTracker 도입, DataStore 단순화 등의 변경사항이 #278의 '운세 생성 실패 상태 지속 문제' 해결 목표를 충족합니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/#278-fortune-create-status

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.

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

🧹 Nitpick comments (2)
app/src/main/java/com/yapp/orbit/OrbitApplication.kt (1)

8-12: WorkManager 제거 이후 Application 구성 단순화 적절해 보입니다

Configuration.Provider / HiltWorkerFactory 를 제거하고 일반 Application 서브클래스로만 둔 선택은, PR 설명대로 WorkManager 기반 트리거를 걷어낸 방향성과 잘 맞습니다. 현재 보이는 범위에서는 추가적인 초기화 누락이나 DI 설정 문제는 없어 보입니다.

추가로, 아래처럼 Kotlin 관용 스타일로 괄호를 정리해도 좋을 것 같습니다 (완전 선택 사항입니다).

-@HiltAndroidApp
-class OrbitApplication() : Application() {
+@HiltAndroidApp
+class OrbitApplication : Application() {
core/datastore/src/test/kotlin/com/yapp/datastore/FortunePreferencesTest.kt (1)

16-66: 운세가 생성되지 않은 경우의 테스트 추가를 고려해 주세요.

현재 테스트는 운세 생성 후의 시나리오를 다루고 있습니다. 운세가 한 번도 생성되지 않았을 때 hasTodayFortune()이 false를 반환하는지 확인하는 테스트를 추가하면 더 완전한 커버리지를 확보할 수 있습니다.

@Test
fun `운세가_생성되지_않았다면_hasTodayFortune이_거짓이다`() = runTest {
    // given
    val dataStore = createNewDataStoreWithFile("empty.preferences_pb")
    val preferences = createFortunePreferencesWithClock(dataStore, fixedClockAtT0)

    // when & then
    val result = preferences.hasTodayFortune()
    assertFalse(result)
}
📜 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 c05e27b and f58ce2e.

📒 Files selected for processing (25)
  • app/build.gradle.kts (0 hunks)
  • app/src/main/AndroidManifest.xml (0 hunks)
  • app/src/main/java/com/yapp/orbit/OrbitApplication.kt (1 hunks)
  • build-logic/src/main/java/com/yapp/convention/HiltAndroid.kt (0 hunks)
  • core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt (5 hunks)
  • core/alarm/src/main/java/com/yapp/alarm/scheduler/PostFortuneTaskScheduler.kt (0 hunks)
  • core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt (4 hunks)
  • core/common/src/main/java/com/yapp/common/di/FortuneTrackerModule.kt (1 hunks)
  • core/common/src/main/java/com/yapp/common/tracker/InMemoryFortuneCreationTracker.kt (1 hunks)
  • core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt (3 hunks)
  • core/datastore/src/test/kotlin/com/yapp/datastore/FortunePreferencesTest.kt (3 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/repositoryimpl/FortuneRepositoryImpl.kt (2 hunks)
  • domain/src/main/java/com/yapp/domain/model/FortuneCreateStatus.kt (0 hunks)
  • domain/src/main/java/com/yapp/domain/model/FortuneCreationState.kt (1 hunks)
  • domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt (2 hunks)
  • domain/src/main/java/com/yapp/domain/tracker/FortuneCreationTracker.kt (1 hunks)
  • feature/fortune/build.gradle.kts (0 hunks)
  • feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt (3 hunks)
  • feature/fortune/src/main/java/com/yapp/fortune/di/SchedulerModule.kt (0 hunks)
  • feature/fortune/src/main/java/com/yapp/fortune/scheduler/WorkManagerPostFortuneTaskScheduler.kt (0 hunks)
  • feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt (0 hunks)
  • feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt (1 hunks)
  • gradle/libs.versions.toml (1 hunks)
💤 Files with no reviewable changes (9)
  • app/build.gradle.kts
  • core/alarm/src/main/java/com/yapp/alarm/scheduler/PostFortuneTaskScheduler.kt
  • feature/fortune/src/main/java/com/yapp/fortune/scheduler/WorkManagerPostFortuneTaskScheduler.kt
  • feature/fortune/build.gradle.kts
  • build-logic/src/main/java/com/yapp/convention/HiltAndroid.kt
  • app/src/main/AndroidManifest.xml
  • domain/src/main/java/com/yapp/domain/model/FortuneCreateStatus.kt
  • feature/fortune/src/main/java/com/yapp/fortune/di/SchedulerModule.kt
  • feature/fortune/src/main/java/com/yapp/fortune/worker/PostFortuneWorker.kt
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: DongChyeon
Repo: YAPP-Github/Orbit-Android PR: 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.
📚 Learning: 2025-09-14T15:32:44.064Z
Learnt from: DongChyeon
Repo: YAPP-Github/Orbit-Android PR: 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:

  • domain/src/main/java/com/yapp/domain/tracker/FortuneCreationTracker.kt
  • core/common/src/main/java/com/yapp/common/tracker/InMemoryFortuneCreationTracker.kt
  • feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt
  • core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt
  • domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt
  • data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt
  • core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt
  • core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt
  • feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt
  • domain/src/main/java/com/yapp/domain/model/FortuneCreationState.kt
📚 Learning: 2025-09-18T04:28:52.855Z
Learnt from: DongChyeon
Repo: YAPP-Github/Orbit-Android PR: 257
File: core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt:70-77
Timestamp: 2025-09-18T04:28:52.855Z
Learning: hasUnseenFortuneFlow와 shouldShowFortuneToolTipFlow는 지속적인 관찰이 아닌 호출 시점의 상태 판단용 Flow이므로, 자정 롤오버 대응을 위한 ticker Flow 결합이 불필요함. Flow가 collect될 때마다 todayEpoch()가 현재 시점으로 계산되어 호출 시점 판단에 충분함.

Applied to files:

  • feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt
  • domain/src/main/java/com/yapp/domain/repository/FortuneRepository.kt
  • data/src/main/java/com/yapp/data/repositoryimpl/FortuneRepositoryImpl.kt
  • core/datastore/src/test/kotlin/com/yapp/datastore/FortunePreferencesTest.kt
  • core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt
  • feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSource.kt
📚 Learning: 2025-09-15T07:43:50.275Z
Learnt from: DongChyeon
Repo: YAPP-Github/Orbit-Android PR: 254
File: data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt:22-34
Timestamp: 2025-09-15T07:43:50.275Z
Learning: FortuneCreateStatusFlow에서 todayEpoch()를 combine 내부에서 직접 호출하는 것이 충분한 이유: 운세 생성할 때마다 fortuneDateEpochFlow가 변경되어 combine이 재평가되므로, 그 순간의 todayEpoch() 계산으로 충분함. 운세 요청 간격 제약으로 인해 자정 롤오버 문제는 실용적으로 발생하지 않음.

Applied to files:

  • core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt
  • data/src/main/java/com/yapp/data/local/datasource/FortuneLocalDataSourceImpl.kt
🧬 Code graph analysis (1)
core/datastore/src/main/java/com/yapp/datastore/FortunePreferences.kt (1)
core/datastore/src/main/java/com/yapp/datastore/UserPreferences.kt (1)
  • todayEpoch (31-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (20)
feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt (1)

141-144: 로직 단순화가 잘 되었습니다.

FortuneCreateStatus 열거형 대신 boolean 기반 접근 방식으로 변경하여 가독성이 향상되었습니다. !hasTodayFortune || hasUnseenFortune 로직은 운세 생성이 필요하거나 미확인 운세가 있는 경우를 모두 올바르게 처리합니다.

core/common/src/main/java/com/yapp/common/tracker/InMemoryFortuneCreationTracker.kt (1)

11-27: 구현이 깔끔합니다.

StateFlow를 사용한 간결한 in-memory 상태 추적 구현입니다. StateFlow의 스레드 안전성과 학습된 정보(운세 생성 요청 간 최소 1분 간격)에 따라 추가적인 동기화 메커니즘이 필요하지 않습니다.

core/common/src/main/java/com/yapp/common/di/FortuneTrackerModule.kt (1)

11-19: DI 설정이 올바릅니다.

싱글톤 스코프로 InMemoryFortuneCreationTrackerFortuneCreationTracker 인터페이스에 바인딩하는 표준적인 Dagger/Hilt 패턴입니다.

domain/src/main/java/com/yapp/domain/model/FortuneCreationState.kt (1)

3-7: 상태 모델링이 적절합니다.

운세 생성 라이프사이클을 표현하는 명확한 sealed class 설계입니다. SuccessfortuneId를 포함하고, 세 가지 상태(Start, Success, Failure)가 모든 시나리오를 커버합니다.

domain/src/main/java/com/yapp/domain/tracker/FortuneCreationTracker.kt (1)

6-11: 인터페이스 설계가 명확합니다.

StateFlow를 통한 반응형 관찰과 상태 전환을 위한 메서드들이 잘 정의되어 있습니다. 도메인 레이어에 적합한 간결한 API입니다.

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

5-24: 인터페이스 단순화가 적절합니다.

FortuneCreateStatus 기반의 복잡한 라이프사이클 메서드들을 제거하고 데이터 영속성에 집중하도록 변경되었습니다. 생성 상태는 FortuneCreationTracker로 분리되고, 이 인터페이스는 운세 데이터(ID, 날짜, 이미지, 점수 등)만 관리합니다. 이는 PR 목표인 "실패 상태가 다음날까지 지속되는 문제"를 해결하는 핵심 변경사항입니다.

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

6-28: 도메인 API 단순화가 아키텍처 목표와 일치합니다.

FortuneCreateStatus 기반의 복잡한 상태 관리를 제거하고 간결한 boolean 체크(hasTodayFortune())와 단순화된 생성 메서드(markFortuneAsCreated(fortuneId))로 대체되었습니다. 이는 영속적인 생성 상태를 in-memory tracker로 분리하는 PR의 핵심 아키텍처 변경을 올바르게 반영합니다.

추가된 메서드들(saveFortuneScore, markFirstAlarmDismissedToday)은 운세 데이터 관리를 위한 정상적인 확장입니다.

core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt (1)

53-85: State-based navigation logic is appropriate.

The branching logic by FortuneCreationState is clear:

  • Start: Fortune creation is needed, so navigate to fortune screen to trigger creation
  • Success: Navigate only if there are unseen fortunes
  • Failure: Error occurred, no navigation (user can retry manually)

However, the referenced verification about how the fortune UI layer (FortuneViewModel or screen) handles reactive state observation could not be completed. The fortune screen should observe tracker.state reactively to handle state transitions that occur while the screen is displayed, particularly if the AlarmService creates fortunes concurrently. Ensure the UI layer properly manages any timing edge cases where state transitions occur between the snapshot taken with .first() and screen display.

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

24-34: LGTM! 간결하게 잘 단순화되었습니다.

복잡한 다단계 운세 생성 라이프사이클(markFortuneAsCreating, markFortuneAsCreated(attemptId, fortuneId), markFortuneAsFailed)이 두 개의 간단한 메서드로 깔끔하게 대체되었습니다. 이 변경은 PR 목표인 DataStore 기반 상태 관리를 단순화하는 것과 잘 일치합니다.

feature/fortune/src/main/java/com/yapp/fortune/FortuneViewModel.kt (2)

29-30: 의존성 주입이 적절하게 구성되었습니다.

FortuneCreationTracker가 생성자 주입으로 추가되어 Hilt DI 패턴과 일관성을 유지합니다.


55-79: No issues identified. The FortuneCreationTracker properly initializes state as StateFlow<FortuneCreationState>(FortuneCreationState.Start), which guarantees immediate emission to collectors. Indefinite waiting cannot occur.

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

18-20: LGTM! 단순화된 API로 깔끔하게 변경되었습니다.

기존의 복잡한 attemptId 기반 로직이 제거되고, 단순한 위임 패턴으로 대체되었습니다.


46-48: LGTM!

hasTodayFortune() 메서드가 적절하게 추가되었습니다. DataStore에서 오늘 운세 존재 여부를 확인하는 간단한 쿼리입니다.

core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt (2)

91-91: LGTM! suspend 함수로의 변경이 적절합니다.

handleIntent가 이제 비동기 호출(hasTodayFortune(), userIdFlow.first(), postFortune() 등)을 수행하므로 suspend 함수로 변경된 것이 올바릅니다. serviceScope.launch 내에서 호출되어 적절하게 처리됩니다.


57-64: LGTM! 새로운 의존성 주입이 적절합니다.

WorkManager 기반 스케줄러 대신 직접 운세 생성을 수행하기 위한 FortuneRepository, UserInfoRepository, FortuneCreationTracker 의존성이 추가되었습니다. PR 목표에 부합하는 변경입니다.

core/datastore/src/test/kotlin/com/yapp/datastore/FortunePreferencesTest.kt (2)

39-51: LGTM! 핵심 케이스가 잘 테스트되었습니다.

오늘 운세 생성 후 hasTodayFortune()이 true를 반환하는지 검증하는 명확한 테스트입니다.


53-66: LGTM! 날짜 경계 로직이 잘 테스트되었습니다.

고정된 Clock을 사용하여 날짜가 변경되었을 때 hasTodayFortune()이 false를 반환하는지 검증합니다. 이는 PR에서 수정하려는 버그(운세 생성 실패 시 다음 날까지 계속 실패)의 핵심 로직입니다.

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

85-99: 간결하고 명확한 구현입니다.

isNewForToday 조건이 ID 변경 또는 날짜 변경을 모두 체크하여 운세가 새로운지 판단하는 로직이 적절합니다. DataStore의 edit이 atomic하게 동작하므로 상태 일관성도 보장됩니다. 기존의 복잡한 attemptId/expiration 로직을 제거하고 단순화한 것이 버그 수정 목적에 부합합니다.


134-138: 적절한 일회성 상태 조회 구현입니다.

hasTodayFortune()이 Flow 구독 대신 first()를 사용하여 호출 시점의 상태를 즉시 반환하는 방식은 ViewModel에서 네비게이션 결정에 활용하기에 적합합니다. 학습 내용에 따르면, 호출 시점의 상태 판단용이므로 이 접근법이 적절합니다.

gradle/libs.versions.toml (1)

38-41: Compose BOM version exists but check library version overrides

Compose BOM 2025.02.00 is a valid stable release (published Feb 12, 2025). However, the individually pinned library versions (compose-navigation 2.8.5, compose-material3 1.4.0, compose-ui 1.8.3) appear to override the BOM's pinned versions and may not be compatible with the stable 2025.02.00 BOM, which targets Compose 1.7.8. When using a BOM, library versions are typically omitted to rely on the BOM's curated compatibility set, or all overrides must be verified for compatibility.

@codecov
Copy link

codecov bot commented Nov 30, 2025

Codecov Report

❌ Patch coverage is 21.62162% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 5.33%. Comparing base (6ee1ab8) to head (f58ce2e).
⚠️ Report is 12 commits behind head on develop.

Files with missing lines Patch % Lines
.../main/java/com/yapp/alarm/services/AlarmService.kt 0.00% 14 Missing ⚠️
...larm/receivers/AlarmInteractionActivityReceiver.kt 0.00% 8 Missing ⚠️
...main/java/com/yapp/datastore/FortunePreferences.kt 72.72% 0 Missing and 3 partials ⚠️
...ata/local/datasource/FortuneLocalDataSourceImpl.kt 0.00% 2 Missing ⚠️
.../yapp/data/repositoryimpl/FortuneRepositoryImpl.kt 0.00% 2 Missing ⚠️

❌ Your project status has failed because the head coverage (5.33%) is below the target coverage (60.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             develop    #279      +/-   ##
============================================
- Coverage       6.24%   5.33%   -0.92%     
+ Complexity        67      58       -9     
============================================
  Files             53      53              
  Lines           4422    4352      -70     
  Branches         774     751      -23     
============================================
- Hits             276     232      -44     
+ Misses          4112    4106       -6     
+ Partials          34      14      -20     
Files with missing lines Coverage Δ
...ata/local/datasource/FortuneLocalDataSourceImpl.kt 0.00% <0.00%> (ø)
.../yapp/data/repositoryimpl/FortuneRepositoryImpl.kt 41.66% <0.00%> (-0.65%) ⬇️
...main/java/com/yapp/datastore/FortunePreferences.kt 62.68% <72.72%> (-1.23%) ⬇️
...larm/receivers/AlarmInteractionActivityReceiver.kt 0.00% <0.00%> (ø)
.../main/java/com/yapp/alarm/services/AlarmService.kt 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@DongChyeon DongChyeon merged commit d76e2a9 into develop Nov 30, 2025
3 of 4 checks passed
@DongChyeon
Copy link
Member Author

운세 생성은 GlobalScope 아니면 Custom Scope에서 실행하자
서비스가 죽으면 serviceScope가 취소되니까

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.

[BUGFIX] 오늘의 운세 생성에 실패할 시 다음날이 되기 전까지 계속 운세 생성에 실패하는 문제

2 participants