Skip to content

feat: 로그아웃/리프레시 구현#66

Merged
clxxrlove merged 8 commits into
developfrom
BOOK-110-feature/#59
Jul 9, 2025
Merged

feat: 로그아웃/리프레시 구현#66
clxxrlove merged 8 commits into
developfrom
BOOK-110-feature/#59

Conversation

@clxxrlove
Copy link
Copy Markdown
Member

@clxxrlove clxxrlove commented Jul 9, 2025

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

  • 로그아웃이 제대로 동작하지 않던 버그 -> TokenProvider를 싱글톤으로 수정
  • Refresh 기능 구현
    • 관련 설계가 잘못되어있어 구조적으로 크게 수정
    • 기존 Storage <-> Network 순환 참조 제거
    • 수정한 설계에서 Network <-> Data 간 순환 참조 발생
      • 클로저 지연 평가를 통해 타이밍 제어, 순환 참조 해결
  • 로그아웃 기능 구현
  • Presentation Layer의 Delegate 패턴 제거
    • Publisher를 통한 bindAction으로 View -> ViewController 액션 전달 방식 변경

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

ScreenRecording_07-08-2025.21-47-12_1.mov

Summary by CodeRabbit

  • 신규 기능

    • 로그아웃 버튼이 로그인 화면에 추가되어 사용자가 직접 로그아웃할 수 있습니다.
    • 로그아웃 기능이 뷰모델 및 도메인 계층에 도입되어 로그아웃 시 토큰 캐시가 안전하게 삭제됩니다.
    • 네트워크 인증 오류(401) 발생 시 자동 토큰 재발급 및 재시도 기능이 추가되어 인증 안정성이 향상되었습니다.
  • 버그 수정

    • 네트워크 오류 유형에 badRequest, retryFailed가 추가되어 오류 처리 신뢰성이 향상되었습니다.
  • 리팩터링

    • 로그인/로그아웃 버튼 이벤트 처리가 델리게이트 방식에서 Combine 기반 이벤트 퍼블리셔로 변경되었습니다.
    • 불필요한 로딩 상태 및 관련 코드가 제거되어 코드가 간결해졌습니다.
  • 기타

    • 토큰 제공자에 refreshToken 속성이 추가되고 캐싱이 개선되었습니다.
    • 네트워크 및 저장소 관련 내부 구조와 의존성 주입 컨테이너 등록이 개선되어 유지보수성이 향상되었습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 9, 2025

