Skip to content

[FIX] 로그인, 회원가입 로직 수정 / 설정 화면 구성#20

Merged
Sangyoon98 merged 4 commits intodevfrom
SPM-354
Nov 4, 2025
Merged

[FIX] 로그인, 회원가입 로직 수정 / 설정 화면 구성#20
Sangyoon98 merged 4 commits intodevfrom
SPM-354

Conversation

@Sangyoon98
Copy link
Copy Markdown
Member

@Sangyoon98 Sangyoon98 commented Nov 4, 2025

📝 Summary

로그인, 회원가입 로직 수정 / 설정 화면 구성

🙏 Question & PR point

📬 Reference

Summary by CodeRabbit

릴리스 노트

  • New Features

    • 설정 화면 추가: 프로필 조회·편집 경로 및 로그아웃 흐름 제공
    • 주문 완료 기능 추가: 주문 처리 흐름에서 완료 동작 지원
  • UI / 텍스트

    • 주문 상태 레이블 확대: 확인·배송·지연·생산·도착 등 추가
    • 사용자 정보 확장: 이메일·에이전시·시작/종료 날짜 표시 지원
    • 문자열 리소스 문구 정비 및 일관성 향상
  • Chores

    • 빌드 설정: 문자열 카탈로그 심볼 생성 활성화

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 4, 2025

Warning

Rate limit exceeded

@Sangyoon98 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 58 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 9996a6a and 7331aaa.

📒 Files selected for processing (1)
  • SampoomManagement/App/ContentView.swift (4 hunks)

Walkthrough

설정 화면과 관련 MVVM을 추가하고 User 모델에 이메일·agencyId·시작/종료일 필드를 확장했으며, 다수의 API·리포지토리에 agencyId 주입 및 인증 검증을 도입하고 Order 흐름에 completeOrder 유스케이스 및 상태 케이스를 추가했습니다.

Changes

코호트 / 파일(s) 변경 요약
프로젝트 설정
SampoomManagement.xcodeproj/project.pbxproj
STRING_CATALOG_GENERATE_SYMBOLS = YES (Debug/Release) 추가
앱 네비게이션 / DI
SampoomManagement/App/ContentView.swift, SampoomManagement/Core/DI/AppDependencies.swift
NavigationStack으로 대시보드 네비게이션 전환 및 Setting 네비게이션 추가; makeSettingViewModel() 팩토리 추가; completeOrderUseCase DI 등록; 여러 리포지토리에 AuthPreferences 주입
인증 모델·DTO 변경
.../Features/Auth/Domain/Models/User.swift, .../Features/Auth/Data/Remote/DTO/GetProfileResponseDTO.swift, .../LoginRequestDTO.swift, .../LoginResponseDTO.swift
User에 email, agencyId, startedAt, endedAt 추가 및 role을 UserRole로 변경; GetProfileDTO 필수 필드 및 새 필드 추가; LoginRequestDTO에 workspace 추가; LoginResponseDTO에서 userName, role 제거
인증 저장소·매퍼·토큰 갱신
.../AuthPreferences.swift, .../AuthMappers.swift, Core/Network/TokenRefreshService.swift, .../AuthRepositoryImpl.swift, .../AuthAPI.swift
AuthPreferences에 신규 키 저장/조회/삭제 로직 추가; 매퍼와 토큰 갱신에서 추가 필드 전파; AuthAPI.getProfile(workspace:) 시그니처 변경
AgencyId 파라미터화 (Cart/Outbound/Part)
.../CartAPI.swift, .../CartRepositoryImpl.swift, .../OutboundAPI.swift, .../OutboundRepositoryImpl.swift, .../PartAPI.swift, .../PartRepositoryImpl.swift
API 엔드포인트에 agencyId 파라미터 추가로 하드코딩 제거; 리포지토리에서 AuthPreferences로 stored user의 agencyId 사용 및 인증 검증 추가
Order 도메인·API·리포지토리·유스케이스
.../OrderAPI.swift, .../OrderRepositoryImpl.swift, .../OrderStatus.swift, .../OrderRepository.swift, .../CompleteOrderUseCase.swift
OrderStatus에 새 케이스(confirmed, shipping, delayed, producing, arrived) 추가; API에 completeOrder(orderId:) 추가 및 기존 receiveOrder에 agencyId 파라미터화; 리포지토리에 completeOrder 구현; CompleteOrderUseCase 추가
UI 컴포넌트 및 리소스
.../StatusChip.swift, .../OrderItem.swift, .../OrderListView.swift, Core/Resources/StringResources.swift
StatusChip의 status 타입을 OrderStatus로 변경 및 표시 로직 갱신; 호출부에서 order.status 전달하도록 변경; StringResources에 Setting/Common/Order 상태 문자열 및 Auth 메시지 확장/수정
주문 상세 흐름
.../OrderDetailViewModel.swift, .../OrderDetailContent.swift
OrderDetailViewModelcompleteOrderUseCase 주입 및 receive 후 complete 호출 추가; StatusChip 인자 타입 변경 반영
설정 기능 신규 추가
.../Features/Setting/UI/SettingView.swift, .../SettingViewModel.swift, .../SettingUiState.swift, .../SettingUiEvent.swift
SettingViewSettingViewModel, 설정 UI 상태/이벤트 추가; 프로필 로드 및 로그아웃 흐름과 네비게이션 콜백 구현
대시보드 UI 변경
.../DashboardView.swift
onSettingClick 콜백 추가; isManager 대신 userRole: UserRole로 역할 판정 변경

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DashboardView
    participant ContentView
    participant SettingView
    participant SettingViewModel
    participant AuthPreferences
    participant SignOutUseCase

    User->>DashboardView: 설정 버튼 클릭
    DashboardView->>ContentView: onSettingClick()
    ContentView->>ContentView: NavigationStack에 .settings 푸시
    ContentView->>SettingView: SettingView 표시

    SettingView->>SettingViewModel: onEvent(.loadProfile)
    SettingViewModel->>AuthPreferences: getStoredUser()
    AuthPreferences-->>SettingViewModel: User (email, agencyId,...)
    SettingViewModel-->>SettingView: user 업데이트

    User->>SettingView: 로그아웃 클릭
    SettingView->>SettingViewModel: onEvent(.logout)
    SettingViewModel->>SignOutUseCase: execute()
    SignOutUseCase->>AuthPreferences: clearUser()
    SignOutUseCase-->>SettingViewModel: 성공
    SettingViewModel-->>SettingView: onNavigateBack()
