-
Notifications
You must be signed in to change notification settings - Fork 0
[FIX/#120] 루틴 작성시 추천 루틴 타입 누락 추가 #121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FIX/#120] 루틴 작성시 추천 루틴 타입 누락 추가 #121
Conversation
Walkthrough등록 플로우 전반에 recommendedRoutineType(String?)을 추가했습니다. 프레젠테이션(MVI 상태/인텐트/뷰모델), 도메인(UseCase/Repository 인터페이스), 데이터(RepositoryImpl/Request DTO) 계층까지 파라미터를 전달하도록 시그니처와 요청 모델을 확장했습니다. 뷰모델은 일부 리듀서 반환 타입과 등록 중복 방지 로직이 조정되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant VM as WriteRoutineViewModel
participant UC as RegisterRoutineUseCase
participant Repo as WriteRoutineRepository
participant DS as RemoteDataSource/API
User->>VM: 추천 루틴 기반 등록 시작
VM->>VM: state.recommendedRoutineType = routine.recommendedRoutineType.categoryName
VM->>UC: invoke(name, repeatDay, startTime, dates, subRoutines, recommendedRoutineType)
UC->>Repo: registerRoutine(..., recommendedRoutineType)
Repo->>DS: POST RegisterRoutineRequest{..., recommendedRoutineType}
DS-->>Repo: Result<Unit>
Repo-->>UC: Result<Unit>
UC-->>VM: Result<Unit>
VM->>VM: 성공 시 사이드이펙트로 네비게이션(상태 유지)
sequenceDiagram
participant VM as WriteRoutineViewModel
Note over VM: 등록 중복 방지 가드(loading==true 시 조기 종료)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
깔끔합니다요! 머지 ㄱㄱ
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/WriteRoutineViewModel.kt (1)
476-497
: Mutex로 임계 구역 보호 적용 예시(등록 경로)중복 등록을 근본적으로 차단하려면 네트워크 호출/인텐트 전송 구간을 뮤텍스로 감싸 주세요.
- WriteRoutineType.Add -> { - sendIntent(WriteRoutineIntent.RegisterRoutineLoading) + WriteRoutineType.Add -> { + sendIntent(WriteRoutineIntent.RegisterRoutineLoading) val subRoutines = if (currentState.selectNotUseSubRoutines) emptyList() else currentState.subRoutineNames.filter { it.isNotEmpty() } val noRepeatRoutine = repeatDay.isEmpty() - - val registerRoutineResult = registerRoutineUseCase( - name = currentState.routineName, - repeatDay = repeatDay, - startTime = startTime.toDomainTime(), - startDate = if (noRepeatRoutine) Date.now().toDomainDate() else currentState.startDate.toDomainDate(), - endDate = if (noRepeatRoutine) Date.now().toDomainDate() else currentState.endDate.toDomainDate(), - subRoutines = subRoutines, - recommendedRoutineType = currentState.recommendedRoutineType, - ) + val registerRoutineResult = try { + registerRoutineUseCase( + name = currentState.routineName, + repeatDay = repeatDay, + startTime = startTime.toDomainTime(), + startDate = if (noRepeatRoutine) Date.now().toDomainDate() else currentState.startDate.toDomainDate(), + endDate = if (noRepeatRoutine) Date.now().toDomainDate() else currentState.endDate.toDomainDate(), + subRoutines = subRoutines, + recommendedRoutineType = currentState.recommendedRoutineType, + ) + } finally { + registerMutex.unlock() + }추가로 필요한 보일러플레이트(파일 상단/클래스 필드):
// import import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.tryLock // class body private val registerMutex = Mutex()
🧹 Nitpick comments (9)
data/src/main/java/com/threegap/bitnagil/data/writeroutine/model/request/RegisterRoutineRequest.kt (1)
20-21
: Json 설정 확인 완료 및 enum 전환 권장– NetworkModule.kt(39–46)에서 이미
Json { ignoreUnknownKeys = true prettyPrint = true explicitNulls = false }로 설정되어 있어, nullable 필드가 null일 경우 JSON에 포함되지 않습니다.
– data/src/main/java/com/threegap/bitnagil/data/common/SafeApiCall.kt 에서 사용하는Json { ignoreUnknownKeys = true }
인스턴스는 기본explicitNulls = true
를 따르지만, 이는 에러 응답 파싱 전용으로 보이므로 요청 직렬화에는 영향이 없습니다.
• 만약 다른 곳에서 별도 Json 인스턴스를 생성하여 직렬화에 사용 중이라면, 동일하게explicitNulls = false
로 맞춰 주시기 바랍니다.
– recommendedRoutineType 필드에 허용 값이 제한적이라면, String 대신 enum 클래스로 전환해 타입 세이프티를 강화하는 것을 권장드립니다.presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/model/mvi/WriteRoutineIntent.kt (1)
25-26
: SetRoutine 생성자에recommendedRoutineType
기본값null
추가 권장
WriteRoutineIntent.SetRoutine
생성자에 새로 추가된recommendedRoutineType: String?
파라미터에 기본값을 두면, 현재 두 곳의 호출부를 수정할 필요 없이 코드를 컴파일할 수 있습니다.
- 대상 호출부:
presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/WriteRoutineViewModel.kt
(85, 114행)제안하는 경미한 수정:
--- a/presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/model/mvi/WriteRoutineIntent.kt +++ b/presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/model/mvi/WriteRoutineIntent.kt @@ -22,7 +22,7 @@ sealed class WriteRoutineIntent { val repeatDays: List<Day>, - val recommendedRoutineType: String?, + val recommendedRoutineType: String? = null, ) : WriteRoutineIntent()이렇게 하면 호출부에
recommendedRoutineType
인자를 명시하지 않아도 기본값(null
)이 적용되어 호출부 변경 없이도 컴파일됩니다.data/src/main/java/com/threegap/bitnagil/data/writeroutine/repositoryImpl/WriteRoutineRepositoryImpl.kt (1)
36-37
: 빈 문자열 방지: 서버로는 null만 보내고 공백/빈 문자열은 제거 권장UI에서 값이 공백으로 들어올 가능성이 있다면, 서버에는 null로 통일하는 편이 안전합니다. 직렬화 시 불필요한 빈 문자열 전송을 방지합니다.
다음 변경을 제안합니다:
- recommendedRoutineType = recommendedRoutineType, + recommendedRoutineType = recommendedRoutineType?.takeIf { it.isNotBlank() },또한 위와 별개로, 앞선 코멘트처럼 JSON 설정에서
explicitNulls = false
가 아니라면 null이 명시적으로 전송됩니다. 서버 계약에 맞춰 전역 설정/전송 형태를 재확인해 주세요.domain/src/main/java/com/threegap/bitnagil/domain/writeroutine/usecase/RegisterRoutineUseCase.kt (1)
19-20
: 기본값 추가 및 타입 세이프티 개선 제안
RegisterRoutineUseCase.invoke
시그니처를처럼 기본값suspend operator fun invoke( …, recommendedRoutineType: String? = null, ): Result<Unit>= null
으로 변경하면 호출부 수정 없이 점진적인 마이그레이션이 가능합니다.recommendedRoutineType
을String?
그대로 두기보다혹은 value class(enum class RecommendedRoutineType { … }@JvmInline value class
)로 래핑해 도메인 계층에서의 문자열 직접 노출을 최소화하고, infra 계층에서만 매핑하도록 구조를 개선하세요.- 허용 가능한 문자열 집합(예: 서버 스키마 카테고리 키)이 정해져 있다면,
require()
또는 전용 매퍼 내에서 사전 검증 로직을 추가해 런타임 오류를 조기에 방지할 것을 권장합니다.호출부 확인 결과, 현재
registerRoutineUseCase
를 사용하는 곳은
WriteRoutineViewModel.kt
482–490행 한 곳뿐이므로
기본값 추가 시점에서도 다른 호출부에 영향이 없습니다.presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/WriteRoutineViewModel.kt (5)
96-97
: 편집 진입 시 recommendedRoutineType을 null로 초기화하는 의도 확인 필요Edit 플로우에서
recommendedRoutineType = null
로 고정하면, 기존에 추천 기반으로 생성된 루틴을 편집할 때 타입 정보가 손실될 수 있습니다. 편집 API가 타입을 받지 않는다면 전송은 필요 없지만, UI 상에서 아이콘/라벨 표시용으로 유지가 필요할 수 있습니다. 도메인 모델에 해당 값이 존재한다면 보존하는 쪽을 검토해 주세요.예시(모델이 있다면):
- recommendedRoutineType = null, + recommendedRoutineType = routine.recommendedRoutineType?.categoryName,
125-126
: NPE 방지: 안전한 호출로 변경 권장추천 루틴 응답에서
recommendedRoutineType
이 누락될 가능성에 대비해 안전 연산자로 방어 코드를 추가하는 편이 안전합니다.- recommendedRoutineType = routine.recommendedRoutineType.categoryName, + recommendedRoutineType = routine.recommendedRoutineType?.categoryName,
136-140
: reduceState의 nullable 반환 계약 명시/검증 필요
reduceState(...): WriteRoutineState?
로 변경해null
을 반환하는 경우 상태 갱신을 생략하는 패턴을 도입하셨습니다. 사용 중인 MVI 베이스(MviViewModel
/Orbit)에서null
을 적절히 no-op 처리하는지 확실히 해두는 것이 좋습니다. 계약이 불명확하면 유지보수자가 오해하기 쉽습니다. 간단한 KDoc 주석으로 “null 반환 시 상태 미갱신” 의도를 명시해 주세요.
223-227
: 성공 시 loading 해제 누락으로 인한 잔상 가능성
RegisterRoutineSuccess
에서 사이드 이펙트만 발행하고return null
로 상태 갱신을 생략하고 있어, 화면 전환이 지연/취소되거나 테스트 환경에서 화면이 잔류할 때 로딩 스피너가 그대로 남을 수 있습니다.EditRoutineSuccess
는loading = false
로 정리하는 것과 일관되게 처리하는 편이 안전합니다.- WriteRoutineIntent.RegisterRoutineSuccess -> { - sendSideEffect(WriteRoutineSideEffect.MoveToPreviousScreen) - - return null - } + WriteRoutineIntent.RegisterRoutineSuccess -> { + sendSideEffect(WriteRoutineSideEffect.MoveToPreviousScreen) + return state.copy(loading = false) + }
256-258
: 상태에 recommendedRoutineType 전달 OK추천 루틴 타입을 상태로 보존해 등록 시점까지 안전하게 전달하는 흐름이 명확합니다. 이후 상태 저장/복원(SavedStateHandle) 고려가 필요하면 동일 키로 보존하는 것도 검토해 주세요.
📜 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.
📒 Files selected for processing (7)
data/src/main/java/com/threegap/bitnagil/data/writeroutine/model/request/RegisterRoutineRequest.kt
(1 hunks)data/src/main/java/com/threegap/bitnagil/data/writeroutine/repositoryImpl/WriteRoutineRepositoryImpl.kt
(2 hunks)domain/src/main/java/com/threegap/bitnagil/domain/writeroutine/repository/WriteRoutineRepository.kt
(1 hunks)domain/src/main/java/com/threegap/bitnagil/domain/writeroutine/usecase/RegisterRoutineUseCase.kt
(2 hunks)presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/WriteRoutineViewModel.kt
(7 hunks)presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/model/mvi/WriteRoutineIntent.kt
(1 hunks)presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/model/mvi/WriteRoutineState.kt
(2 hunks)
🔇 Additional comments (4)
presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/model/mvi/WriteRoutineState.kt (2)
32-33
: 상태에 recommendedRoutineType 추가: LGTMUI 상태에 추천 루틴 타입을 포함하는 방향은 요구사항과 일치합니다. 직렬화(@parcelize) 관점에서도 필드가 말단에 추가되어 호환성 이슈가 낮습니다.
83-84
: Init에서 null 초기화 적절초기 진입 시 추천 루틴이 아닐 수 있으므로 기본값 null 설정은 합리적입니다. 이후 추천 루틴 진입 경로에서만 실제 값으로 세팅하면 됩니다.
data/src/main/java/com/threegap/bitnagil/data/writeroutine/repositoryImpl/WriteRoutineRepositoryImpl.kt (1)
27-28
: 레포지토리 시그니처 확장: LGTM도메인 인터페이스 변경과 일치하며, 파이프라인이 자연스럽게 Request DTO로 전달되도록 구성되어 있습니다.
presentation/src/main/java/com/threegap/bitnagil/presentation/writeroutine/WriteRoutineViewModel.kt (1)
488-490
: UseCase로의 recommendedRoutineType 전파 확인등록 호출에
recommendedRoutineType
이 누락 없이 전달됩니다. PR 목표와 일치합니다.
[ PR Content ]
루틴 작성시 누락된 추천 루틴 타입을 추가합니다.
Related issue
Screenshot 📸
KakaoTalk_Video_2025-08-21-21-11-49.mp4
Work Description
To Reviewers 📢
Summary by CodeRabbit