Skip to content

리팩토링 및 토큰 로직 수정#35

Merged
Sangyoon98 merged 2 commits intomainfrom
dev
Nov 10, 2025
Merged

리팩토링 및 토큰 로직 수정#35
Sangyoon98 merged 2 commits intomainfrom
dev

Conversation

@Sangyoon98
Copy link
Member

@Sangyoon98 Sangyoon98 commented Nov 10, 2025

📝 Summary

리팩토링 및 토큰 로직 수정

🙏 Question & PR point

📬 Reference

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 회원가입 및 로그인 개선
    • 새로운 화면 추가: 부품 관리, 주문 관리, 아웃바운드 처리, 직원 관리, 설정
    • 장바구니 및 주문 상태 관리 기능 강화
    • 대시보드 개선
  • 보안

    • 사용자 인증 정보 암호화 적용
  • 개선사항

    • 로그아웃 처리 개선
    • 전역 로딩 상태 관리 추가
    • 오류 처리 강화
  • 기타

    • 앱 버전 업데이트 (1.0.3 → 1.0.4)

@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Walkthrough

앱의 버전을 1.0.4로 업데이트하고, 토큰 로그아웃 이벤트 기반의 인증 처리 시스템을 도입하며, 로그인·회원가입·설정 화면을 포함한 확장된 네비게이션 그래프를 추가합니다. 또한 AuthPreferences에 암호화를 적용하고 다양한 저장소 및 UI 컴포넌트에 설명 주석을 추가합니다.

Changes

Cohort / File(s) Summary
빌드 설정
app/build.gradle.kts
versionCode 4→5, versionName "1.0.3"→"1.0.4"로 업데이트
네비게이션
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt
로그아웃 이벤트 전역 감시자, 로딩 가드 추가; ROUTE_SIGNUP, ROUTE_PARTS, ROUTE_PART_LIST, ROUTE_ORDER_DETAIL, ROUTE_SETTINGS, ROUTE_EMPLOYEE, ROUTE_DASHBOARD, ROUTE_OUTBOUND, ROUTE_CART, ROUTE_ORDERS 신규 라우트 및 화면 컴포저블 추가; 하단 네비게이션 바, FAB 상태 보존 네비게이션 추가
토큰 로그아웃 인프라
app/src/main/java/com/sampoom/android/core/network/TokenLogoutEmitter.kt
SharedFlow 기반 로그아웃 이벤트 발행 싱글톤 컴포넌트 추가
DI 설정
app/src/main/java/com/sampoom/android/core/di/NetworkModule.kt
TokenInterceptor 생성자에 TokenLogoutEmitter 주입; TokenRefreshService 프로바이더 추가; OkHttpClient tokenAuthenticator 제거
토큰 인터셉터 및 인증
app/src/main/java/com/sampoom/android/core/network/TokenInterceptor.kt, app/src/main/java/com/sampoom/android/core/network/TokenAuthenticator.kt
TokenLogoutEmitter 의존성 추가; 401 응답 시 로그아웃 이벤트 발행; proceedAndLogoutOnForbidden 헬퍼 메서드 도입
에러 처리
app/src/main/java/com/sampoom/android/core/network/ErrorHandling.kt
Throwable.serverMessageOrNull() 확장 함수 추가 (HttpException에서 서버 에러 메시지 추출)
인증 저장소
app/src/main/java/com/sampoom/android/core/preferences/AuthPreferences.kt
CryptoManager 의존성 추가; 저장 및 조회 시 암호화/복호화 적용
인증 API 및 저장소
app/src/main/java/com/sampoom/android/feature/auth/data/remote/api/AuthApi.kt, app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt
AuthApi refresh 엔드포인트에 X-No-Auth 헤더 추가; signUp, signOut, refreshToken, clearTokens, isSignedIn, getVendorList 메서드 추가 및 확장
인증 UI 레이어
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt, app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt, app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpScreen.kt, app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt, app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpUiEvent.kt, app/src/main/java/com/sampoom/android/feature/auth/ui/AuthViewModel.kt
uiState 수집 순서 개선; LoginViewModel 생성자 파라미터 명명 개선 (singIn→loginUseCase, getProfile→getProfileUseCase); SignUpScreen 상태 초기화 및 드롭다운 UI 추가; BranchChanged 이벤트 제거; AuthViewModel에 TokenLogoutEmitter 주입
UI 컴포넌트
app/src/main/java/com/sampoom/android/core/ui/component/CommonButton.kt
@Composable 애노테이션 추가
카트 기능
app/src/main/java/com/sampoom/android/feature/cart/data/repository/CartRepositoryImpl.kt, app/src/main/java/com/sampoom/android/feature/cart/ui/CartListScreen.kt
저장소 메서드 설명 주석 추가; CartSection, CartPartItem 프라이빗 컴포저블 추가
대시보드 기능
app/src/main/java/com/sampoom/android/feature/dashboard/data/repository/DashboardRepositoryImpl.kt, app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt, app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.kt
저장소 메서드 주석 추가; DashboardScreen에서 UserPosition 기반 isManager 판정 로직 추가; 섹션 헤더 주석 추가
주문 기능
app/src/main/java/com/sampoom/android/feature/order/data/repository/OrderRepositoryImpl.kt, app/src/main/java/com/sampoom/android/feature/order/ui/OrderDetailContent.kt, app/src/main/java/com/sampoom/android/feature/order/ui/OrderItem.kt, app/src/main/java/com/sampoom/android/feature/order/ui/OrderResultBottomSheet.kt
저장소 메서드 설명 주석 추가; UI 섹션 주석 추가; OrderPartItem Divider 높이 지정 (0.5.dp); OrderCompleteHeader 프라이빗 컴포저블 추가
출고 기능
app/src/main/java/com/sampoom/android/feature/outbound/data/repository/OutboundRepositoryImpl.kt, app/src/main/java/com/sampoom/android/feature/outbound/ui/OutboundListScreen.kt
저장소 메서드 주석 추가; OutboundSection, OutboundPartItem 프라이빗 컴포저블 추가
부품 기능
app/src/main/java/com/sampoom/android/feature/part/data/remote/api/PartApi.kt, app/src/main/java/com/sampoom/android/feature/part/data/repository/PartRepositoryImpl.kt, app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt, app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt
API 및 저장소 메서드 설명 주석 추가; PartListItemCard 프라이빗 컴포저블 추가; SearchResultsList 공개 컴포저블, resourceMapper, PartItemCard, SearchPartItem 프라이빗 컴포저블 추가
사용자 기능
app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt, app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt, app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListScreen.kt
API 및 저장소 메서드 설명 주석 추가; EmployeeListScreen에서 coroutineScope 및 listState 생성 제거

