[SPM-433] 프로필 수정 및 회원 관리 구현#30
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 변경 사항 분석요약사용자 인증 및 관리 기능을 재구조화하여 User 모델을 auth에서 user 기능 패키지로 이동하고, 직원 목록 관리, 프로필 편집, 대시보드 개선 등 새로운 기능을 추가했습니다. Material3 의존성이 추가되었습니다. 변경 사항
시퀀스 다이어그램sequenceDiagram
participant User as 사용자
participant LoginVM as LoginViewModel
participant AuthRepo as AuthRepository
participant UserRepo as UserRepository
participant ProfileUC as GetProfileUseCase
participant AuthPrefs as AuthPreferences
User->>LoginVM: 로그인 시도
LoginVM->>AuthRepo: signIn(email, password)
AuthRepo-->>LoginVM: Result<User> (기본 필드)
LoginVM->>ProfileUC: 프로필 조회 ("AGENCY")
ProfileUC->>UserRepo: getProfile("AGENCY")
UserRepo->>AuthPrefs: 저장된 토큰 조회
UserRepo-->>ProfileUC: Result<User> (완전한 정보)
ProfileUC-->>LoginVM: Result<User>
LoginVM->>AuthPrefs: User 저장
LoginVM-->>User: 로그인 성공
sequenceDiagram
participant User as 사용자
participant DashboardScreen as DashboardScreen
participant AppNavHost as AppNavHost
participant EmployeeListScreen as EmployeeListScreen
participant EmployeeListVM as EmployeeListViewModel
participant UserRepo as UserRepository
User->>DashboardScreen: 직원 버튼 클릭
DashboardScreen->>AppNavHost: onEmployeeClick()
AppNavHost->>EmployeeListScreen: ROUTE_EMPLOYEE 네비게이션
EmployeeListScreen->>EmployeeListVM: 로드 시작
EmployeeListVM->>UserRepo: getEmployeeList() (페이징)
UserRepo-->>EmployeeListVM: Flow<PagingData<Employee>>
EmployeeListVM-->>EmployeeListScreen: 직원 목록 표시
User->>EmployeeListScreen: 직원 편집 클릭
EmployeeListScreen->>EmployeeListScreen: 바텀 시트 열기 (EditEmployeeBottomSheet)
예상 코드 리뷰 난이도🎯 4 (복잡) | ⏱️ ~60분 특별 주의 사항
관련 PR
제안 레이블
제안 검토자
축하 시
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt (1)
49-66: login API 응답에 필요한 사용자 정보가 부족합니다. 현재 여러 필드가 빈 문자열과 기본값으로 초기화되고 있습니다.검증 결과, 리뷰 의견이 정확합니다.
LoginResponseDto는 userId, accessToken, refreshToken, expiresIn 4개 필드만 제공하지만, User 모델은 userName, email, role, workspace, branch, agencyId 등 14개 필드를 필요로 합니다. 현재toModel()매퍼는 다음과 같이 처리하고 있습니다:
- userName, email, role, workspace, branch: 빈 문자열 ("")
- position: 하드코딩된 기본값 (UserPosition.STAFF)
- agencyId: 0 (유효하지 않은 ID)
- startedAt, endedAt: null
이는 불완전한 User 객체가 애플리케이션 상태에 저장되도록 하므로, 사용자 관련 기능(역할 기반 접근 제어, 이메일 작업, 프로필 표시 등)이 제대로 작동할 수 없습니다. login API에서 이 정보들을 응답으로 받거나, 로그인 후 별도로 프로필 정보를 조회하여 User 객체를 완성해야 합니다.
app/src/main/java/com/sampoom/android/feature/auth/data/mapper/AuthMappers.kt (1)
9-23: 로그인 직후 저장되는 User 정보가 비어 있어 후속 요청이 실패합니다.
LoginResponseDto.toModel()에서workspace,role,branch,agencyId,userName,UserRepository.getProfile(workspace: String)같은 호출은 저장된User.workspace값을 그대로 사용하므로, 현재 구현대로면 빈 workspace로 API를 호출해 400/404를 유발하고 프로필/직원 리스트 기능이 전부 막힙니다. DTO가 제공하는 실제 필드를 그대로 매핑하도록 원래의 구현을 복구하거나 동일한 데이터를 채워 넣어 주세요.app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt (1)
193-195: 컴파일 오류: 상태 복사 구문이 불완전합니다.
copy(loading = false, )구문이 미완성이라 빌드가 실패합니다. 누락된 필드를 명시해 주세요.- _state.update { - it.copy(loading = false, ) - } + _state.update { + it.copy(loading = false, success = false) + }
🧹 Nitpick comments (4)
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (1)
91-105: 하드코딩된 "AGENCY" 문자열을 상수로 추출하세요.로그인 성공 후 프로필을 가져오는 로직은 올바르게 구현되었습니다. 하지만
"AGENCY"문자열이 하드코딩되어 있어 유지보수성이 떨어집니다.다음과 같이 상수로 추출하는 것을 권장합니다:
@HiltViewModel class LoginViewModel @Inject constructor( private val messageHandler: GlobalMessageHandler, private val singIn: LoginUseCase, private val getProfile: GetProfileUseCase, private val application: Application ) : ViewModel() { private companion object { private const val TAG = "LoginViewModel" + private const val DEFAULT_WORKSPACE = "AGENCY" }그리고 사용 부분을 다음과 같이 변경하세요:
- getProfile("AGENCY") + getProfile(DEFAULT_WORKSPACE)app/src/main/java/com/sampoom/android/feature/user/data/mapper/UserMappers.kt (1)
27-31: 직책 변환 시 로깅 추가를 고려해보세요.잘못된 직책 값이 전달될 때 자동으로 STAFF로 변환되는데, 디버깅을 위해 이러한 경우를 로깅하면 API 계약 문제를 더 쉽게 파악할 수 있습니다.
다음과 같이 로깅을 추가할 수 있습니다:
private fun String.toUserPosition(): UserPosition = try { UserPosition.valueOf(this.uppercase()) } catch (_: IllegalArgumentException) { + Log.w("UserMappers", "Invalid position value: $this, defaulting to STAFF") UserPosition.STAFF }app/src/main/java/com/sampoom/android/feature/user/data/paging/EmployeePagingSource.kt (1)
34-34: 하드코딩된 문자열 상수화 권장
"AGENCY"문자열이 하드코딩되어 있습니다. 향후 유지보수성을 위해 상수나 enum으로 추출하는 것을 권장합니다.예시:
companion object { private const val WORKSPACE_TYPE_AGENCY = "AGENCY" } // 사용: val response = api.getEmployeeList(WORKSPACE_TYPE_AGENCY, agencyId, page, pageSize)app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt (1)
67-67: 역할 기반 관리자 체크로 간소화됨
UserPosition열거형 체크에서role == "ADMIN"문자열 비교로 변경되어 로직이 간소화되었습니다. 다만"ADMIN"문자열이 하드코딩되어 있습니다.향후 유지보수를 위해 역할 문자열을 상수로 추출하는 것을 고려해보세요:
private const val ROLE_ADMIN = "ADMIN" // 사용: val isManager = user?.role == ROLE_ADMINAlso applies to: 78-78
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (58)
app/build.gradle.kts(1 hunks)app/src/main/java/com/sampoom/android/MainActivityViewModel.kt(1 hunks)app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt(3 hunks)app/src/main/java/com/sampoom/android/core/network/TokenRefreshService.kt(1 hunks)app/src/main/java/com/sampoom/android/core/preferences/AuthPreferences.kt(1 hunks)app/src/main/java/com/sampoom/android/core/util/AuthValidator.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/auth/data/mapper/AuthMappers.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/auth/data/remote/api/AuthApi.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/auth/data/remote/dto/UpdateProfileRequestDto.kt(0 hunks)app/src/main/java/com/sampoom/android/feature/auth/data/remote/dto/UpdateProfileResponseDto.kt(0 hunks)app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt(2 hunks)app/src/main/java/com/sampoom/android/feature/auth/domain/repository/AuthRepository.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/auth/domain/usecase/GetStoredUserUseCase.kt(0 hunks)app/src/main/java/com/sampoom/android/feature/auth/domain/usecase/LoginUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/auth/domain/usecase/SignUpUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt(4 hunks)app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt(4 hunks)app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt(12 hunks)app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardViewModel.kt(2 hunks)app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.kt(7 hunks)app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingUiEvent.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingUiState.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingViewModel.kt(3 hunks)app/src/main/java/com/sampoom/android/feature/user/data/mapper/UserMappers.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/paging/EmployeePagingSource.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EditEmployeeRequestDto.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EditEmployeeResponseDto.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EmployeeDto.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EmployeeListDto.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/GetProfileResponseDto.kt(2 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/UpdateProfileRequestDto.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/UpdateProfileResponseDto.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/di/UserModules.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/model/Employee.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/model/EmployeeList.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/model/User.kt(2 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/repository/UserRepository.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/usecase/EditEmployeeUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/usecase/GetEmployeeUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/usecase/GetProfileUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/usecase/GetStoredUserUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/domain/usecase/UpdateProfileUseCase.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeBottomSheet.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeUiEvent.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeUiState.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeViewModel.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListScreen.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListUiEvent.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListUiState.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListViewModel.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileBottomSheet.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileUiEvent.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileUiState.kt(1 hunks)app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileViewModel.kt(1 hunks)app/src/main/res/values/strings.xml(2 hunks)gradle/libs.versions.toml(2 hunks)
💤 Files with no reviewable changes (3)
- app/src/main/java/com/sampoom/android/feature/auth/domain/usecase/GetStoredUserUseCase.kt
- app/src/main/java/com/sampoom/android/feature/auth/data/remote/dto/UpdateProfileRequestDto.kt
- app/src/main/java/com/sampoom/android/feature/auth/data/remote/dto/UpdateProfileResponseDto.kt
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-15T14:15:21.212Z
Learnt from: Sangyoon98
Repo: 33-Auto/Sampoom-Management-Android PR: 15
File: app/src/main/java/com/sampoom/android/feature/auth/domain/AuthValidator.kt:12-15
Timestamp: 2025-10-15T14:15:21.212Z
Learning: The email validation regex pattern in AuthValidator.kt (app/src/main/java/com/sampoom/android/feature/auth/domain/AuthValidator.kt) was decided after consultation with the backend team. The pattern "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+" is intentionally restrictive to match backend requirements.
Applied to files:
app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.ktapp/src/main/java/com/sampoom/android/core/util/AuthValidator.kt
📚 Learning: 2025-10-23T12:27:55.160Z
Learnt from: Sangyoon98
Repo: 33-Auto/Sampoom-Management-Android PR: 19
File: app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt:81-81
Timestamp: 2025-10-23T12:27:55.160Z
Learning: In the Sampoom-Management-Android project, PullToRefreshBox's isRefreshing parameter is intentionally set to false across screens (PartListScreen, CartListScreen, OrderDetailScreen, OrderListScreen, OutboundListScreen) while the internal Indicator still uses the loading state from uiState. This is a deliberate pattern where loading state is managed separately and Pull-to-Refresh only activates on user action.
Applied to files:
app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.ktapp/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt
🧬 Code graph analysis (11)
app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListScreen.kt (7)
app/src/main/java/com/sampoom/android/core/ui/component/ErrorContent.kt (1)
ErrorContent(17-36)app/src/main/java/com/sampoom/android/core/ui/component/EmptyContent.kt (1)
EmptyContent(11-26)app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeBottomSheet.kt (1)
EditEmployeeBottomSheet(32-113)app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (3)
backgroundCardColor(253-254)textColor(256-257)textSecondaryColor(259-260)app/src/main/java/com/sampoom/android/core/util/PositionToKorean.kt (1)
positionToKorean(5-17)app/src/main/java/com/sampoom/android/core/util/FormatDate.kt (1)
formatDate(5-26)app/src/main/java/com/sampoom/android/core/ui/component/CommonButton.kt (1)
CommonButton(46-173)
app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeViewModel.kt (3)
app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt (1)
editEmployee(23-28)app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (1)
editEmployee(101-132)app/src/main/java/com/sampoom/android/feature/user/domain/repository/UserRepository.kt (1)
editEmployee(13-13)
app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt (1)
app/src/main/java/com/sampoom/android/core/util/AuthValidator.kt (3)
validateEmail(7-18)validatePassword(21-43)validatePasswordCheck(46-56)
app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileViewModel.kt (3)
app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt (1)
updateProfile(20-21)app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (1)
updateProfile(62-92)app/src/main/java/com/sampoom/android/feature/user/domain/repository/UserRepository.kt (1)
updateProfile(11-11)
app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileBottomSheet.kt (2)
app/src/main/java/com/sampoom/android/core/ui/component/CommonTextField.kt (1)
CommonTextField(28-143)app/src/main/java/com/sampoom/android/core/ui/component/CommonButton.kt (1)
CommonButton(46-173)
app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.kt (1)
app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileBottomSheet.kt (1)
UpdateProfileBottomSheet(27-84)
app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (1)
app/src/main/java/com/sampoom/android/core/util/DelayNetwork.kt (1)
retry(7-30)
app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingViewModel.kt (1)
app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardViewModel.kt (1)
refreshUser(130-134)
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (1)
app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListScreen.kt (1)
EmployeeListScreen(62-251)
app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeBottomSheet.kt (3)
app/src/main/java/com/sampoom/android/core/ui/component/CommonTextField.kt (1)
CommonTextField(28-143)app/src/main/java/com/sampoom/android/core/util/PositionToKorean.kt (1)
positionToKorean(5-17)app/src/main/java/com/sampoom/android/core/ui/component/CommonButton.kt (1)
CommonButton(46-173)
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (3)
app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt (2)
getProfile(16-37)getProfile(17-18)app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (1)
getProfile(28-60)app/src/main/java/com/sampoom/android/feature/user/domain/repository/UserRepository.kt (1)
getProfile(10-10)
🪛 detekt (1.23.8)
app/src/main/java/com/sampoom/android/feature/user/data/paging/EmployeePagingSource.kt
[warning] 31-31: 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 (56)
app/src/main/java/com/sampoom/android/feature/auth/domain/usecase/LoginUseCase.kt (1)
3-3: User 모델 패키지 이동이 전체 코드베이스에서 일관되게 반영되었습니다.LoginUseCase.kt의 import 변경이 올바르게 적용되었으며, AuthRepository 인터페이스도 동일한 새로운 User 타입을 사용하도록 업데이트되었습니다. 이전 import 경로에 대한 참조는 코드베이스에서 찾을 수 없으며, 모든 타입 시그니처가 일관되게 유지되고 있습니다.
app/src/main/java/com/sampoom/android/feature/auth/domain/repository/AuthRepository.kt (2)
6-22: 마이그레이션 검증 완료 - 문제 없음AuthRepository에서
getProfile메서드가 완전히 제거되었으며, 다음과 같이 올바르게 마이그레이션되었습니다:
- UserRepository 인터페이스에
getProfile메서드 정의- GetProfileUseCase가 user feature에서 구현
- SignUpViewModel과 LoginViewModel이 GetProfileUseCase를 사용하도록 업데이트
- 마이그레이션되지 않은 AuthRepository.getProfile 호출 없음
관심사의 분리가 적절히 수행되었고 모든 호출 지점이 새로운 위치로 마이그레이션되었습니다.
4-4: 마이그레이션이 완료되고 올바르게 구현되었습니다.검증 결과, User 모델의 패키지 이동이 완전히 완료되었습니다:
- AuthRepository.kt: 새로운 경로
com.sampoom.android.feature.user.domain.model.User올바르게 import됨- 이전 import 경로 제거됨:
com.sampoom.android.feature.auth.domain.model.User에 대한 참조 없음- 모든 사용처 업데이트됨: 30개 이상의 파일에서 새로운 import 경로를 일관되게 사용 중
- 관심사 분리 달성: auth.domain.model은 VendorList와 Vendor만 보유하며, User는 user.domain으로 완전히 이동됨
app/src/main/java/com/sampoom/android/MainActivityViewModel.kt (1)
6-7: LGTM!User 모델과 GetStoredUserUseCase의 패키지 이동이 올바르게 반영되었습니다.
app/src/main/java/com/sampoom/android/feature/user/domain/usecase/EditEmployeeUseCase.kt (1)
7-11: LGTM!Use case 구현이 Clean Architecture 패턴을 올바르게 따르고 있으며, 단일 책임 원칙을 준수합니다.
app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/UpdateProfileRequestDto.kt (1)
3-5: LGTM!프로필 업데이트를 위한 간단한 DTO 구조가 적절합니다.
app/src/main/java/com/sampoom/android/core/util/AuthValidator.kt (1)
1-1: LGTM!AuthValidator를
core.util패키지로 이동하여 여러 기능 모듈에서 공유할 수 있도록 한 것은 좋은 리팩토링입니다.app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt (1)
12-12: LGTM!User 모델이 user 도메인으로 올바르게 이동되었습니다.
app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EditEmployeeResponseDto.kt (1)
3-8: LGTM!직원 편집 응답을 위한 DTO 구조가 적절하며, 필드 타입이 올바르게 정의되었습니다.
app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EditEmployeeRequestDto.kt (1)
3-5: 검증 완료: 직원 식별자는 URL 경로 매개변수로 올바르게 전달됩니다.
EditEmployeeRequestDto는 올바르게 설계되었습니다. 직원 식별자(userId)는@Path("userId")매개변수를 통해 URL 경로(/user/profile/{userId})로 전달되며, 요청 본문에는 수정할 필드(position)만 포함됩니다. 이는 표준 REST API 패턴입니다.app/src/main/java/com/sampoom/android/feature/user/domain/usecase/GetProfileUseCase.kt (1)
7-11: LGTM!Use case 구현이 올바르며, 클린 아키텍처 패턴을 잘 따르고 있습니다. Repository로의 단순한 위임 패턴이 적절하게 적용되었습니다.
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (2)
9-10: LGTM!Validator 클래스들을
core.util로 이동한 것은 적절한 리팩토링입니다. 공통 유틸리티를 core 패키지에 배치하는 것이 아키텍처 관점에서 올바릅니다.
21-24: LGTM!
GetProfileUseCase의존성 추가가 적절합니다. 생성자 주입 패턴이 올바르게 적용되었습니다.app/src/main/res/values/strings.xml (2)
117-126: LGTM!직원 관리 관련 문자열 리소스가 적절하게 추가되었습니다. 네이밍 컨벤션이 일관성 있게 유지되고 있습니다.
140-141: LGTM!프로필 수정 관련 문자열 리소스가 적절하게 추가되었습니다.
app/src/main/java/com/sampoom/android/feature/auth/domain/usecase/SignUpUseCase.kt (1)
3-3: LGTM!User 모델을 user feature로 이동한 리팩토링이 적절합니다. 도메인 모델을 해당 feature 패키지에 배치하는 것이 아키텍처 관점에서 올바릅니다.
app/src/main/java/com/sampoom/android/core/network/TokenRefreshService.kt (1)
6-6: LGTM!User 모델 import 경로 변경이 적절합니다. 다른 파일들과 일관성 있게 user feature 패키지를 사용하고 있습니다.
app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardViewModel.kt (2)
13-14: LGTM!User 및 GetStoredUserUseCase를 user feature 패키지로 이동한 import 변경이 적절합니다.
130-134: LGTM!
refreshUser()메서드 구현이 올바릅니다. 사용자 정보를 갱신하는 명확한 public API를 제공하고 있습니다.app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingUiEvent.kt (1)
1-6: EditProfile 이벤트 제거는 안전합니다. 활성 사용 사례가 없습니다.검증 결과, SettingUiEvent 인터페이스에 정의된 이벤트는 LoadProfile과 NameChanged이며, SettingViewModel의 onEvent() 메서드도 이 두 이벤트만 처리합니다. SettingScreen에서도 SettingUiEvent.LoadProfile만 사용 중입니다. EditProfile 이벤트는 현재 코드베이스 어디에서도 참조되지 않으므로, 제거로 인한 문제는 없습니다.
app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EmployeeListDto.kt (2)
3-6: 페이징 처리된 직원 목록 응답 구조가 적절합니다.
EmployeeListDto는 직원 목록(users)과 메타데이터(meta)를 포함하는 표준적인 페이징 응답 구조입니다.
8-15: 페이징 메타데이터 구조가 완벽합니다.
EmployeeMetaDto는 페이징 처리에 필요한 모든 정보(현재 페이지, 전체 페이지, 전체 요소 수, 페이지 크기, 다음/이전 페이지 존재 여부)를 포함하고 있습니다.app/src/main/java/com/sampoom/android/feature/user/domain/model/User.kt (1)
1-19: User 도메인 모델의 패키지 재구성이 적절합니다.
auth패키지에서user패키지로 이동한 것은 도메인 책임의 명확한 분리를 위한 좋은 리팩토링입니다. 데이터 구조는 그대로 유지되어 안전한 변경입니다.app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/UpdateProfileResponseDto.kt (1)
3-6: 프로필 업데이트 응답 DTO 구조가 적절합니다.업데이트 후 변경된 필드(
userId,userName)만 반환하는 간결한 구조입니다.app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/GetProfileResponseDto.kt (1)
1-14: GetProfileResponseDto의 패키지 재구성이 일관성 있습니다.User 도메인 모델과 동일하게
user패키지로 이동하여 관련 타입들이 함께 위치하도록 개선되었습니다.app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingUiState.kt (2)
1-1: UI 패키지 재구성이 적절합니다.
setting.ui에서dashboard.ui로 변경하여 설정 화면이 대시보드의 일부임을 명확히 표현합니다.
3-3: User 모델 import가 올바르게 업데이트되었습니다.User 도메인 모델의 패키지 변경에 맞춰 import 경로가 정확히 수정되었습니다.
app/src/main/java/com/sampoom/android/feature/user/domain/usecase/UpdateProfileUseCase.kt (1)
7-11: 프로필 업데이트 유스케이스 구현이 적절합니다.리포지토리와 뷰모델 사이의 추상화 계층을 제공하며, 향후 비즈니스 로직 추가를 위한 확장 지점을 제공합니다.
app/src/main/java/com/sampoom/android/core/preferences/AuthPreferences.kt (1)
10-10: User 모델 import가 올바르게 업데이트되었습니다.User 도메인 모델의 패키지 변경에 따라 AuthPreferences의 import도 정확히 수정되어 전체 코드베이스의 일관성이 유지됩니다.
app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeUiState.kt (1)
5-10: 직원 수정 UI 상태 구조가 적절합니다.로딩(
isLoading), 에러(error), 성공(isSuccess) 상태와 직원 데이터(employee)를 모두 포함한 완전한 UI 상태 관리 구조입니다.app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileUiState.kt (1)
5-10: 깔끔한 UI 상태 모델입니다.프로필 업데이트 화면의 상태를 명확하게 표현하고 있으며, 로딩/에러/성공 상태를 적절히 관리하고 있습니다.
app/src/main/java/com/sampoom/android/feature/user/domain/usecase/GetEmployeeUseCase.kt (1)
9-13: Use case 구현이 적절합니다.Paging 데이터를 반환하는 깔끔한 use case 구조입니다.
app/src/main/java/com/sampoom/android/feature/user/ui/EditEmployeeUiEvent.kt (1)
6-10: UI 이벤트 모델이 잘 설계되었습니다.sealed interface 패턴을 사용하여 타입 안전한 이벤트 처리가 가능합니다.
app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListUiState.kt (1)
5-10: 직원 목록 UI 상태가 적절합니다.목록, 로딩, 에러 상태와 함께 선택된 직원 정보를 포함하여 바텀시트 편집 플로우를 지원합니다.
app/src/main/java/com/sampoom/android/feature/user/domain/usecase/GetStoredUserUseCase.kt (1)
7-11: 저장된 사용자 조회 use case가 적절합니다.suspend 함수를 사용하여 비동기 저장소 접근을 처리하고 있습니다.
app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileUiEvent.kt (1)
5-9: 프로필 업데이트 이벤트 모델이 잘 구성되었습니다.초기화, 업데이트, 닫기 이벤트를 타입 안전하게 처리할 수 있습니다.
app/src/main/java/com/sampoom/android/feature/user/data/mapper/UserMappers.kt (3)
11-25: 프로필 조회 응답 매핑이 적절합니다.GetProfile API 응답을 User 도메인 모델로 변환하며, 토큰 정보는 별도로 관리되므로 빈 문자열로 설정하는 것이 합리적입니다.
62-73: EmployeeDto 매핑이 깔끔합니다.모든 필드를 직접 매핑하여 데이터 손실 없이 변환하고 있습니다.
33-47: 리뷰 의견 재평가 완료: 문제 없음코드 검증 결과, 해당 리뷰 의견은 부정확합니다.
UpdateProfileResponseDto.toModel()은UserRepositoryImpl.updateProfile()에서만 호출되며, 반환된 부분적인 User 객체는 직접 사용되지 않습니다. 저장소 계층에서 다음과 같이 처리됩니다:
- API 응답에서 userId, userName 추출
- 저장된 사용자 정보(preferences)에서 accessToken, refreshToken 등 토큰 데이터 복원
- 원본 사용자 객체에서 email, role 등 유지
- 이 세 가지를 병합하여 완전한 User 객체 생성 후 반환
따라서 프로필 업데이트 후에도 사용자 정보가 손실되지 않으며, UI에서도 빈 필드를 보지 않습니다. API가 변경된 필드만 반환하는 것은 의도된 설계이며, 리포지토리가 이를 적절히 처리하고 있습니다.
Likely an incorrect or invalid review comment.
app/src/main/java/com/sampoom/android/feature/user/data/remote/dto/EmployeeDto.kt (1)
5-16: 직원 DTO 구조가 적절합니다.모든 필수 필드를 포함하고 있으며, 선택적 날짜 필드에 nullable 타입을 사용하는 것이 적절합니다.
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (3)
52-52: 변경사항 확인됨
SettingScreen과User모델의 import 경로 변경 및EmployeeListScreen추가가 도메인 재구성과 일치합니다. 새로운ROUTE_EMPLOYEE상수도 기존 네이밍 컨벤션을 따릅니다.Also applies to: 58-59, 79-79
215-221: 구현 확인됨직원 목록 화면의 네비게이션 설정이 적절하며, 다른 상세 화면들과 일관된 패턴을 따릅니다.
244-246: 콜백 연결 확인됨
onEmployeeClick콜백이 적절하게 설정되었으며,parentNavController를 사용하여 하단 네비게이션 외부로 이동하는 패턴이 다른 네비게이션 동작들과 일관됩니다.app/src/main/java/com/sampoom/android/feature/user/data/paging/EmployeePagingSource.kt (2)
12-20: 의존성 주입 구현 확인됨
AssistedInject와AssistedFactory패턴이 적절하게 사용되었습니다.
22-27: 페이징 새로고침 로직 확인됨
getRefreshKey구현이 양방향 페이징의 표준 패턴을 따릅니다.app/src/main/java/com/sampoom/android/feature/user/ui/UpdateProfileViewModel.kt (3)
15-34: ViewModel 구조 확인됨Hilt를 사용한 의존성 주입,
StateFlow를 통한 상태 노출, 레이블 바인딩 패턴이 모두 적절합니다.
36-58: 이벤트 핸들링 확인됨이벤트 기반 아키텍처가 잘 구현되었으며, 상태 업데이트가 적절합니다.
60-95: 프로필 업데이트 로직 확인됨에러 핸들링, 로딩 상태 관리, 불변 객체 업데이트 등이 모두 적절하게 구현되었습니다. 백엔드 메시지 추출 및 폴백 처리도 잘 되어 있습니다.
app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (3)
24-26: 구현 확인됨
getStoredUser의 간단한 위임 패턴이 적절합니다.
94-99: 페이징 구현 확인됨Paging 3 라이브러리의 표준 패턴을 따르며, 페이지 크기 20도 적절합니다.
101-132: 직원 수정 구현 확인됨API 호출, 예외 처리(메시지 포함), 그리고
takeIf를 사용한 스마트한 병합 로직이 잘 구현되었습니다.app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt (3)
89-89: 사용자 새로고침 추가 확인됨Pull-to-refresh 시 사용자 정보를 새로고침하는 것은 적절한 추가입니다.
126-126: 콜백 연결 확인됨
onEmployeeClick콜백이 컴포넌트 계층(DashboardScreen→ButtonSection→ButtonCard)을 통해 적절하게 전달되고 있으며,ButtonCard의 기본 파라미터를 통해 선택적으로 사용 가능하도록 설계되었습니다.Also applies to: 154-160, 231-252, 310-310
265-275: 텍스트 포맷팅 개선 확인됨코드 가독성을 위한 포맷팅 변경과 문자열 리소스 사용이 적절합니다.
Also applies to: 287-298
app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListViewModel.kt (1)
17-37: ViewModel 구조 및 페이징 설정 확인됨Hilt를 사용한 의존성 주입과
cachedIn을 통한 페이징 데이터 캐싱이 적절하게 구현되었습니다.app/src/main/java/com/sampoom/android/feature/auth/data/remote/api/AuthApi.kt (1)
5-5: API 도메인 분리 개선 확인됨
signUp엔드포인트가 AuthApi에 추가되었고, 프로필 관련 엔드포인트(getProfile,updateProfile)가 제거되어 UserApi로 이동한 것은 적절한 도메인 분리입니다. 인증 관련 기능과 사용자 프로필 관리를 명확히 구분하여 단일 책임 원칙을 따릅니다.Also applies to: 10-11, 18-20
📝 Summary
프로필 수정 및 회원 관리 구현
🙏 Question & PR point
📬 Reference
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항