"""

Walkthrough

이 변경사항은 로그아웃 및 토큰 리프레시 기능의 구현을 중심으로, 인증 관련 저장소, 네트워크 계층, 프레젠테이션 계층, 도메인 계층에 걸쳐 다양한 구조체와 프로토콜, 의존성 주입 등록 및 이벤트 흐름을 확장 및 개선합니다. 또한, 기존 델리게이트 패턴을 Combine 기반 이벤트 퍼블리셔로 전환하고, 관련된 에러 처리 및 상태 관리를 통합합니다.

Changes

파일/경로 그룹 변경 요약
.../DTO/Response/EmptyResponse.swift EmptyResponse에 명시적 이니셜라이저(init(), init(from:)) 추가
.../Error/NetworkError.swift NetworkErrorbadRequest, retryFailed 케이스 추가
.../Interface/Network/RefreshHandler.swift RefreshHandler 프로토콜 신설, 토큰 리프레시 메서드 정의
.../Interface/Storage/TokenProvider.swift
.../TokenStorage/KeychainTokenProvider.swift
refreshIfNeeded() 메서드 제거, refreshToken 프로퍼티 추가 및 캐싱 구현
.../Sources/Repository/DefaultAuthRepository.swift tokenProvider 의존성 추가, 로그아웃/계정삭제 시 캐시 클리어, 리프레시 구현, 로깅 강화, RefreshHandler 프로토콜 채택
.../Sources/DataAssembly.swift AuthRepository 등록 시 TokenProvider 주입, RefreshHandler 등록 추가
.../Sources/Helper/AuthInterceptor.swift retryIfNeeded 메서드 제거
.../Sources/Helper/AuthRetrier.swift AuthRetrier 구조체 신설, 인증 실패 시 리프레시 및 재시도 로직 구현
.../Sources/Provider/OAuthNetworkProvider.swift authRetrier 의존성 추가, 리프레시/재시도 로직 통합, 204 응답 처리, 로깅 강화
.../Sources/NetworkAssembly.swift OAuthNetworkProvider 등록 시 AuthRetrier 주입 및 리프레시 핸들러 연결
.../Sources/Extension/RequestTarget+.swift 에러 매핑 구문 단축화(기능 변화 없음)
.../DomainAssembly.swift LogoutUseCase 등록 추가
.../UseCase/DefaultLogoutUseCase.swift DefaultLogoutUseCase 신설, 로그아웃 유스케이스 구현
.../StorageAssembly.swift TokenProvider 등록을 싱글턴 스코프로 변경
.../AuthFlow/View/LoginView.swift 델리게이트 제거, Combine 기반 이벤트 퍼블리셔 도입, 로그아웃 버튼 추가
.../AuthFlow/View/LoginViewController.swift 델리게이트 기반 처리 제거, Combine 구독으로 전환, 로딩 상태 구독 삭제
.../AuthFlow/ViewModel/LoginViewModel.swift 로딩 상태 제거, 에러 처리 통합, 로그아웃 액션/사이드이펙트 추가, LogoutUseCase 의존성 주입

Sequence Diagram(s)

sequenceDiagram
actor User
participant LoginView
participant LoginViewController
participant LoginViewModel
participant LogoutUseCase
participant AuthRepository
participant TokenProvider

User->>LoginView: 로그아웃 버튼 탭
LoginView-->>LoginViewController: .logoutButtonTapped 이벤트 (Combine)
LoginViewController-->>LoginViewModel: .logoutButtonTapped 액션
LoginViewModel-->>LoginViewModel: .logout 사이드이펙트 발생
LoginViewModel->>LogoutUseCase: execute()
LogoutUseCase->>AuthRepository: logout()
AuthRepository->>TokenProvider: clearCache()
AuthRepository->>AuthRepository: 토큰스토어 클리어
LogoutUseCase-->>LoginViewModel: 완료
LoginViewModel-->>LoginViewController: .logoutSuccessed 액션

Loading
sequenceDiagram
participant OAuthNetworkProvider
participant AuthRetrier
participant RefreshHandler
participant TokenProvider

OAuthNetworkProvider->>AuthRetrier: retryIfNeeded(response, data)
AuthRetrier->>TokenProvider: refreshToken 조회
AuthRetrier->>RefreshHandler: refresh(token)
RefreshHandler-->>AuthRetrier: 완료/실패
AuthRetrier-->>OAuthNetworkProvider: 완료/에러
Loading

Assessment against linked issues

Objective Addressed Explanation
로그아웃 구현 (#59)
리프레시 구현 (#59)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
EmptyResponse에 명시적 초기화 구현 (src/Projects/BKData/Sources/DTO/Response/EmptyResponse.swift) 로그인/로그아웃/리프레시 기능과 직접 관련 없는 기본 구조체 초기화 명시화로, 기능 요구사항과는 별개임

Possibly related PRs

Suggested reviewers

  • doyeonk429

Poem

🐰
로그아웃, 리프레시, 깔끔하게
버튼 한 번에 캐시도 날아가네
Combine 흐름에 이벤트 춤추고
새 유스케이스로 마음도 가벼워
이제 로그인도, 로그아웃도
토끼처럼 깡총, 깡총, 자유롭게!

"""


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e3bc1d and eee7ba9.

📒 Files selected for processing (1)
  • src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BOOK-110-feature/#59

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or @coderabbitai 요약 to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

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

🧹 Nitpick comments (5)
src/Projects/BKNetwork/Sources/NetworkAssembly.swift (1)