Loading
sequenceDiagram
    participant OrderVM
    participant OrderRepo
    participant OrderAPI
    participant CompleteUseCase

    OrderVM->>OrderRepo: receiveOrder(orderId)
    OrderRepo->>OrderAPI: receiveOrder(agencyId, orderId)
    OrderAPI-->>OrderRepo: success
    OrderRepo-->>OrderVM: success

    OrderVM->>CompleteUseCase: execute(orderId)
    CompleteUseCase->>OrderRepo: completeOrder(orderId)
    OrderRepo->>OrderAPI: completeOrder(orderId)
    OrderAPI-->>OrderRepo: success
    OrderRepo-->>OrderVM: 완료 응답
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • 주의가 필요한 파일/영역:
    • Cart/Outbound/Part API·Repository 호출부의 agencyId 전달 및 일관성 검증
    • GetProfileResponseDTO의 optional→required 변경으로 인한 디코딩 호환성 및 매퍼 처리
    • AuthPreferences의 저장/rollback/삭제 로직(새 키 포함) 및 TokenRefreshService에서의 User 생성 변화
    • StatusChip 타입 변경에 따른 모든 호출부(UI 컴포넌트들)
    • Order receive → complete 연속 흐름의 에러 처리(트랜잭션성) 및 테스트

Possibly related PRs

  • 33-Auto/Sampoom-Management-iOS#18 — ContentView 및 대시보드 네비게이션 관련 중복 변경
  • 33-Auto/Sampoom-Management-iOS#15 — OrderStatus 확장 및 StatusChip API 변경 관련
  • 33-Auto/Sampoom-Management-iOS#17 — 인증·토큰 갱신 및 AuthPreferences 관련 중복 변경

Suggested labels

ready-to-merge

Suggested reviewers

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

Poem

🐰 설정을 지켜보는 토끼 한 마리,
코드 숲에 agencyId와 이메일 심었네.
네비게이션 쓱쓱, 로그아웃은 부드럽게,
주문은 받자마자 마무리까지 척척!
킁킁, 머지 한 입만 주세요 🥕

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 로그인/회원가입 로직 수정과 설정 화면 구성이라는 주요 변경 사항을 명확하게 반영하고 있으며, 변경 집합의 핵심 내용을 정확하게 요약하고 있습니다.

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
Copy Markdown
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: 4

Caution

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

⚠️ Outside diff range comments (2)
SampoomManagement/Features/Auth/Data/Remote/API/AuthAPI.swift (1)

98-104: URL 인코딩 누락으로 프로필 조회가 실패합니다
workspace를 쿼리 스트링에 직접 삽입하면 공백이나 한글·특수문자가 포함된 워크스페이스 값에서 URLConvertible이 URL 생성에 실패하여 AFError.invalidURL를 던집니다. 멀티테넌트 환경에서 실제 워크스페이스 이름을 전달하면 바로 재현됩니다. parameters로 넘겨 Alamofire가 URLEncoding을 적용하도록 바꾸거나, 최소한 addingPercentEncoding으로 안전하게 인코딩해 주세요.
예시 수정안:

-        return try await networkManager.request(
-            endpoint: "user/profile?workspace=\(workspace)",
-            method: .get,
-            parameters: nil,
-            responseType: GetProfileResponseDTO.self
-        )
+        return try await networkManager.request(
+            endpoint: "user/profile",
+            method: .get,
+            parameters: ["workspace": workspace],
+            responseType: GetProfileResponseDTO.self
+        )

(onlydust.com)

SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)

29-60: saveUser의 원자성 보장은 좋지만 agencyId 검증이 누락되었습니다.

롤백 메커니즘으로 부분 저장 실패를 처리하는 것은 좋은 접근 방식입니다. 하지만 agencyId의 유효성 검증이 없습니다.