Sequence Diagram(s)

sequenceDiagram
    participant App as App/NavHost
    participant Auth as AuthViewModel
    participant Interceptor as TokenInterceptor
    participant Authenticator as TokenAuthenticator
    participant Emitter as TokenLogoutEmitter
    participant Repo as AuthRepository

    App->>Auth: Collect tokenLogoutEmitter.events
    
    Interceptor->>Interceptor: proceedAndLogoutOnForbidden()
    Note over Interceptor: 401 응답 감지
    
    Interceptor->>Emitter: emit()
    activate Emitter
    Emitter-->>Auth: logoutEvent 발행
    deactivate Emitter
    
    Auth->>Repo: signOut()
    activate Repo
    Repo-->>Auth: 성공/실패
    deactivate Repo
    
    Auth->>App: 로그인 화면으로 네비게이션

    rect rgb(200, 220, 255)
    Note over App,Emitter: 토큰 갱신 흐름
    Authenticator->>Authenticator: 토큰 만료 감지
    Authenticator->>Repo: refreshToken()
    alt 갱신 성공
        Repo-->>Authenticator: 신규 토큰 반환
        Authenticator-->>Interceptor: 새 요청 진행
    else 갱신 실패
        Authenticator->>Emitter: emit()
        Emitter-->>Auth: logoutEvent 발행
        Auth->>App: 로그인 화면 이동
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

추가 주의 필요 영역:

  • TokenLogoutEmitter 통합: 토큰 기반 로그아웃 이벤트가 여러 계층(TokenInterceptor, TokenAuthenticator, AuthViewModel)에 걸쳐 연쇄적으로 호출되므로, 이벤트 발행 타이밍과 중복 방지 로직 검증 필요
  • AuthPreferences 암호화: CryptoManager를 사용한 모든 데이터 저장/조회 경로에서 암호화/복호화가 일관성 있게 적용되었는지 확인, 기존 평문 저장 데이터의 마이그레이션 전략 부재 검토
  • AppNavHost 네비게이션 그래프: 10개 이상의 신규 라우트, 하단 네비게이션 바, FAB 상태 보존 로직이 복잡하게 통합되어 있으므로, 백스택 처리 및 상태 복원 동작 검증
  • runBlocking 사용: TokenInterceptor 내에서 runBlocking으로 suspend 함수를 호출하고 있으므로, 메인 스레드 블로킹 가능성과 성능 영향 평가
  • UI 컴포저블 추가: CartSection/CartPartItem, OutboundSection/OutboundPartItem 등 동일한 구조의 컴포저블이 반복 추가되었으므로, 공통 추상화 또는 재사용 가능성 검토