30-38: 에러 매핑 로직을 개선해주세요.

클로저 내부에서 @Autowired를 사용하여 순환 참조 문제를 해결한 것은 좋은 접근입니다. 하지만 모든 AuthErrorNetworkError.retryFailed로 일괄 매핑하면 구체적인 에러 정보가 손실됩니다.

다음과 같이 에러 타입별로 세분화된 매핑을 고려해보세요:

return handler.refresh(token: token)
-    .mapError { _ in NetworkError.retryFailed }
+    .mapError { error in
+        switch error {
+        case .serverError:
+            return NetworkError.retryFailed
+        case .missingToken:
+            return NetworkError.unauthorized
+        default:
+            return NetworkError.retryFailed
+        }
+    }
    .eraseToAnyPublisher()
src/Projects/BKPresentation/Sources/AuthFlow/View/LoginViewController.swift (1)

18-33: Combine 기반 이벤트 처리로의 전환이 잘 구현되었습니다.

델리게이트 패턴에서 Combine 기반으로의 전환으로 반응형 프로그래밍의 장점을 잘 활용했습니다. 하지만 프로바이더별 분기 처리에서 확장성을 개선할 수 있습니다.

다음과 같이 switch 문을 사용하여 타입 안전성을 높이는 것을 고려해보세요:

case .loginButtonTapped(let provider):
-    if provider == .apple {
-        self.viewModel.send(.appleLoginButtonTapped)
-    } else if provider == .kakao {
-        self.viewModel.send(.kakaoLoginButtonTapped)
-    }
+    switch provider {
+    case .apple:
+        self.viewModel.send(.appleLoginButtonTapped)
+    case .kakao:
+        self.viewModel.send(.kakaoLoginButtonTapped)
+    }

이렇게 하면 새로운 프로바이더 추가 시 컴파일 타임에 누락된 케이스를 확인할 수 있습니다.

src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (1)

55-60: clearCache() 호출의 에러 처리를 추가하세요.

tokenProvider.clearCache()가 실패할 수 있는 경우를 대비해 에러 처리를 추가하는 것이 좋습니다.

clearCache()가 에러를 반환하도록 설계되어 있다면 에러 처리 코드를 생성해드릴까요?

src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift (1)

9-13: 로딩 상태 제거가 사용자 경험에 미칠 영향을 고려하세요.

isLoading 상태가 제거되어 인증 과정 중 로딩 표시가 불가능해졌습니다. 사용자가 버튼을 여러 번 탭하는 것을 방지하기 위해 로딩 상태 관리가 필요할 수 있습니다.

로딩 상태를 다시 추가하거나 다른 방식으로 중복 탭을 방지하는 코드를 생성해드릴까요?

src/Projects/BKPresentation/Sources/AuthFlow/View/LoginView.swift (1)

26-33: 디자인 시스템의 색상을 사용하세요.

로그아웃 버튼의 배경색이 .red로 하드코딩되어 있습니다. 일관된 UI를 위해 디자인 시스템의 색상을 사용하는 것이 좋습니다.

     private let logoutButton: UIButton = {
         let button = UIButton(type: .roundedRect)
-        button.backgroundColor = .red
+        button.backgroundColor = DesignSystem.Colors.danger // 또는 적절한 디자인 시스템 색상
         button.setTitle("로그아웃", for: .normal)
         button.setTitleColor(.black, for: .normal)
         button.layer.cornerRadius = LayoutConstants.buttonCornerRadius
         return button
     }()
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6d2efb and 17a4fa1.

📒 Files selected for processing (18)
  • src/Projects/BKData/Sources/DTO/Response/EmptyResponse.swift (1 hunks)
  • src/Projects/BKData/Sources/DataAssembly.swift (2 hunks)
  • src/Projects/BKData/Sources/Error/NetworkError.swift (1 hunks)
  • src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift (1 hunks)
  • src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift (0 hunks)
  • src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (4 hunks)
  • src/Projects/BKDomain/Sources/DomainAssembly.swift (1 hunks)
  • src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift (0 hunks)
  • src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/NetworkAssembly.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (2 hunks)
  • src/Projects/BKPresentation/Sources/AuthFlow/View/LoginView.swift (6 hunks)
  • src/Projects/BKPresentation/Sources/AuthFlow/View/LoginViewController.swift (1 hunks)
  • src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift (5 hunks)
  • src/Projects/BKStorage/Sources/StorageAssembly.swift (1 hunks)
  • src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift (0 hunks)
