Skip to content

Conversation

@wjdrjs00
Copy link
Collaborator

@wjdrjs00 wjdrjs00 commented Nov 23, 2025

Related issue 🛠

Work Description ✏️

  • 온보딩 플로우 관련 비지니스 로직 구현
    • 사용자 역할 기반의 분기처리 로직 구현

Screenshot 📸

  • N/A

Uncompleted Tasks 😅

  • 회원가입 ux 개선하기
  • api 연동 작업 시 로그인 화면/로직 같이 구현하기

Summary by CodeRabbit

릴리즈 노트

  • 새로운 기능

    • 사용자 역할 선택 기반의 개선된 온보딩 흐름 추가
    • 사용 사용자 및 보호자 역할별 맞춤형 사용자 경험 제공
  • 개선 사항

    • 회원가입 프로필 화면의 성별 선택 로직 개선
    • 인증 코드 입력 화면의 버튼 활성화 조건 강화
    • 뒤로 가기 네비게이션 처리 개선
    • 상태 관리 및 사이드 이펙트 처리 강화

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

@wjdrjs00 wjdrjs00 self-assigned this Nov 23, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

Walkthrough

온보딩 흐름에 StateFlow/SharedFlow 기반 상태 및 사이드 이펙트를 도입하고, 도메인 모델(Gender, UserRole)을 추가했으며, 네비게이션에 clearBackStack 옵션과 UserConnection(userRole) 라우트 파라미터를 적용했습니다.

Changes