agencyId 검증을 추가하는 것을 고려하세요:

 func saveUser(_ user: User) throws {
+    guard user.agencyId > 0 else {
+        throw KeychainError.invalidData
+    }
     do {
         try keychain.save(user.accessToken, for: Keys.accessToken)
         // ...

KeychainError enum에 invalidData 케이스 추가:

enum KeychainError: Error {
    case unknown(OSStatus)
    case invalidData
}
🧹 Nitpick comments (5)
SampoomManagement.xcodeproj/project.pbxproj (1)

217-217: 문자열 카탈로그 심볼 생성 활성화 승인

문자열 카탈로그 심볼 생성을 활성화하여 로컬라이제이션 지원을 강화하는 변경사항이 올바르게 적용되었습니다.

참고: 이 설정이 프로젝트 레벨(lines 217, 275)과 타겟 레벨(lines 306, 341) 모두에 존재합니다. 타겟 레벨 설정이 우선하므로 프로젝트 레벨의 중복 설정은 실질적인 영향이 없지만, 원한다면 프로젝트 레벨의 설정을 제거하여 설정을 단순화할 수 있습니다.

Also applies to: 275-275

SampoomManagement/Core/Resources/StringResources.swift (1)

80-93: 중복 상수 정의를 확인해주세요.

Common.confirmCommon.ok가 모두 "확인"으로 정의되어 있고, Common.closeNavigation.close가 모두 "닫기"로 정의되어 있습니다. 일관성을 위해 하나의 정의만 사용하거나, 서로 다른 용도라면 명확한 네이밍이 필요합니다.

SampoomManagement/Features/Outbound/Data/Repository/OutboundRepositoryImpl.swift (1)

20-22: 반복적인 키체인 접근으로 인한 성능 영향을 고려하세요.

모든 메서드에서 preferences.getStoredUser()를 호출하여 키체인에 접근하고 있습니다. 키체인 접근은 상대적으로 비용이 높은 작업이며, 사용자가 Outbound 작업을 연속으로 수행할 경우 성능 저하가 발생할 수 있습니다.

다음 중 하나를 고려하세요:

  1. 초기화 시 사용자 정보를 캐싱하고 주기적으로 갱신
  2. Repository를 actor로 변환하여 캐싱된 사용자 정보를 안전하게 공유

옵션 1: 초기화 시 캐싱

 class OutboundRepositoryImpl: OutboundRepository {
     private let api: OutboundAPI
     private let preferences: AuthPreferences
+    private var cachedUser: User?
     
     init(api: OutboundAPI, preferences: AuthPreferences) {
         self.api = api
         self.preferences = preferences
     }
+    
+    private func getUser() throws -> User {
+        if let cached = cachedUser {
+            return cached
+        }
+        guard let user = try preferences.getStoredUser() else {
+            throw NetworkError.unauthorized
+        }
+        cachedUser = user
+        return user
+    }
     
     func getOutboundList() async throws -> OutboundList {
-        guard let user = try preferences.getStoredUser() else {
-            throw NetworkError.unauthorized
-        }
+        let user = try getUser()
         let data: [OutboundDto] = try await api.getOutboundList(agencyId: user.agencyId)
         // ...
     }

Also applies to: 29-31, 36-38, 44-46, 51-53, 58-60

SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift (1)

44-45: endedAt 필드의 nil 처리 일관성 개선

startedAt은 빈 문자열일 때 nil로 변환하지만, endedAt은 그대로 전달됩니다. 빈 문자열이 들어올 경우 일관성을 위해 nil로 변환하는 것이 좋습니다.

다음 diff를 적용하여 일관성을 개선하세요:

             agencyId: self.organizationId,
             startedAt: self.startedAt.isEmpty ? nil : self.startedAt,
-            endedAt: self.endedAt
+            endedAt: self.endedAt.isEmpty ? nil : self.endedAt
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (1)

35-37: 프로필 편집 기능 구현 예정

TODO 주석이 남아있습니다. 이 기능을 구현할 계획이라면 이슈를 생성하여 추적하는 것을 권장합니다.

프로필 편집 기능의 초기 구현 코드를 생성하거나, GitHub 이슈를 생성하여 이 작업을 추적하시겠습니까?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed2c94c and 73b4a2f.

📒 Files selected for processing (34)
  • SampoomManagement.xcodeproj/project.pbxproj (2 hunks)
  • SampoomManagement/App/ContentView.swift (4 hunks)
  • SampoomManagement/Core/DI/AppDependencies.swift (5 hunks)
  • SampoomManagement/Core/Network/TokenRefreshService.swift (1 hunks)
  • SampoomManagement/Core/Resources/StringResources.swift (5 hunks)
  • SampoomManagement/Core/UI/Components/OrderItem.swift (1 hunks)
  • SampoomManagement/Core/UI/Components/StatusChip.swift (2 hunks)
  • SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (4 hunks)
  • SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift (3 hunks)
  • SampoomManagement/Features/Auth/Data/Remote/API/AuthAPI.swift (2 hunks)
  • SampoomManagement/Features/Auth/Data/Remote/DTO/GetProfileResponseDTO.swift (1 hunks)
  • SampoomManagement/Features/Auth/Data/Remote/DTO/LoginRequestDTO.swift (1 hunks)
  • SampoomManagement/Features/Auth/Data/Remote/DTO/LoginResponseDTO.swift (0 hunks)
  • SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1 hunks)
  • SampoomManagement/Features/Auth/Domain/Models/User.swift (2 hunks)
  • SampoomManagement/Features/Cart/Data/Remote/API/CartAPI.swift (5 hunks)
  • SampoomManagement/Features/Cart/Data/Repository/CartRepositoryImpl.swift (1 hunks)
  • SampoomManagement/Features/Dashboard/UI/DashboardView.swift (3 hunks)
  • SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (1 hunks)
  • SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (1 hunks)
  • SampoomManagement/Features/Order/Domain/Models/OrderStatus.swift (2 hunks)
  • SampoomManagement/Features/Order/Domain/Repository/OrderRepository.swift (1 hunks)
  • SampoomManagement/Features/Order/Domain/UseCase/CompleteOrderUseCase.swift (1 hunks)
  • SampoomManagement/Features/Order/UI/OrderDetailContent.swift (1 hunks)
  • SampoomManagement/Features/Order/UI/OrderDetailViewModel.swift (3 hunks)
  • SampoomManagement/Features/Order/UI/OrderListView.swift (1 hunks)
  • SampoomManagement/Features/Outbound/Data/Remote/API/OutboundAPI.swift (6 hunks)
  • SampoomManagement/Features/Outbound/Data/Repository/OutboundRepositoryImpl.swift (1 hunks)
  • SampoomManagement/Features/Part/Data/Remote/API/PartAPI.swift (1 hunks)
  • SampoomManagement/Features/Part/Data/Repository/PartRepositoryImpl.swift (2 hunks)
  • SampoomManagement/Features/Setting/UI/SettingUiEvent.swift (1 hunks)
  • SampoomManagement/Features/Setting/UI/SettingUiState.swift (1 hunks)
  • SampoomManagement/Features/Setting/UI/SettingView.swift (1 hunks)
  • SampoomManagement/Features/Setting/UI/SettingViewModel.swift (1 hunks)
💤 Files with no reviewable changes (1)
  • SampoomManagement/Features/Auth/Data/Remote/DTO/LoginResponseDTO.swift
🧰 Additional context used
🧬 Code graph analysis (21)
SampoomManagement/Features/Setting/UI/SettingUiEvent.swift (2)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (2)
  • loadProfile (43-49)
  • logout (51-61)
SampoomManagement/Features/Auth/Data/Remote/API/AuthAPI.swift (1)
  • logout (72-79)
SampoomManagement/Features/Order/Domain/Repository/OrderRepository.swift (2)
SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (1)
  • completeOrder (49-56)
SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (1)
  • completeOrder (62-64)
SampoomManagement/Features/Order/UI/OrderDetailViewModel.swift (1)
SampoomManagement/Features/Order/Domain/UseCase/CompleteOrderUseCase.swift (1)
  • execute (17-19)
SampoomManagement/Features/Setting/UI/SettingView.swift (2)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (3)
  • onEvent (31-41)
  • loadProfile (43-49)
  • logout (51-61)
SampoomManagement/Core/Utilities/DateFormatterUtil.swift (1)
  • formatDate (16-50)
SampoomManagement/Features/Outbound/Data/Repository/OutboundRepositoryImpl.swift (2)
SampoomManagement/Features/Outbound/Data/Remote/API/OutboundAPI.swift (6)
  • getOutboundList (19-27)
  • processOutbound (44-53)
  • addOutbound (30-41)
  • deleteOutbound (56-65)
  • deleteAllOutbound (82-91)
  • updateOutbound (68-79)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Cart/Data/Repository/CartRepositoryImpl.swift (2)
SampoomManagement/Features/Cart/Data/Remote/API/CartAPI.swift (5)
  • getCartList (19-29)
  • addCart (32-43)
  • deleteCart (46-55)
  • deleteAllCart (72-81)
  • updateCart (58-69)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Part/Data/Repository/PartRepositoryImpl.swift (2)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Part/Data/Remote/API/PartAPI.swift (2)
  • getPartList (36-43)
  • searchParts (45-62)
SampoomManagement/Features/Part/Data/Remote/API/PartAPI.swift (2)
SampoomManagement/Features/Part/Data/Repository/PartRepositoryImpl.swift (2)
  • getPartList (27-32)
  • searchParts (34-39)
SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift (2)
  • toModel (11-27)
  • toModel (31-47)
SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (3)
SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (2)
  • completeOrder (62-64)
  • receiveOrder (66-71)
SampoomManagement/Core/Network/NetworkManager.swift (2)
  • request (42-106)
  • request (108-181)
SampoomManagement/Features/Order/UI/OrderDetailViewModel.swift (1)
  • receiveOrder (104-127)
SampoomManagement/Features/Order/Domain/UseCase/CompleteOrderUseCase.swift (2)
SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (1)
  • completeOrder (49-56)
SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (1)
  • completeOrder (62-64)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/KeychainManager.swift (3)
  • save (24-43)
  • delete (73-85)
  • get (45-71)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
  • refreshToken (17-69)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
  • refreshToken (98-138)
SampoomManagement/Features/Cart/Data/Remote/API/CartAPI.swift (4)
SampoomManagement/Features/Cart/Data/Repository/CartRepositoryImpl.swift (4)
  • getCartList (19-26)
  • addCart (28-34)
  • deleteCart (36-41)
  • deleteAllCart (43-48)
SampoomManagement/Core/Network/NetworkManager.swift (2)
  • request (42-106)
  • request (108-181)
SampoomManagement/Features/Outbound/Data/Remote/API/OutboundAPI.swift (1)
  • toDictionary (96-99)
SampoomManagement/Features/Cart/UI/CartListViewModel.swift (2)
  • deleteCart (181-206)
  • deleteAllCart (227-252)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
  • refreshToken (98-138)
SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (3)
SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (2)
  • completeOrder (49-56)
  • receiveOrder (59-66)
SampoomManagement/Features/Order/UI/OrderDetailViewModel.swift (1)
  • receiveOrder (104-127)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Outbound/Data/Remote/API/OutboundAPI.swift (2)
SampoomManagement/Features/Outbound/Data/Repository/OutboundRepositoryImpl.swift (5)
  • getOutboundList (19-26)
  • addOutbound (35-41)
  • processOutbound (28-33)
  • deleteOutbound (43-48)
  • deleteAllOutbound (50-55)
SampoomManagement/Core/Network/NetworkManager.swift (2)
  • request (42-106)
  • request (108-181)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Setting/UI/SettingUiState.swift (1)
  • copy (19-27)
SampoomManagement/Core/Utilities/GlobalMessageHandler.swift (1)
  • showMessage (21-30)
SampoomManagement/App/ContentView.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Core/DI/AppDependencies.swift (1)
  • makeSettingViewModel (218-224)
SampoomManagement/Features/Auth/UI/AuthViewModel.swift (1)
  • signOut (40-50)
SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift (2)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
  • refreshToken (17-69)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
  • refreshToken (98-138)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
  • refreshToken (17-69)
SampoomManagement/Core/Resources/StringResources.swift (2)
SampoomManagement/Features/Auth/Data/Remote/API/AuthAPI.swift (1)
  • logout (72-79)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (1)
  • logout (51-61)
SampoomManagement/Features/Auth/Data/Remote/API/AuthAPI.swift (1)
SampoomManagement/Core/Network/NetworkManager.swift (2)
  • request (42-106)
  • request (108-181)
🪛 SwiftLint (0.57.0)
SampoomManagement/Features/Setting/UI/SettingView.swift

[Warning] 89-89: TODOs should be resolved (Edit profile)

(todo)

SampoomManagement/Features/Setting/UI/SettingViewModel.swift

[Warning] 36-36: TODOs should be resolved (Implement edit profile)

(todo)

🔇 Additional comments (30)
SampoomManagement/Core/UI/Components/OrderItem.swift (1)

31-31: 변경사항이 올바릅니다!

StatusChipOrderStatus 열거형을 직접 전달하도록 변경되어 타입 안정성이 향상되었습니다. 문자열 기반 접근 방식보다 컴파일 타임 검증이 가능합니다.

SampoomManagement/Features/Cart/Data/Remote/API/CartAPI.swift (2)

19-29: 멀티테넌트 지원이 올바르게 적용되었습니다!

하드코딩된 agency-1 대신 동적 agencyId 파라미터를 사용하도록 변경되어 멀티테넌트 아키텍처를 올바르게 지원합니다. 리포지토리 구현체에서 저장된 사용자의 agencyId를 전달하는 것도 확인되었습니다.


32-43: 모든 메서드가 일관되게 업데이트되었습니다.

addCart, deleteCart, updateCart, deleteAllCart 메서드 모두 동일한 패턴으로 agencyId 파라미터를 사용하도록 업데이트되어 일관성이 유지되고 있습니다.

Also applies to: 46-55, 58-69, 72-81

SampoomManagement/Features/Outbound/Data/Remote/API/OutboundAPI.swift (2)

19-27: 엔드포인트 업데이트가 올바르게 적용되었습니다.

getOutboundList 메서드가 동적 agencyId를 사용하도록 올바르게 변경되었습니다.


30-41: 에러 핸들링 개선과 일관된 멀티테넌트 지원이 추가되었습니다!

모든 메서드에 agencyId 파라미터가 추가되었을 뿐만 아니라, 이전에 누락되었던 response.success 검증이 addOutbound, processOutbound, deleteOutbound, updateOutbound, deleteAllOutbound 메서드에 추가되어 에러 핸들링이 개선되었습니다.

Also applies to: 44-53, 56-65, 68-79, 82-91

SampoomManagement/Core/Resources/StringResources.swift (3)

187-193: 설정 화면 문자열 리소스가 추가되었습니다.

새로운 설정 화면을 위한 문자열 리소스가 올바르게 추가되었습니다.


224-234: 인증 유효성 검증 메시지가 확장되었습니다.

비밀번호 복잡성, 길이 제한 등에 대한 상세한 유효성 검증 메시지가 추가되어 사용자 경험이 개선되었습니다. 마침표를 제거하여 메시지 스타일도 일관되게 정리되었습니다.


177-185: 변경사항 검증 완료 - 안전성 확인됨

주문 상태 변경이 올바르게 구현되었습니다.

검증 결과:

  • ✅ 모든 8개 상태(pending, confirmed, shipping, delayed, producing, arrived, completed, canceled)가 OrderStatus 열거형에 정의됨
  • ✅ 모든 상태가 StatusChip에서 StringResources.Order 속성으로 매핑됨
  • ✅ 기존 상태 문자열 "승인대기" 참조 없음 (안전한 변경)
  • ✅ 백엔드 데이터(열거형 raw values: "PENDING" 등)와 UI 표시 문자열(StringResources: 한글)이 분리되어 있음
  • OrderStatusCodable 프로토콜로 기존 주문 데이터 역직렬화 문제 없음

새로운 상태들(producing, delayed 등)도 UI에서 올바르게 표시됩니다.

SampoomManagement/Features/Order/UI/OrderDetailContent.swift (1)

81-81: 타입 안전성 개선이 적용되었습니다!

OrderStatus 열거형을 직접 전달하도록 변경되어 다른 파일들과 일관되게 타입 안전성이 개선되었습니다.

SampoomManagement/Features/Setting/UI/SettingUiEvent.swift (1)

10-14: 설정 화면 이벤트 정의가 올바릅니다!

설정 화면을 위한 UI 이벤트 열거형이 명확하게 정의되었습니다. SettingViewModel에서 이러한 이벤트를 올바르게 처리하는 것도 확인되었습니다.

SampoomManagement/Features/Auth/Data/Remote/DTO/LoginRequestDTO.swift (1)

11-11: 리뷰 코멘트의 전제가 정확하지 않습니다.

검색 결과에 따르면 workspace 필드는 호출자가 제공하는 값이 아니라 AuthAPI.swift:20에서 **하드코딩된 값 "AGENCY"**로 설정됩니다. 따라서 호출하는 쪽에서 빈 문자열이나 유효하지 않은 값을 제공할 수 없으며, 추가 검증이 필요하지 않습니다.

현재 구조:

  • workspace는 AuthAPI 내부에서만 결정되는 상수값 ("AGENCY")
  • 실제 사용자 입력은 emailpassword이며, 이들은 검증 없이 그대로 전달됨

만약 입력값 검증이 필요하다면, 이는 workspace가 아닌 emailpassword 필드에 적용되어야 합니다.

Likely an incorrect or invalid review comment.

SampoomManagement/Features/Outbound/Data/Repository/OutboundRepositoryImpl.swift (1)

12-16: AuthPreferences 의존성 추가가 적절합니다.

멀티테넌트 지원을 위해 AuthPreferences를 주입하여 사용자의 agencyId를 가져오는 접근 방식이 올바릅니다.

SampoomManagement/Core/Network/TokenRefreshService.swift (1)

51-65: 토큰 갱신 시 확장된 사용자 필드를 올바르게 유지합니다.

기존 사용자 정보의 email, branch, agencyId, startedAt, endedAt 필드를 새로운 토큰 정보와 함께 올바르게 전파하고 있습니다.

SampoomManagement/Features/Dashboard/UI/DashboardView.swift (1)

15-15: 설정 화면 연동이 잘 구현되었습니다.

onSettingClick 콜백을 추가하여 설정 화면으로의 네비게이션을 적절하게 처리하고 있습니다.

Also applies to: 35-35

SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (2)

18-18: 새로운 사용자 필드를 위한 키 추가가 적절합니다.

userEmail, agencyId, startedAt, endedAt를 키체인에 저장하기 위한 키들이 올바르게 정의되었습니다.

Also applies to: 24-26


75-116: 기존 사용자 데이터 마이그레이션이 필수입니다.

getStoredUser()agencyIdemail을 필수 필드로 요구하므로 (lines 80, 86-87), 이전 버전에서 로그인한 기존 사용자는 두 가지 심각한 문제를 겪게 됩니다:

  1. 앱 상태 불일치: isSignedIn()hasToken()만 확인하므로 기존 사용자는 로그인 상태를 유지합니다. 하지만 실제 기능 사용 시 모든 저장소에서 getStoredUser()를 호출하면 실패하거나 NetworkError.unauthorized 또는 AuthError.tokenRefreshFailed를 던집니다.

  2. 사용자 경험 악화: 기존 사용자는 자동으로 로그아웃되지 않고 앱이 열리지만, 주문 조회, 카트 추가 등 대부분의 기능이 중단됩니다.

필요한 조치:

  • getStoredUser()가 누락된 agencyId/email에 대해 기본값을 제공하거나
  • 프로필 API를 호출하여 누락된 데이터를 채워 키체인에 저장하는 마이그레이션 로직을 구현하거나
  • AuthViewModel.updateLoginState() 또는 TokenRefreshService에서 getStoredUser() 실패를 감지하여 자동 로그아웃 처리
SampoomManagement/Features/Part/Data/Remote/API/PartAPI.swift (2)

36-43: 멀티테넌트 지원을 위한 agencyId 파라미터 추가가 적절합니다.

getPartList 메서드가 agencyId를 받아 agency별로 부품 목록을 조회하도록 올바르게 업데이트되었습니다.


45-62: 검색 엔드포인트에 agencyId 파라미터가 올바르게 추가되었습니다.

searchParts 메서드가 agencyId를 받아 agency 범위 내에서 부품을 검색하도록 올바르게 업데이트되었습니다.

SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (2)

48-56: 주문 완료 처리를 별도 메서드로 분리한 것이 적절합니다.

completeOrder 메서드가 주문 완료 상태 변경을 명확하게 처리하며, 적절한 에러 처리를 포함하고 있습니다.


58-66: 대리점별 주문 입고 처리에 agencyId 파라미터가 올바르게 추가되었습니다.

receiveOrder 메서드가 대리점 범위로 올바르게 스코핑되었으며, 관련 코드 스니펫(OrderDetailViewModel)에서 두 메서드를 순차적으로 호출하는 것을 확인할 수 있습니다.

SampoomManagement/Features/Auth/Domain/Models/User.swift (1)

13-13: 확장된 사용자 프로필 필드가 적절하게 추가되었습니다.

email, agencyId, startedAt, endedAt 필드가 올바르게 추가되었으며, agencyId는 필수, startedAt/endedAt는 선택적으로 적절하게 정의되었습니다.

Also applies to: 22-24

SampoomManagement/Features/Auth/Data/Remote/DTO/GetProfileResponseDTO.swift (1)

12-20: 백엔드 API 스키마 확인이 필수입니다. 현재 필수 필드 변경이 API 계약과 일치하는지 검증할 수 없습니다.

저장소에서 API 응답 예시, 테스트 픽스처, 또는 백엔드 API 문서를 찾을 수 없었습니다. 다음을 확인하세요:

  • 백엔드 API 문서: user/profile?workspace=AGENCY 엔드포인트가 모든 필드(userName, email, role, position, workspace, branch, organizationId, startedAt)를 항상 반환하는지 확인
  • 현재 에러 처리: AuthRepositoryImpl.swift 라인 60-69에서 응답이 없거나 디코딩 실패 시 preferences를 초기화하고 에러를 재던짐 (동작 정상)
  • 테스트: 백엔드가 필드를 누락하는 시나리오에 대한 테스트가 필요한 경우, 옵셔널 필드로 변경하거나 폴백 값 처리 추가

백엔드 팀과 API 응답 스키마를 확인하고, 필드 누락 가능성이 있으면 관련 필드를 옵셔널로 변경하거나 기본값 처리를 추가하세요.

SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift (2)

50-68: LGTM!

토큰 정보는 유지하면서 프로필 정보(email, role, agencyId, startedAt, endedAt 포함)를 병합하는 로직이 올바르게 구현되었습니다.


14-25: 로그인 후 agencyId 기본값 관련 우려 - 검증 완료

검증 결과, 현재 구현은 실제로 안전하고 의도된 설계입니다:

  1. 임시 상태의 분리: LoginResponseDTO.toModel()에서 생성된 agencyId=0인 User 객체는 메모리에만 존재하고 절대 저장되지 않습니다.

  2. 필수 병합 과정: 프로필 조회는 로그인 흐름의 필수 과정으로, mergeWith(profile:)에서 profile.agencyId로 실제 값이 덮어씌워집니다 (AuthMappers.swift:63).

  3. 완전한 데이터만 저장: preferences.saveUser(mergedUser)로 저장되는 것은 프로필 데이터가 병합된 완전한 User 객체입니다.

  4. 저장소 안전성: 모든 Repository의 getStoredUser()는 항상 완전한 프로필 정보를 포함한 User를 반환하므로, guard 문의 보호 아래 agencyId=0이 API 호출로 전달될 수 없습니다.

추가 작업이 필요하지 않습니다.

SampoomManagement/Core/DI/AppDependencies.swift (3)

65-65: LGTM!

completeOrderUseCase가 올바르게 선언되고 초기화되었습니다. 주문 완료 플로우를 지원하는 적절한 추가입니다.

Also applies to: 138-138


107-107: LGTM!

Part, Outbound, Cart 리포지토리에 authPreferences 의존성을 주입하여 멀티테넌트 기능(agencyId 기반 API 호출)을 지원합니다. 일관된 패턴으로 구현되었습니다.

Also applies to: 115-115, 125-125


207-216: LGTM!

ViewModel 팩토리 메서드들이 올바르게 구현되었습니다:

  • makeOrderDetailViewModelcompleteOrderUseCase 의존성 추가
  • 새로운 makeSettingViewModel 팩토리가 필요한 의존성(authPreferences, signOutUseCase, globalMessageHandler)과 함께 적절히 구성됨

Also applies to: 218-224

SampoomManagement/Features/Setting/UI/SettingViewModel.swift (3)

12-29: LGTM!

@MainActor로 UI 스레드 안전성을 보장하고, 의존성 주입 패턴이 깔끔하게 구현되었습니다. ObservableObject 프로토콜 준수도 적절합니다.


51-61: LGTM!

로그아웃 로직이 적절하게 구현되었습니다:

  • 비동기 Task를 사용하여 sign-out 실행
  • NetworkErrorerrorDescription 우선 사용, fallback으로 localizedDescription 사용
  • GlobalMessageHandler를 통한 사용자 피드백 제공

fire-and-forget 방식의 Task 사용은 로그아웃이 뷰 해제 후에도 완료되어야 하므로 적절합니다.


43-49: getStoredUser()throws 선언과 실제 구현이 불일치합니다.

AuthPreferences.getStoredUser()throws로 선언되어 있지만 내부의 catch 블록(라인 112-115)이 모든 에러를 포착하고 nil을 반환하므로, 실제로는 절대 에러를 던지지 않습니다.

따라서 SettingViewModel.loadProfile()try와 catch 블록(라인 46-48)은 실행될 수 없는 데드 코드입니다.

해결방법:

  • getStoredUser()throws 선언을 제거하거나
  • 에러를 내부에서 처리하지 말고 호출자에게 전파하도록 리팩토링

Likely an incorrect or invalid review comment.

Comment thread SampoomManagement/Features/Dashboard/UI/DashboardView.swift Outdated
Comment thread SampoomManagement/Features/Setting/UI/SettingUiState.swift
Comment thread SampoomManagement/Features/Setting/UI/SettingView.swift
Copy link
Copy Markdown
Member

@CHOOSLA CHOOSLA 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
Copy Markdown

@Lee-Jong-Jin Lee-Jong-Jin 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
Copy Markdown
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: 2

🧹 Nitpick comments (1)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (1)

38-40: Deprecated 이벤트 케이스 처리 개선 제안

logout 이벤트 케이스가 deprecated로 표시되어 있지만 여전히 switch문에 포함되어 있습니다. 향후 유지보수를 위해 다음 중 하나를 고려해주세요:

  • 이 케이스를 완전히 제거하고 SettingUiEvent enum에서도 삭제
  • 또는 유지가 필요한 이유를 주석에 명확히 기록
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73b4a2f and c99f695.

📒 Files selected for processing (9)
  • SampoomManagement/App/ContentView.swift (4 hunks)
  • SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (4 hunks)
  • SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift (3 hunks)
  • SampoomManagement/Features/Auth/Domain/Models/User.swift (1 hunks)
  • SampoomManagement/Features/Dashboard/UI/DashboardView.swift (3 hunks)
  • SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (1 hunks)
  • SampoomManagement/Features/Setting/UI/SettingUiState.swift (1 hunks)
  • SampoomManagement/Features/Setting/UI/SettingView.swift (1 hunks)
  • SampoomManagement/Features/Setting/UI/SettingViewModel.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • SampoomManagement/Features/Auth/Data/Mappers/AuthMappers.swift
  • SampoomManagement/Features/Setting/UI/SettingUiState.swift
🧰 Additional context used
🧬 Code graph analysis (6)
SampoomManagement/App/ContentView.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Core/DI/AppDependencies.swift (1)
  • makeSettingViewModel (218-224)
SampoomManagement/Features/Auth/UI/AuthViewModel.swift (1)
  • signOut (40-50)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/KeychainManager.swift (3)
  • save (24-43)
  • delete (73-85)
  • get (45-71)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
  • refreshToken (17-69)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
  • refreshToken (98-138)
SampoomManagement/Features/Setting/UI/SettingView.swift (2)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (3)
  • onEvent (31-42)
  • loadProfile (44-50)
  • logout (52-61)
SampoomManagement/Core/Utilities/DateFormatterUtil.swift (1)
  • formatDate (16-50)
SampoomManagement/Features/Auth/Domain/Models/User.swift (2)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
  • refreshToken (17-69)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
  • refreshToken (98-138)
SampoomManagement/Features/Setting/UI/SettingViewModel.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Setting/UI/SettingUiState.swift (1)
  • copy (19-34)
SampoomManagement/Core/Utilities/GlobalMessageHandler.swift (1)
  • showMessage (21-30)
SampoomManagement/Features/Order/Data/Repository/OrderRepositoryImpl.swift (3)
SampoomManagement/Features/Order/Data/Remote/API/OrderAPI.swift (2)
  • completeOrder (49-56)
  • receiveOrder (59-66)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Features/Order/UI/OrderDetailViewModel.swift (1)
  • receiveOrder (104-127)
🪛 SwiftLint (0.57.0)
SampoomManagement/Features/Setting/UI/SettingView.swift

[Warning] 92-92: TODOs should be resolved (Edit profile)

(todo)

SampoomManagement/Features/Setting/UI/SettingViewModel.swift

[Warning] 36-36: TODOs should be resolved (Implement edit profile)

(todo)

🔇 Additional comments (7)
SampoomManagement/Features/Setting/UI/SettingView.swift (1)

41-48: 비동기 로그아웃 흐름 정돈 감사합니다.
확인 버튼에서 viewModel.logout() 성공 여부를 기다린 뒤 상위 콜백을 호출하는 구조라, 이전에 보고된 강제 로그아웃 문제가 해소되었습니다.

SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (3)

18-26: 새로운 키 정의가 올바르게 추가되었습니다.

userEmail, agencyId, startedAt, endedAt 키가 일관된 네이밍 컨벤션으로 추가되었습니다.


35-43: 새로운 필드 저장 로직이 올바르게 구현되었습니다.

email, agencyId, startedAt, endedAt 필드가 적절히 저장되고 있으며, 롤백 로직에도 포함되어 있습니다. 다만 42-43번 라인에서 optional 날짜 필드를 빈 문자열로 저장한 후 getStoredUser에서 다시 nil로 변환하는 방식은 작동하지만, 빈 문자열과 nil 간의 의미 차이가 있을 수 있으니 주의가 필요합니다.


151-159: 로그아웃 시 새로운 필드가 올바르게 삭제됩니다.

clear() 메서드가 새로운 필드(userEmail, agencyId, startedAt, endedAt)를 모두 삭제하도록 확장되었습니다.

SampoomManagement/Features/Setting/UI/SettingViewModel.swift (3)

12-29: MVVM 구조와 의존성 주입이 잘 구현되었습니다.

@mainactor 애노테이션이 적절히 사용되었고, 의존성이 생성자를 통해 주입되어 테스트 가능성이 높습니다. User의 옵셔널 타입도 AuthPreferences.getStoredUser()가 nil을 반환할 수 있는 것과 일관성이 있습니다.


44-50: 프로필 로드 로직이 적절히 구현되었습니다.

getStoredUser()의 반환값과 예외를 적절히 처리하고 있습니다. 다만 AuthPreferences.getStoredUser()가 필수 필드(email, agencyId) 누락 시 nil을 반환하는 점을 고려하면, 사용자에게 nil 상태와 오류 상태를 구분하여 표시하는 것이 좋을 수 있습니다.


52-61: 비동기 로그아웃 로직이 잘 구현되었습니다.

async/await를 적절히 사용하고 있으며, NetworkError에 대한 특별 처리와 GlobalMessageHandler를 통한 사용자 피드백이 잘 구현되어 있습니다. Bool 반환값으로 호출자가 성공/실패를 처리할 수 있습니다.

Comment thread SampoomManagement/App/ContentView.swift
Comment thread SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift Outdated
Copy link
Copy Markdown
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: 1

Caution

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

⚠️ Outside diff range comments (1)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)

77-95: 마이그레이션 전략에 agencyId 및 email 기본값 검증 필요

검증을 통해 마이그레이션 로직의 위험이 확인되었습니다.

문제점:

  1. agencyId=0 기본값 (AuthPreferences.swift 93줄):

    • CartRepositoryImpl, OrderRepositoryImpl, PartRepositoryImpl, OutboundRepositoryImpl의 모든 API 호출이 user.agencyId를 매개변수로 사용
    • 검증 없음: 어떤 리포지토리도 agencyId가 0인지 확인하지 않음
    • 결과: 레거시 사용자가 새 필드 없이 저장된 경우, 모든 API 호출이 agencyId=0으로 전송되어 백엔드에서 거부될 가능성이 높음
    • 사용자는 명확한 로그아웃이 아닌 애매한 API 오류만 경험
  2. email="" 기본값: UI 유효성 검사(!email.isEmpty)를 통과하지만 의미상 부정확

필수 수정:

  • Line 77-95: getStoredUser() 반환 후 또는 각 리포지토리 호출 전에 agencyId > 0 검증 추가
  • 또는 앱 시작 시 누락된 필드 감지 시 프로필 API 재호출 강제 또는 명시적 재로그인 플로우 구현
  • email 기본값을 유효한 플레이스홀더나 빈 문자열 대신 null/optional로 변경 고려
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c99f695 and 9996a6a.

📒 Files selected for processing (3)
  • SampoomManagement/App/ContentView.swift (4 hunks)
  • SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (5 hunks)
  • SampoomManagement/Features/Auth/UI/AuthViewModel.swift (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/KeychainManager.swift (3)
  • save (24-43)
  • delete (73-85)
  • get (45-71)
SampoomManagement/Core/Network/TokenRefreshService.swift (1)
  • refreshToken (17-69)
SampoomManagement/Features/Auth/Data/Repository/AuthRepositoryImpl.swift (1)
  • refreshToken (98-138)
SampoomManagement/App/ContentView.swift (3)
SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (1)
  • getStoredUser (75-116)
SampoomManagement/Core/DI/AppDependencies.swift (1)
  • makeSettingViewModel (218-224)
SampoomManagement/Features/Auth/UI/AuthViewModel.swift (1)
  • handleSignedOutState (68-71)
🔇 Additional comments (5)
SampoomManagement/Features/Auth/UI/AuthViewModel.swift (1)

48-71: 상태 갱신 헬퍼 분리 👍

로그아웃 흐름에서 UI 상태를 전용 메서드로 분리해 SettingView 등에서 재사용할 수 있게 된 점이 깔끔합니다. 중복 호출 우려도 사라졌습니다.

SampoomManagement/App/ContentView.swift (1)

77-78: UI 콜백에서 상태만 처리하도록 정리된 점 좋습니다

SettingViewModel이 네트워크 로그아웃을 처리한 뒤에는 여기서 UI 상태만 갱신하면 되기에, 이제 중복 네트워크 호출 걱정 없이 흐름이 명확해졌습니다.

SampoomManagement/Features/Auth/Data/Local/Preferences/AuthPreferences.swift (3)

18-18: 새로운 키 추가 확인

userEmail, agencyId, startedAt, endedAt 키가 추가되어 확장된 User 모델과 일치합니다.

Also applies to: 24-26


29-61: saveUser 구현 적절함

새로운 필드(email, agencyId, startedAt, endedAt) 저장 및 실패 시 롤백 처리가 일관되게 구현되었습니다. startedAt/endedAt의 nil 처리도 적절합니다.


145-164: clear 구현 적절함

로그아웃 시 새로운 필드(userEmail, agencyId, startedAt, endedAt)를 포함한 모든 키가 삭제됩니다.

Comment thread SampoomManagement/App/ContentView.swift Outdated
@Sangyoon98 Sangyoon98 merged commit 9de3e18 into dev Nov 4, 2025
3 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.

3 participants