Skip to content

Conversation

@uson1004
Copy link
Member

@uson1004 uson1004 commented Oct 28, 2025

개요

https://drive.google.com/file/d/1kPvDZ2Ta0tqk69P0ZkUZwY8VD3ph81UC/view?usp=share_link
면접 후기 작성 플로우 영상입니다
용량 제한으로 구글 드라이브로 올립니다

    Screenshot_20251028_151253 Screenshot_20251028_151323

작업 내용

  • 리뷰 작성
  • 리뷰 조회, 리뷰 검색, 리뷰 필터링을 개발하였습니다
  • 모듈을 생성하였습니다.
  • 데이터클래스 형태의 인자를 주고받을 수 있도록 구현하였습니다
  • 바텀 네비게이션을 추가하였습니다
  • ReviewState, Proccess 이넘 클래스 추가

할 말

compose ui에서 개선할 수 있는 부분 봐주시면 좋을 거 같습니다

Summary by CodeRabbit

  • 새로운 기능

    • 후기 작성 흐름 추가(다단계 작성, 질문/답 입력, 완료 화면)
    • 후기 필터 및 검색 기능 추가
    • 내 후기 조회 및 후기 카운트/질문 조회 기능 추가
    • 하단 네비게이션에 후기 메뉴 추가 및 관련 아이콘·문구 추가
  • 개선사항

    • 후기 상세 화면 및 리뷰 목록 UI 개선
    • API 필터링 옵션(페이지, 지역, 유형 등) 확장
    • 지원 상태 텍스트 및 색상 매핑 업데이트

Copy link
Contributor

@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: 17

♻️ Duplicate comments (18)
core/common/src/main/java/team/retum/common/enums/ApplyStatus.kt (1)

12-13: DOC_FAILED 상태의 UI 처리 누락

과거 리뷰에서 이미 지적되었듯이, 새로 추가된 DOC_FAILED 상태가 ApplyCompanyItem.kt의 색상 매핑에서 명시적으로 처리되지 않습니다. PROCESSING 상태는 UI에서 올바르게 처리되고 있으나, DOC_FAILEDelse 분기로 빠져 의도하지 않은 onPrimary 색상이 할당됩니다.

feature/home/src/main/java/team/retum/home/ui/ApplyCompanyItem.kt (1)

48-54: DOC_FAILED 상태가 여전히 처리되지 않습니다

과거 리뷰에서 지적된 것처럼, ApplyStatus.DOC_FAILEDwhen 표현식에서 명시적으로 처리되지 않아 else 분기를 통해 onPrimary 색상이 할당됩니다. DOC_FAILED("서류 탈락")는 의미상 FAILED("탈락")와 유사하므로 error 색상으로 매핑되어야 합니다.

다음과 같이 수정하세요:

-        ApplyStatus.FAILED, ApplyStatus.REJECTED -> JobisTheme.colors.error
+        ApplyStatus.FAILED, ApplyStatus.DOC_FAILED, ApplyStatus.REJECTED -> JobisTheme.colors.error
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostExpectReviewViewModel.kt (2)

12-27: 중첩 setState 호출을 제거해야 합니다.
setAnswersetQuestionsetState 블록 안에서 다시 setButtonEnabled를 호출하면서 또 다른 setState를 트리거하고 있습니다. BaseViewModel.setStateMutableStateFlow.update를 사용하므로 이 패턴은 마지막 호출이 값을 덮어써 상태 플리커나 레이스를 일으킬 수 있습니다. 한 번의 setState 안에서 필드와 buttonEnabled를 동시에 계산·반영하도록 정리해 주세요.

-    internal fun setAnswer(answer: String) = setState {
-        setButtonEnabled(answer = answer)
-        state.value.copy(answer = answer)
-    }
-
-    internal fun setQuestion(question: String) = setState {
-        setButtonEnabled(question = question)
-        state.value.copy(question = question)
-    }
-
-    private fun setButtonEnabled(
-        answer: String = state.value.answer,
-        question: String = state.value.question,
-    ) = setState {
-        state.value.copy(buttonEnabled = answer.isNotBlank() && question.isNotBlank())
-    }
+    internal fun setAnswer(answer: String) {
+        val question = state.value.question
+        setState {
+            state.value.copy(
+                answer = answer,
+                buttonEnabled = answer.isNotBlank() && question.isNotBlank(),
+            )
+        }
+    }
+
+    internal fun setQuestion(question: String) {
+        val answer = state.value.answer
+        setState {
+            state.value.copy(
+                question = question,
+                buttonEnabled = answer.isNotBlank() && question.isNotBlank(),
+            )
+        }
+    }

29-36: setEmpty가 상태를 실제로 비우지 못합니다.
setEmptycopy만 호출하고 setState로 적용하지 않아 onNextClick이 이전 질문/답변 값을 그대로 전파합니다. 버튼 비활성화도 되지 않습니다. 먼저 상태를 비우고 버튼도 꺼지게 만든 뒤 사이드 이펙트를 보내도록 수정해 주세요.

-    internal fun setEmpty() {
-        with(state.value) {
-            copy(
-                question = "",
-                answer = "",
-            )
-        }
-        onNextClick()
-    }
+    internal fun setEmpty() {
+        setState {
+            state.value.copy(
+                question = "",
+                answer = "",
+                buttonEnabled = false,
+            )
+        }
+        onNextClick()
+    }
feature/post-review/src/main/res/values/strings.xml (1)

30-30: 이전 리뷰 코멘트가 이미 반영되었습니다.

"잘못된 요청이에요"로 올바르게 수정되어 있습니다.

feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (3)

22-23: navArgument 타입 명시 필요 및 companyId는 LongType 사용

이전 리뷰에서 지적된 문제가 아직 해결되지 않았습니다. navArgument 블록에 type =을 명시하고, companyIdLongType으로 변경하여 수동 파싱을 제거해야 합니다.

다음 diff를 적용하세요:

-            navArgument(ResourceKeys.COMPANY_NAME) { NavType.StringType },
-            navArgument(ResourceKeys.COMPANY_ID) { NavType.StringType },
+            navArgument(ResourceKeys.COMPANY_NAME) { type = NavType.StringType },
+            navArgument(ResourceKeys.COMPANY_ID) { type = NavType.LongType },

29-30: companyName URI 인코딩 및 companyId 타입 안전성 개선

이전 리뷰에서 지적된 문제가 아직 해결되지 않았습니다:

  1. 공백이나 특수문자가 포함된 회사명은 네비게이션 경로를 깨뜨립니다.
  2. companyId를 String으로 받아 파싱하면서 0L 디폴트를 사용하면 실패를 숨깁니다.

다음 diff를 적용하세요:

+import android.net.Uri
-import kotlin.text.toLongOrNull
@@
-            companyName = it.arguments?.getString(ResourceKeys.COMPANY_NAME) ?: "",
-            companyId = it.arguments?.getString(ResourceKeys.COMPANY_ID)?.toLongOrNull() ?: 0L,
+            companyName = requireNotNull(it.arguments).getString(ResourceKeys.COMPANY_NAME).orEmpty(),
+            companyId = requireNotNull(it.arguments).getLong(ResourceKeys.COMPANY_ID),

35-39: navigateToPostReview에서 companyName URI 인코딩 필요

이전 리뷰에서 지적된 문제가 아직 해결되지 않았습니다. companyName을 URI 인코딩하지 않으면 공백이나 특수문자로 인해 네비게이션이 실패할 수 있습니다.

다음 diff를 적용하세요:

+import android.net.Uri
@@
 fun NavController.navigateToPostReview(companyName: String, companyId: Long) {
-    navigate("$NAVIGATION_POST_REVIEW/$companyName/$companyId") {
+    navigate("$NAVIGATION_POST_REVIEW/${Uri.encode(companyName)}/$companyId") {
         popUpTo(NAVIGATION_POST_NEXT_REVIEW) { inclusive = false }
         popUpTo(NAVIGATION_POST_EXPECT_REVIEW) { inclusive = false }
     }
 }
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (2)

19-29: 질문 로드 실패 처리 누락

이전 리뷰에서 지적된 문제가 아직 해결되지 않았습니다. 네트워크 실패 시 상태가 갱신되지 않아 UX가 멈춘 것처럼 보일 수 있습니다.

다음과 같이 실패 분기를 추가하는 것을 권장합니다:

         viewModelScope.launch(Dispatchers.IO) {
             fetchQuestionsUseCase().onSuccess {
                 setState {
                     state.value.copy(
                         questions = it.questions,
+                        answers = List(it.questions.size) { "" },
+                        qnaElements = emptyList(),
+                        buttonEnabled = false,
                     )
                 }
+            }.onFailure {
+                setState {
+                    state.value.copy(
+                        questions = emptyList(),
+                        answers = emptyList(),
+                        qnaElements = emptyList(),
+                        buttonEnabled = false,
+                    )
+                }
+                // TODO: 실패 사이드이펙트/토스트 노출
             }
         }

47-61: answers 길이 검증 및 버튼 활성화 로직 누락

이전 리뷰에서 지적된 것처럼, 질문 수와 answers 길이가 불일치하면 zip으로 데이터가 잘려나가 데이터 유실이 발생합니다. 또한 모든 답변이 채워졌을 때만 버튼을 활성화해야 합니다.

다음과 같이 길이 검증과 버튼 활성화를 함께 반영해주세요:

     internal fun setQuestion() {
         setState {
             with(state.value) {
-                val updatedQuestions = questions.map { it.id }
-                copy(
-                    qnaElements = updatedQuestions.zip(answers).map { (q, a) ->
-                        PostReviewContent(
-                            question = q,
-                            answer = a,
-                        )
-                    },
-                )
+                val ids = questions.map { it.id }
+                val pairs = ids.zip(answers)
+                val allAnswered = answers.size == ids.size && answers.all { it.isNotBlank() }
+                copy(
+                    qnaElements = pairs.map { (q, a) -> PostReviewContent(question = q, answer = a) },
+                    answers = answers,
+                    buttonEnabled = allAnswered,
+                )
             }
         }
     }
feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (2)

55-55: answers 리스트 고정 크기로 인한 크래시 가능성

이전 리뷰에서 지적된 문제가 아직 해결되지 않았습니다. 질문 수(state.questions.size)와 answers 크기가 불일치하면 answers[page]에서 IndexOutOfBoundsException이 발생합니다.

다음 diff를 적용하세요:

-    val answers = remember { mutableStateListOf("", "", "") }
+    val answers = remember(state.questions) {
+        mutableStateListOf(*Array(state.questions.size) { "" })
+    }

또는 toMutableStateList() 사용:

+import androidx.compose.runtime.toMutableStateList
@@
-    val answers = remember { mutableStateListOf("", "", "") }
+    val answers = remember(state.questions) {
+        List(state.questions.size) { "" }.toMutableStateList()
+    }

166-166: 마지막 페이지 하드코딩 제거 필요

이전 리뷰에서 지적된 문제가 아직 해결되지 않았습니다. 페이지 수가 3이 아닐 경우 흐름이 깨집니다. 마지막 인덱스를 동적으로 계산해야 합니다.

다음 diff를 적용하세요:

                     onClick = {
                         setQuestion()
                         coroutineScope.launch {
-                            if (pagerState.currentPage != 2) pagerState.animateScrollToPage(pagerState.currentPage + 1) else onPostExpectReviewClick()
+                            val lastPageIndex = pagerState.pageCount - 1
+                            if (pagerState.currentPage < lastPageIndex) {
+                                pagerState.animateScrollToPage(pagerState.currentPage + 1)
+                            } else {
+                                onPostExpectReviewClick()
+                            }
                         }
                     },
feature/post-review/src/main/java/team/retum/post/review/ui/PostExpectReviewScreen.kt (1)

88-154: 하단 배치가 깨지지 않도록 Column 에 전체 높이를 부여하세요

Spacer(weight = 1f) 로 버튼을 하단에 붙이려면 부모 Column 이 가용 높이를 차지해야 합니다. 현재 Modifier.fillMaxSize() 가 없어 버튼이 중간에 머무릅니다. 기존 지적과 동일하니 아래와 같이 수정해 주세요.

-import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
@@
-    Column {
+    Column(
+        modifier = Modifier.fillMaxSize(),
+    ) {
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)

33-39: 라우트 인코딩 누락으로 인한 네비게이션 실패

JSON 안에 /, ?, % 등이 포함되면 경로가 분리되어 목적지 매칭이 실패하고, 예외를 메시지 없이 던져 디버깅도 어렵습니다. Uri.encode/Uri.decode와 명시적인 예외 메시지를 추가해 주세요.

+import android.net.Uri
@@
 fun NavController.navigateToPostNextReview(reviewData: PostReviewData) {
-    navigate("$NAVIGATION_POST_NEXT_REVIEW/${reviewData.toJsonString()}")
+    val payload = Uri.encode(reviewData.toJsonString())
+    navigate("$NAVIGATION_POST_NEXT_REVIEW/$payload")
 }
 
 internal fun NavBackStackEntry.getReviewData(): PostReviewData {
-    val reviewData = arguments?.getString(ResourceKeys.REVIEW_DATA) ?: throw NullPointerException()
-    return reviewData.toReviewData()
+    val encoded = requireNotNull(arguments?.getString(ResourceKeys.REVIEW_DATA)) {
+        "Missing '${ResourceKeys.REVIEW_DATA}' argument for $NAVIGATION_POST_NEXT_REVIEW"
+    }
+    return Uri.decode(encoded).toReviewData()
 }
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewScreen.kt (1)

704-708: 힌트 문자열을 필드 용도에 맞게 교체해주세요.

면접관 수 입력 필드에 여전히 search 문자열을 사용하고 있어 UX가 어색합니다. 면접관 수에 맞는 새로운 string 리소스를 추가한 뒤 해당 리소스를 사용해주세요.

-            hint = stringResource(id = R.string.search),
+            hint = stringResource(id = R.string.hint_interviewer_count),

hint_interviewer_count 리소스 추가도 함께 반영해야 합니다.

feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (3)

107-116: [DUPLICATE] Compose SnapshotStateList를 IO 스레드에서 변경하는 스레드 안전성 문제

Line 114에서 techs.addAll(it.codes)Dispatchers.IO에서 호출하면 스냅샷 충돌 및 크래시 위험이 있습니다. 이 문제는 이전 리뷰에서 이미 지적되었습니다.

메인 스레드에서 변경하거나 StateFlow로 변경하세요:

 internal fun fetchCodes(keyword: String?) =
     viewModelScope.launch(Dispatchers.IO) {
         fetchCodeUseCase(
             keyword = keyword,
             type = CodeType.JOB,
             parentCode = null,
         ).onSuccess {
-            techs.addAll(it.codes)
+            withContext(Dispatchers.Main) {
+                techs.addAll(it.codes)
+            }
         }
     }

130-140: [DUPLICATE] 버튼 활성화 로직 역전 및 NPE 위험

Line 137에서 !state.value.keyword?.isNotEmpty()!!는 키워드가 입력되면 버튼을 비활성화하는 역전된 로직이며, keyword가 null일 경우 NPE 위험이 있습니다. 이 문제는 이전 리뷰에서 이미 지적되었습니다.

수정 적용:

 else -> {
-   setState { state.value.copy(buttonEnabled = !state.value.keyword?.isNotEmpty()!!) }
+   setState {
+       state.value.copy(
+           buttonEnabled = !state.value.keyword.isNullOrEmpty()
+       )
+   }
 }

187-197: [DUPLICATE] interviewerCount 파싱 시 크래시 위험

Line 191에서 count.toInt()는 빈 문자열이나 숫자가 아닌 입력 시 NumberFormatException을 발생시킵니다. 이 문제는 이전 리뷰에서 이미 지적되었습니다.

안전한 파싱 적용:

 internal fun onNextClick() {
     with(state.value) {
+        val parsedCount = count.toIntOrNull()
+        if (parsedCount == null || parsedCount <= 0) {
+            postSideEffect(PostReviewSideEffect.BadRequest)
+            return
+        }
         postSideEffect(PostReviewSideEffect.MoveToNext(
             companyId = companyId,
-            interviewerCount = count.toInt(),
+            interviewerCount = parsedCount,
             jobCode = selectedTech ?: 0,
             interviewType = interviewType,
             location = interviewLocation,
         ))
     }
 }
🧹 Nitpick comments (10)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (1)

33-47: 에러 핸들링 추가를 고려하세요.

fetchCodeUseCase 실패 시 처리가 없어 사용자가 빈 목록만 보게 됩니다. 에러 상태를 추가하거나 로깅을 고려하세요.

             fetchCodeUseCase(
                 keyword = null,
                 type = CodeType.JOB,
                 parentCode = null,
             ).onSuccess {
                 setState {
                     state.value.copy(
                         majorList = it.codes,
                     )
                 }
+            }.onFailure {
+                // 로깅 또는 에러 상태 처리 고려
             }
feature/post-review/src/main/java/team/retum/post/review/model/PostReviewData.kt (1)

30-38: deprecated API 사용을 피하세요.

URLEncoder.encode(String, String)URLDecoder.decode(String, String)는 deprecated API입니다. StandardCharsets를 사용하여 현대적이고 안전한 API로 변경하는 것을 권장합니다.

다음과 같이 수정하세요:

+import java.nio.charset.StandardCharsets
+
 internal fun PostReviewData.toJsonString(): String {
     val json = Json.encodeToString(this)
-    return URLEncoder.encode(json, "UTF-8")
+    return URLEncoder.encode(json, StandardCharsets.UTF_8)
 }
 
 internal fun String.toReviewData(): PostReviewData {
-    val decoded = URLDecoder.decode(this, "UTF-8")
+    val decoded = URLDecoder.decode(this, StandardCharsets.UTF_8)
     return Json.decodeFromString<PostReviewData>(decoded)
 }
feature/review/src/main/java/team/retum/review/ui/ReviewScreen.kt (1)

77-89: items() 확장 함수 대신 itemsIndexed() 사용을 권장합니다.

items(state.reviews.size)와 인덱스 접근 대신, LazyColumn의 itemsIndexed() 확장 함수를 사용하면 더 간결하고 안전합니다.

다음과 같이 리팩토링할 수 있습니다:

+import androidx.compose.foundation.lazy.itemsIndexed
+
-        LazyColumn {
-            items(state.reviews.size) {
-                val review = state.reviews[it]
+        LazyColumn {
+            itemsIndexed(state.reviews) { _, review ->
                 ReviewItems(
                     companyImageUrl = review.companyLogoUrl,
                     companyName = review.companyName,
                     reviewId = review.reviewId,
                     writer = review.writer,
                     major = review.major,
                     onReviewDetailClick = onReviewDetailClick,
                 )
             }
         }
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1)

38-38: TODO 주석: API 요청 최적화 필요

빈번한 API 요청 문제를 해결해야 합니다. 캐싱, 요청 중복 제거, 또는 상태 관리 개선 등의 방법을 고려해보세요.

이 문제를 해결하는 구현을 생성하거나 새로운 이슈를 열어드릴까요?

feature/review/src/main/java/team/retum/review/viewmodel/SearchReviewsViewModel.kt (1)

33-60: 검색어가 비면 결과도 초기화해 주세요

검색어를 모두 지우면 fetchReviews() 는 호출되지 않는데, 이전 검색 결과가 그대로 남아 있어 화면과 검색어가 불일치합니다. 공백일 때는 리스트와 빈 상태 플래그를 초기화하는 편이 자연스럽습니다.

         viewModelScope.launch {
-            state.map { it.keyword }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS).collect {
-                if (!it.isNullOrBlank()) {
-                    fetchReviews()
-                }
+            state.map { it.keyword }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS).collect { keyword ->
+                if (keyword.isNullOrBlank()) {
+                    setState {
+                        state.value.copy(
+                            reviews = emptyList(),
+                            showRecruitmentsEmptyContent = false,
+                        )
+                    }
+                } else {
+                    fetchReviews()
                 }
             }
         }
feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (5)

113-122: 파라미터 수가 많아 데이터 클래스 사용 권장

8개의 파라미터를 개별적으로 전달하고 있습니다. 유지보수성과 가독성 향상을 위해 데이터 클래스로 그룹화하는 것을 고려해보세요.

다음과 같이 데이터 클래스를 사용할 수 있습니다:

data class StudentInfoData(
    val writer: String,
    val major: String,
    val year: Int,
    val companyName: String,
    val location: InterviewLocation,
    val type: InterviewType,
    val interviewerCount: Int,
    val selectedTabIndex: Int,
)

@Composable
private fun StudentInfo(data: StudentInfoData) {
    // implementation
}

133-140: 복잡한 문자열 포맷팅 로직 단순화 권장

중첩된 stringResource 호출과 조건문이 가독성을 저해합니다. 로직을 별도로 추출하는 것을 고려해보세요.

다음과 같이 리팩토링할 수 있습니다:

val reviewType = if (selectedTabIndex != 0) {
    stringResource(id = R.string.reviewed_question)
} else {
    stringResource(id = R.string.interview_review)
}

JobisText(
    text = stringResource(
        id = R.string.review_writer_title,
        writer,
        reviewType,
    ),
    style = JobisTypography.PageTitle,
)

254-258: 텍스트 오버플로우 처리 명시 권장

maxLines = 3을 설정했지만 JobisText의 기본 overflow 속성에 의존하고 있습니다. 명시적으로 TextOverflow.Ellipsis를 지정하는 것이 좋습니다.

JobisText의 기본값이 Ellipsis이므로 현재는 문제없지만, 명시성을 위해 다음과 같이 작성할 수 있습니다:

Text(
    text = buildAnnotatedString { /* ... */ },
    style = JobisTypography.Description,
    modifier = Modifier
        .padding(top = 12.dp)
        .fillMaxWidth(0.5f),
    maxLines = 3,
    overflow = TextOverflow.Ellipsis, // 명시적 지정
)

274-274: 사용하지 않는 index 변수 제거 권장

forEachIndexed를 사용하지만 index 변수를 사용하지 않습니다. forEach로 변경하는 것을 고려하세요.

-    review.forEachIndexed { index, reviewItem ->
+    review.forEach { reviewItem ->

344-350: 답변 텍스트 오버플로우 처리 검토

maxLines = 3을 설정했지만 긴 답변이 잘릴 경우 사용자가 전체 내용을 볼 방법이 없습니다. 확장 상태에서는 전체 텍스트를 표시하거나, 최소한 말줄임표가 표시되도록 해야 합니다.

확장 상태에서는 전체 답변을 표시하는 것을 고려하세요:

                            JobisText(
                                text = reviewItem.answer,
                                color = JobisTheme.colors.inverseOnSurface,
                                style = JobisTypography.Description,
                                textAlign = TextAlign.Center,
-                                maxLines = 3,
+                                // 확장된 상태에서는 전체 텍스트 표시
                            )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac5b061 and 13a317c.

⛔ Files ignored due to path filters (1)
  • feature/bookmark/src/main/res/drawable/ic_empty_bookmark.png is excluded by !**/*.png
📒 Files selected for processing (86)
  • app/build.gradle.kts (1 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (3 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (3 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/root/RootNavigation.kt (2 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/root/RootScreen.kt (5 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/ui/BottomMenu.kt (2 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/ui/BottomNavigationBar.kt (1 hunks)
  • app/src/main/res/drawable/ic_review.xml (1 hunks)
  • app/src/main/res/values/strings.xml (1 hunks)
  • core/common/src/main/java/team/retum/common/enums/ApplyStatus.kt (1 hunks)
  • core/common/src/main/java/team/retum/common/enums/InterviewLocation.kt (1 hunks)
  • core/common/src/main/java/team/retum/common/enums/InterviewType.kt (1 hunks)
  • core/common/src/main/java/team/retum/common/enums/ReviewProcess.kt (1 hunks)
  • core/common/src/main/java/team/retum/common/utils/ResourceKeys.kt (1 hunks)
  • core/data/src/main/java/team/retum/data/repository/review/ReviewRepository.kt (1 hunks)
  • core/data/src/main/java/team/retum/data/repository/review/ReviewRepositoryImpl.kt (2 hunks)
  • core/design-system/src/main/java/team/retum/jobisdesignsystemv2/foundation/JobisColor.kt (1 hunks)
  • core/design-system/src/main/java/team/retum/jobisdesignsystemv2/foundation/JobisIcon.kt (1 hunks)
  • core/design-system/src/main/java/team/retum/jobisdesignsystemv2/review/ReviewContent.kt (1 hunks)
  • core/design-system/src/main/res/drawable/ic_asterisk.xml (1 hunks)
  • core/design-system/src/main/res/drawable/ic_success.xml (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/FetchReviewDetailEntity.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/FetchReviewsEntity.kt (2 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/MyReviews.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/PostReviewEntity.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/QuestionsEntity.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/ReviewsCountEntity.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/usecase/review/FetchMyReviewUseCase.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/usecase/review/FetchQuestionsUseCase.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/usecase/review/FetchReviewsCountUseCase.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/usecase/review/FetchReviewsUseCase.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/api/ReviewApi.kt (2 hunks)
  • core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSource.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSourceImpl.kt (2 hunks)
  • core/network/src/main/java/team/retum/network/di/RequestUrls.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/model/request/PostReviewRequest.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/model/response/FetchMyReviewResponse.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/model/response/FetchQuestionsResponse.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/model/response/FetchReviewDetailResponse.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/model/response/FetchReviewsCountResponse.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/model/response/FetchReviewsResponse.kt (1 hunks)
  • feature/bookmark/src/main/java/team/retum/bookmark/ui/BookmarkScreen.kt (1 hunks)
  • feature/company/src/main/java/team/retum/company/navigation/CompanyDetailsNavigation.kt (1 hunks)
  • feature/company/src/main/java/team/retum/company/ui/CompanyDetailsScreen.kt (3 hunks)
  • feature/company/src/main/java/team/retum/company/viewmodel/CompanyDetailsViewModel.kt (1 hunks)
  • feature/home/src/main/java/team/retum/home/ui/ApplyCompanyItem.kt (1 hunks)
  • feature/home/src/main/java/team/retum/home/ui/HomeScreen.kt (1 hunks)
  • feature/mypage/src/main/java/team/retum/jobis/navigation/MyPageNavigation.kt (1 hunks)
  • feature/mypage/src/main/java/team/retum/jobis/ui/MyPageScreen.kt (3 hunks)
  • feature/post-review/.gitignore (1 hunks)
  • feature/post-review/build.gradle.kts (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/model/PostReviewData.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostExpectReviewScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostExpectReviewViewModel.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (1 hunks)
  • feature/post-review/src/main/res/values/strings.xml (1 hunks)
  • feature/review/build.gradle.kts (2 hunks)
  • feature/review/src/main/java/team/retum/review/navigation/PostReviewNavigation.kt (0 hunks)
  • feature/review/src/main/java/team/retum/review/navigation/ReviewDetailsNavigation.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/navigation/ReviewFilterNavigation.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/navigation/ReviewNavigation.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/navigation/ReviewsNavigation.kt (0 hunks)
  • feature/review/src/main/java/team/retum/review/navigation/SearchReviewsNavigation.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/ui/PostReviewScreen.kt (0 hunks)
  • feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (2 hunks)
  • feature/review/src/main/java/team/retum/review/ui/ReviewFilterScreen.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/ui/ReviewScreen.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/ui/ReviewsScreen.kt (0 hunks)
  • feature/review/src/main/java/team/retum/review/ui/SearchReviewScreen.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/ui/component/ReviewItems.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/PostReviewViewModel.kt (0 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewDetailsViewModel.kt (2 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewViewModel.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewsViewModel.kt (0 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/SearchReviewsViewModel.kt (1 hunks)
  • feature/review/src/main/res/values/strings.xml (1 hunks)
  • settings.gradle.kts (1 hunks)
💤 Files with no reviewable changes (6)
  • feature/review/src/main/java/team/retum/review/navigation/PostReviewNavigation.kt
  • feature/review/src/main/java/team/retum/review/viewmodel/PostReviewViewModel.kt
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewsViewModel.kt
  • feature/review/src/main/java/team/retum/review/ui/PostReviewScreen.kt
  • feature/review/src/main/java/team/retum/review/navigation/ReviewsNavigation.kt
  • feature/review/src/main/java/team/retum/review/ui/ReviewsScreen.kt
🧰 Additional context used
🧬 Code graph analysis (31)
app/build.gradle.kts (1)
buildSrc/src/main/kotlin/GradlePluginExtensions.kt (1)
  • implementation (15-17)
feature/review/build.gradle.kts (1)
buildSrc/src/main/kotlin/GradlePluginExtensions.kt (1)
  • implementation (15-17)
feature/post-review/src/main/java/team/retum/post/review/ui/PostExpectReviewScreen.kt (4)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/textfield/JobisTextField.kt (1)
  • JobisTextField (355-436)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/button/JobisButton.kt (1)
  • JobisButton (322-340)
feature/review/src/main/java/team/retum/review/navigation/SearchReviewsNavigation.kt (1)
feature/review/src/main/java/team/retum/review/ui/SearchReviewScreen.kt (1)
  • SearchReview (19-33)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1)
  • PostReviewComplete (29-47)
feature/review/src/main/java/team/retum/review/ui/ReviewScreen.kt (4)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewViewModel.kt (4)
  • setYear (23-25)
  • setCode (19-21)
  • setLocation (31-33)
  • clearReview (35-44)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisLargeTopAppBar (153-181)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/button/JobisIconButton.kt (1)
  • JobisIconButton (74-93)
feature/review/src/main/java/team/retum/review/ui/component/ReviewItems.kt (1)
  • ReviewItems (25-81)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/review/ReviewContent.kt (1)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/card/JobisCard.kt (1)
  • JobisCard (43-81)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (2)
  • setState (60-64)
  • postSideEffect (106-110)
feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (5)
app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (1)
  • navigateToPostExpectReview (149-151)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)
  • navigateToPostExpectReview (31-33)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/textfield/JobisTextField.kt (1)
  • JobisTextField (355-436)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (2)
  • setAnswer (31-41)
  • setQuestion (47-61)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (2)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (1)
  • navigateToPostReview (35-40)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostExpectReviewScreen.kt (1)
  • PostExpectReview (34-76)
app/src/main/java/team/retum/jobisandroidv2/root/RootScreen.kt (1)
feature/review/src/main/java/team/retum/review/navigation/ReviewNavigation.kt (1)
  • review (10-24)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (1)
  • PostNextReview (45-81)
feature/post-review/build.gradle.kts (1)
buildSrc/src/main/kotlin/GradlePluginExtensions.kt (2)
  • android (8-10)
  • implementation (15-17)
feature/review/src/main/java/team/retum/review/ui/ReviewFilterScreen.kt (4)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/button/JobisButton.kt (1)
  • JobisButton (322-340)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/checkbox/CheckBox.kt (1)
  • JobisCheckBox (21-66)
feature/review/src/main/java/team/retum/review/ui/component/ReviewItems.kt (1)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (5)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/tab/TabBar.kt (1)
  • TabBar (21-68)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/card/JobisCard.kt (1)
  • JobisCard (43-81)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/empty/EmptyContent.kt (1)
  • EmptyContent (21-56)
feature/review/src/main/java/team/retum/review/navigation/ReviewNavigation.kt (1)
feature/review/src/main/java/team/retum/review/ui/ReviewScreen.kt (1)
  • Review (24-50)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (2)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (2)
  • setState (60-64)
  • postSideEffect (106-110)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostExpectReviewViewModel.kt (1)
  • setButtonEnabled (22-27)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewScreen.kt (1)
  • PostReview (66-135)
feature/review/src/main/java/team/retum/review/navigation/ReviewFilterNavigation.kt (1)
feature/review/src/main/java/team/retum/review/ui/ReviewFilterScreen.kt (1)
  • ReviewFilter (47-66)
feature/review/src/main/java/team/retum/review/ui/SearchReviewScreen.kt (4)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/textfield/JobisTextField.kt (1)
  • JobisTextField (355-436)
feature/review/src/main/java/team/retum/review/ui/component/ReviewItems.kt (1)
  • ReviewItems (25-81)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/empty/EmptyContent.kt (1)
  • EmptyContent (21-56)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostExpectReviewViewModel.kt (3)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (2)
  • setState (60-64)
  • postSideEffect (106-110)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (2)
  • setButtonEnabled (130-140)
  • onNextClick (187-197)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (1)
  • onNextClick (63-71)
feature/review/src/main/java/team/retum/review/viewmodel/SearchReviewsViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewScreen.kt (9)
app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (1)
  • navigateToPostNextReview (141-143)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)
  • navigateToPostNextReview (33-35)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisLargeTopAppBar (153-181)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/button/JobisButton.kt (1)
  • JobisButton (322-340)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (6)
  • setButtonClear (179-185)
  • setInterviewType (151-158)
  • setInterviewLocation (160-167)
  • setChecked (142-149)
  • setKeyword (59-67)
  • setSelectedTech (104-105)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/button/JobisIconButton.kt (1)
  • JobisIconButton (74-93)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/textfield/JobisTextField.kt (1)
  • JobisTextField (355-436)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/checkbox/CheckBox.kt (1)
  • JobisCheckBox (21-66)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewDetailsViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
feature/review/src/main/java/team/retum/review/navigation/ReviewDetailsNavigation.kt (1)
feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (1)
  • ReviewDetails (48-75)
feature/company/src/main/java/team/retum/company/viewmodel/CompanyDetailsViewModel.kt (1)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewViewModel.kt (1)
  • fetchReviewsUseCase (14-63)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (7)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (1)
  • postReview (15-33)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)
  • postNextReview (17-31)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)
  • postExpectReview (15-29)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1)
  • postReviewComplete (10-22)
feature/review/src/main/java/team/retum/review/navigation/ReviewDetailsNavigation.kt (1)
  • reviewDetails (13-29)
feature/review/src/main/java/team/retum/review/navigation/ReviewFilterNavigation.kt (1)
  • reviewFilter (10-18)
feature/review/src/main/java/team/retum/review/navigation/SearchReviewsNavigation.kt (1)
  • searchReview (10-22)
🪛 detekt (1.23.8)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt

[warning] 38-38: A call to the default constructor of an exception was detected. Instead one of the constructor overloads should be called. This allows to provide more meaningful exceptions.

(detekt.exceptions.ThrowingExceptionsWithoutMessageOrCause)

🔇 Additional comments (50)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/review/ReviewContent.kt (2)

22-23: 좋은 리팩토링입니다!

reviewId 타입을 String에서 Long으로 변경하고 onClick 시그니처를 (Long) -> Unit으로 단순화한 것은 훌륭한 개선입니다. ID에 Long 타입을 사용하는 것이 더 표준적이며 타입 안정성을 높여줍니다. 또한 네비게이션에는 리뷰 ID만 필요하므로 API가 더욱 명확해졌습니다.


27-27: 구현이 올바릅니다.

onClick 핸들러에 reviewId만 전달하도록 구현이 정확하게 업데이트되었습니다. writer 파라미터는 여전히 UI 표시에 사용되고 있어 적절합니다.

core/network/src/main/java/team/retum/network/di/RequestUrls.kt (1)

85-90: 리뷰 API 경로 리팩토링 확인 완료
상세·목록·질문·집계·내 리뷰 경로가 공통 path 기반으로 정리되어 새 Retrofit 시그니처와 일관됩니다. GET/POST 경로도 상수 재사용이 가능해 혼선이 줄어들 것 같습니다.

core/common/src/main/java/team/retum/common/enums/ApplyStatus.kt (1)

6-6: SEND 라벨 변경 의도를 확인하세요.

"지원 중"에서 "전송"으로 라벨이 변경되었습니다. 이 변경이 의도된 것이며 모든 UI 텍스트와 사용자 경험상 일관성이 있는지 확인이 필요합니다.

feature/home/src/main/java/team/retum/home/ui/ApplyCompanyItem.kt (1)

51-51: LGTM: SEND와 PROCESSING 상태 처리가 올바르게 추가됨

새로 추가된 SENDPROCESSING 상태를 secondary 색상으로 매핑한 것은 적절합니다.

feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (2)

61-91: LGTM!

필터 선택 토글 로직이 올바르게 구현되었습니다. 동일한 값 재선택 시 선택 해제하는 패턴이 사용자 경험에 적합합니다.


94-113: LGTM!

ReviewsFilterState 데이터 클래스가 적절하게 정의되었습니다. @Immutable 어노테이션과 팩토리 메서드 패턴이 Compose 모범 사례에 부합합니다.

feature/review/src/main/java/team/retum/review/viewmodel/ReviewDetailsViewModel.kt (1)

34-36: LGTM!

setTabIndex 함수는 탭 인덱스를 올바르게 업데이트하며, 구현이 명확합니다.

feature/bookmark/src/main/java/team/retum/bookmark/ui/BookmarkScreen.kt (1)

135-135: 드로어블 리소스 변경 - 시각적 적절성 검증 필요

ic_empty_bookmark에서 설계 시스템의 제네릭 ic_empty로 변경되었습니다. 새 리소스는 디자인 시스템에 존재하며(core/design-system/src/main/res/drawable/ic_empty.png), 이 변경이 BookmarkScreen에만 적용되어 있습니다.

확인 사항:

  • 제네릭 ic_empty가 북마크 빈 상태 컨텍스트에 시각적으로 적절한지 검증
  • 이것이 의도된 디자인 시스템 통합인지 확인

contentDescription은 여전히 "empty bookmark"이므로, 선택된 아이콘이 북마크 컨텍스트와 일치하는지 확인해주세요.

feature/post-review/src/main/res/values/strings.xml (1)

1-58: LGTM!

문자열 리소스가 화면별로 잘 정리되어 있으며, 한국어 표기법도 적절합니다.

app/src/main/java/team/retum/jobisandroidv2/ui/BottomNavigationBar.kt (1)

28-28: LGTM!

하단 네비게이션에 Review 메뉴 아이템이 올바르게 추가되었습니다.

settings.gradle.kts (1)

47-47: LGTM!

새로운 post-review 모듈이 올바르게 추가되었습니다.

app/src/main/res/values/strings.xml (1)

6-6: LGTM!

후기 기능을 위한 문자열 리소스가 올바르게 추가되었습니다.

core/design-system/src/main/res/drawable/ic_asterisk.xml (1)

1-9: LGTM!

필수 입력 표시를 위한 별표 아이콘이 올바르게 정의되었습니다.

feature/company/src/main/java/team/retum/company/viewmodel/CompanyDetailsViewModel.kt (1)

45-53: LGTM!

fetchReviewsUseCase의 확장된 시그니처에 맞게 파라미터가 올바르게 전달되고 있습니다. 회사 상세 화면에서는 companyId만 필요하므로 나머지 파라미터를 null로 전달하는 것이 적절합니다.

app/src/main/java/team/retum/jobisandroidv2/ui/BottomMenu.kt (2)

10-10: LGTM!

NAVIGATION_REVIEW import가 올바르게 추가되었습니다.


29-33: LGTM!

Review 하단 메뉴 아이템이 기존 패턴과 일관되게 잘 정의되었습니다.

core/common/src/main/java/team/retum/common/enums/ReviewProcess.kt (1)

4-8: 검증 완료 - 모든 변경이 올바르게 적용되었습니다.

검증 결과, ReviewProcess 열거형의 상수 변경(QUESTION, TECH, FINISH → INTERVIEW_TYPE, INTERVIEW_LOCATION, TECH_STACK, INTERVIEWER_COUNT, SUMMARY)이 코드베이스 전체에 완전하고 일관되게 적용되었습니다:

  • 제거된 상수에 대한 직접 참조 없음
  • 문자열 기반 참조 없음
  • 모든 사용처에서 새로운 상수로 업데이트됨 (PostReviewViewModel.kt, PostReviewScreen.kt)

breaking change이지만 변경이 완전하게 처리되어 컴파일 오류나 런타임 문제가 발생하지 않습니다.

core/design-system/src/main/java/team/retum/jobisdesignsystemv2/foundation/JobisIcon.kt (1)

40-40: 변경 사항이 적절합니다.

기존 패턴을 따라 새로운 아이콘 상수를 추가했습니다.

core/design-system/src/main/res/drawable/ic_success.xml (1)

1-9: 벡터 드로어블이 올바르게 정의되었습니다.

표준 벡터 드로어블 형식을 따르고 있으며, 성공 완료 화면에서 사용될 아이콘으로 적절합니다.

core/network/src/main/java/team/retum/network/model/response/FetchReviewDetailResponse.kt (2)

23-27: 내부 데이터 클래스 리팩토링이 적절합니다.

Detail에서 QnAs로 명명이 개선되었고, area 필드가 제거되어 구조가 단순화되었습니다. 명명이 더 명확해졌습니다.


10-20: 검증 완료 - 모든 변경사항이 올바르게 반영되었습니다.

새로운 필드 구조가 모든 계층에서 일관되게 처리되고 있습니다. JSON 필드명(review_id, company_name, company_name 등)이 모두 적절한 snake_case로 설정되어 있으며, API → DataSource → Repository → UseCase → ViewModel 전체 파이프라인에서 toEntity() 확장함수를 통해 정상적으로 매핑되고 있습니다. QnAs 중첩 클래스도 별도 매핑함수로 지원되고 있습니다.

app/build.gradle.kts (1)

118-118: 모듈 의존성 추가가 적절합니다.

새로운 post-review 기능 모듈을 앱에 통합하는 표준적인 방식입니다.

app/src/main/res/drawable/ic_review.xml (1)

1-9: 벡터 드로어블이 올바르게 정의되었습니다.

하단 네비게이션용 리뷰 아이콘이 적절한 크기(20dp)와 색상으로 정의되었습니다.

core/domain/src/main/java/team/retum/usecase/entity/ReviewsCountEntity.kt (1)

5-11: 엔티티 정의와 매핑이 적절합니다.

단순하고 명확한 엔티티 구조를 따르고 있으며, 네트워크 응답에서 도메인 엔티티로의 매핑이 올바르게 구현되었습니다. totalPageCountLong 타입을 사용한 것도 적절합니다.

core/common/src/main/java/team/retum/common/enums/InterviewType.kt (1)

3-7: 백엔드 API 스펙 확인이 필요합니다.

현재 InterviewType 열거형은 명시적인 직렬화 어노테이션이 없으며, Moshi의 기본 동작에 따라 INDIVIDUAL, GROUP, OTHER 형식으로 직렬화됩니다. 코드베이스에서 커스텀 어댑터나 테스트 파일을 찾을 수 없었으므로, 백엔드 API가 실제로 이 형식을 기대하는지 백엔드 스펙을 통해 직접 확인해야 합니다.

core/common/src/main/java/team/retum/common/enums/InterviewLocation.kt (1)

3-8: 백엔드 API 스펙을 통해 enum 직렬화 형식 검증 필요

InterviewLocation enum은 Moshi에 의해 enum 상수명이 그대로 직렬화됩니다 (DAEJEON, SEOUL, GYEONGGI, OTHER). InterviewType과 동일하게 명시적인 직렬화 어노테이션이 없으므로, 백엔드가 정확히 이 형식을 기대하는지 API 문서 또는 백엔드 팀을 통해 확인하세요.

enum 상수는 이미 요청/응답 클래스(PostReviewRequest.kt, FetchReviewDetailResponse.kt)에서 사용 중이므로, 기존 백엔드 계약이 일치하는지 재확인하시기 바랍니다.

core/domain/src/main/java/team/retum/usecase/entity/MyReviews.kt (1)

1-23: LGTM!

도메인 엔티티와 변환 로직이 깔끔하게 구현되어 있습니다. 적절한 가시성 제어자 사용과 불변성 보장이 잘 되어 있습니다.

core/network/src/main/java/team/retum/network/model/response/FetchReviewsCountResponse.kt (1)

1-9: LGTM!

간단하고 명확한 응답 모델입니다. Moshi 어댑터 생성과 JSON 매핑이 적절하게 구성되어 있습니다.

feature/review/src/main/java/team/retum/review/navigation/ReviewNavigation.kt (1)

1-28: LGTM!

Jetpack Compose Navigation을 활용한 깔끔한 네비게이션 구성입니다. 콜백 기반 설계가 적절하며 확장 함수를 통한 API가 사용하기 편리합니다.

core/domain/src/main/java/team/retum/usecase/usecase/review/FetchMyReviewUseCase.kt (1)

1-13: LGTM!

간단하고 명확한 Use Case 구현입니다. runCatching을 통한 에러 처리와 엔티티 변환이 적절하게 구성되어 있습니다.

core/network/src/main/java/team/retum/network/model/response/FetchMyReviewResponse.kt (1)

1-15: LGTM!

네트워크 응답 모델이 깔끔하게 구성되어 있습니다. Moshi 어댑터 생성과 JSON 필드 매핑이 적절합니다.

core/network/src/main/java/team/retum/network/model/response/FetchReviewsResponse.kt (1)

12-17: LGTM!

응답 모델의 필드 업데이트가 적절합니다. reviewId의 타입 변경(String → Long)과 새로운 필드들(companyName, companyLogoUrl, major) 추가가 확장된 기능 요구사항과 잘 맞습니다.

feature/review/src/main/java/team/retum/review/ui/component/ReviewItems.kt (1)

26-81: LGTM!

리뷰 아이템 컴포저블의 구현이 깔끔합니다. 이미지 URL이 비어있을 때의 폴백 처리, 텍스트 오버플로우 처리, 클릭 이벤트 전달 등이 모두 적절하게 구현되어 있습니다.

feature/company/src/main/java/team/retum/company/navigation/CompanyDetailsNavigation.kt (1)

15-15: Long 기반 리뷰 식별자로의 전환이 적절합니다.

리뷰 상세 네비게이션 파라미터를 (String, String)에서 (Long)으로 변경하여 타입 안정성과 일관성이 개선되었습니다.

core/domain/src/main/java/team/retum/usecase/usecase/review/FetchQuestionsUseCase.kt (1)

7-13: LGTM!

UseCase의 구현이 간결하고 적절합니다. runCatching을 사용하여 에러를 Result로 래핑하는 방식이 적절하며, 호출자가 성공/실패를 처리할 수 있도록 되어 있습니다.

core/domain/src/main/java/team/retum/usecase/entity/QuestionsEntity.kt (1)

16-16: 네이밍 패턴 일관성 확인 완료 - 지적 사항 없음

프로젝트 전체의 toEntity() 함수 패턴을 검토한 결과, QuestionsEntity.kt의 함수명과 구조는 이미 프로젝트의 표준 네이밍 규칙과 완벽하게 일치합니다. 18개 이상의 엔티티 파일에서 internal fun ResponseType.toEntity() = EntityType(...) 패턴을 따르고 있으며, QuestionsEntity.kt도 동일한 규칙을 준수하고 있습니다. TODO 주석은 제거해도 무방합니다.

Likely an incorrect or invalid review comment.

core/domain/src/main/java/team/retum/usecase/usecase/review/FetchReviewsUseCase.kt (1)

12-14: 파라미터 위임 검증 완료

확장된 필터 인자가 repository 계층으로 정확히 전달되고 runCatching 으로 오류를 포장하는 흐름이 명확합니다.

core/data/src/main/java/team/retum/data/repository/review/ReviewRepositoryImpl.kt (1)

20-49: 데이터소스 위임이 올바르게 정렬되었습니다

repository 계층에서 추가된 필터 파라미터를 전부 data source 에 네임드 인자로 넘겨주어 매핑 오류 위험이 없습니다.

core/domain/src/main/java/team/retum/usecase/entity/PostReviewEntity.kt (1)

7-21: 도메인 엔티티 구조 변경이 적절합니다.

면접 후기 엔티티에 새로운 필드들(interviewType, location, jobCode, interviewerCount, question, answer)이 추가되었고, PostReviewContentEntity의 question 타입이 String에서 Long으로 변경되어 식별자로서 더 적합한 타입을 사용하게 되었습니다.

core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSource.kt (1)

27-31: 새로운 리뷰 관련 메서드 추가가 적절합니다.

fetchQuestions(), fetchReviewsCount(), fetchMyReviews() 메서드가 추가되어 리뷰 기능의 API 표면이 확장되었습니다.

app/src/main/java/team/retum/jobisandroidv2/root/RootScreen.kt (1)

59-62: 리뷰 관련 콜백 추가 및 전달이 올바르게 구현되었습니다.

새로운 콜백들(onReviewFilterClick, onSearchReviewClick, onReviewDetailClick)이 Root → RootScreen → review 컴포저블로 일관되게 전달되고 있으며, onPostReviewClick의 시그니처도 추가 파라미터를 받도록 적절히 업데이트되었습니다.

Also applies to: 99-101, 135-138, 185-189

app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (1)

201-203: reviewId 타입이 Long으로 변경된 것이 적절합니다.

이전 String 타입에서 Long으로 변경되어 도메인 모델과 일관성을 갖추게 되었습니다.

app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (1)

118-133: 포스트 리뷰 네비게이션 체인이 올바르게 구성되었습니다.

postReview → postNextReview → postExpectReview → postReviewComplete 흐름이 적절한 콜백과 함께 구성되었습니다. 각 단계가 필요한 데이터를 다음 단계로 전달하고 있습니다.

core/network/src/main/java/team/retum/network/api/ReviewApi.kt (1)

24-47: 리뷰 API 확장이 적절하게 구현되었습니다.

fetchReviews가 페이지네이션 및 다중 필터링을 지원하도록 확장되었고, 새로운 엔드포인트들(fetchQuestions, fetchReviewsCount, fetchMyReviews)이 추가되어 리뷰 기능을 충분히 지원합니다. 모든 쿼리 파라미터가 nullable로 선언되어 선택적 필터링이 가능합니다.

feature/review/src/main/java/team/retum/review/ui/ReviewFilterScreen.kt (1)

47-66: UI 구조와 컴포넌트 구성이 잘 되어 있습니다.

ReviewFilter 진입점부터 세부 섹션들(Skills, Years, InterviewType, Location)까지 잘 구조화되어 있으며, 애니메이션과 상태 관리가 적절하게 구현되었습니다. FlowRow를 사용한 레이아웃과 색상 전환 애니메이션이 좋은 사용자 경험을 제공합니다.

Also applies to: 68-119, 123-373

feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (4)

77-110: 명시적 데이터 플로우로 개선된 구조

ViewModel 상태에 직접 의존하지 않고 명시적인 파라미터를 통한 데이터 전달 방식으로 변경하여 테스트 가능성과 재사용성이 향상되었습니다.


162-172: 열거형 매핑 로직이 올바르게 구현됨

InterviewTypeInterviewLocation 열거형의 모든 케이스를 exhaustive하게 처리하고 있어 안전합니다.


194-201: 깔끔한 위임 패턴

InterviewReviewReviewContent로 명확하게 위임하고 있습니다.


207-207: 빈 값 검증 로직 확인 필요

현재 !review.answer.isBlank() || !review.question.isBlank() 로직은 둘 중 하나라도 비어있지 않으면 콘텐츠를 표시합니다. 의도가 "둘 다 존재해야 표시"라면 && 연산자를 사용해야 합니다.

의도한 로직이 다음 중 어느 것인지 확인하세요:

  • 현재: 질문 또는 답변 중 하나라도 있으면 표시
  • 제안: 질문과 답변이 모두 있어야 표시 (&& 사용)
// 제안하는 변경
if (!review.answer.isBlank() && !review.question.isBlank()) {
    // show content
}

Comment on lines +22 to +27
companion object {
var code: Long? = null
var year: Int? = null
var interviewType: InterviewType? = null
var location: InterviewLocation? = null
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

companion object의 mutable static state를 제거하세요.

companion object에 var로 선언된 필터 상태는 여러 문제를 야기합니다:

  • ViewModel 인스턴스 간 상태 공유로 인한 예기치 않은 동작
  • 메모리 누수 위험 (정적 참조가 계속 유지)
  • 단위 테스트 불가능 (테스트 간 격리 불가)
  • ReviewsFilterState에 동일한 속성이 이미 존재하여 중복

모든 필터 상태는 ReviewsFilterState 인스턴스를 통해 관리되어야 합니다.

다음 diff를 적용하여 companion object를 제거하세요:

-    companion object {
-        var code: Long? = null
-        var year: Int? = null
-        var interviewType: InterviewType? = null
-        var location: InterviewLocation? = null
-    }
-
     init {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt
around lines 22 to 27, remove the companion object that defines mutable static
vars (code, year, interviewType, location) and stop using static state; instead,
add those properties to and manage them via the existing ReviewsFilterState
instance held by the ViewModel (initialize/update/read from the state object,
expose changes via LiveData/StateFlow as appropriate), eliminate any references
to ReviewFilterViewModel.Companion.* across the codebase, and adjust
constructors/usage so each ViewModel instance uses its own ReviewsFilterState to
avoid shared mutable static state.

@Team-return Team-return deleted a comment from coderabbitai bot Nov 4, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (11)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (2)

22-27: companion object의 mutable static state를 제거해야 합니다.

이전 리뷰에서 지적된 critical 이슈가 여전히 해결되지 않았습니다. companion object의 가변 정적 변수들은 다음 문제를 야기합니다:

  • ViewModel 인스턴스 간 상태 공유로 인한 예측 불가능한 동작
  • 메모리 누수 위험
  • 테스트 격리 불가능
  • ReviewsFilterState에 동일한 속성이 이미 존재하여 중복

모든 필터 상태는 ReviewsFilterState를 통해 관리되어야 합니다.

다음 diff를 적용하여 companion object를 제거하세요:

-    companion object {
-        var code: Long? = null
-        var year: Int? = null
-        var interviewType: InterviewType? = null
-        var location: InterviewLocation? = null
-    }
-
     init {

29-31: init에서 getLocalYears()를 호출해야 합니다.

getLocalYears()가 호출되지 않아 ReviewsFilterState.years가 항상 빈 리스트로 유지됩니다. 이는 년도 필터 UI가 제대로 작동하지 않는 원인이 됩니다.

다음 diff를 적용하세요:

     init {
         fetchCodes()
+        getLocalYears()
     }
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)

20-29: JSON 역직렬화 오류 처리 확인 필요

it.getReviewData()(라인 25)가 JSON 파싱 실패 시 예외를 던질 수 있습니다. 이전 리뷰에서 지적된 것처럼, toReviewData() 구현에 try-catch 블록이 없는 경우 앱이 크래시될 수 있습니다.

getReviewData()toReviewData() 구현에서 JSON 파싱 실패와 URL 디코딩 실패를 처리하고, 실패 시 적절한 에러 UI를 표시하거나 안전하게 뒤로 이동하도록 개선하세요.

feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)

38-41: 예외 메시지 누락 및 오류 처리 미흡

라인 39에서 메시지 없이 NullPointerException()을 던지는 것은 디버깅을 어렵게 만듭니다. 또한 toReviewData() 호출 시 JSON 파싱 실패를 처리하지 않아 앱 크래시 위험이 있습니다.

다음과 같이 개선하세요:

 internal fun NavBackStackEntry.getReviewData(): PostReviewData {
-    val reviewData = arguments?.getString(ResourceKeys.REVIEW_DATA) ?: throw NullPointerException()
-    return reviewData.toReviewData()
+    val raw = requireNotNull(arguments?.getString(ResourceKeys.REVIEW_DATA)) {
+        "Missing '${ResourceKeys.REVIEW_DATA}' argument for $NAVIGATION_POST_NEXT_REVIEW"
+    }
+    return try {
+        raw.toReviewData()
+    } catch (e: Exception) {
+        throw IllegalArgumentException("Failed to parse review data: ${e.message}", e)
+    }
 }
feature/review/src/main/java/team/retum/review/viewmodel/ReviewDetailsViewModel.kt (2)

24-29: 에러 처리 누락으로 실패 시 사용자 피드백 없음

fetchReviewDetailsUseCase가 실패할 경우 아무런 상태 변화도 없어서 사용자는 로딩이 끝났는지조차 알 수 없습니다. 최소한 실패 플래그를 상태에 기록해 UI가 에러를 표시하거나 재시도 버튼을 노출할 수 있도록 해야 합니다.

     internal fun fetchReviewDetails() {
         viewModelScope.launch(Dispatchers.IO) {
-            fetchReviewDetailsUseCase(state.value.reviewId).onSuccess {
-                setState { state.value.copy(reviewDetail = it) }
-            }
+            fetchReviewDetailsUseCase(state.value.reviewId)
+                .onSuccess {
+                    setState { state.value.copy(reviewDetail = it, hasError = false) }
+                }
+                .onFailure {
+                    setState { state.value.copy(hasError = true) }
+                }
         }
     }
 internal data class ReviewDetailsState(
+    val hasError: Boolean,
     val selectedTabIndex: Int,
     val reviewId: Long,
     val reviewDetail: FetchReviewDetailEntity,
 ) {
     companion object {
         fun getInitialState() = ReviewDetailsState(
+            hasError = false,
             selectedTabIndex = 0,
             reviewId = 0L,
             reviewDetail = FetchReviewDetailEntity(

45-59: 초기 상태가 실제 데이터처럼 보이는 기본값 사용

초기 상태에서 InterviewType.INDIVIDUALInterviewLocation.GYEONGGI를 넣으면 데이터 로딩 전에도 실제 값처럼 렌더링돼 사용자가 혼동할 수 있습니다. 중립값(OTHER)으로 바꾸거나 로딩 상태를 분리해 주세요.

                 type = InterviewType.INDIVIDUAL,
-                location = InterviewLocation.GYEONGGI,
+                type = InterviewType.OTHER,
+                location = InterviewLocation.OTHER,
feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (1)

173-177: 마지막 페이지 인덱스 하드코딩으로 흐름 깨짐

질문 수가 3개가 아니면 pagerState.currentPage != 2 조건이 바로 틀어져서 다음/완료 전환이 망가집니다. 마지막 페이지를 동적으로 계산하세요.

                 JobisButton(
                     text = stringResource(id = R.string.next),
                     color = ButtonColor.Primary,
                     onClick = {
                         setQuestion()
                         coroutineScope.launch {
-                            if (pagerState.currentPage != 2) pagerState.animateScrollToPage(pagerState.currentPage + 1) else onPostExpectReviewClick()
+                            val lastPageIndex = pagerState.pageCount - 1
+                            if (pagerState.currentPage < lastPageIndex) {
+                                pagerState.animateScrollToPage(pagerState.currentPage + 1)
+                            } else {
+                                onPostExpectReviewClick()
+                            }
                         }
                     },
                 )
app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (1)

55-58: 콜백 시그니처 불일치 확인 필요

navigator::navigateToPostReview가 메서드 참조로 전달되고 있으나, navigateToPostReview(companyName: String, companyId: Long) 파라미터를 필요로 합니다. 이는 파라미터가 없는 콜백으로 전달될 수 없습니다.

다음 스크립트로 실제 호출 방식을 확인하여 컴파일 오류 여부를 검증하세요:

#!/bin/bash
# root 함수의 onPostReviewClick 파라미터 타입 확인
ast-grep --pattern $'fun NavGraphBuilder.root(
  $$$
  onPostReviewClick: $TYPE,
  $$$
)'

# RootScreen에서 onPostReviewClick 호출 방식 확인
rg -n 'onPostReviewClick' --type=kt -A 2 -B 2
feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (2)

95-103: 데이터 유효성 검증 권장

yearinterviewerCount를 검증 없이 toString()으로 변환하고 있습니다. 서버에서 0이나 음수 값이 전달될 경우 의미 없는 문자열이 UI에 표시될 수 있습니다.

도메인 계층(FetchReviewDetailEntity)에 유효성 검증을 추가하는 것을 권장합니다. 다음 스크립트로 현재 검증 로직 여부를 확인하세요:

#!/bin/bash
# FetchReviewDetailEntity에 유효성 검증 어노테이션이 있는지 확인
rg -n '@field:|@Min|@Max|@Positive' core/domain/src/main/java/team/retum/usecase/entity/FetchReviewDetailEntity.kt

# 응답 모델에서 유효성 검증 확인
fd FetchReviewDetailResponse.kt --exec cat {}

60-64: TODO 주석 제거 필요

프로덕션 코드에 TODO 주석이 남아있습니다. 실제 데이터 처리가 완료되었다면 주석을 제거하고, 미완료 작업이라면 구현을 완료해야 합니다.

다음과 같이 TODO 주석을 제거하세요:

 LaunchedEffect(reviewId) {
-    // TODO : 실 값 들어왔을 때 UI 호출
     reviewDetailsViewModel.setReviewId(reviewId)
     reviewDetailsViewModel.fetchReviewDetails()
 }
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (1)

159-177: 면접관 수 파싱 시 예외 처리 누락

count.toInt()가 빈 문자열이나 숫자가 아닌 입력을 받으면 NumberFormatException이 발생합니다. 안전한 파싱과 유효성 검증을 추가해야 합니다.

다음 diff를 적용하여 안전한 파싱을 구현하세요:

 internal fun onNextClick() {
     with(state.value) {
-        if (interviewType != null && interviewLocation != null) {
-            postSideEffect(
-                PostReviewSideEffect.MoveToNext(
-                    companyId = companyId,
-                    interviewerCount = count.toInt(),
-                    jobCode = selectedTech ?: 0,
-                    interviewType = interviewType,
-                    location = interviewLocation,
-                ),
-            )
+        val parsedCount = count.toIntOrNull()
+        if (parsedCount == null || parsedCount <= 0) {
+            postSideEffect(PostReviewSideEffect.BadRequest)
+            return
+        }
+        if (interviewType != null && interviewLocation != null) {
+            postSideEffect(
+                PostReviewSideEffect.MoveToNext(
+                    companyId = companyId,
+                    interviewerCount = parsedCount,
+                    jobCode = selectedTech ?: 0,
+                    interviewType = interviewType,
+                    location = interviewLocation,
+                ),
+            )
         } else {
             postSideEffect(
                 PostReviewSideEffect.SelectTechAndCount
             )
         }
     }
 }
🧹 Nitpick comments (4)
feature/mypage/src/main/java/team/retum/jobis/ui/MyPageScreen.kt (2)

15-16: 미사용 import를 제거하거나 LazyColumn 사용을 고려하세요.

LazyColumnitems를 import했지만 실제로는 forEach를 사용하고 있습니다.


198-205: 이전 NPE 위험이 해결되었습니다. 성능 최적화를 위해 LazyColumn 사용을 고려하세요.

reviewableItem을 로컬 변수로 캡처하여 이전 리뷰에서 지적된 NPE 위험이 해결되었습니다.

다만 Compose에서 forEach를 사용하면 각 항목이 개별적으로 추적되지 않아 재구성 시 비효율적일 수 있습니다. 목록이 길어질 경우 이미 import한 LazyColumnitems()를 사용하는 것을 권장합니다.

적용 가능한 diff:

-            state.reviewableCompany?.let { reviewable ->
-                reviewable.forEach { reviewableItem ->
-                    WriteInterviewReview(
-                        companyName = reviewableItem.name,
-                        onClick = { onPostReviewClick(reviewableItem.name, reviewableItem.id) },
-                    )
-                }
-            }
+            state.reviewableCompany?.let { reviewable ->
+                LazyColumn {
+                    items(
+                        items = reviewable,
+                        key = { it.id }
+                    ) { reviewableItem ->
+                        WriteInterviewReview(
+                            companyName = reviewableItem.name,
+                            onClick = { onPostReviewClick(reviewableItem.name, reviewableItem.id) },
+                        )
+                    }
+                }
+            }
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1)

29-45: 사용하지 않는 파라미터 제거 고려

onBackPressed 파라미터가 정의되어 있지만(라인 31) 실제로 사용되지 않습니다. 이 파라미터가 향후 사용 예정이 아니라면 제거를 고려하세요.

 internal fun PostReviewComplete(
-    onBackPressed: () -> Unit,
     navigateToMyPage: () -> Unit,
     postReviewViewModel: PostReviewViewModel = hiltViewModel(),
 )
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (1)

66-88: 예외 처리 범위 확장 권장

postReview 메서드가 BadRequestException만 처리하고 있습니다. 네트워크 오류나 기타 예외 상황에 대한 처리를 추가하면 사용자 경험이 개선됩니다.

다음과 같이 일반 예외 처리를 추가하는 것을 고려해보세요:

 internal fun postReview(reviewData: PostReviewData) {
     viewModelScope.launch(Dispatchers.IO) {
         postReviewUseCase(
             postReviewRequest = PostReviewEntity(
                 interviewType = reviewData.interviewType,
                 location = reviewData.location,
                 companyId = reviewData.companyId,
                 jobCode = reviewData.jobCode,
                 interviewerCount = reviewData.interviewerCount,
                 qnaElements = reviewData.qnaElements.map { it.toEntity() },
                 question = reviewData.question,
                 answer = reviewData.answer,
             ),
         ).onSuccess {
             postSideEffect(PostReviewSideEffect.Success)
         }.onFailure {
             when (it) {
                 is BadRequestException -> {
                     postSideEffect(PostReviewSideEffect.BadRequest)
                 }
+                else -> {
+                    postSideEffect(PostReviewSideEffect.BadRequest)
+                }
             }
         }
     }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13a317c and b511287.

📒 Files selected for processing (35)
  • app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (4 hunks)
  • app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (3 hunks)
  • core/data/src/main/java/team/retum/data/repository/review/ReviewRepository.kt (1 hunks)
  • core/data/src/main/java/team/retum/data/repository/review/ReviewRepositoryImpl.kt (2 hunks)
  • core/domain/src/main/java/team/retum/usecase/entity/FetchReviewDetailEntity.kt (1 hunks)
  • core/domain/src/main/java/team/retum/usecase/usecase/review/FetchReviewDetailUseCase.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/api/ReviewApi.kt (2 hunks)
  • core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSource.kt (1 hunks)
  • core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSourceImpl.kt (2 hunks)
  • core/network/src/main/java/team/retum/network/model/response/FetchReviewDetailResponse.kt (1 hunks)
  • feature/company/src/main/java/team/retum/company/navigation/CompanyDetailsNavigation.kt (1 hunks)
  • feature/company/src/main/java/team/retum/company/ui/CompanyDetailsScreen.kt (4 hunks)
  • feature/home/src/main/java/team/retum/home/ui/ApplyCompanyItem.kt (1 hunks)
  • feature/mypage/src/main/java/team/retum/jobis/navigation/MyPageNavigation.kt (2 hunks)
  • feature/mypage/src/main/java/team/retum/jobis/ui/MyPageScreen.kt (4 hunks)
  • feature/mypage/src/main/java/team/retum/jobis/viewmodel/MyPageViewModel.kt (2 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewScreen.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostExpectReviewViewModel.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (1 hunks)
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (1 hunks)
  • feature/post-review/src/main/res/values/strings.xml (1 hunks)
  • feature/review/build.gradle.kts (1 hunks)
  • feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (2 hunks)
  • feature/review/src/main/java/team/retum/review/ui/ReviewScreen.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewDetailsViewModel.kt (2 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/ReviewViewModel.kt (1 hunks)
  • feature/review/src/main/java/team/retum/review/viewmodel/SearchReviewsViewModel.kt (1 hunks)
  • feature/review/src/main/res/values/strings.xml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • feature/mypage/src/main/java/team/retum/jobis/navigation/MyPageNavigation.kt
  • feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt
  • feature/review/src/main/java/team/retum/review/viewmodel/SearchReviewsViewModel.kt
  • feature/review/build.gradle.kts
  • feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewScreen.kt
  • core/domain/src/main/java/team/retum/usecase/entity/FetchReviewDetailEntity.kt
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt
  • feature/company/src/main/java/team/retum/company/navigation/CompanyDetailsNavigation.kt
  • feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostExpectReviewViewModel.kt
  • feature/review/src/main/java/team/retum/review/ui/ReviewScreen.kt
🧰 Additional context used
🧬 Code graph analysis (12)
feature/mypage/src/main/java/team/retum/jobis/viewmodel/MyPageViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewDetailsViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (3)
app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (1)
  • navigateToMyPage (134-136)
feature/mypage/src/main/java/team/retum/jobis/navigation/MyPageNavigation.kt (1)
  • navigateToMyPage (33-38)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (7)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewNavigation.kt (1)
  • postReview (15-33)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)
  • postNextReview (18-32)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)
  • postExpectReview (16-30)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1)
  • postReviewComplete (10-22)
feature/review/src/main/java/team/retum/review/navigation/ReviewDetailsNavigation.kt (1)
  • reviewDetails (13-29)
feature/review/src/main/java/team/retum/review/navigation/ReviewFilterNavigation.kt (1)
  • reviewFilter (10-18)
feature/review/src/main/java/team/retum/review/navigation/SearchReviewsNavigation.kt (1)
  • searchReview (10-22)
feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (5)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)
  • navigateToPostExpectReview (32-34)
app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (1)
  • navigateToPostExpectReview (154-156)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/textfield/JobisTextField.kt (1)
  • JobisTextField (355-436)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostNextReviewViewModel.kt (2)
  • setAnswer (34-44)
  • setQuestion (50-64)
feature/review/src/main/java/team/retum/review/ui/ReviewDetailsScreen.kt (5)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/appbar/JobisTopAppBar.kt (1)
  • JobisSmallTopAppBar (124-144)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/tab/TabBar.kt (1)
  • TabBar (21-68)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/text/JobisText.kt (1)
  • JobisText (24-45)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/card/JobisCard.kt (1)
  • JobisCard (43-81)
core/design-system/src/main/java/team/retum/jobisdesignsystemv2/empty/EmptyContent.kt (1)
  • EmptyContent (21-56)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1)
  • PostReviewComplete (29-45)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (1)
  • setState (60-64)
feature/review/src/main/java/team/retum/review/viewmodel/ReviewViewModel.kt (2)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (2)
  • setState (60-64)
  • postSideEffect (106-110)
feature/review/src/main/java/team/retum/review/viewmodel/SearchReviewsViewModel.kt (1)
  • fetchReviewsUseCase (19-67)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostNextReviewScreen.kt (1)
  • PostNextReview (47-90)
feature/post-review/src/main/java/team/retum/post/review/viewmodel/PostReviewViewModel.kt (1)
core/common/src/main/java/team/retum/common/base/BaseViewModel.kt (2)
  • setState (60-64)
  • postSideEffect (106-110)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)
feature/post-review/src/main/java/team/retum/post/review/ui/PostExpectReviewScreen.kt (1)
  • PostExpectReview (34-76)
🪛 detekt (1.23.8)
feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt

[warning] 39-39: A call to the default constructor of an exception was detected. Instead one of the constructor overloads should be called. This allows to provide more meaningful exceptions.

(detekt.exceptions.ThrowingExceptionsWithoutMessageOrCause)

🔇 Additional comments (22)
feature/home/src/main/java/team/retum/home/ui/ApplyCompanyItem.kt (1)

48-53: 이전 리뷰 코멘트가 완벽하게 반영되었으며, when 표현식이 완전 매칭입니다.

검증 결과, ApplyStatus enum의 모든 10개 케이스가 when 표현식에서 처리되고 있습니다:

  • DOC_FAILED가 error 색상 분기에 올바르게 추가됨 (이전 리뷰 반영 완료)
  • SENDPROCESSING이 secondary 색상에 적절하게 매핑됨
  • 모든 상태가 의미론적으로 올바른 색상에 분류됨

else 분기 제거로 인해 when 표현식이 완전 매칭이 되었으며, 컴파일 시점에 누락된 케이스를 감지할 수 있습니다. 코드 변경사항은 문제가 없습니다.

feature/review/src/main/java/team/retum/review/viewmodel/ReviewFilterViewModel.kt (1)

49-56: getLocalYears()가 coroutine 없이 순수 계산만 수행합니다.

현재 구현은 setState를 직접 호출하여 년도 범위를 계산합니다. 계산이 매우 가볍기 때문에 별도의 dispatcher가 필요하지 않으며, 이는 적절한 구현입니다. 다만 init에서 호출되지 않는 문제는 여전히 해결되어야 합니다.

feature/review/src/main/res/values/strings.xml (1)

1-42: 문자열 리소스 구조가 잘 정리되었습니다.

이전 리뷰에서 제기된 제거된 문자열 리소스 참조 문제는 작성자가 확인 완료했습니다. 새로 추가된 문자열 리소스들은 리뷰 상세, 필터, 검색 화면을 위한 포괄적인 내용을 포함하고 있으며, 명명 규칙과 구조가 일관적입니다.

feature/mypage/src/main/java/team/retum/jobis/viewmodel/MyPageViewModel.kt (2)

101-107: 리뷰 가능한 회사 목록 저장 변경 사항 검증 완료

변경사항이 제대로 구현되었음을 확인했습니다. ViewModel의 상태 필드 타입 변경(List<ReviewableCompaniesEntity.ReviewableCompanyEntity>?)이 UI 컴포넌트에서 올바르게 처리되고 있습니다.

MyPageScreen.kt의 UI 레이어에서 null 안전성 검사와 리스트 반복 처리가 구현되어 있습니다:

  • Null 체크: state.reviewableCompany?.let { reviewable ->
  • 리스트 반복: reviewable.forEach { reviewableItem ->

별도의 조치가 필요하지 않습니다.


124-144: 통합 검증 완료 - 모든 우려사항 확인됨

reviewableCompany 필드의 타입 변경(단일 엔티티 → 리스트)이 일관성 있게 구현되었습니다.

  • MyPageScreen.kt (198-205): state.reviewableCompany?.let으로 안전하게 처리하고 forEach를 통해 각 회사를 반복 렌더링
  • 콜백 연결: 각 항목의 onClick에서 onPostReviewClick(reviewableItem.name, reviewableItem.id) 정확하게 전달
  • 상태 초기화: ViewModel에서 정상적으로 null로 설정되고, 로드 시 리스트 할당 (it.companies)
  • 빈 상태 처리: null/빈 리스트 모두 안전하게 처리 (렌더링 안 함)

모든 원래 검증 요청사항이 확인되었으며 구현이 완전합니다.

feature/company/src/main/java/team/retum/company/ui/CompanyDetailsScreen.kt (2)

156-156: 콜백 전달 방식이 올바르게 업데이트되었습니다.

새로운 시그니처 () -> Unit에 맞춰 navigateToReviews를 직접 전달하도록 변경한 것이 적절합니다. 이전에는 companyIdcompanyName 파라미터와 함께 호출했지만, 이제는 파라미터 없는 콜백으로 올바르게 전달하고 있습니다.


54-55: 네비게이션 시그니처 변경은 올바르게 구현되었습니다.

검증 결과, 변경 사항이 일관성 있게 적용되어 있습니다:

  • navigateToReviewDetails: (Long) → Unit - ReviewDetails 화면은 reviewId만으로 필요한 모든 데이터(회사명 포함)를 조회
  • navigateToReviews: () → Unit - Review 목록 화면이 별도의 매개변수 없이 전체 리뷰 조회
  • 모든 호출 지점이 업데이트됨 (MainNavigation.kt, CompanyDetailsScreen.kt)
  • Review 엔티티에 companyName, companyId 포함되어 있어 네비게이션을 통한 추가 전달 불필요

리뷰 화면들은 reviewId만 받아 백엔드에서 전체 리뷰 데이터를 조회하도록 설계되어 있으므로, 회사 정보 접근에 문제가 없습니다.

core/domain/src/main/java/team/retum/usecase/usecase/review/FetchReviewDetailUseCase.kt (1)

10-12: 타입 일관성 개선 완료

reviewId 타입을 Long으로 변경하여 데이터 레이어 전반의 타입 일관성을 개선했습니다. 불필요한 타입 변환을 제거하고 타입 안정성을 높였습니다.

core/network/src/main/java/team/retum/network/model/response/FetchReviewDetailResponse.kt (1)

8-28: 응답 모델 구조 검증 필요

FetchReviewDetailResponseqnaResponse: List<QnAs>(라인 18)와 별도로 최상위 레벨에 question, answer 필드(라인 19-20)가 존재합니다. 이 구조가 의도된 것인지 확인이 필요합니다:

  • 만약 최상위 필드가 "예상 질문"을 나타내는 것이라면 명확한 네이밍(예: expectedQuestion, expectedAnswer)을 권장합니다.
  • 만약 중복 데이터라면 제거를 검토하세요.

백엔드 API 명세를 확인하여 이 필드들의 의도와 사용처를 명확히 해주세요.

feature/post-review/src/main/java/team/retum/post/review/navigation/PostReviewCompleteNavigation.kt (1)

1-26: LGTM!

표준 Compose Navigation 패턴을 올바르게 구현했습니다. 라우트 상수 정의, NavGraphBuilder 확장, NavController 확장이 모두 일관성 있게 작성되었습니다.

feature/post-review/src/main/java/team/retum/post/review/navigation/PostExpectReviewNavigation.kt (1)

32-34: URI 인코딩 적용 완료

Uri.encode()를 사용하여 JSON 문자열을 안전하게 인코딩했습니다. 이전 리뷰 피드백이 반영되었습니다.

feature/post-review/src/main/java/team/retum/post/review/ui/PostReviewCompleteScreen.kt (1)

47-88: LGTM!

완료 화면 UI 구현이 깔끔하고 디자인 시스템을 일관성 있게 사용했습니다.

core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSource.kt (2)

15-23: 필터 파라미터 null 허용 설계 적절함

모든 필터 파라미터를 nullable로 설계하여 선택적 필터링을 유연하게 지원할 수 있습니다.


25-31: LGTM!

reviewId 타입을 Long으로 변경하고 새로운 데이터 조회 메서드들을 추가하여 API 표면을 확장했습니다. 타입 일관성이 개선되었습니다.

feature/post-review/src/main/java/team/retum/post/review/navigation/PostNextReviewNavigation.kt (2)

22-30: navArgument 타입 지정 완료, JSON 파싱 오류 처리 추가 필요

navArgumenttype = NavType.StringType를 올바르게 지정했습니다(라인 24).

그러나 it.getReviewData()(라인 27) 호출 시 JSON 파싱 실패 예외를 처리하지 않으면 앱이 크래시될 수 있습니다. try-catch로 감싸고 실패 시 적절한 오류 처리를 추가하세요.


34-36: URI 인코딩 적용 완료

Uri.encode()를 사용하여 JSON 문자열을 안전하게 인코딩했습니다.

core/network/src/main/java/team/retum/network/datasource/review/ReviewDataSourceImpl.kt (2)

21-39: LGTM!

많은 파라미터를 가진 메서드에서 named arguments를 사용하여 가독성과 정확성을 높였습니다. RequestHandler를 통한 일관된 오류 처리 패턴도 올바르게 적용되었습니다.


41-51: LGTM!

reviewId 타입을 Long으로 정확히 사용하고, 새로운 데이터 조회 메서드들을 일관된 패턴으로 구현했습니다.

app/src/main/java/team/retum/jobisandroidv2/JobisNavigator.kt (1)

19-220: 네비게이션 구조 개선이 잘 이루어졌습니다.

면접 후기 작성 플로우를 위한 새로운 네비게이션 메서드들이 추가되었고, 파라미터 전달도 적절하게 구현되었습니다. 이전 리뷰에서 지적된 사용되지 않는 파라미터 문제도 해결된 것으로 확인됩니다.

app/src/main/java/team/retum/jobisandroidv2/navigation/MainNavigation.kt (1)

118-133: post-review 네비게이션 플로우가 잘 구성되었습니다.

새로운 면접 후기 작성 플로우를 위한 네비게이션 그래프가 적절히 연결되어 있습니다. 각 단계별 화면 전환과 백 네비게이션 처리가 올바르게 구현되었습니다.

core/network/src/main/java/team/retum/network/api/ReviewApi.kt (1)

25-47: API 확장이 잘 설계되었습니다.

fetchReviews의 쿼리 파라미터 방식 변경과 새로운 엔드포인트 추가가 적절합니다. nullable 쿼리 파라미터를 사용하여 선택적 필터링을 지원하고, reviewId를 String에서 Long으로 변경하여 타입 안전성도 개선되었습니다.

feature/post-review/src/main/res/values/strings.xml (1)

1-64: 문자열 리소스가 잘 구성되었습니다.

면접 후기 작성 플로우를 위한 포괄적인 문자열 리소스가 추가되었습니다. 한글 맞춤법도 올바르게 적용되었고(이전 리뷰에서 지적된 "잘못된" 띄어쓰기 수정됨), 일관된 명명 규칙을 따르고 있습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

기능 구현 비즈니스 로직을 작성합니다. 리팩토링 코드를 리팩토링 합니다.

Projects

Development

Successfully merging this pull request may close these issues.

면접후기 기능 리팩토링

2 participants