Possibly related PRs

Suggested labels

ready-to-merge

Suggested reviewers

  • Lee-Jong-Jin
  • yangjiseonn
  • CHOOSLA
  • taemin3
  • vivivim

Poem

🐰✨ 토큰 춤을 춘다네, 로그아웃 이벤트 속에서,
암호화된 길을 따라 데이터는 안전하게,
새로운 라우트들이 펼쳐진다, 부품부터 주문까지,
네비게이션 그래프가 우거진 숲을 이루고,
버전 1.0.4, 우리의 앱도 한 발 나아가네! 🚀

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.64% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목 '리팩토링 및 토큰 로직 수정'은 변경 사항의 주요 내용과 일치합니다. 토큰 로그아웃 이미터 추가, 토큰 인터셉터/인증자 수정, 암호화 기능 추가 등 토큰 로직 개선과 다양한 UI/저장소 리팩토링이 포함되어 있습니다.
✨ 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 dev

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

@vivivim vivivim left a comment

Choose a reason for hiding this comment

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

리팩토링 굿

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

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/order/data/repository/OrderRepositoryImpl.kt (2)

35-70: 제네릭 Exception 사용 - 의미 있는 에러 메시지 필요함

Line 38에서 사용자 정보 조회 실패 시 메시지 없는 Exception()을 throw하고 있습니다. 이는 디버깅을 어렵게 하고 에러 처리를 불명확하게 만듭니다.

