Conversation
Walkthrough사용자 ID를 DataStore에 저장하고 관리하는 TokenManager 인터페이스와 구현체를 추가하고, OkHttp의 AuthInterceptor와 TokenAuthenticator를 통해 요청에 사용자 ID를 자동으로 포함시키고 인증 실패(401) 시 처리하도록 통합한 변경사항입니다. Changes
Sequence DiagramssequenceDiagram
participant Client as 클라이언트 코드
participant AuthInt as AuthInterceptor
participant TokenMgr as TokenManager
participant DataStore as DataStore
participant OkHttp as OkHttp Chain
participant Server as 서버
Client->>AuthInt: HTTP 요청
AuthInt->>TokenMgr: getId() (blocking)
TokenMgr->>DataStore: 캐시 확인 또는 DataStore 읽기
DataStore-->>TokenMgr: 사용자 ID 반환
TokenMgr-->>AuthInt: ID 반환
alt ID가 존재하는 경우
AuthInt->>OkHttp: X-User-Id 헤더 추가된 요청
else ID가 없는 경우
AuthInt->>OkHttp: 원본 요청 전달
end
OkHttp->>Server: 수정된 요청 전송
Server-->>OkHttp: 응답 (200 또는 401)
alt 401 Unauthorized 응답
OkHttp->>TokenAuthenticator: 인증 처리 필요
TokenAuthenticator->>TokenMgr: clearId() (runBlocking)
TokenMgr->>DataStore: 저장된 ID 삭제
DataStore-->>TokenMgr: 완료
TokenMgr-->>TokenAuthenticator: 완료
TokenAuthenticator-->>OkHttp: null 반환 (재시도 없음)
end
OkHttp-->>Client: 최종 응답
sequenceDiagram
participant App as 애플리케이션
participant TokenMgr as TokenManagerImpl
participant Cache as 메모리 캐시
participant DataStore as DataStore<Preferences>
App->>TokenMgr: saveId(12345)
TokenMgr->>Cache: ID 저장
TokenMgr->>DataStore: 저장 작업 실행
DataStore-->>TokenMgr: 완료
App->>TokenMgr: getId()
TokenMgr->>Cache: 캐시 확인
alt 캐시에 존재
Cache-->>TokenMgr: 12345 반환
else 캐시에 없음
TokenMgr->>DataStore: 읽기 작업 실행
DataStore-->>TokenMgr: 12345 반환
TokenMgr->>Cache: 캐시 업데이트
end
TokenMgr-->>App: ID 반환
App->>TokenMgr: clearId()
TokenMgr->>Cache: 캐시 초기화
TokenMgr->>DataStore: 키 삭제 작업 실행
DataStore-->>TokenMgr: 완료
TokenMgr-->>App: 완료
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 분 Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/cherrish/android/core/local/model/UserPreferences.kt`:
- Around line 1-5: Remove the unused data class UserPreferences: delete the
UserPreferences declaration (data class UserPreferences) since TokenManagerImpl
uses DataStore<Preferences> with longPreferencesKey("user_id") directly; ensure
no other references to UserPreferences remain and run a project-wide search for
"UserPreferences" to confirm safe removal.
In `@app/src/main/java/com/cherrish/android/core/network/AuthInterceptor.kt`:
- Around line 16-17: Logging the raw user ID via Timber.d("User ID: $id")
exposes PII; update the AuthInterceptor where you call runBlocking {
tokenManager.getId() } and Timber.d to either (1) only log in debug builds by
checking BuildConfig.DEBUG before calling Timber.d, or (2) mask the id (e.g.,
show only last 4 chars or a hash) before logging so the full identifier is never
written to logs; apply the chosen approach consistently where
tokenManager.getId() is used.
In
`@app/src/main/java/com/cherrish/android/data/repositoryimpl/CalendarRepositoryImpl.kt`:
- Around line 18-20: The current use of the non-null assertion data!!.toModel()
inside runCatching risks an NPE and hides a clear error; change the block in
calendarDataSource.getCalendarMonthly to explicitly check response.data and
either map it or throw a clear exception (e.g. val resp =
calendarDataSource.getCalendarMonthly(year, month); val model =
resp.data?.toModel() ?: throw IllegalStateException("getCalendarMonthly returned
null data for year=$year month=$month")) so runCatching surfaces a meaningful
error; apply the same pattern to calendarDataSource.getCalendarDaily and
calendarDataSource.getCalendarEventDowntime, replacing data!!.toModel() with a
null-safe check that throws a descriptive exception when data is null.
In
`@app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt`:
- Around line 36-67: OnDateClick currently launches a coroutine inside
_uiState.updateSuccess (anti-pattern) causing async state races; remove
viewModelScope.launch from inside updateSuccess and perform synchronous state
changes first then start the coroutine. Specifically: in onDateClick, when
current mode is CalendarDisplayMode.Downtime, call _uiState.updateSuccess
synchronously to set selectedDate (and keep currentState or set a temporary
transitional state), then outside that update start viewModelScope.launch to
call calendarRepository.getCalendarDaily(date.toString()) and in its onSuccess
call _uiState.updateSuccess to set calendarDisplayMode to Normal and populate
procedureInfoList (using ProcedureInfoModel and formatProcedureDay as before);
keep loadDailyCalendar usage for the non-downtime branch. Use the same symbols:
onDateClick, _uiState.updateSuccess, viewModelScope.launch,
calendarRepository.getCalendarDaily, loadDailyCalendar, ProcedureInfoModel.
- Around line 79-96: The updateSuccess block in onEventClick must not call the
asynchronous loadDowntimeDetail(procedureId) because that creates a race;
instead, only perform synchronous state transformations inside
_uiState.updateSuccess (set calendarDisplayMode to CalendarDisplayMode.Downtime
with selectedProcedureId or to Normal as before), then after updateSuccess
completes call loadDowntimeDetail(procedureId) from the caller context (e.g.,
launch it in viewModelScope or the existing coroutine scope) so the async work
runs outside the updateSuccess block; reference symbols: onEventClick,
_uiState.updateSuccess, loadDowntimeDetail, CalendarDisplayMode.Downtime,
CalendarDisplayMode.Normal, cachedProcedureCountByDate, selectedProcedureId.
🧹 Nitpick comments (9)
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt (1)
237-241: 접근성(Accessibility) 고려 권장
contentDescription = null은 순수 장식용 이미지에 적합하지만, 이 이미지가 "일정이 없음" 상태를 시각적으로 전달한다면 스크린 리더 사용자를 위해 의미 있는 설명을 추가하는 것이 좋습니다.♻️ 접근성 개선 제안
Image( painter = painterResource(id = R.drawable.img_calendar_empty_view), - contentDescription = null, + contentDescription = "일정 없음 이미지", modifier = Modifier.padding(8.dp) )app/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.kt (1)
8-14: 날짜 파싱 실패 시 예외 처리를 고려하세요.
LocalDateTime.parse(scheduledAt)는 유효하지 않은 형식의 문자열이 들어올 경우DateTimeParseException을 발생시킵니다. 서버 응답 형식이 항상 ISO-8601을 보장한다면 괜찮지만, 방어적 코딩을 위해 예외 처리나 형식 검증을 추가하는 것을 권장합니다.♻️ 예외 처리 추가 제안
+import java.time.format.DateTimeParseException + fun formatProcedureDay(scheduledAt: String): String { - val dateTime = LocalDateTime.parse(scheduledAt) + val dateTime = try { + LocalDateTime.parse(scheduledAt) + } catch (e: DateTimeParseException) { + return scheduledAt // fallback to original string + } val month = dateTime.month.value val day = dateTime.dayOfMonth val dayOfWeek = dateTime.dayOfWeek.toKoreanName() return "${month}월 ${day}일 $dayOfWeek" }app/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.kt (1)
17-18:cachedProcedureCountByDate에ImmutableMap사용을 권장합니다.
@Immutable어노테이션이 적용된 data class에서procedureInfoList는ImmutableList를 사용하지만,cachedProcedureCountByDate는 표준Map을 사용하고 있습니다. Compose의 안정성(stability) 추론과 불필요한 recomposition 방지를 위해kotlinx.collections.immutable.ImmutableMap을 사용하는 것이 일관성 있습니다.♻️ 권장 수정안
import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf `@Immutable` data class CalendarUiState( val selectedYearMonth: YearMonth = YearMonth.now(), val calendarDisplayMode: CalendarDisplayMode = CalendarDisplayMode.Normal(), val selectedDate: LocalDate? = LocalDate.now(), val procedureInfoList: ImmutableList<ProcedureInfoModel> = persistentListOf(), - val cachedProcedureCountByDate: Map<LocalDate, Int> = emptyMap() + val cachedProcedureCountByDate: ImmutableMap<LocalDate, Int> = persistentMapOf() )app/src/main/java/com/cherrish/android/core/network/TokenAuthenticator.kt (1)
21-23:runBlocking사용 시 주의OkHttp의
authenticate()는 dispatcher 스레드에서 호출되므로runBlocking사용이 해당 스레드를 블로킹합니다. 현재clearId()가 간단한 DataStore 작업이라면 큰 문제는 없지만, 네트워크 호출이 추가되면 데드락 위험이 있습니다.app/src/main/java/com/cherrish/android/core/local/TokenManagerImpl.kt (1)
25-31: 캐시 업데이트 시 잠재적 race condition
cachedId가 null일 때 여러 코루틴이 동시에getId()를 호출하면, 모두 DataStore를 읽게 됩니다. 동일 값을 읽으므로 기능적으로는 문제없지만, 불필요한 I/O가 발생할 수 있습니다.현재 사용 패턴에서 동시 접근이 드물다면 괜찮지만, 빈번한 동시 접근이 예상된다면
Mutex를 사용한 동기화를 고려해보세요.♻️ Mutex를 사용한 개선 예시
+import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock class TokenManagerImpl `@Inject` constructor( private val dataStore: DataStore<Preferences> ) : TokenManager { + private val mutex = Mutex() + `@Volatile` private var cachedId: Long? = null override suspend fun getId(): Long? { - return cachedId ?: dataStore.data.map { preferences -> - preferences[KEY_USER_ID] - }.first().also { - cachedId = it - } + cachedId?.let { return it } + return mutex.withLock { + cachedId ?: dataStore.data.map { preferences -> + preferences[KEY_USER_ID] + }.first().also { + cachedId = it + } + } }app/src/main/java/com/cherrish/android/core/network/AuthInterceptor.kt (1)
15-17:runBlocking사용에 대한 고려사항인터셉터에서
runBlocking은 OkHttp의 디스패처 스레드를 차단합니다. 현재 구현은 동작하지만, 고부하 상황에서 스레드 풀 고갈 가능성이 있습니다.ID를 메모리에 캐싱하거나,
@Volatile변수와 함께 비동기 업데이트 패턴을 고려해볼 수 있습니다.app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.kt (1)
104-128:ProcedureScheduleInfo의downTimeDuration타입이 nullable로 남아있습니다.
ProcedureInfoItem의 공개 파라미터는Int(Line 33)로 변경되었지만, 내부 컴포저블ProcedureScheduleInfo의 파라미터는 여전히Int?(Line 108)입니다. 일관성을 위해 non-nullableInt로 변경하는 것이 좋습니다.♻️ 제안하는 수정
`@Composable` private fun ProcedureScheduleInfo( colors: ProcedureColors, procedureDay: String, - downTimeDuration: Int? + downTimeDuration: Int ) {app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt (2)
125-132: 이벤트를ProcedureInfoModel로 변환하는 로직이 중복됩니다.동일한 매핑 로직이 3곳(lines 49-56, 125-132, 149-156)에서 반복되고 있습니다. 확장 함수로 추출하면 유지보수성이 향상됩니다.
♻️ 확장 함수 추출 제안
// CalendarViewModel.kt 또는 별도 매퍼 파일에 추가 private fun List<CalendarDailyEvent>.toProcedureInfoModels() = map { event -> ProcedureInfoModel( procedureId = event.userProcedureId, procedureName = event.name, procedureDay = formatProcedureDay(event.scheduledAt), downTimeDuration = event.downtimeDays ) }.toImmutableList()사용 예시:
-procedureInfoList = dailyResponse.events.map { event -> - ProcedureInfoModel( - procedureId = event.userProcedureId, - procedureName = event.name, - procedureDay = formatProcedureDay(event.scheduledAt), - downTimeDuration = event.downtimeDays - ) -}.toImmutableList() +procedureInfoList = dailyResponse.events.toProcedureInfoModels()Also applies to: 149-156
59-59: 빈 에러 핸들러로 인해 사용자 피드백이 누락됩니다.모든
.onLogFailure { }핸들러가 비어있어 네트워크 실패 시 사용자에게 아무런 피드백이 제공되지 않습니다. 로딩 상태가 무한히 지속되거나 이전 데이터가 그대로 표시될 수 있습니다.최소한 에러 상태를 UI에 반영하거나 토스트/스낵바로 사용자에게 알리는 것을 권장합니다:
.onLogFailure { error -> _uiState.update { UiState.Error(error) } // 또는 기존 데이터 유지하며 에러 메시지만 표시 }Also applies to: 138-138, 159-159, 186-186
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
app/src/main/res/drawable/img_calendar_empty_view.pngis excluded by!**/*.png,!**/*.png
📒 Files selected for processing (35)
.kotlin/sessions/kotlin-compiler-1697198284998868167.saliveapp/src/main/java/com/cherrish/android/core/local/TokenManager.ktapp/src/main/java/com/cherrish/android/core/local/TokenManagerImpl.ktapp/src/main/java/com/cherrish/android/core/local/constant/DataStoreConstant.ktapp/src/main/java/com/cherrish/android/core/local/di/DataStoreModule.ktapp/src/main/java/com/cherrish/android/core/local/model/UserPreferences.ktapp/src/main/java/com/cherrish/android/core/network/AuthInterceptor.ktapp/src/main/java/com/cherrish/android/core/network/BaseResponse.ktapp/src/main/java/com/cherrish/android/core/network/NetworkModule.ktapp/src/main/java/com/cherrish/android/core/network/TokenAuthenticator.ktapp/src/main/java/com/cherrish/android/data/di/DataSourceModule.ktapp/src/main/java/com/cherrish/android/data/di/RepositoryModule.ktapp/src/main/java/com/cherrish/android/data/di/ServiceModule.ktapp/src/main/java/com/cherrish/android/data/model/CalendarDailyResponseModel.ktapp/src/main/java/com/cherrish/android/data/model/CalendarDownTimeResponseModel.ktapp/src/main/java/com/cherrish/android/data/model/CalendarMonthlyRequestModel.ktapp/src/main/java/com/cherrish/android/data/model/CalendarMonthlyResponseModel.ktapp/src/main/java/com/cherrish/android/data/remote/datasource/CalendarDataSource.ktapp/src/main/java/com/cherrish/android/data/remote/datasourceimpl/CalendarDataSourceImpl.ktapp/src/main/java/com/cherrish/android/data/remote/dto/request/.gitkeepapp/src/main/java/com/cherrish/android/data/remote/dto/request/CalendarDailyRequestDto.ktapp/src/main/java/com/cherrish/android/data/remote/dto/request/CalendarMonthlyRequestDto.ktapp/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarDailyResponseDto.ktapp/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarDownTimeResponseDto.ktapp/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarMonthlyResponseDto.ktapp/src/main/java/com/cherrish/android/data/remote/service/CalendarService.ktapp/src/main/java/com/cherrish/android/data/repository/CalendarRepository.ktapp/src/main/java/com/cherrish/android/data/repositoryimpl/CalendarRepositoryImpl.ktapp/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.ktapp/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.ktapp/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.ktapp/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.ktapp/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureInfoModel.ktapp/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.ktapp/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt
⚙️ CodeRabbit configuration file
**/*.kt: - Jetpack Compose 구조, 상태 관리, recomposition 최적화에 집중
- ViewModel, UiState, 단방향 데이터 흐름 패턴 검토
- 불필요한 recomposition 가능성, remember/derivedStateOf 적절한 사용 확인
- 네이밍 컨벤션, 가독성, Google 권장 Android 아키텍처 준수 여부
Files:
app/src/main/java/com/cherrish/android/core/local/constant/DataStoreConstant.ktapp/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureInfoModel.ktapp/src/main/java/com/cherrish/android/core/network/BaseResponse.ktapp/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.ktapp/src/main/java/com/cherrish/android/data/di/RepositoryModule.ktapp/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarDownTimeResponseDto.ktapp/src/main/java/com/cherrish/android/data/remote/datasource/CalendarDataSource.ktapp/src/main/java/com/cherrish/android/core/network/NetworkModule.ktapp/src/main/java/com/cherrish/android/data/model/CalendarMonthlyRequestModel.ktapp/src/main/java/com/cherrish/android/core/local/model/UserPreferences.ktapp/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.ktapp/src/main/java/com/cherrish/android/core/network/TokenAuthenticator.ktapp/src/main/java/com/cherrish/android/data/remote/service/CalendarService.ktapp/src/main/java/com/cherrish/android/data/remote/dto/request/CalendarMonthlyRequestDto.ktapp/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.ktapp/src/main/java/com/cherrish/android/data/repository/CalendarRepository.ktapp/src/main/java/com/cherrish/android/data/remote/datasourceimpl/CalendarDataSourceImpl.ktapp/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarMonthlyResponseDto.ktapp/src/main/java/com/cherrish/android/core/local/TokenManager.ktapp/src/main/java/com/cherrish/android/data/di/DataSourceModule.ktapp/src/main/java/com/cherrish/android/core/local/TokenManagerImpl.ktapp/src/main/java/com/cherrish/android/data/model/CalendarDailyResponseModel.ktapp/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarDailyResponseDto.ktapp/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.ktapp/src/main/java/com/cherrish/android/data/di/ServiceModule.ktapp/src/main/java/com/cherrish/android/core/network/AuthInterceptor.ktapp/src/main/java/com/cherrish/android/data/remote/dto/request/CalendarDailyRequestDto.ktapp/src/main/java/com/cherrish/android/data/model/CalendarMonthlyResponseModel.ktapp/src/main/java/com/cherrish/android/data/model/CalendarDownTimeResponseModel.ktapp/src/main/java/com/cherrish/android/core/local/di/DataStoreModule.ktapp/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.ktapp/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.ktapp/src/main/java/com/cherrish/android/data/repositoryimpl/CalendarRepositoryImpl.kt
🧠 Learnings (1)
📚 Learning: 2026-01-12T19:49:27.085Z
Learnt from: nhyeonii
Repo: TEAM-Cherrish/Cherrish-Android PR: 41
File: app/src/main/java/com/cherrish/android/presentation/challenge/ChallengeScreen.kt:30-39
Timestamp: 2026-01-12T19:49:27.085Z
Learning: When a Jetpack Compose screen composable receives a Scaffold paddingValues: PaddingValues parameter (commonly from Scaffold), apply it to the root container's modifier first (e.g., .padding(paddingValues)) before applying any additional padding. This ensures content respects system bars (status/navigation) and avoids layout overlap. This pattern should be followed across presentation screens under app/src/main/java/com/cherrish/android/presentation/ to maintain consistent insets handling.
Applied to files:
app/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureInfoModel.ktapp/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.ktapp/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.ktapp/src/main/java/com/cherrish/android/presentation/calendar/CalendarUiState.ktapp/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.ktapp/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.ktapp/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt
🧬 Code graph analysis (1)
app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt (1)
app/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.kt (1)
formatProcedureDay(8-14)
⏰ 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). (2)
- GitHub Check: PR Build Check
- GitHub Check: PR Lint Check
🔇 Additional comments (35)
app/src/main/java/com/cherrish/android/data/di/RepositoryModule.kt (2)
3-4: LGTM! 패키지 구조가 명확합니다.인터페이스(
repository)와 구현체(repositoryimpl)를 분리한 구조는 Clean Architecture 원칙을 따르고 있습니다.
14-18: LGTM! Hilt DI 바인딩이 올바르게 구성되었습니다.
@Binds와@Singleton조합이 적절하며,CalendarRepository인터페이스를 통한 의존성 주입이 정상적으로 동작할 것입니다.app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureScheduleCard.kt (3)
3-3: LGTM!
EmptyCardView에서 새로 추가된Image컴포저블에 필요한 import입니다.Also applies to: 28-28
52-63: 스크롤 상태 감지 로직 개선 확인
canScrollBackward와canScrollForward를 활용한 로직이 그라데이션 오버레이 표시 조건을 더 정확하게 판단합니다.derivedStateOf를remember로 감싼 패턴은 recomposition 최적화에 적합합니다.
84-84: 디자인 수정 반영 확인
EmptyCardView의 상단 패딩이 64.dp에서 50.dp로 조정되었습니다.app/src/main/java/com/cherrish/android/presentation/calendar/util/CalendarCalculator.kt (1)
16-24: LGTM!
when표현식을 사용하여 모든DayOfWeek케이스를 exhaustive하게 처리하고 있으며, 한국어 요일 이름 매핑이 명확합니다.app/src/main/java/com/cherrish/android/core/local/TokenManager.kt (1)
3-7: 인터페이스 설계가 적절합니다.간결하고 명확한 인터페이스 설계입니다.
suspend함수 사용으로 DataStore의 비동기 특성을 잘 반영하고 있습니다.다만, 인터페이스 이름이
TokenManager인데 메서드들은Id를 다루고 있어 약간의 불일치가 있습니다. 향후 실제 토큰(access token, refresh token 등)도 관리할 계획이라면 현재 이름이 적절하고, 그렇지 않다면UserIdManager같은 이름이 더 명확할 수 있습니다.app/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarDownTimeResponseDto.kt (1)
6-20: LGTM!DTO 구조가 깔끔하고
kotlinx.serialization규칙을 잘 따르고 있습니다. 모든 필드에@SerialName어노테이션을 명시적으로 지정하여 JSON 키 매핑이 명확합니다.app/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarMonthlyResponseDto.kt (1)
6-10: LGTM!단일 필드를 가진 간결한 DTO입니다.
Map<Int, Long>타입은 일별 시술 개수를 표현하기에 적절하며,kotlinx.serialization이 Map 직렬화를 지원합니다.app/src/main/java/com/cherrish/android/core/network/BaseResponse.kt (1)
8-9:BaseResponse.code필드 타입이 새로 정의되었으므로, 추가 검토가 필요합니다.
code필드가 새로 생성된BaseResponse클래스에서String타입으로 정의되었습니다. 현재 코드베이스에서code필드를 직접 사용하는 부분이 없으므로, 현재로서는 호환성 문제가 없습니다. 다만 향후 이 필드를 사용할 때String타입에 맞게 처리되는지 확인이 필요합니다. API 응답 스펙에서 실제로code가 문자열 형식인지 확인하시기 바랍니다.app/src/main/java/com/cherrish/android/data/model/CalendarMonthlyResponseModel.kt (1)
5-11: LGTM!DTO와 도메인 모델을 분리하고 mapper extension function을 사용한 구조가 깔끔합니다. 데이터 레이어와 프레젠테이션 레이어 간의 명확한 경계를 유지하는 좋은 패턴입니다.
app/src/main/java/com/cherrish/android/presentation/calendar/util/ProcedureUtil.kt (1)
47-66: LGTM!
downTimeDuration을 nullable(Int?)에서 non-null(Int)로 변경하고, null 체크 대신== 0체크를 사용한 것은 더 명확한 설계입니다. "다운타임 없음"을 0으로 표현하는 것이 null보다 의미가 명확하고, 관련 모델(ProcedureInfoModel)과의 일관성도 유지됩니다.app/src/main/java/com/cherrish/android/data/di/ServiceModule.kt (1)
14-18: LGTM!Hilt DI 모듈에서
DummyService를CalendarService로 교체한 것이 적절합니다.@Singleton스코프와 Retrofit 서비스 생성 패턴이 올바르게 적용되었습니다.app/src/main/java/com/cherrish/android/data/remote/dto/request/CalendarDailyRequestDto.kt (1)
6-10: LGTM!
kotlinx.serialization을 사용한 깔끔한 DTO 정의입니다.CalendarMonthlyRequestDto와 일관된 패턴을 따르고 있습니다.app/src/main/java/com/cherrish/android/core/network/TokenAuthenticator.kt (1)
18-26: 토큰 갱신 로직 없이 ID만 삭제하고 null 반환현재 구현은 401 응답 시
clearId()만 호출하고null을 반환하여 재시도하지 않습니다. 일반적인Authenticator패턴은 토큰을 갱신한 후 새 토큰으로 요청을 재시도합니다.의도된 동작이라면 괜찮지만, 토큰 갱신 후 재시도가 필요하다면 추가 구현이 필요합니다.
app/src/main/java/com/cherrish/android/data/model/CalendarDownTimeResponseModel.kt (1)
5-21: LGTM!DTO에서 Model로의 매핑 패턴이 깔끔하게 구현되었습니다. 확장 함수를 사용한 변환은 Kotlin의 관용적인 패턴입니다.
app/src/main/java/com/cherrish/android/data/remote/datasource/CalendarDataSource.kt (1)
8-12: LGTM!인터페이스 설계가 깔끔합니다.
suspend함수를 사용한 비동기 처리와BaseResponse래퍼를 통한 일관된 응답 처리가 잘 구현되었습니다.app/src/main/java/com/cherrish/android/data/remote/dto/response/CalendarDailyResponseDto.kt (1)
6-28: LGTM!DTO 구조가 깔끔하게 정의되었습니다.
@Serializable어노테이션과 중첩 데이터 클래스 사용이 적절합니다.참고:
@SerialName이 프로퍼티명과 동일한 경우 생략 가능하지만, 명시적으로 작성하는 것도 API 계약을 명확히 하는 좋은 방법입니다.app/src/main/java/com/cherrish/android/data/remote/datasourceimpl/CalendarDataSourceImpl.kt (1)
11-29: LGTM!
CalendarDataSource인터페이스의 구현이 깔끔합니다.CalendarService로의 위임 패턴을 사용하여 테스트 용이성과 관심사 분리가 잘 되어 있습니다.app/src/main/java/com/cherrish/android/data/di/DataSourceModule.kt (1)
14-18: LGTM!Hilt의
@Binds패턴을 올바르게 사용하여 CalendarDataSource 바인딩을 구성했습니다. DummyDataSource에서 실제 CalendarDataSource로의 전환이 깔끔합니다.app/src/main/java/com/cherrish/android/data/model/CalendarDailyResponseModel.kt (2)
6-18: LGTM!데이터 모델 정의가 명확하고, DTO와 Model 계층 분리가 잘 되어 있습니다.
20-23: 널 안전성 우려 해소됨
CalendarDailyResponseDto의events필드는List<EventDto>로 정의되어 있어 비-널러블(non-nullable)입니다. 따라서this.events.map()호출은 안전하며 NPE 위험이 없습니다.Likely an incorrect or invalid review comment.
app/src/main/java/com/cherrish/android/data/repository/CalendarRepository.kt (1)
7-20: LGTM!Repository 인터페이스 설계가 깔끔합니다.
Result<T>반환 타입으로 일관된 에러 처리가 가능하고, suspend 함수를 통한 비동기 처리가 적절합니다.app/src/main/java/com/cherrish/android/core/local/TokenManagerImpl.kt (1)
11-23: LGTM!DataStore와 인메모리 캐시를 조합한 TokenManager 구현이 적절합니다.
@Volatile어노테이션으로 기본적인 가시성을 보장하고, DataStore를 통한 영속성도 잘 처리되어 있습니다.app/src/main/java/com/cherrish/android/core/local/di/DataStoreModule.kt (1)
17-36: LGTM!DataStoreModule DI 구성이 깔끔합니다.
preferencesDataStoredelegate를 사용한 DataStore 생성과 TokenManager 추상화를 통한 의존성 주입이 잘 구성되어 있습니다.app/src/main/java/com/cherrish/android/core/local/constant/DataStoreConstant.kt (1)
1-5: LGTM!DataStore 이름을 상수로 깔끔하게 정의했습니다. 중앙 집중식 상수 관리로 유지보수성이 좋습니다.
app/src/main/java/com/cherrish/android/core/network/NetworkModule.kt (1)
69-71: 인터셉터 순서 검토 필요현재
loggingInterceptor가authInterceptor전에 추가되어 있어, 인증 헤더(X-User-Id)가 로그에 기록되지 않습니다.만약 디버깅 목적으로 인증 헤더도 로깅하려면 순서를 바꿔야 하고, 보안상 헤더를 로깅하지 않으려면 현재 순서가 맞습니다. 의도한 동작인지 확인해 주세요.
app/src/main/java/com/cherrish/android/presentation/calendar/model/ProcedureInfoModel.kt (1)
5-11: LGTM!
@Immutable어노테이션이 적절히 적용되어 Compose의 안정성(stability)을 보장합니다.downTimeDuration을 non-nullable로 변경한 것이 관련 UI 컴포넌트들(ProcedureInfoItem, ProcedureUtil)과 일관성 있게 정렬되어 있습니다.app/src/main/java/com/cherrish/android/data/remote/dto/request/CalendarMonthlyRequestDto.kt (1)
6-12: LGTM!kotlinx.serialization을 사용한 깔끔한 DTO 구현입니다.
@SerialName어노테이션으로 JSON 필드명을 명시적으로 지정한 것이 유지보수성에 좋습니다.app/src/main/java/com/cherrish/android/data/model/CalendarMonthlyRequestModel.kt (1)
5-13: LGTM!데이터 레이어에서 모델과 DTO를 분리하고 extension function으로 매핑하는 패턴이 적절합니다. 단방향 데이터 변환이 명확하게 구현되어 있습니다.
app/src/main/java/com/cherrish/android/presentation/calendar/component/ProcedureInfoItem.kt (1)
29-75: 조건부 클릭 로직이 잘 구현되어 있습니다.
remember를 사용한 색상 메모이제이션과Modifier.then()을 활용한 조건부 클릭 가능 modifier 적용이 적절합니다.downTimeDuration이 0일 때 클릭을 비활성화하는 로직이 명확합니다.app/src/main/java/com/cherrish/android/data/remote/service/CalendarService.kt (1)
11-27: LGTM!Retrofit 서비스 인터페이스가 잘 구현되어 있습니다. suspend 함수 사용으로 코루틴 지원이 적절하고,
BaseResponse래퍼를 통한 일관된 응답 처리 패턴이 좋습니다.getCalendarDaily의date파라미터는LocalDate.toString()으로 ISO-8601 형식(yyyy-MM-dd)으로 전달되므로 표준 포맷이 이미 적용되어 있습니다.app/src/main/java/com/cherrish/android/presentation/calendar/CalendarViewModel.kt (3)
25-34: LGTM! ViewModel 설정 및 초기화가 올바릅니다.Hilt를 통한 의존성 주입과
UiState.Loading초기 상태 설정이 적절합니다. init 블록에서 초기 데이터 로드를 트리거하는 패턴도 권장되는 방식입니다.
69-77: LGTM! 월 변경 로직이 명확합니다.현재 월이면 오늘 날짜를, 아니면 해당 월의 1일을 선택하는 로직이 적절합니다.
163-188: 동일 날짜가 여러 상태 목록에 존재할 경우 덮어쓰기 동작 확인 필요
buildMap에서sensitiveDays→cautionDays→recoveryDays순서로 처리되므로, 동일 날짜가 여러 목록에 있으면 마지막 상태(RECOVERY)만 유지됩니다. 이것이 의도된 우선순위인지 확인이 필요합니다.서버 응답에서 날짜 중복이 발생하지 않는다면 문제없지만, 비즈니스 로직상 우선순위가 다르다면(예:
SENSITIVE가 최우선) 처리 순서를 변경하거나 중복 체크 로직을 추가해야 합니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
sohee6989
left a comment
There was a problem hiding this comment.
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!수고하셨습니다!!!!!!!!!!!!!!!!!!!
| procedureDay = procedure.procedureDay, | ||
| downTimeDuration = procedure.downTimeDuration, | ||
| procedureType = getProcedureType( | ||
| displayMode, |
There was a problem hiding this comment.
p3: 파라미터명 써주시면 가독성이 좀 더 좋을 것 같습니다~!!
싫으시면 어쩔수없구요ㅜ

Related issue 🛠
Work Description ✏️
Screenshot 📸
Screen_Recording_20260116_002737_Cherrish.mp4
Uncompleted Tasks 😅
To Reviewers 📢
캘린더 뷰 찐 최종 ~~~
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항
✏️ Tip: You can customize this high-level summary in your review settings.