💤 Files with no reviewable changes (3)
  • src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift
  • src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift
  • src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/Constant/PresentationKeys.swift:3-5
Timestamp: 2025-07-07T13:53:13.006Z
Learning: clxxrlove prefers using enum over struct for constants namespace due to better runtime performance, memory layout, and compiler optimizations. Enum prevents instantiation at compile time without needing private init().
src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKData/Sources/DataAssembly.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKPresentation/Sources/AuthFlow/View/LoginViewController.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKPresentation/Sources/AuthFlow/View/LoginView.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
🧬 Code Graph Analysis (7)
src/Projects/BKDomain/Sources/DomainAssembly.swift (1)
src/Projects/BKCore/Sources/DiContainer/DIContainer.swift (1)
  • register (25-46)
src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift (1)
src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (1)
  • refresh (86-104)
src/Projects/BKData/Sources/DataAssembly.swift (1)
src/Projects/BKCore/Sources/DiContainer/DIContainer.swift (1)
  • register (25-46)
src/Projects/BKPresentation/Sources/AuthFlow/View/LoginViewController.swift (1)
src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift (1)
  • send (47-51)
src/Projects/BKNetwork/Sources/NetworkAssembly.swift (1)
src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (1)
  • refresh (86-104)
src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift (1)
src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (1)
  • logout (48-63)
src/Projects/BKPresentation/Sources/AuthFlow/View/LoginView.swift (1)
src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift (1)
  • send (47-51)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (7)
src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift (1)

23-23: 구문 간소화 개선 승인

명시적인 NetworkError.invalidURL에서 .invalidURL 단축 표현으로 변경하여 코드 가독성을 향상시켰습니다. 기능적으로는 동일하며 Swift의 타입 추론을 잘 활용한 좋은 개선입니다.

src/Projects/BKStorage/Sources/StorageAssembly.swift (1)

18-19: TokenProvider 싱글톤 도입 검증 완료
TokenProvider가 NetworkAssembly, DataAssembly, StorageAssembly의 모든 @Autowired 주입 지점에서 동일 인스턴스로 사용됨을 확인했습니다. 의도한 로그아웃 버그 수정 효과에 부합하며 추가 조치가 필요 없습니다.

src/Projects/BKDomain/Sources/DomainAssembly.swift (1)

48-55: DefaultLogoutUseCase 구현체 존재 확인 및 로그아웃 UseCase 등록 승인

DefaultLogoutUseCase 구현체가 src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift에 정상적으로 존재함을 확인했습니다.
의존성 주입 설정도 다른 UseCase들과 일관되게 적용되어 있어 변경 사항을 승인합니다.

src/Projects/BKData/Sources/DTO/Response/EmptyResponse.swift (1)

3-6: EmptyResponse 명시적 초기화자 구현 승인 (일관성 확인 완료)

EmptyResponse에 public init(from:)와 public init()를 추가한 변경사항을 승인합니다.
다음 사용처에서 HTTP 204 처리 및 Decodable 구조체 동작이 올바르게 적용됨을 확인했습니다:

  • src/Projects/BKData/Sources/Repository/DefaultAuthStateRepository.swift (type: EmptyResponse.self 사용)
  • src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (type: EmptyResponse.self 사용)
  • src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (HTTP 204 → EmptyResponse 반환)

위 일관된 구현을 기반으로 코드 변경을 승인합니다.

src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift (1)

7-9: 토큰 리프레시 프로토콜 설계가 잘 구현되었습니다.