Cohort / File(s) Summary
Navigation infra
app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt, core/navigation/src/main/java/com/moa/app/navigation/NavigationOptions.kt
NavigationOptionsclearBackStack: Boolean = false 추가. ObserveNavigationEvents의 Navigate 처리: clearBackStack==true면 그래프 루트(graph.id)로 popUpTo(inclusive=true) 하고, 그렇지 않으면 기존 route 기반 popUpTo(inclusive/saveState) 동작 유지.
Route type change
core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt
UserConnection을 싱글턴 객체에서 data class UserConnection(val userRole: String)로 변경하여 라우트에 userRole 파라미터 추가.
Domain models
domain/src/main/kotlin/.../Gender.kt, domain/src/main/kotlin/.../UserRole.kt
Gender enum(MALE,FEMALE) 추가. UserRole enum(PARENT,CHILD) 추가 및 fromString() 유틸 구현.
Onboarding dependency
feature/onboarding/build.gradle.kts
implementation(projects.domain) 의존성 추가.
User Connection (UI + VM + model)
feature/onboarding/src/.../connection/UserConnectionScreen.kt, .../UserConnectionViewModel.kt, .../model/UserConnectionUiState.kt
ViewModel에 SavedStateHandle을 사용한 uiState: StateFlow<UserConnectionUiState] 도입, updateUserCode(), navigateToNext(), navigateToBack() 추가. Screen이 lifecycle-aware하게 uiState를 수집하고 back/next 버튼 및 입력 활성화 제어하도록 변경.
User Role selection (UI + VM + models)
feature/onboarding/src/.../role/SelectUserRoleScreen.kt, .../SelectUserRoleViewModel.kt, .../model/SelectUserUiState.kt, .../model/SelectUserSideEffect.kt
ViewModel에 uiState: StateFlowsideEffect: SharedFlow 추가, updateUserRole(), navigateToBack() 구현. CHILD 선택 시 ShowToast 사이드이펙트 발행. Screen은 MaTopAppBar 추가 및 lifecycle-aware 수집/토스트 처리 도입.
Sign-up state refactor
feature/onboarding/src/.../signup/*
상태 패키지 .state.model로 이동. SignUpProfileUiState.gender 타입을 Gender?로 변경하고 isGenderMale/isGenderFemale/isNextEnabled 계산 속성 추가. 인증 버튼 활성화 조건(authCode.isNotEmpty()) 적용.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SelectVM as SelectUserRoleViewModel
    participant SelectScreen as SelectUserRoleScreen
    participant Navigator
    participant ConnVM as UserConnectionViewModel
    participant ConnScreen as UserConnectionScreen

    User->>SelectScreen: 화면 진입
    SelectScreen->>SelectVM: uiState 수집
    User->>SelectScreen: 역할 선택
    SelectScreen->>SelectVM: updateUserRole(role)
    SelectVM->>SelectVM: _uiState 업데이트
    alt role == CHILD
        SelectVM->>SelectScreen: sideEffect ShowToast
        SelectScreen->>User: 토스트 표시
    else role == PARENT
        User->>SelectScreen: Next 클릭
        SelectScreen->>SelectVM: navigateToUserConnection()
        SelectVM->>Navigator: navigate(AppRoute.UserConnection(role))
        Navigator->>ConnScreen: 라우트 param 전달
        ConnScreen->>ConnVM: SavedStateHandle로 초기화
        ConnVM->>ConnVM: uiState 초기화
        User->>ConnScreen: 코드 입력
        ConnScreen->>ConnVM: updateUserCode(code)
        ConnVM->>ConnVM: _uiState 업데이트
        User->>ConnScreen: Next 클릭
        ConnScreen->>ConnVM: navigateToNext()
        ConnVM->>Navigator: navigate(..., clearBackStack=true)
        Navigator->>Navigator: popUpTo(graph.id, inclusive=true)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • 주의 파일:
    • SelectUserRoleViewModel.kt — StateFlow/SharedFlow 로직, side-effect 흐름 검증
    • UserConnectionViewModel.kt — SavedStateHandle에서 라우트 파라미터 추출 및 clearBackStack 네비게이션
    • AppRoute.kt — UserConnection 타입 변경에 따른 호출부 영향 범위 점검
    • ObserveNavigationEvents.kt — popUpTo 동작(특히 inclusive/saveState 조합)과 기존 시나리오 호환성 확인

Possibly related PRs

Poem

🐰 온보딩 길 따라 폴더를 건너뛰네,
State를 품고 라우트에 역할을 새기네.
ClearBackStack 깃발 펄럭이며,
토스트 한 점과 버튼의 빛,
햇살처럼 작게 건네네 — 점프! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive PR 설명이 필수 섹션은 포함하지만 Work Description이 비어있고 Uncompleted Tasks가 불명확하여 충분하지 않습니다. Work Description 섹션에 주요 변경 사항과 구현된 비즈니스 로직을 상세히 기술하고, Uncompleted Tasks를 구체적으로 작성해주세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 이슈 번호(#35)와 온보딩 플로우 비즈니스 로직 구현을 명확히 설명하며, 변경 사항의 핵심을 잘 요약하고 있습니다.
Linked Issues check ✅ Passed 변경 사항이 이슈 #35의 목표인 온보딩 플로우 비즈니스 로직 구현 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경 사항이 온보딩 플로우의 비즈니스 로직 구현과 관련된 범위 내에 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/35-onboarding-flow-logic

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: 2

🧹 Nitpick comments (12)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt (1)

153-153: 인증번호 길이 검증을 추가하는 것을 고려하세요.

현재 버튼은 인증번호가 비어있지 않을 때만 활성화되지만, 플레이스홀더 텍스트(141번 줄)에서 "4자리 인증번호"를 요구하고 있습니다. 길이 검증을 추가하면 잘못된 입력으로 인한 불필요한 검증 시도를 방지할 수 있습니다.

다음과 같이 수정을 고려해보세요:

-                enabled = uiState.authCode.isNotEmpty(),
+                enabled = uiState.authCode.length == 4,
domain/src/main/kotlin/com/moa/app/domain/auth/model/UserRole.kt (1)

15-21: fromString 메서드를 더 관용적인 방식으로 개선할 수 있습니다.

현재 구현은 하드코딩된 문자열 매칭을 사용합니다. Kotlin의 enumValueOf 또는 entries.find를 활용하면 더 간결하고 유지보수가 용이합니다.

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

 companion object {
     fun fromString(userRole: String): UserRole {
-        return when (userRole) {
-            "PARENT" -> PARENT
-            "CHILD" -> CHILD
-            else -> throw IllegalArgumentException("Invalid UserRole: $userRole")
-        }
+        return runCatching { enumValueOf<UserRole>(userRole) }
+            .getOrElse { throw IllegalArgumentException("Invalid UserRole: $userRole") }
     }
 }
core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1)

41-41: UserConnection 라우트의 userRole 표현 방식

도메인에서 이미 UserRole 모델을 쓰고 있다면, 여기서도 String 대신 enum(or 래퍼 타입)을 직접 쓰는 편이 타입 세이프티와 리팩터링 측면에서 더 안전합니다.
지금처럼 String 을 유지해야 한다면, role.toString() / fromString 변환 로직을 한 곳(확장 함수나 mapper)으로 모아 두면 오타나 값 변경 시 추적이 더 쉬울 것 같습니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/model/SelectUserUiState.kt (1)

5-21: 역할 기반 UI 상태 캡슐화 👍

userRole 하나에서 isUserRoleSenior / isUserRoleGuardian / isNextEnabled 를 파생시키는 구조가 깔끔하고, 뷰에서 조건식을 직접 다루지 않아도 되어 유지보수에 좋아 보입니다.

다만 도메인 enum 값(PARENT / CHILD)과 UI 용어(“시니어” / “보호자”)의 매핑이 직관적이지 않을 수 있으니, 의도를 짧게 KDoc 이나 주석으로 남겨 두면 이후 합류한 팀원들이 맥락을 이해하기 더 쉬울 것 같습니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionScreen.kt (1)

30-86: UserConnectionScreen 상태 바인딩 구조가 명확합니다

uiStatecollectAsStateWithLifecycle 로 수집해서 UserConnectionContent 로만 내려보내고, 화면 쪽에서는 userCode / isUserSenior / isNextEnabled 등 파생 상태만 사용하도록 한 구조가 Compose 권장 패턴과 잘 맞습니다. 시니어인 경우 입력창 비활성, 보호자인 경우 코드 길이에 따라 버튼 활성/비활성 되는 흐름도 UserConnectionUiState 와 일관됩니다.

사소한 부분으로는

  • onOtpTextChange = { onChangedUserCode(it) }onOtpTextChange = onChangedUserCode 로 단순화
  • "회원코드 입력" 같은 하드코딩 문자열을 string 리소스로 추출
    정도만 추후에 정리해 두면 더 깔끔할 것 같습니다.
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/model/UserConnectionUiState.kt (1)

5-33: UserConnectionUiState 파생 값 로직 및 네이밍

isUserSenior 를 기준으로 타이틀/버튼 텍스트와 isNextEnabled 를 모두 파생시키는 구조가 명확해서, 화면 쪽에서는 조건식을 알 필요가 없어 잘 정리된 것 같습니다.

다만 두 가지 정도만 확인/정리해 두면 좋겠습니다.

  1. isNextEnabled 는 시니어(PARENT) 인 경우 항상 true 인데, 즉 회원코드가 비어 있어도 “넘어가기” 가 가능하다는 의미입니다. 실제 온보딩 UX 기획이 “시니어는 코드 없이도 다음 단계로 진행 가능” 이라는 전제를 가지고 있는지 한 번만 다시 확인 부탁드립니다.
  2. 프로퍼티 이름이 setTitle / setButtonTitle 이라 setter 처럼 읽힐 수 있어서, title / buttonTitle 처럼 명사형 이름으로 바꾸면 코드 읽을 때 의도가 더 자연스럽게 전달될 것 같습니다.
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/model/SignUpProfileUiState.kt (1)

1-30: Gender 도입 및 다음 버튼 활성화 조건이 명확합니다

문자열 대신 Gender? 를 사용하고, isNextEnabledgender != null 을 포함시킨 부분이 도메인 모델과 잘 맞고, 성별 선택이 안 되면 다음으로 못 넘어가게 제어하는 의도도 분명합니다. isGenderMale / isGenderFemale 파생 프로퍼티 덕분에 뷰 코드도 단순해질 것 같습니다.

다만 다른 UiState 들(SelectUserUiState.INIT, UserConnectionUiState.INIT)은 초기 상태를 대문자 INIT 상수로 노출하는데, 여기만 init(소문자) 라는 이름을 쓰고 있어 API 일관성 측면에서 조금 튀어 보입니다. 가능하다면 이쪽도 INIT 으로 맞추고, 호출부에서 사용하는 이름도 함께 정리해 두는 것을 추천드립니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleViewModel.kt (1)

40-53: CHILD 가드/토스트/라우트 문자열 매핑 일관성 확인 권장

  • UserRole.CHILD 선택 시 토스트만 띄우고 네비게이션을 막는 로직은 스펙상 의도라면 괜찮지만, UI 텍스트(“보호자”)·도메인 enum 이름(CHILD)·토스트 메시지가 서로 헷갈릴 여지가 있어 한 번 더 정합성 확인을 추천합니다.
  • 토스트 메시지 문자열을 ViewModel에 하드코딩하기보다는, 나중 i18n·문구 변경을 고려해 상수/리소스 ID 등으로 추상화해 두면 유지보수에 유리합니다.
  • AppRoute.UserConnection(role.toString())UserRole.fromString 구현과 강하게 결합되므로, 추후 toString 오버라이드나 표현 변경 가능성을 막기 위해 name 혹은 전용 code 프로퍼티로 직렬화하는 방식을 검토해 보셔도 좋겠습니다.
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleScreen.kt (2)

40-55: sideEffect 수집 패턴은 적절하나 키와 컨텍스트 사용은 미세 조정 여지 있음

LaunchedEffect + flowWithLifecycleSharedFlow를 수집하는 구조는 문제 없어 보입니다. 다만:

  • LaunchedEffect(Unit) 대신 LaunchedEffect(lifecycleOwner.lifecycle) 정도로 두면 lifecycleOwner 교체 상황에서도 안전합니다.
  • Toastcontext를 그대로 넘기는 방식도 현재 구조(컴포저블 dispose 시 코루틴 취소)라면 누수 위험은 낮지만, 필요시 applicationContext 사용도 고려할 수 있습니다.

85-89: 하드코딩된 사용자 노출 문자열은 string 리소스로 분리하는 편이 좋습니다

제목/설명/버튼 텍스트를 모두 코드에서 직접 Korean 문자열로 관리하고 있는데, 다국어 지원·카피 수정 빈도를 고려하면 R.string.* 리소스로 분리해 두는 편이 유지보수와 테스트 모두에 유리합니다.

Also applies to: 112-121, 147-155, 168-169

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionViewModel.kt (2)

42-51: popUpTo/clearBackStack 조합이 의도한 온보딩 종료 플로우와 맞는지 확인 권장

navigateToSeniorHome에서 popUpTo = AppRoute.UserConnection(userRole), inclusive = true, clearBackStack = true로 설정해 온보딩 스택을 정리하고 있는데, 이 조합이 실제 내비게이션 구현에서 “온보딩 전체 스택 정리 후 홈 진입”과 정확히 대응하는지 한 번 시나리오 기준으로 검증해 보시면 좋겠습니다.


53-59: 현재 CHILD(보호자) 플로우는 사실상 막혀 있으므로 TODO 상태가 실 플로우와 맞는지 재확인 필요

이전 역할 선택 화면에서 이미 UserRole.CHILD에 대해 네비게이션을 막고 있으므로, 현 시점에서 navigateToNextelse(비-senior) 분기는 사실상 도달 불가능한 상태일 가능성이 큽니다. 스펙상 보호자 플로우를 아직 열지 않는 것이 맞다면, 주석에 그 맥락(이전 화면에서 가드됨)을 적어 두거나, 나중에 활성화할 TODO 티켓과 링크해 두면 추후 변경 시 혼동을 줄일 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0259292 and bf51d96.

📒 Files selected for processing (18)
  • app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt (1 hunks)
  • core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1 hunks)
  • core/navigation/src/main/java/com/moa/app/navigation/NavigationOptions.kt (1 hunks)
  • domain/src/main/kotlin/com/moa/app/domain/auth/model/Gender.kt (1 hunks)
  • domain/src/main/kotlin/com/moa/app/domain/auth/model/UserRole.kt (1 hunks)
  • feature/onboarding/build.gradle.kts (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionScreen.kt (3 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionViewModel.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/model/UserConnectionUiState.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleScreen.kt (3 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleViewModel.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/model/SelectUserSideEffect.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/model/SelectUserUiState.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt (2 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt (3 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpSharedViewModel.kt (2 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/model/SignUpPhoneAuthUiState.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/model/SignUpProfileUiState.kt (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionScreen.kt (2)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/topbar/MaTopAppBar.kt (1)
  • MaTopAppBar (20-52)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/textfield/MaOtpTextField.kt (1)
  • MaOtpTextField (29-82)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleScreen.kt (3)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/topbar/MaTopAppBar.kt (1)
  • MaTopAppBar (20-52)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/button/MaSelectButton.kt (1)
  • MaSelectButton (30-64)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/button/MaButton.kt (1)
  • MaButton (30-68)
app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt (1)
core/navigation/src/main/java/com/moa/app/navigation/NavigationOptions.kt (1)
  • popUpTo (13-24)
⏰ 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: Run Unit Tests
  • GitHub Check: Run ktlint
🔇 Additional comments (15)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt (1)

30-30: import 경로 변경이 일관되게 반영되었습니다.

검증 결과, SignUpPhoneAuthUiState의 import 경로 변경이 코드베이스 전체에서 올바르게 적용되었습니다:

  • SignUpPhoneAuthScreen.kt (line 30): 새 import 경로 사용 ✓
  • SignUpSharedViewModel.kt (line 6): 새 import 경로 사용 ✓
  • 클래스 정의: model 패키지에서 올바르게 위치 ✓
  • 이전 import 경로 사용 없음 ✓
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/model/SignUpPhoneAuthUiState.kt (1)

1-23: 패키지 구조 개선이 적절합니다.

UI 상태 클래스를 model 패키지로 이동한 것은 코드 구조를 명확하게 하는 좋은 리팩토링입니다.

feature/onboarding/build.gradle.kts (1)

14-14: 도메인 모듈 의존성 추가가 적절합니다.

온보딩 플로우에서 도메인 모델(Gender, UserRole)을 사용하기 위한 필수 의존성입니다.

domain/src/main/kotlin/com/moa/app/domain/auth/model/Gender.kt (1)

1-3: 간단하고 명확한 도메인 모델입니다.

성별을 나타내는 enum이 타입 안전성을 제공하여 문자열 리터럴 사용보다 우수합니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpSharedViewModel.kt (3)

5-7: 도메인 모델 사용으로 타입 안전성이 향상되었습니다.

Gender enum 사용과 업데이트된 패키지 구조가 코드베이스를 개선합니다.


47-51: Gender enum 사용이 적절합니다.

문자열 리터럴 대신 Gender.MALEGender.FEMALE을 사용하여 타입 안전성과 리팩토링 용이성이 향상되었습니다.


64-78: API 통합 TODO는 PR 목표와 일치합니다.

PR 설명에 따르면 서버 스펙 확정 후 별도 작업으로 API 통합을 진행할 예정이므로, 현재 TODO 주석은 적절합니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/model/SelectUserSideEffect.kt (1)

1-5: 사이드 이펙트 처리를 위한 좋은 패턴입니다.

Sealed interface를 사용한 사이드 이펙트 모델링은 타입 안전하고 확장 가능한 접근 방식입니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt (2)

32-32: 패키지 구조 변경이 일관되게 적용되었습니다.

SignUpProfileUiStatemodel 패키지에서 import하여 모듈 재구성과 일치합니다.


224-244: Gender 기반 UI 상태 속성을 올바르게 사용하고 있습니다.

isGenderMaleisGenderFemale 계산 속성을 사용하여 버튼 선택 상태를 표시하는 것이 깔끔하고 읽기 쉽습니다.

core/navigation/src/main/java/com/moa/app/navigation/NavigationOptions.kt (1)

11-19: clearBackStack 옵션이 올바르게 구현되어 있습니다.

ObserveNavigationEvents.kt 라인 28-37에서 clearBackStack 플래그가 정확히 처리되고 있습니다:

  • clearBackStack=true일 때: popUpTo(navController.graph.id) + inclusive=true로 전체 백스택 초기화
  • clearBackStack=false일 때: 제공된 popUpTo 라우트 사용
  • if/else 구조로 popUpTo보다 올바른 우선순위 적용

문서의 명시 사항과 구현이 일치하며, UserConnectionViewModel.kt에서도 실제 사용이 확인됩니다.

app/src/main/kotlin/com/moa/app/navigation/ObserveNavigationEvents.kt (1)

28-37: clearBackStack 분기 처리 의도 확인

clearBackStack == true 일 때 popUpTo(navController.graph.id) { inclusive = true } 로 전체 스택을 비우고, 그렇지 않을 때만 options.popUpTo / inclusive / saveState 를 적용하는 구조라, 온보딩 → 메인 같은 “완전 초기화” 시나리오에는 잘 맞는 구현 같습니다.

다만 호출 측에서 clearBackStackpopUpTo 가 동시에 설정될 수 있다면 현재는 항상 clearBackStack 이 우선하는 셈이라, 이 우선순위가 기획/호출부 의도와 정확히 일치하는지만 한 번 더 확인해 보시면 좋겠습니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleViewModel.kt (1)

27-35: UI 상태 & 역할 업데이트 로직 구조는 적절합니다

StateFlow/MutableStateFlow로 INIT 상태를 노출하고, updateUserRole에서 copy 기반으로 갱신하는 패턴은 깔끔하고 추적도 용이합니다. 현재 요구사항 기준으로 추가적인 방어 로직은 없어도 될 것 같습니다.

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/role/SelectUserRoleScreen.kt (1)

68-72: 역할 버튼과 UserRole 매핑/상태는 명확하나, 향후 스펙 변경 시 영향 범위만 인지해 두면 좋겠습니다

  • 상단 선택지에서 “저는 본인이에요” → UserRole.PARENT, “가족이나 보호자” → UserRole.CHILD로 매핑하고, 선택 여부는 uiState.isUserRoleSenior / isUserRoleGuardian으로 표현되어 ViewModel 로직과 일관적으로 동작할 것으로 보입니다.
  • 현재는 CHILD 선택 시 이전 ViewModel에서 네비게이션을 막고 토스트만 띄우므로, 향후 보호자 플로우를 열 때 이 부분(콜백, isNextEnabled 계산, 이후 화면 로직)까지 한 번에 손봐야 한다는 점만 인지해 두시면 될 것 같습니다.

Also applies to: 93-157

feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionViewModel.kt (1)

24-36: userRole 문자열 파싱 시 예외/디폴트 처리 여부 한 번만 점검해 주세요

SavedStateHandle에서 가져온 userRole을 곧바로 UserRole.fromString(role)에 넘기고 있어서, 네비게이션 인자가 잘못되었을 때의 동작(예외 발생 vs 디폴트 값 반환)을 확인해 둘 필요가 있습니다. 잘못된 값이 들어와도 앱이 크래시하지 않도록 fromString 구현 혹은 이 호출부에서의 방어 로직을 한 번만 검토해 주세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
domain/src/main/kotlin/com/moa/app/domain/auth/model/UserRole.kt (1)

14-22: fromString 구현을 더 간결하게 개선할 수 있습니다.

현재 when 표현식을 사용한 구현도 정확하지만, Kotlin의 enumValues() 또는 entries.find를 활용하면 더 간결하고 유지보수하기 쉬운 코드로 개선할 수 있습니다.

다음 diff를 적용하여 개선할 수 있습니다:

     companion object {
         fun fromString(userRole: String): UserRole {
-            return when (userRole) {
-                "PARENT" -> PARENT
-                "CHILD" -> CHILD
-                else -> throw IllegalArgumentException("Invalid UserRole: $userRole")
-            }
+            return entries.find { it.name == userRole }
+                ?: throw IllegalArgumentException("Invalid UserRole: $userRole")
         }
     }
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionViewModel.kt (1)

53-59: 보호자(Guardian) 플로우가 미구현 상태입니다.

시니어가 아닌 경우(보호자) 처리 로직에 TODO가 남아있습니다. PR 목표에 따라 일부 작업을 연기하는 것으로 보이지만, 현재 상태에서는 보호자가 "다음" 버튼을 눌러도 아무 동작도 하지 않습니다.

보호자 플로우 구현 코드를 생성하거나 이를 추적할 이슈를 생성하도록 도와드릴까요?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf51d96 and 1ac0b37.

📒 Files selected for processing (2)
  • domain/src/main/kotlin/com/moa/app/domain/auth/model/UserRole.kt (1 hunks)
  • feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionViewModel.kt (1 hunks)
⏰ 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)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/connection/UserConnectionViewModel.kt (3)

61-61: navigateToBack 구현이 올바르게 수정되었습니다.

이전 리뷰에서 지적된 타입 불일치 문제가 해결되었습니다. 현재 구현은 navigator.navigateBack()을 직접 호출하여 Unit을 반환하므로, onBackClick: () -> Unit 파라미터와 타입이 정확히 일치합니다.


42-51: 온보딩 완료 후 백스택 정리가 적절히 구현되었습니다.

navigateToSeniorHome 메서드가 private으로 변경되고 clearBackStack = true 옵션이 추가되어, 시니어 홈 화면 진입 후 뒤로가기로 온보딩 화면에 재진입하는 것을 방지합니다. 이는 일반적인 온보딩 플로우 패턴에 부합합니다.


26-31: StateFlow 기반 상태 관리가 올바르게 구현되었습니다.

private _uiState와 public uiState로 불변성을 보장하고, update 함수를 사용한 상태 갱신 패턴이 적절히 적용되었습니다. updateUserCode 메서드는 UI에서 사용자 입력을 반영하는 명확한 인터페이스를 제공합니다.

Also applies to: 38-40

@wjdrjs00 wjdrjs00 merged commit 5f89647 into develop Nov 23, 2025
4 checks passed
@wjdrjs00 wjdrjs00 deleted the feature/35-onboarding-flow-logic branch November 23, 2025 17:46
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.

[Feature] 온보딩 플로우 관련 비즈니스 로직을 구현합니다.

2 participants