Skip to content

[Refactor/#72] 회원연결 API Response Type을 변경합니다.#73

Merged
wjdrjs00 merged 4 commits intodevelopfrom
refactor/72-user-connection-api
Jan 10, 2026
Merged

[Refactor/#72] 회원연결 API Response Type을 변경합니다.#73
wjdrjs00 merged 4 commits intodevelopfrom
refactor/72-user-connection-api

Conversation

@wjdrjs00
Copy link
Collaborator

@wjdrjs00 wjdrjs00 commented Jan 10, 2026

Related issue 🛠

Work Description ✏️

  • 회원연결 API Response Type을 Profile -> Unit으로 변경했습니다.
  • 네트워크 응답 처리 로직을 개선했습니다.

Screenshot 📸

  • N/A

Uncompleted Tasks 😅

  • N/A

Summary by CodeRabbit

  • 버그 수정

    • 네트워크 응답 처리 로직 개선 및 null 안전성 강화
    • 응답 실패 시 더 명확한 에러 메시지 제공
  • 개선 사항

    • 특정 API의 응답 페이로드가 제거되어 연결 흐름이 단순화됨
    • 온보딩 연결 UI에 로딩 플래그(isLoading) 적용으로 상태 관리 개선
  • 테스트

    • 응답 null 처리 관련 단위 테스트가 nullable 타입 성공 시나리오로 업데이트됨

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

@wjdrjs00 wjdrjs00 self-assigned this Jan 10, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Walkthrough

회원연결 API의 응답 타입을 ProfileResponse에서 Unit으로 변경하고, 네트워크 응답 처리 로직을 재구조화(성공 여부 우선 검사·null 안전성 개선)했으며, 데이터·저장소·UI 계층에서 해당 변경을 반영하고 로딩 플래그명을 isLoginisLoading으로 변경했습니다.

Changes

코호트 / 파일(들) 변경 요약
네트워크 응답 처리
core/network/src/main/kotlin/com/moa/app/network/adapter/NetworkResultCallAdapter.kt, core/network/src/main/kotlin/com/moa/app/network/adapter/ResponseHandler.kt, core/network/src/main/kotlin/com/moa/app/network/adapter/UnitResponseHandler.kt
ResponseHandler 생성식 소폭 변경 및 handle 로직 재구조화: HTTP 성공 여부를 먼저 검사하고 body 안전하게 처리, 최종 오류 경로 단일화
서비스 API 시그니처
data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt
connectToSenior 반환 타입을 NetworkResult<ProfileResponse>NetworkResult<Unit>으로 변경
데이터 소스 인터페이스/구현
data/src/main/kotlin/com/moa/app/data/user/datasource/UserDataSource.kt, data/src/main/kotlin/com/moa/app/data/user/datasourceImpl/UserDataSourceImpl.kt
connectToSenior 반환타입을 Result<ProfileResponse>Result<Unit>으로 변경 및 구현부 호출 결과 매핑 단순화
저장소 계층
data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt
connectToSenior 호출 결과를 데이터소스에서 반환된 Result<Unit>을 그대로 반환하도록 단순화
응답 모델 제거
data/src/main/kotlin/com/moa/app/data/user/model/response/ProfileResponse.kt
ProfileResponse 데이터 클래스 삭제
UI 상태 및 ViewModel
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/model/ConnectionCheckUiState.kt, feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/ConnectionCheckViewModel.kt
UI 상태 플래그 isLoginisLoading으로 이름 변경 및 로딩 상태 설정/해제 로직 갱신
테스트
core/network/src/test/kotlin/com/moa/app/network/adapter/ResponseHandlerTest.kt
nullable 데이터 처리 관련 테스트 기대치 조정: nullable 타입에서 data=null은 성공(null)로 처리, 비즈니스 실패(success=false)는 Error로 검증

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI/Screen
    participant VM as ViewModel
    participant Repo as Repository
    participant DS as DataSource
    participant Service as UserService
    participant Net as NetworkAdapter

    UI->>VM: connectToSenior(userId)
    VM->>VM: isLoading = true
    VM->>Repo: connectToSenior(userId)
    Repo->>DS: connectToSenior(userId)
    DS->>Service: connectToSenior(userId)
    Service->>Net: execute request
    Net-->>Service: NetworkResult<Unit>
    Service-->>DS: NetworkResult<Unit>
    DS-->>Repo: Result<Unit>
    Repo-->>VM: Result<Unit>
    alt Success
        VM->>VM: isLoading = false
        VM->>UI: navigate to guardian home
    else Failure
        VM->>VM: isLoading = false
        VM->>UI: show error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • [Feature/#28] network module을 구성합니다. #31: 네트워크 어댑터 및 응답 처리 클래스(NetworkResultCallAdapter, ResponseHandler, UnitResponseHandler)와 테스트 변경을 포함한 동일한 영역을 수정함 — 직접적인 코드 레벨 연관성 있음

Poem

🐰 ProfileResponse는 이제 안녕,
Unit으로 가볍게 손을 흔들고,
isLoading 깃발이 바람에 펄럭이며,
응답은 안전하게, 흐름은 부드럽게,
당근 간식으로 축하할래요~ 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 '회원연결 API Response Type을 변경합니다'로 변경 사항의 핵심을 명확하게 설명하고 있으며, 실제 코드 변경(ProfileResponse → Unit 타입 변경)과 일치합니다.
Description check ✅ Passed PR 설명이 관련 이슈(#72) 참조, 작업 내용(API Response Type 변경 및 네트워크 응답 처리 개선), 템플릿 준수 등 필수 정보를 포함하고 있습니다.
Linked Issues check ✅ Passed PR은 이슈 #72의 요구사항인 ProfileResponse → Unit 타입 변경을 완벽하게 구현하였으며, 관련 모든 파일에서 일관되게 적용되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 회원연결 API Response Type 변경 및 관련 네트워크 응답 처리 로직 개선으로 범위 내에 있으며, 불필요한 외부 변경은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1c62067 and dd46f42.

📒 Files selected for processing (1)
  • core/network/src/test/kotlin/com/moa/app/network/adapter/ResponseHandlerTest.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Unit Tests
🔇 Additional comments (3)
core/network/src/test/kotlin/com/moa/app/network/adapter/ResponseHandlerTest.kt (3)

153-154: LGTM: 명확한 테스트 클래스명 개선

"타입 안전성 및 Nullable 테스트"로 변경하여 테스트의 목적이 더욱 명확해졌습니다.


157-171: LGTM: Nullable 타입 처리 테스트 로직이 정확합니다

ResponseHandler<TestData?>를 생성하고 data=null인 성공 응답에 대해 Success(null)을 반환하는지 검증하는 로직이 올바르게 구현되었습니다. 이는 회원연결 API의 Unit 응답 타입 변경과 관련하여 nullable 페이로드를 안전하게 처리할 수 있음을 보장합니다.


174-187: LGTM: 비즈니스 실패 케이스 검증 로직이 명확합니다

success=false인 경우 데이터의 null 여부와 관계없이 반드시 NetworkResult.Error를 반환하는지 검증합니다. 에러 메시지도 정확하게 전달되는지 확인하여 비즈니스 로직 실패 시나리오를 철저히 검증하고 있습니다.


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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/network/src/main/kotlin/com/moa/app/network/adapter/NetworkResultCallAdapter.kt (1)

15-24: ResponseHandler() 타입 추론이 명시적으로 지정되지 않아서 타입 안전성이 불명확합니다.

현재 코드에서 if 분기의 한쪽은 UnitResponseHandler() as ResponseHandler<Any>로 명시적으로 캐스팅하고, 다른 쪽은 ResponseHandler()로 두어서 타입 추론에 의존하고 있습니다. ResponseHandler<T>는 invariant 제네릭 클래스이므로, 두 분기의 타입이 명확하게 일치해야 합니다.

handler 변수에 명시적 타입을 지정하지 않으면 컴파일러가 두 분기의 공통 상위 타입으로 추론하게 되어, 타입 체킹이 느슨해질 수 있습니다. 안전하고 명확하게 하려면 val handler: ResponseHandler<Any> 형태로 명시적 타입을 선언하고, ResponseHandler<Any>()로 제네릭 파라미터를 지정하는 것이 좋습니다.

제안 diff
 @Suppress("UNCHECKED_CAST")
 override fun adapt(call: Call<BaseResponse<*>>): Call<NetworkResult<*>> {
-    val handler = if (successType == Unit::class.java) {
-        UnitResponseHandler() as ResponseHandler<Any>
-    } else {
-        ResponseHandler()
-    }
+    val handler: ResponseHandler<Any> = if (successType == Unit::class.java) {
+        UnitResponseHandler() as ResponseHandler<Any>
+    } else {
+        ResponseHandler<Any>()
+    }
 
     return NetworkResultCall(call as Call<BaseResponse<Any>>, handler) as Call<NetworkResult<*>>
 }
🧹 Nitpick comments (3)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/model/ConnectionCheckUiState.kt (1)

8-23: isLoading 기본값을 주면 초기화/복사 실수 여지가 줄어듭니다.

ConnectionCheckUiState.INIT로 통일하는 전략이면 현재도 OK인데, isLoading이 non-default라 생성/테스트 코드에서 누락되기 쉬워요. 아래처럼 기본값을 주면 안전합니다.

제안 diff
 data class ConnectionCheckUiState(
-    val isLoading: Boolean,
+    val isLoading: Boolean = false,
     val seniorProfile: SeniorProfile?,
 ) {
@@
     companion object Companion {
         val INIT = ConnectionCheckUiState(
-            isLoading = false,
             seniorProfile = null,
         )
     }
 }
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/ConnectionCheckViewModel.kt (2)

39-52: isLoading 해제는 finally로 보장하는 편이 더 안전합니다.

현재 fold의 onSuccess/onFailure에서만 isLoading=false로 복구해서, 예외가 발생하면 로딩이 영구 고착될 수 있어요.

제안 diff
 private fun loadSeniorProfile(userId: Long) {
     viewModelScope.launch {
-        _uiState.update { it.copy(isLoading = true) }
-        fetchSeniorProfilesUseCase(userId).fold(
-            onSuccess = { seniorProfile ->
-                _uiState.update { it.copy(isLoading = false, seniorProfile = seniorProfile) }
-            },
-            onFailure = { t ->
-                _uiState.update { it.copy(isLoading = false) }
-                Timber.e("loadSeniorProfile: $t")
-            },
-        )
+        _uiState.update { it.copy(isLoading = true) }
+        try {
+            fetchSeniorProfilesUseCase(userId).fold(
+                onSuccess = { seniorProfile ->
+                    _uiState.update { it.copy(seniorProfile = seniorProfile) }
+                },
+                onFailure = { t ->
+                    Timber.e(t, "loadSeniorProfile failed")
+                },
+            )
+        } finally {
+            _uiState.update { it.copy(isLoading = false) }
+        }
     }
 }

54-69: 연결 API는 중복 호출 가드(또는 버튼 disable)가 있으면 더 견고합니다.

빠른 연타로 connectToSenior()가 여러 번 실행될 수 있어요(서버 side-effect가 있으면 특히). UI에서 버튼 disable을 이미 한다면 OK이고, 아니면 VM에서도 가드가 있으면 안전합니다. 또한 로그는 Timber.e(t, ...) 형태가 좋아요.

제안 diff(가드 + finally + Timber)
 fun connectToSenior() {
     viewModelScope.launch {
+        if (_uiState.value.isLoading) return@launch
         _uiState.update { it.copy(isLoading = true) }
-        connectToSeniorUseCase(userId).fold(
-            onSuccess = {
-                _uiState.update { it.copy(isLoading = false) }
-                navigateToGuardianHome()
-            },
-            onFailure = { t ->
-                _uiState.update { it.copy(isLoading = false) }
-                Timber.e("connectToSenior: $t")
-            }
-        )
+        try {
+            connectToSeniorUseCase(userId).fold(
+                onSuccess = {
+                    navigateToGuardianHome()
+                },
+                onFailure = { t ->
+                    Timber.e(t, "connectToSenior failed")
+                }
+            )
+        } finally {
+            _uiState.update { it.copy(isLoading = false) }
+        }
     }
 }
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55049f5 and 1c62067.

📒 Files selected for processing (10)
  • core/network/src/main/kotlin/com/moa/app/network/adapter/NetworkResultCallAdapter.kt
  • core/network/src/main/kotlin/com/moa/app/network/adapter/ResponseHandler.kt
  • core/network/src/main/kotlin/com/moa/app/network/adapter/UnitResponseHandler.kt
  • data/src/main/kotlin/com/moa/app/data/user/datasource/UserDataSource.kt
  • data/src/main/kotlin/com/moa/app/data/user/datasourceImpl/UserDataSourceImpl.kt
  • data/src/main/kotlin/com/moa/app/data/user/model/response/ProfileResponse.kt
  • data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt
  • data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/ConnectionCheckViewModel.kt
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/model/ConnectionCheckUiState.kt
💤 Files with no reviewable changes (1)
  • data/src/main/kotlin/com/moa/app/data/user/model/response/ProfileResponse.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-21T09:07:31.486Z
Learnt from: wjdrjs00
Repo: team-memory-care/MoA-Android PR: 31
File: core/network/src/main/kotlin/com/moa/app/network/adapter/NetworkResultCall.kt:36-37
Timestamp: 2025-11-21T09:07:31.486Z
Learning: The MoA-Android project exclusively uses Retrofit suspend functions for network calls in the core/network module. The NetworkResultCall.execute() method intentionally throws UnsupportedOperationException because synchronous execution is not needed.

Applied to files:

  • core/network/src/main/kotlin/com/moa/app/network/adapter/NetworkResultCallAdapter.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Unit Tests
🔇 Additional comments (6)
data/src/main/kotlin/com/moa/app/data/user/datasource/UserDataSource.kt (1)

6-14: connectToSeniorResult<Unit>로 단순화한 건 변경 의도에 잘 맞습니다.

(호출 측에서 더 이상 응답 바디를 기대하지 않으니) 데이터 레이어 의존성도 같이 줄어드는 방향이라 좋습니다.

data/src/main/kotlin/com/moa/app/data/user/repositoryImpl/UserRepositoryImpl.kt (1)

39-41: 불필요한 Result 래핑 제거로 더 깔끔해졌습니다.

core/network/src/main/kotlin/com/moa/app/network/adapter/UnitResponseHandler.kt (1)

8-19: Unit 응답 처리 로직이 올바르게 개선되었습니다.

HTTP 응답이 성공(2xx)일 때 body가 null이거나 body.success가 true인 경우를 성공으로 처리하는 로직이 Unit 반환 타입에 적합합니다. 의미있는 데이터 페이로드가 없는 API에 대해 올바른 접근입니다.

data/src/main/kotlin/com/moa/app/data/user/datasourceImpl/UserDataSourceImpl.kt (1)

26-28: 데이터 소스 구현이 올바르게 업데이트되었습니다.

Result<ProfileResponse>에서 Result<Unit>으로의 반환 타입 변경과 함께 toResult { it }에서 toResult()로 변경한 것이 적절합니다. Unit 응답에는 매핑할 데이터가 없으므로 변환 함수가 불필요합니다.

core/network/src/main/kotlin/com/moa/app/network/adapter/ResponseHandler.kt (1)

8-21: 응답 처리 로직이 안전하게 개선되었습니다.

변경된 로직의 장점:

  • HTTP 상태를 먼저 확인하여 더 논리적인 흐름 제공
  • 데이터 응답(T != Unit)에 대해 non-null body를 요구하는 것이 적절함
  • body?.message ?: "Unknown Error"로 null 안전성 향상
  • Line 20의 최종 에러 반환으로 명확한 에러 처리 경로 제공

Line 14의 UNCHECKED_CASTBaseResponse<T> 계약이 준수된다면 안전합니다. UnitResponseHandler가 null body를 허용하는 것과 달리, 이 핸들러는 데이터 응답을 위해 body를 요구하는 것이 올바른 설계입니다.

data/src/main/kotlin/com/moa/app/data/user/service/UserService.kt (1)

24-24: API 반환 타입 변경이 올바르게 적용되었습니다.

connectToSenior의 반환 타입이 NetworkResult<Unit>로 변경되었으며, 서비스 계층부터 뷰모델까지 모든 레이어에서 일관되게 적용되었습니다. 데이터소스, 레포지토리, 유스케이스를 거쳐 뷰모델에서 .fold()로 올바르게 처리되고 있습니다.

@wjdrjs00 wjdrjs00 merged commit 6e41083 into develop Jan 10, 2026
4 checks passed
@wjdrjs00 wjdrjs00 deleted the refactor/72-user-connection-api branch January 10, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] 회원연결 API Response Type를 변경합니다.

1 participant