Line 38의 에러 메시지 추가 제안:

  override suspend fun createOrder(cartList: CartList): Result<Order> {
      return runCatching {
-         val agencyName = authPreferences.getStoredUser()?.branch ?: throw Exception()
+         val agencyName = authPreferences.getStoredUser()?.branch ?: throw Exception("사용자 정보 조회 실패: branch 정보가 없습니다")

80-92: 제네릭 Exception 사용 - 의미 있는 에러 메시지 필요함

Line 83에서 사용자 정보 조회 실패 시 메시지 없는 Exception()을 throw하고 있습니다. createOrder와 동일한 문제로, 에러 원인을 파악하기 어렵습니다.

Line 83의 에러 메시지 추가 제안:

  override suspend fun receiveOrder(items: List<Pair<Long, Long>>): Result<Unit> {
      return runCatching {
-         val agencyId = authPreferences.getStoredUser()?.agencyId ?: throw Exception()
+         val agencyId = authPreferences.getStoredUser()?.agencyId ?: throw Exception("사용자 정보 조회 실패: agencyId 정보가 없습니다")
app/src/main/java/com/sampoom/android/core/di/NetworkModule.kt (1)

44-64: TokenAuthenticator 가 클라이언트에서 제거되어 토큰 갱신이 중단됩니다.

.authenticator(tokenAuthenticator) 호출이 빠지면서 OkHttp 가 더 이상 TokenAuthenticator를 실행하지 못해 TokenRefreshService 기반의 자동 재발급이 작동하지 않습니다. 액세스 토큰이 만료되면 401 이후 곧바로 TokenLogoutEmitter만 발동해 사용자가 매번 다시 로그인해야 하는 회귀가 발생하므로, 인증기를 다시 연결해 주세요.

-    fun provideOkHttpClient(
-        tokenInterceptor: TokenInterceptor,
-//        tokenAuthenticator: TokenAuthenticator
-    ): OkHttpClient {
+    fun provideOkHttpClient(
+        tokenInterceptor: TokenInterceptor,
+        tokenAuthenticator: TokenAuthenticator
+    ): OkHttpClient {
         return OkHttpClient.Builder()
             .connectTimeout(30, TimeUnit.SECONDS)
             .readTimeout(30, TimeUnit.SECONDS)
             .writeTimeout(30, TimeUnit.SECONDS)
             .addInterceptor(
                 HttpLoggingInterceptor().apply {
                     level = if (BuildConfig.DEBUG)
                         HttpLoggingInterceptor.Level.BODY
                     else
                         HttpLoggingInterceptor.Level.NONE
                     redactHeader("Authorization") // 토큰 비식별화
                     redactHeader("Cookie") // 쿠키 비식별화
                 }
             )
             .addInterceptor(tokenInterceptor) // 토큰 자동 삽입
-//            .authenticator(tokenAuthenticator) // 토큰 갱신 (Interceptor 대신)
+            .authenticator(tokenAuthenticator) // 토큰 갱신
             .build()
     }
🧹 Nitpick comments (10)
app/src/main/java/com/sampoom/android/feature/order/ui/OrderItem.kt (1)

30-30: KDoc 문서화를 더 상세하게 작성하세요.

현재 주석은 섹션 레이블만 제공하고 있습니다. 공개 Composable 함수로서 매개변수 설명과 함수의 목적을 문서화하면 사용자 경험이 개선됩니다.

다음과 같이 개선할 수 있습니다:

/**
 * 주문 정보를 카드 형태로 표시하는 Composable 컴포넌트입니다.
 *
 * @param order 표시할 주문 정보
 * @param onClick 카드 클릭 시 호출되는 콜백 함수
 */
app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.kt (1)

240-245: 공개 함수의 KDoc 문서화 완성도 향상을 고려하세요.

현재 추가된 KDoc 주석들은 함수의 목적을 간단히 설명하고 있습니다. 특히 UserSection 같은 공개 함수의 경우, Kotlin 표준 관례에 따라 파라미터(@param user, @param modifier)와 반환 설명을 포함하면 API 사용자에게 더 유용한 문서화가 될 것입니다.

다음과 같이 확장된 KDoc을 제안합니다:

-/** 프로필 조회 섹션 */
+/**
+ * 사용자 프로필 정보를 표시하는 섹션 컴포저블입니다.
+ *
+ * @param user 표시할 사용자 정보
+ * @param modifier 이 컴포저블에 적용할 수정자
+ */
 @Composable
 fun UserSection(
     user: User?,
     modifier: Modifier = Modifier
 )
app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt (1)

19-19: 문서화 개선이 좋습니다!

각 API 메서드 위에 한글 주석을 추가하여 코드 가독성을 향상시켰습니다. 주석이 일관된 형식으로 작성되었으며 각 엔드포인트의 목적을 명확하게 설명합니다.

선택적으로, IDE 자동완성 및 문서 생성 도구와의 더 나은 통합을 위해 KDoc 형식(/** */)을 사용하는 것을 고려해볼 수 있습니다:

-    // 프로필 조회
+    /**
+     * 프로필 조회
+     */
     @GET("user/profile")
     suspend fun getProfile(@Query("workspace") workspace: String): ApiResponse<GetProfileResponseDto>

Also applies to: 23-23, 27-27, 35-35, 44-44

app/src/main/java/com/sampoom/android/feature/outbound/data/repository/OutboundRepositoryImpl.kt (2)

16-16: 문서화 추가가 코드 가독성을 향상시킵니다.

각 메서드에 KDoc 주석을 추가하여 코드의 이해도가 개선되었습니다.

선택적으로, 더 포괄적인 문서화를 위해 매개변수와 반환 값 설명을 추가할 수 있습니다. 예:

-    /** 출고 목록 추가 */
+    /**
+     * 출고 목록 추가
+     * @param partId 부품 ID
+     * @param quantity 수량
+     * @return 성공 시 Result.success, 실패 시 Result.failure
+     */
     override suspend fun addOutbound(

Also applies to: 26-26, 35-35, 48-48, 57-57, 66-66


17-24: 예외 처리를 더 구체적으로 개선할 수 있습니다.

모든 메서드에서 agencyId가 null일 때와 API 호출이 실패할 때 제네릭 Exception을 사용하고 있습니다. 더 구체적인 예외 타입이나 명확한 에러 메시지를 사용하면 디버깅과 에러 처리가 개선됩니다.

예시:

override suspend fun getOutboundList(): Result<OutboundList> {
    return runCatching {
        val agencyId = authPreferences.getStoredUser()?.agencyId 
            ?: throw IllegalStateException("User agency ID not found")
        val dto = api.getOutboundList(agencyId)
        val outboundItems = dto.data.map { it.toModel() }
        OutboundList(items = outboundItems)
    }
}

Also applies to: 27-33, 36-46, 49-55, 58-64, 67-80

app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (1)

25-197: 문서화 추가 잘 하셨습니다!

모든 public 메서드에 명확한 한국어 문서화 주석을 추가하여 코드의 가독성과 유지보수성이 향상되었습니다.

선택적 개선 제안: Line 25의 getStoredUser() 메서드의 경우, 로컬 저장소에서 조회한다는 것을 명확히 하기 위해 "로컬에 저장된 유저 프로필 조회" 또는 "저장된 유저 프로필 조회"로 수정하는 것을 고려해보세요.

-    /** 유저 프로필 조회 */
+    /** 로컬에 저장된 유저 프로필 조회 */
     override suspend fun getStoredUser(): User? {
app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt (1)

80-82: 불필요한 빈 else 블록을 제거하세요.

빈 else 블록은 불필요하며 정적 분석 도구에서도 경고를 발생시킵니다. 조건이 거짓일 때 아무 동작도 필요하지 않으므로 else 블록을 제거하는 것이 더 깔끔합니다.

다음 diff를 적용하여 빈 else 블록을 제거하세요:

             validatePassword()
             if (_state.value.passwordCheck.isNotBlank()) {
                 validatePasswordCheck()
-            } else { }
+            }
         }
app/src/main/java/com/sampoom/android/feature/cart/ui/CartListScreen.kt (1)

255-410: UI 컴포넌트 분리가 잘 되어 있습니다.

CartSectionCartPartItem으로 UI를 깔끔하게 분리했습니다. 한국어 문서화 주석도 명확합니다.

참고: OutboundListScreen.kt와 매우 유사한 패턴입니다. 향후 두 화면 간 코드 중복이 증가하면 공통 컴포넌트 추출을 고려해보시기 바랍니다.

app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt (1)

43-46: 회원가입 후 즉시 로그인 재시도 패턴 검증 필요

회원가입 성공 후 500ms 대기하고 최대 5회 로그인을 재시도하는 패턴이 독특합니다. 이는 서버에서 회원가입 후 즉시 계정을 사용할 수 없는 일시적인 지연이 있음을 의미하는 것으로 보입니다.

이 패턴이 실제 서버 동작과 일치하는지, 그리고 더 나은 해결책(예: 서버에서 회원가입 완료 후 즉시 사용 가능하도록 개선)은 없는지 확인해 보시기 바랍니다.

app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (1)

530-589: 공용 컴포저블에는 modifier 주입을 허용해주세요.

SearchResultsList가 내부에서 Modifier.fillMaxSize()를 고정 적용하고 있어 다른 화면에서 재사용하기가 어렵습니다. modifier 파라미터를 열어두면 호출처에서 크기·패딩 등을 유연하게 제어할 수 있습니다.

-fun SearchResultsList(
-    searchResults: LazyPagingItems<SearchResult>,
-    onPartClick: (Part) -> Unit,
-) {
-    LazyColumn(
-        modifier = Modifier.fillMaxSize(),
+fun SearchResultsList(
+    searchResults: LazyPagingItems<SearchResult>,
+    onPartClick: (Part) -> Unit,
+    modifier: Modifier = Modifier.fillMaxSize(),
+) {
+    LazyColumn(
+        modifier = modifier,
         verticalArrangement = Arrangement.spacedBy(8.dp),
         contentPadding = PaddingValues(16.dp)
     ) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05f43bd and 598eeea.

📒 Files selected for processing (36)
  • app/build.gradle.kts (1 hunks)
  • app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (11 hunks)
  • app/src/main/java/com/sampoom/android/core/di/NetworkModule.kt (4 hunks)
  • app/src/main/java/com/sampoom/android/core/network/ErrorHandling.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/core/network/TokenAuthenticator.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/core/network/TokenInterceptor.kt (3 hunks)
  • app/src/main/java/com/sampoom/android/core/network/TokenLogoutEmitter.kt (1 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 (7 hunks)
  • app/src/main/java/com/sampoom/android/core/ui/component/CommonButton.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/repository/AuthRepositoryImpl.kt (5 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/AuthViewModel.kt (3 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/LoginViewModel.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpScreen.kt (9 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpUiEvent.kt (0 hunks)
  • app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/cart/data/repository/CartRepositoryImpl.kt (5 hunks)
  • app/src/main/java/com/sampoom/android/feature/cart/ui/CartListScreen.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/dashboard/data/repository/DashboardRepositoryImpl.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt (7 hunks)
  • app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/order/data/repository/OrderRepositoryImpl.kt (4 hunks)
  • app/src/main/java/com/sampoom/android/feature/order/ui/OrderDetailContent.kt (5 hunks)
  • app/src/main/java/com/sampoom/android/feature/order/ui/OrderItem.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/order/ui/OrderResultBottomSheet.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/outbound/data/repository/OutboundRepositoryImpl.kt (6 hunks)
  • app/src/main/java/com/sampoom/android/feature/outbound/ui/OutboundListScreen.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/remote/api/PartApi.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/data/repository/PartRepositoryImpl.kt (4 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (1 hunks)
  • app/src/main/java/com/sampoom/android/feature/part/ui/PartScreen.kt (5 hunks)
  • app/src/main/java/com/sampoom/android/feature/user/data/remote/api/UserApi.kt (2 hunks)
  • app/src/main/java/com/sampoom/android/feature/user/data/repository/UserRepositoryImpl.kt (5 hunks)
  • app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListScreen.kt (0 hunks)
💤 Files with no reviewable changes (2)
  • app/src/main/java/com/sampoom/android/feature/user/ui/EmployeeListScreen.kt
  • app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpUiEvent.kt
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-29T02:47:43.820Z
Learnt from: Sangyoon98
Repo: 33-Auto/Sampoom-Management-Android PR: 22
File: app/src/main/java/com/sampoom/android/feature/order/domain/repository/OrderRepository.kt:6-9
Timestamp: 2025-10-29T02:47:43.820Z
Learning: In the Sampoom Management Android project, the backend API returns single Order items wrapped in an OrderList structure even for single-item operations like getOrderDetail(orderId) and createOrder(). The repository layer correctly uses Result<OrderList> as the return type to match the backend response format, rather than Result<Order>.

Applied to files:

  • app/src/main/java/com/sampoom/android/feature/order/ui/OrderItem.kt
  • app/src/main/java/com/sampoom/android/feature/order/ui/OrderResultBottomSheet.kt
  • app/src/main/java/com/sampoom/android/feature/order/data/repository/OrderRepositoryImpl.kt
📚 Learning: 2025-10-29T02:47:47.061Z
Learnt from: Sangyoon98
Repo: 33-Auto/Sampoom-Management-Android PR: 22
File: app/src/main/java/com/sampoom/android/feature/cart/data/repository/CartRepositoryImpl.kt:16-22
Timestamp: 2025-10-29T02:47:47.061Z
Learning: Developer Sangyoon98 prefers to use runCatching for consistent error handling in repository implementations, rather than explicit try-catch blocks, in the CartRepositoryImpl class (app/src/main/java/com/sampoom/android/feature/cart/data/repository/CartRepositoryImpl.kt).

Applied to files:

  • app/src/main/java/com/sampoom/android/feature/part/data/repository/PartRepositoryImpl.kt
  • app/src/main/java/com/sampoom/android/feature/cart/data/repository/CartRepositoryImpl.kt
  • app/src/main/java/com/sampoom/android/feature/order/data/repository/OrderRepositoryImpl.kt
🧬 Code graph analysis (3)
app/src/main/java/com/sampoom/android/feature/order/ui/OrderDetailContent.kt (1)
app/src/main/java/com/sampoom/android/core/ui/theme/Color.kt (1)
  • textSecondaryColor (259-260)
app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (1)
app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (1)
  • LoginScreen (41-154)
app/src/main/java/com/sampoom/android/feature/auth/ui/AuthViewModel.kt (2)
app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt (1)
  • signOut (72-81)
app/src/main/java/com/sampoom/android/feature/auth/domain/repository/AuthRepository.kt (1)
  • signOut (17-17)
🪛 detekt (1.23.8)
app/src/main/java/com/sampoom/android/feature/auth/ui/SignUpViewModel.kt

[warning] 82-82: This empty block of code can be removed.

(detekt.empty-blocks.EmptyElseBlock)

🔇 Additional comments (31)
app/build.gradle.kts (1)

35-36: 버전 업데이트가 적절하게 적용되었습니다.

versionCode를 4에서 5로, versionName을 "1.0.3"에서 "1.0.4"로 업데이트한 것은 의미론적 버전 관리(semantic versioning)에 맞게 패치 버전 업데이트를 반영하고 있습니다. 변경 사항은 문법적으로도 정확합니다.

다만, PR 요약에서 토큰 기반 인증 시스템, 네비게이션 그래프 확장, 암호화 기능 등 광범위한 변경이 언급되고 있는데, 이러한 기능 구현을 위해 새로운 의존성이 필요한지 확인해주시기 바랍니다.

app/src/main/java/com/sampoom/android/feature/order/data/repository/OrderRepositoryImpl.kt (4)

27-33: 문서화 주석 추가로 코드 가독성 개선됨

getOrderList 메서드에 대한 KotlinDoc 주석이 적절하게 추가되었습니다.


72-78: 문서화 주석 추가로 코드 가독성 개선됨

completeOrder 메서드에 대한 KotlinDoc 주석이 적절하게 추가되었습니다.


94-101: 문서화 주석 추가로 코드 가독성 개선됨

getOrderDetail 메서드에 대한 KotlinDoc 주석이 적절하게 추가되었습니다.


103-109: 문서화 주석 추가로 코드 가독성 개선됨

cancelOrder 메서드에 대한 KotlinDoc 주석이 적절하게 추가되었습니다.

app/src/main/java/com/sampoom/android/feature/order/ui/OrderItem.kt (1)

31-92: 코드 로직은 양호합니다.

Composable 함수의 구현이 올바릅니다:

  • 적절한 null-safety 처리 (elvis operator 사용)
  • 일관된 레이아웃 구조 (Column, Row 계층화)
  • 올바른 테마 색상 및 타이포그래피 적용
  • StatusChip 및 포맷팅 유틸리티 적절히 사용
app/src/main/java/com/sampoom/android/feature/dashboard/ui/SettingScreen.kt (2)

187-192: UserSection의 가시성(visibility)을 명확히 하세요.

UserSection은 현재 이 파일 내의 SettingScreen 함수에서만 사용되고 있으나 공개 함수로 노출되어 있습니다. 외부 모듈에서 사용할 계획이 있다면 KDoc에 @param@return을 추가하여 공개 API로 완성하고, 그렇지 않다면 private 수정자를 추가하여 SettingSection과 일관성을 유지하는 것이 좋습니다.


54-185: 프로필 로딩 및 로그아웃 로직이 토큰 이벤트 시스템과 잘 통합되어 있습니다.

SettingScreen의 전체 구조는 PR의 새로운 토큰 로그아웃 이벤트 기반 인증 처리 시스템과 잘 맞춰져 있습니다. 상태 관리, 다이얼로그 처리, 그리고 onLogoutClick 콜백 통합이 모두 적절하게 구현되어 있습니다.

app/src/main/java/com/sampoom/android/feature/cart/data/repository/CartRepositoryImpl.kt (1)

16-66: 문서화 주석이 명확하고 잘 작성됨

모든 공개 메서드에 간결하고 명확한 한국어 문서화 주석이 추가되었습니다. 이는 유지보수성을 향상시킵니다.

app/src/main/java/com/sampoom/android/feature/dashboard/data/repository/DashboardRepositoryImpl.kt (1)

15-15: 문서화 추가가 좋습니다!

각 메서드에 대한 설명 주석을 추가하여 코드 가독성과 유지보수성을 향상시켰습니다.

Also applies to: 24-24

app/src/main/java/com/sampoom/android/feature/part/data/remote/api/PartApi.kt (1)

13-13: API 메서드 문서화가 명확합니다.

각 API 엔드포인트에 대한 설명 주석을 추가하여 API 인터페이스의 목적이 명확해졌습니다.

Also applies to: 17-17, 21-21, 28-28

app/src/main/java/com/sampoom/android/feature/order/ui/OrderDetailContent.kt (2)

36-36: UI 컴포넌트 문서화가 명확합니다.

각 Composable 함수에 대한 KDoc 주석을 추가하여 UI 구조를 이해하기 쉽게 만들었습니다.

Also applies to: 74-74, 131-131, 177-177


225-225: Divider 높이 명시가 적절합니다.

명시적으로 높이를 0.5dp로 설정하여 일관된 시각적 구분선을 제공합니다.

app/src/main/java/com/sampoom/android/core/ui/component/CommonButton.kt (1)

46-47: 코드 레이아웃 정리.

공백 줄 추가로 가독성이 개선되었습니다.

app/src/main/java/com/sampoom/android/feature/auth/data/remote/api/AuthApi.kt (2)

18-18: API 엔드포인트 문서화가 명확합니다.

각 인증 관련 API 엔드포인트에 대한 설명 주석을 추가하여 API 인터페이스의 목적이 명확해졌습니다.

Also applies to: 23-23, 28-28, 32-32, 37-37


25-25: 토큰 갱신 엔드포인트에 X-No-Auth 헤더 추가가 올바릅니다.

토큰 갱신(refresh) 엔드포인트는 만료된 토큰으로 새 토큰을 발급받는 용도이므로, 인증 불필요 헤더를 추가하는 것이 적절합니다. 이는 signup 및 login 엔드포인트와 일관성이 있습니다.

app/src/main/java/com/sampoom/android/feature/order/ui/OrderResultBottomSheet.kt (2)

45-45: Bottom Sheet 문서화가 명확합니다.

주문 완료 Bottom Sheet에 대한 설명 주석을 추가하여 컴포넌트의 목적이 명확해졌습니다.


145-171: 헤더를 별도 Composable 함수로 분리한 것이 좋습니다.

OrderCompleteHeader()를 별도의 private Composable 함수로 추출하여 코드 재사용성과 가독성을 향상시켰습니다. KDoc 주석도 명확하며 구현이 적절합니다.

app/src/main/java/com/sampoom/android/feature/auth/ui/LoginScreen.kt (1)

50-50: 상태 수집 위치 개선이 적절합니다.

uiState 수집을 Composable 상단으로 이동하여 코드 구조가 개선되었으며, LaunchedEffect에서 사용하기 전에 상태를 사용할 수 있게 되었습니다. 중복 수집도 제거되어 더 효율적입니다.

app/src/main/java/com/sampoom/android/feature/outbound/ui/OutboundListScreen.kt (1)

259-413: UI 컴포넌트 구조가 일관성 있습니다.

CartListScreen.kt와 동일한 패턴으로 UI를 구성했습니다. 일관성이 좋습니다.

app/src/main/java/com/sampoom/android/feature/auth/data/repository/AuthRepositoryImpl.kt (2)

76-80: 로그아웃 실패 시에도 토큰을 삭제하는 로직 검증 필요

로그아웃 API 호출이 실패해도 로컬 토큰을 삭제합니다(Lines 78-79). 이는 보안상 안전한 선택일 수 있지만, 네트워크 일시 장애 시 불필요한 로그아웃이 발생할 수 있습니다.

이 동작이 의도된 것인지 확인하고, 특정 오류 코드(예: 401 인증 실패)에만 토큰을 삭제하는 것이 더 적절한지 검토해 보시기 바랍니다.


56-62: 로그인 및 관련 API 호출에서 하드코딩된 workspace 값 재검토 필요

AuthRepositoryImpl.kt 라인 58에서 workspace를 "AGENCY"로 하드코딩한 것이 확인되었습니다. 추가 조사 결과, 이 패턴이 getProfile(), editEmployee(), updateEmployeeStatus() 등 여러 API 호출에서 일관되게 반복되고 있습니다.

주목할 점은 SignUpViewModel에서는 workspace 파라미터를 받아 회원가입 시 사용하지만, 로그인(login()) 메서드에서는 이를 무시하고 "AGENCY"로 고정되어 있다는 것입니다. 이러한 불일치는 다음 중 하나를 검토해야 함을 의미합니다:

  • AGENCY만 지원된다면: SignUp 흐름에서 workspace 파라미터를 제거하고 일관성 있게 상수 값으로 통일
  • 여러 workspace를 지원해야 한다면: 로그인 시에도 workspace 파라미터를 받아 사용하고, 사용자 세션에 저장하여 이후 모든 API 호출에서 활용
app/src/main/java/com/sampoom/android/feature/part/data/repository/PartRepositoryImpl.kt (1)

23-57: 문서화가 명확합니다.

각 메서드에 한국어 문서 주석이 추가되어 가독성이 향상되었습니다. runCatching을 사용한 에러 처리도 팀의 기존 패턴과 일치합니다.

app/src/main/java/com/sampoom/android/core/network/TokenRefreshService.kt (1)

12-12: 문서화 추가 확인

간단하고 명확한 문서 주석이 추가되었습니다.

app/src/main/java/com/sampoom/android/feature/part/ui/PartListScreen.kt (1)

210-266: 리스트 아이템 컴포넌트가 잘 분리되었습니다.

PartListItemCard를 별도 composable로 분리하여 코드 가독성이 향상되었습니다. 한국어 문서 주석도 명확합니다.

app/src/main/java/com/sampoom/android/core/network/TokenAuthenticator.kt (3)

14-14: 문서화 추가 확인

명확한 한국어 문서 주석이 추가되었습니다.


18-19: TokenLogoutEmitter 통합이 올바르게 구현되었습니다.

새로운 토큰 로그아웃 이벤트 시스템을 위한 tokenRefreshServicetokenLogoutEmitter 의존성이 추가되었습니다. PR의 핵심 변경사항과 일치합니다.


44-56: 403 오류 처리 일관성 확인 필요

Lines 44-50에서 400/401 오류는 토큰 삭제와 함께 로그아웃 이벤트를 발생시키지만, Lines 52-56의 403(권한 없음) 오류는 토큰만 삭제하고 로그아웃 이벤트를 발생시키지 않습니다.

403 오류도 인증 실패와 유사하게 로그아웃 이벤트를 발생시켜야 하는지 확인해 보시기 바랍니다. 일관된 사용자 경험을 위해 403도 로그아웃 처리하는 것이 적절할 수 있습니다.

app/src/main/java/com/sampoom/android/feature/dashboard/ui/DashboardScreen.kt (2)

79-87: 관리자 권한 체크 로직이 개선되었습니다.

UserPosition enum을 사용한 집합 기반 체크로 변경되어 더 명확하고 유지보수하기 쉬운 코드가 되었습니다. 이전의 단순한 role 체크보다 훨씬 견고합니다.


196-531: 섹션 문서화가 잘 되어 있습니다.

각 주요 composable 함수에 명확한 한국어 문서 주석이 추가되어 코드 가독성이 크게 향상되었습니다.

app/src/main/java/com/sampoom/android/app/navigation/AppNavHost.kt (1)

119-126: 전역 로그아웃 이벤트 처리 👍

TokenLogoutEmitter 수집으로 어디서든 로그아웃 발생 시 백스택을 정리하고 즉시 로그인 화면으로 돌려보낼 수 있게 되어 흐름이 매우 명확해졌습니다.

@Sangyoon98 Sangyoon98 merged commit 26e48dd into main Nov 10, 2025
6 checks passed
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.

2 participants