단일 책임 원칙을 따르는 간결하고 명확한 프로토콜입니다. Combine 기반의 비동기 처리와 도메인 특화 에러 타입을 사용하여 타입 안전성을 확보했습니다.

src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift (1)

6-18: Clean Architecture 유스케이스 패턴이 잘 구현되었습니다.

의존성 주입을 통한 레포지토리 추상화와 단순한 위임 패턴으로 유스케이스 레이어의 역할을 명확히 정의했습니다. 향후 로그아웃 관련 비즈니스 로직 확장 시 이 레이어에서 처리할 수 있는 좋은 구조입니다.

src/Projects/BKData/Sources/DataAssembly.swift (1)

16-21: AuthRepository의 TokenProvider 의존성 추가가 잘 구현되었습니다.

토큰 캐시 관리를 위한 TokenProvider 의존성 추가가 적절합니다.

Comment thread src/Projects/BKData/Sources/Error/NetworkError.swift
Comment thread src/Projects/BKData/Sources/DataAssembly.swift
Comment thread src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift Outdated
Comment thread src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift
Comment thread src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift
Comment thread src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift Outdated
Comment thread src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift Outdated
Copy link
Copy Markdown

@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

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17a4fa1 and 16a4a8b.

📒 Files selected for processing (7)
  • src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift (1 hunks)
  • src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (4 hunks)
  • src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/NetworkAssembly.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (2 hunks)
  • src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Projects/BKNetwork/Sources/NetworkAssembly.swift
  • src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift
  • src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#66
File: src/Projects/BKData/Sources/DataAssembly.swift:49-60
Timestamp: 2025-07-09T02:32:03.794Z
Learning: clxxrlove prefers separating protocol registrations for RefreshHandler and AuthRepository even when using the same implementation (DefaultAuthRepository) to maintain Interface Segregation Principle, where RefreshHandler focuses on token refresh and AuthRepository handles broader authentication operations.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/Constant/PresentationKeys.swift:3-5
Timestamp: 2025-07-07T13:53:13.006Z
Learning: clxxrlove prefers using enum over struct for constants namespace due to better runtime performance, memory layout, and compiler optimizations. Enum prevents instantiation at compile time without needing private init().
src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift (2)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#66
File: src/Projects/BKData/Sources/DataAssembly.swift:49-60
Timestamp: 2025-07-09T02:32:03.794Z
Learning: clxxrlove prefers separating protocol registrations for RefreshHandler and AuthRepository even when using the same implementation (DefaultAuthRepository) to maintain Interface Segregation Principle, where RefreshHandler focuses on token refresh and AuthRepository handles broader authentication operations.
src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift (1)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift (2)
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#66
File: src/Projects/BKData/Sources/DataAssembly.swift:49-60
Timestamp: 2025-07-09T02:32:03.794Z
Learning: clxxrlove prefers separating protocol registrations for RefreshHandler and AuthRepository even when using the same implementation (DefaultAuthRepository) to maintain Interface Segregation Principle, where RefreshHandler focuses on token refresh and AuthRepository handles broader authentication operations.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift (1)

3-7: 프로토콜 개선이 잘 되었습니다!

refreshIfNeeded() 메소드를 제거하고 refreshToken 프로퍼티를 추가한 것이 좋은 설계 결정입니다. 이로써 TokenProvider의 책임이 더 명확해졌습니다.

src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift (1)

13-14: HTTP 400 에러 처리 추가 👍

클라이언트 요청 오류(400)에 대한 명시적 처리를 추가한 것이 좋습니다. 더 정확한 에러 핸들링이 가능해집니다.

src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift (1)

10-10: refreshToken 캐싱 구현이 잘 되었습니다!

accessToken과 동일한 패턴으로 refreshToken 캐싱을 구현하여 일관성이 유지되었고, clearCache()도 적절히 업데이트되었습니다.

Also applies to: 29-41, 45-45

src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift (1)

39-39: 보안 개선이 잘 적용되었습니다!

리프레시 토큰의 처음 10자만 로깅하도록 수정하여 보안이 향상되었습니다.

Comment on lines +20 to +41
func retryIfNeeded(
_ response: URLResponse,
_ data: Data
) -> AnyPublisher<Void, NetworkError> {
guard let httpResponse = response as? HTTPURLResponse else {
return Fail(error: .invalidResponse)
.eraseToAnyPublisher()
}

guard httpResponse.statusCode == 401 else {
return Fail(error: .retryTrigger)
.eraseToAnyPublisher()
}

guard let refreshToken = tokenProvider.refreshToken else {
return Fail(error: .retryFailed)
.eraseToAnyPublisher()
}

Log.debug("[Refresh] RefreshToken: \(refreshToken.prefix(10))", logger: AppLogger.auth)
return refreshHandler(refreshToken)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

관심사 분리를 위한 아키텍처 개선 제안

현재 구현은 401 감지와 토큰 리프레시를 모두 처리하고 있어 책임이 과중합니다. 더 나은 아키텍처를 위해 다음과 같이 개선하는 것을 제안합니다:

func retryIfNeeded(
    _ response: URLResponse,
    _ data: Data
) -> AnyPublisher<Void, NetworkError> {
    guard let httpResponse = response as? HTTPURLResponse else {
        return Fail(error: .invalidResponse)
            .eraseToAnyPublisher()
    }
    
    guard httpResponse.statusCode == 401 else {
-        return Fail(error: .retryTrigger)
+        return Just(())
+            .setFailureType(to: NetworkError.self)
            .eraseToAnyPublisher()
    }

-    guard let refreshToken = tokenProvider.refreshToken else {
-        return Fail(error: .retryFailed)
-            .eraseToAnyPublisher()
-    }
-
-    Log.debug("[Refresh] RefreshToken: \(refreshToken.prefix(10))", logger: AppLogger.auth)
-    return refreshHandler(refreshToken)
+    // 401이면 retryTrigger를 던져서 상위 레이어에서 처리하도록 함
+    return Fail(error: .retryTrigger)
+        .eraseToAnyPublisher()
}

그리고 OAuthNetworkProvider에서 기존 Publisher+.swiftretryIf 확장을 활용:

.retryIf({ $0 == .retryTrigger }, maxRetries: 1)

이렇게 하면:

  • ✅ 관심사 분리: 401 감지와 리프레시 로직 분리
  • ✅ 재시도 횟수 제한: 무한 재시도 방지
  • ✅ 기존 인프라 활용: retryIf 확장 사용
🤖 Prompt for AI Agents
In src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift around lines 20 to
41, the retryIfNeeded function currently handles both 401 response detection and
token refresh, causing responsibility overlap. Refactor by separating concerns:
remove the 401 status code check and token refresh logic from this function, and
instead use the existing retryIf extension in OAuthNetworkProvider with a
condition checking for .retryTrigger error and a maxRetries limit of 1. This
will delegate retry logic to the retryIf extension, enforce retry limits, and
keep the code modular.

@clxxrlove clxxrlove force-pushed the BOOK-110-feature/#59 branch from 1216b17 to 8e3bc1d Compare July 9, 2025 04:26
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (1)

64-69: 에러 처리 로직을 명확히 하세요.

.retryFailed 에러를 성공으로 변환하는 로직이 있는데, 이는 재시도 실패 시에도 원본 응답으로 파이프라인을 계속 진행하겠다는 의미로 보입니다. 이 동작이 의도된 것인지 확인하고, 필요시 주석을 추가하여 의도를 명확히 하세요.

다음과 같이 주석을 추가하여 의도를 명확히 할 수 있습니다:

.catch { error -> AnyPublisher<Void, NetworkError> in
    if case .retryFailed = error {
+       // 재시도 실패 시 원본 응답으로 계속 진행하여 
+       // 후속 validation에서 적절한 에러 처리
        return Just(()).setFailureType(to: NetworkError.self).eraseToAnyPublisher()
    }
    return Fail(error: error).eraseToAnyPublisher()
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1216b17 and 8e3bc1d.

📒 Files selected for processing (19)
  • src/Projects/BKData/Sources/DTO/Response/EmptyResponse.swift (1 hunks)
  • src/Projects/BKData/Sources/DataAssembly.swift (2 hunks)
  • src/Projects/BKData/Sources/Error/NetworkError.swift (1 hunks)
  • src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift (1 hunks)
  • src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift (1 hunks)
  • src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift (4 hunks)
  • src/Projects/BKDomain/Sources/DomainAssembly.swift (1 hunks)
  • src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift (0 hunks)
  • src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/NetworkAssembly.swift (1 hunks)
  • src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (2 hunks)
  • src/Projects/BKPresentation/Sources/AuthFlow/View/LoginView.swift (6 hunks)
  • src/Projects/BKPresentation/Sources/AuthFlow/View/LoginViewController.swift (1 hunks)
  • src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift (5 hunks)
  • src/Projects/BKStorage/Sources/StorageAssembly.swift (1 hunks)
  • src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift (2 hunks)
💤 Files with no reviewable changes (1)
  • src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift
✅ Files skipped from review due to trivial changes (1)
  • src/Projects/BKDomain/Sources/UseCase/DefaultLogoutUseCase.swift
🚧 Files skipped from review as they are similar to previous changes (16)
  • src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift
  • src/Projects/BKDomain/Sources/DomainAssembly.swift
  • src/Projects/BKData/Sources/Interface/Storage/TokenProvider.swift
  • src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift
  • src/Projects/BKData/Sources/DTO/Response/EmptyResponse.swift
  • src/Projects/BKData/Sources/Error/NetworkError.swift
  • src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift
  • src/Projects/BKData/Sources/DataAssembly.swift
  • src/Projects/BKStorage/Sources/TokenStorage/KeychainTokenProvider.swift
  • src/Projects/BKStorage/Sources/StorageAssembly.swift
  • src/Projects/BKData/Sources/Repository/DefaultAuthRepository.swift
  • src/Projects/BKPresentation/Sources/AuthFlow/View/LoginView.swift
  • src/Projects/BKNetwork/Sources/Helper/AuthRetrier.swift
  • src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift
  • src/Projects/BKNetwork/Sources/NetworkAssembly.swift
  • src/Projects/BKPresentation/Sources/AuthFlow/View/LoginViewController.swift
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#66
File: src/Projects/BKData/Sources/DataAssembly.swift:49-60
Timestamp: 2025-07-09T02:32:03.794Z
Learning: clxxrlove prefers separating protocol registrations for RefreshHandler and AuthRepository even when using the same implementation (DefaultAuthRepository) to maintain Interface Segregation Principle, where RefreshHandler focuses on token refresh and AuthRepository handles broader authentication operations.
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/Constant/PresentationKeys.swift:3-5
Timestamp: 2025-07-07T13:53:13.006Z
Learning: clxxrlove prefers using enum over struct for constants namespace due to better runtime performance, memory layout, and compiler optimizations. Enum prevents instantiation at compile time without needing private init().
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (2)

11-11: 의존성 주입 구조가 올바르게 구현되었습니다.

AuthRetrier 의존성이 적절히 추가되고 초기화되었습니다. 생성자 주입 패턴을 따르고 있어 테스트 가능성과 유지보수성이 좋습니다.

Also applies to: 16-16, 20-20


58-73: 재시도 로직 응답값 검증 필요

handleRetryIfNeeded가 재시도 성공/실패 구분 없이 항상 원본 (data, response)를 반환하고 있습니다.
그러나 AuthRetrier.retryIfNeeded의 실제 구현이 확인되지 않아, 재시도 성공 시 새로운 응답을 반환해야 하는지 여부를 검토해야 합니다.

확인해야 할 항목:

  • AuthRetrier.retryIfNeeded가 정의된 위치 및 구현 내용 확인
  • 재시도 성공 시 새로운 (Data, URLResponse)를 emit하도록 의도된 로직인지 검증

원하는 파일을 찾으려면 다음 명령어를 실행해 보세요:

rg 'struct AuthRetrier' -R .
rg 'func retryIfNeeded' -R .

Comment on lines +40 to +46
if httpResponse.statusCode == 204 {
if let empty = EmptyResponse() as? T {
return empty
} else {
throw NetworkError.invalidResponse
}
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jul 9, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

HTTP 204 응답 처리 로직을 개선하세요.

현재 구현에서 EmptyResponse()를 생성한 후 T 타입으로 캐스팅하는 방식은 런타임에 실패할 수 있습니다. 타입 안전성을 위해 컴파일 타임에 검증하는 방법을 고려해보세요.

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

-if let empty = EmptyResponse() as? T {
-    return empty
-} else {
-    throw NetworkError.invalidResponse
-}
+if T.self == EmptyResponse.self {
+    return EmptyResponse() as! T
+} else {
+    throw NetworkError.invalidResponse
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if httpResponse.statusCode == 204 {
if let empty = EmptyResponse() as? T {
return empty
} else {
throw NetworkError.invalidResponse
}
}
if httpResponse.statusCode == 204 {
if T.self == EmptyResponse.self {
return EmptyResponse() as! T
} else {
throw NetworkError.invalidResponse
}
}
🤖 Prompt for AI Agents
In src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift around
lines 40 to 46, the current handling of HTTP 204 responses creates an
EmptyResponse instance and casts it to type T at runtime, which may fail. To
improve type safety, modify the code to check at compile time if T is
EmptyResponse or a compatible type before returning, avoiding unsafe casting.
Implement a generic constraint or use conditional logic that ensures the
returned value matches T without forced casting, and throw
NetworkError.invalidResponse if the types are incompatible.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

강제 캐스팅하는 것보단 나을거 같아요...

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@clxxrlove 맞습니다! 타입을 먼저 확인하고 나서 캐스팅하는 방식이 더 안전하죠. 런타임에 실패할 수 있는 옵셔널 캐스팅보다는 컴파일 타임에 타입을 검증하는 방법이 훨씬 예측 가능하고 안전합니다.


🧠 Learnings used
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/Constant/PresentationKeys.swift:3-5
Timestamp: 2025-07-07T13:53:13.006Z
Learning: clxxrlove prefers using enum over struct for constants namespace due to better runtime performance, memory layout, and compiler optimizations. Enum prevents instantiation at compile time without needing private init().

Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift:109-111
Timestamp: 2025-07-07T13:47:32.784Z
Learning: The LoginViewModel's authenticateWithToken case in src/Projects/BKPresentation/Sources/AuthFlow/ViewModel/LoginViewModel.swift is test code and not important for implementation according to the user.

Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#66
File: src/Projects/BKData/Sources/DataAssembly.swift:49-60
Timestamp: 2025-07-09T02:32:03.794Z
Learning: clxxrlove prefers separating protocol registrations for RefreshHandler and AuthRepository even when using the same implementation (DefaultAuthRepository) to maintain Interface Segregation Principle, where RefreshHandler focuses on token refresh and AuthRepository handles broader authentication operations.

Comment thread src/Projects/BKData/Sources/Interface/Network/RefreshHandler.swift
@doyeonk429 doyeonk429 self-requested a review July 9, 2025 04:33
Copy link
Copy Markdown
Member

@doyeonk429 doyeonk429 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다 ! refresh 처리 깔끔 - ⭐

@clxxrlove clxxrlove merged commit c25dee1 into develop Jul 9, 2025
2 checks passed
@clxxrlove clxxrlove deleted the BOOK-110-feature/#59 branch July 9, 2025 04:35
@coderabbitai coderabbitai Bot mentioned this pull request Jul 21, 2025
10 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Jul 30, 2025
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BOOK-110/feat] 로그아웃/리프레시 구현

2 participants