diff --git a/Data/Sources/Repository/Kakao/KakaoFinalizeRepository.swift b/Data/Sources/Repository/Kakao/KakaoFinalizeRepository.swift deleted file mode 100644 index b02be179..00000000 --- a/Data/Sources/Repository/Kakao/KakaoFinalizeRepository.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// KakaoFinalizeRepository.swift -// Data -// -// Created by Assistant on 12/5/25. -// - -import Foundation -import Domain -import Moya -import NetworkService - -public final class KakaoFinalizeRepository: KakaoFinalizeRepositoryProtocol { - private let provider: MoyaProvider - - public init(provider: MoyaProvider = .default) { - self.provider = provider - } - - public func finalize(ticket: String) async throws -> AuthResult { - let body = KakaoFinalizeRequestDTO(ticket: ticket) - let response: BaseResponse = try await provider.request(.kakaoFinalize(body: body)) - guard let data = response.data else { - throw NetworkError.noData - } - return data.toDomain() - } - -} diff --git a/Domain/Sources/Repository/Analytics/AnalyticsRepositoryProtocol.swift b/Domain/Sources/Repository/Analytics/AnalyticsRepositoryProtocol.swift index 880db1b4..652564ff 100644 --- a/Domain/Sources/Repository/Analytics/AnalyticsRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Analytics/AnalyticsRepositoryProtocol.swift @@ -1,6 +1,22 @@ import Foundation - +import Dependencies /// Analytics 이벤트 전송을 위한 Repository 프로토콜 public protocol AnalyticsRepositoryProtocol: Sendable { func sendEvent(_ event: AnalyticsEvent) async } + +// MARK: - Dependencies +public struct AnalyticsRepositoryDependency: DependencyKey { + public static var liveValue: AnalyticsRepositoryProtocol { + fatalError("AnalyticsRepositoryDependency liveValue not implemented") + } + public static var previewValue: AnalyticsRepositoryProtocol = MockAnalyticsRepository() + public static var testValue: AnalyticsRepositoryProtocol = MockAnalyticsRepository() +} + +public extension DependencyValues { + var analyticsRepository: AnalyticsRepositoryProtocol { + get { self[AnalyticsRepositoryDependency.self] } + set { self[AnalyticsRepositoryDependency.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/Auth/AuthRepositoryProtocol.swift b/Domain/Sources/Repository/Auth/AuthRepositoryProtocol.swift index 6f5ed4b3..b1ed4e68 100644 --- a/Domain/Sources/Repository/Auth/AuthRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Auth/AuthRepositoryProtocol.swift @@ -6,17 +6,34 @@ // import Foundation +import Dependencies public protocol AuthRepositoryProtocol { - // 세션/토큰 - func refresh(token: String) async throws -> TokenResult - func logout(sessionId: String) async throws -> LogoutStatus - func delete() async throws -> AuthDeleteStatus - func registerDeviceToken(token: String) async throws -> DeviceToken + // 세션/토큰 + func refresh(token: String) async throws -> TokenResult + func logout(sessionId: String) async throws -> LogoutStatus + func delete() async throws -> AuthDeleteStatus + func registerDeviceToken(token: String) async throws -> DeviceToken + + // 인증/가입 + func checkUser(input: OAuthUserInput) async throws -> OAuthCheckUser + func login(input: OAuthUserInput) async throws -> AuthResult + func signUp(input: OAuthUserInput) async throws -> AuthResult + func finalizeKakao(ticket: String) async throws -> AuthResult +} + +// MARK: - Dependencies +public struct AuthRepositoryDependency: DependencyKey { + public static var liveValue: AuthRepositoryProtocol { + fatalError("AuthRepositoryDependency liveValue not implemented") + } + public static var previewValue: AuthRepositoryProtocol = MockAuthRepository() + public static var testValue: AuthRepositoryProtocol = MockAuthRepository() +} - // 인증/가입 - func checkUser(input: OAuthUserInput) async throws -> OAuthCheckUser - func login(input: OAuthUserInput) async throws -> AuthResult - func signUp(input: OAuthUserInput) async throws -> AuthResult - func finalizeKakao(ticket: String) async throws -> AuthResult +public extension DependencyValues { + var authRepository: AuthRepositoryProtocol { + get { self[AuthRepositoryDependency.self] } + set { self[AuthRepositoryDependency.self] = newValue } + } } diff --git a/Domain/Sources/Repository/Country/CountryRepositoryProtocol.swift b/Domain/Sources/Repository/Country/CountryRepositoryProtocol.swift index 38261433..0b3aa91a 100644 --- a/Domain/Sources/Repository/Country/CountryRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Country/CountryRepositoryProtocol.swift @@ -6,7 +6,24 @@ // import Foundation +import Dependencies public protocol CountryRepositoryProtocol { func fetchCountries() async throws -> [Country] } + +// MARK: - Dependencies +public struct CountryRepositoryDependencyKey: DependencyKey { + public static var liveValue: CountryRepositoryProtocol { + fatalError("CountryRepositoryDependency liveValue not implemented") + } + public static var previewValue: CountryRepositoryProtocol = MockCountriesRepository() + public static var testValue: CountryRepositoryProtocol = MockCountriesRepository() +} + +public extension DependencyValues { + var countryRepository: CountryRepositoryProtocol { + get { self[CountryRepositoryDependencyKey.self] } + set { self[CountryRepositoryDependencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/Country/ExchangeRateRepositoryProtocol.swift b/Domain/Sources/Repository/Country/ExchangeRateRepositoryProtocol.swift index c62d7ae4..b63531f1 100644 --- a/Domain/Sources/Repository/Country/ExchangeRateRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Country/ExchangeRateRepositoryProtocol.swift @@ -6,7 +6,23 @@ // import Foundation +import Dependencies public protocol ExchangeRateRepositoryProtocol { func fetchExchangeRate(base: String) async throws -> ExchangeRate } + +public struct ExchangeRateRepositoryDependencyKey: DependencyKey { + public static var liveValue: ExchangeRateRepositoryProtocol { + fatalError("ExchangeRateRepositoryDependencyKey liveValue not implemented") + } + public static var previewValue: ExchangeRateRepositoryProtocol = MockExchangeRateRepository() + public static var testValue: ExchangeRateRepositoryProtocol = MockExchangeRateRepository() +} + +public extension DependencyValues { + var exchangeRateRepository: ExchangeRateRepositoryProtocol { + get { self[ExchangeRateRepositoryDependencyKey.self] } + set { self[ExchangeRateRepositoryDependencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/ExpenseRepositoryProtocol.swift b/Domain/Sources/Repository/Expense/ExpenseRepositoryProtocol.swift similarity index 100% rename from Domain/Sources/Repository/ExpenseRepositoryProtocol.swift rename to Domain/Sources/Repository/Expense/ExpenseRepositoryProtocol.swift diff --git a/Domain/Sources/Repository/Mock/MockExpenseRepository.swift b/Domain/Sources/Repository/Expense/Mock/MockExpenseRepository.swift similarity index 100% rename from Domain/Sources/Repository/Mock/MockExpenseRepository.swift rename to Domain/Sources/Repository/Expense/Mock/MockExpenseRepository.swift diff --git a/Domain/Sources/Repository/Login/LoginRepositoryProtocol.swift b/Domain/Sources/Repository/Login/LoginRepositoryProtocol.swift index 7e3b13cf..12367e7c 100644 --- a/Domain/Sources/Repository/Login/LoginRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Login/LoginRepositoryProtocol.swift @@ -4,7 +4,25 @@ // // Created by Wonji Suh on 11/26/25. // +import Foundation +import Dependencies public protocol LoginRepositoryProtocol { - func login(input: OAuthUserInput) async throws -> AuthResult + func login(input: OAuthUserInput) async throws -> AuthResult +} + +// MARK: - Dependencies +public struct LoginRepositoryDependency: DependencyKey { + public static var liveValue: LoginRepositoryProtocol { + fatalError("LoginRepositoryDependency liveValue not implemented") + } + public static var previewValue: LoginRepositoryProtocol = MockLoginRepository() + public static var testValue: LoginRepositoryProtocol = MockLoginRepository() +} + +public extension DependencyValues { + var loginRepository: LoginRepositoryProtocol { + get { self[LoginRepositoryDependency.self] } + set { self[LoginRepositoryDependency.self] = newValue } + } } diff --git a/Domain/Sources/Repository/OAuth/Apple/AppleOAuthRepositoryProtocol.swift b/Domain/Sources/Repository/OAuth/Apple/AppleOAuthRepositoryProtocol.swift index 19f12861..dbacc147 100644 --- a/Domain/Sources/Repository/OAuth/Apple/AppleOAuthRepositoryProtocol.swift +++ b/Domain/Sources/Repository/OAuth/Apple/AppleOAuthRepositoryProtocol.swift @@ -9,19 +9,21 @@ import Foundation import Dependencies public protocol AppleOAuthRepositoryProtocol { - func signIn() async throws -> AppleOAuthPayload + func signIn() async throws -> AppleOAuthPayload } // MARK: - Dependencies -public struct AppleOAuthServiceDependency: DependencyKey { - public static var liveValue: AppleOAuthRepositoryProtocol = MockAppleOAuthRepository() - public static var previewValue: AppleOAuthRepositoryProtocol = MockAppleOAuthRepository() - public static var testValue: AppleOAuthRepositoryProtocol = MockAppleOAuthRepository() +public struct AppleOAuthRepositoryDependencyKey: DependencyKey { + public static var liveValue: AppleOAuthRepositoryProtocol { + fatalError("AppleOAuthServiceDependency liveValue not implemented") + } + public static var previewValue: AppleOAuthRepositoryProtocol = MockAppleOAuthRepository() + public static var testValue: AppleOAuthRepositoryProtocol = MockAppleOAuthRepository() } public extension DependencyValues { - var appleOAuthService: AppleOAuthRepositoryProtocol { - get { self[AppleOAuthServiceDependency.self] } - set { self[AppleOAuthServiceDependency.self] = newValue } - } + var appleOAuthRepository: AppleOAuthRepositoryProtocol { + get { self[AppleOAuthRepositoryDependencyKey.self] } + set { self[AppleOAuthRepositoryDependencyKey.self] = newValue } + } } diff --git a/Domain/Sources/Repository/OAuth/Google/GoogleOAuthRepositoryProtocol.swift b/Domain/Sources/Repository/OAuth/Google/GoogleOAuthRepositoryProtocol.swift index 8c9457a0..e885772e 100644 --- a/Domain/Sources/Repository/OAuth/Google/GoogleOAuthRepositoryProtocol.swift +++ b/Domain/Sources/Repository/OAuth/Google/GoogleOAuthRepositoryProtocol.swift @@ -1,5 +1,5 @@ // -// GoogleOAuthServicing.swift +// GoogleOAuthRepositoryProtocol.swift // Domain // // Created by Wonji Suh on 11/17/25. @@ -9,6 +9,21 @@ import Foundation import Dependencies public protocol GoogleOAuthRepositoryProtocol { - func signIn() async throws -> GoogleOAuthPayload + func signIn() async throws -> GoogleOAuthPayload } +// MARK: - Dependencies +public struct GoogleOAuthRepositoryDependencyKey: DependencyKey { + public static var liveValue: GoogleOAuthRepositoryProtocol { + fatalError("GoogleOAuthServiceDependency liveValue not implemented") + } + public static var previewValue: GoogleOAuthRepositoryProtocol = MockGoogleOAuthRepository() + public static var testValue: GoogleOAuthRepositoryProtocol = MockGoogleOAuthRepository() +} + +public extension DependencyValues { + var googleOAuthRepository: GoogleOAuthRepositoryProtocol { + get { self[GoogleOAuthRepositoryDependencyKey.self] } + set { self[GoogleOAuthRepositoryDependencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/OAuth/Kakao/KakaoFinalizeRepositoryProtocol.swift b/Domain/Sources/Repository/OAuth/Kakao/KakaoFinalizeRepositoryProtocol.swift deleted file mode 100644 index da0d7d22..00000000 --- a/Domain/Sources/Repository/OAuth/Kakao/KakaoFinalizeRepositoryProtocol.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// KakaoFinalizeRepositoryProtocol.swift -// Domain -// -// Created by Assistant on 12/5/25. -// - -import Foundation - -public protocol KakaoFinalizeRepositoryProtocol { - func finalize(ticket: String) async throws -> AuthResult -} diff --git a/Domain/Sources/Repository/OAuth/Kakao/KakaoOAuthRepositoryProtocol.swift b/Domain/Sources/Repository/OAuth/Kakao/KakaoOAuthRepositoryProtocol.swift index af9ca25b..defb3794 100644 --- a/Domain/Sources/Repository/OAuth/Kakao/KakaoOAuthRepositoryProtocol.swift +++ b/Domain/Sources/Repository/OAuth/Kakao/KakaoOAuthRepositoryProtocol.swift @@ -9,5 +9,21 @@ import Foundation import Dependencies public protocol KakaoOAuthRepositoryProtocol { - func signIn() async throws -> KakaoOAuthPayload + func signIn() async throws -> KakaoOAuthPayload } + +// MARK: - Dependencies +public struct KakaoOAuthRepositoryDependencyKey: DependencyKey { + public static var liveValue: KakaoOAuthRepositoryProtocol { + fatalError("KakaoOAuthRepositoryDependency liveValue not implemented") + } + public static var previewValue: KakaoOAuthRepositoryProtocol = MockKakaoOAuthRepository() + public static var testValue: KakaoOAuthRepositoryProtocol = MockKakaoOAuthRepository() +} + +public extension DependencyValues { + var kakaoOAuthRepository: KakaoOAuthRepositoryProtocol { + get { self[KakaoOAuthRepositoryDependencyKey.self] } + set { self[KakaoOAuthRepositoryDependencyKey.self] = newValue } + } +} \ No newline at end of file diff --git a/Domain/Sources/Repository/OAuth/Kakao/MockKakaoFinalizeRepository.swift b/Domain/Sources/Repository/OAuth/Kakao/MockKakaoFinalizeRepository.swift deleted file mode 100644 index 2949e691..00000000 --- a/Domain/Sources/Repository/OAuth/Kakao/MockKakaoFinalizeRepository.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// MockKakaoFinalizeRepository.swift -// Domain -// -// Created by Assistant on 12/5/25. -// - -import Foundation - -public final class MockKakaoFinalizeRepository: KakaoFinalizeRepositoryProtocol { - public init() {} - - public func finalize(ticket: String) async throws -> AuthResult { - let tokens = AuthTokens( - authToken: "mock-kakao-auth-\(ticket.prefix(6))", - accessToken: "mock-kakao-access-\(ticket.prefix(6))", - refreshToken: "mock-kakao-refresh", - sessionID: "mock-kakao-session" - ) - return AuthResult( - userId: "mock-kakao-user", - name: "Mock Kakao", - provider: .kakao, - token: tokens - ) - } -} diff --git a/Domain/Sources/Repository/OAuth/OAuth/OAuthRepositoryProtocol.swift b/Domain/Sources/Repository/OAuth/OAuth/OAuthRepositoryProtocol.swift index 6fb41e8a..91ada265 100644 --- a/Domain/Sources/Repository/OAuth/OAuth/OAuthRepositoryProtocol.swift +++ b/Domain/Sources/Repository/OAuth/OAuth/OAuthRepositoryProtocol.swift @@ -6,15 +6,32 @@ // import Foundation -import ComposableArchitecture +import Dependencies public protocol OAuthRepositoryProtocol { - func signIn( - provider: SocialType, - idToken: String, - nonce: String?, - displayName: String?, - authorizationCode: String? - ) async throws -> UserProfile - func updateUserDisplayName(_ name: String) async throws + func signIn( + provider: SocialType, + idToken: String, + nonce: String?, + displayName: String?, + authorizationCode: String? + ) async throws -> UserProfile + + func updateUserDisplayName(_ name: String) async throws +} + +// MARK: - Dependencies +public struct OAuthRepositoryDependency: DependencyKey { + public static var liveValue: OAuthRepositoryProtocol { + fatalError("OAuthRepositoryDependency liveValue not implemented") + } + public static var previewValue: OAuthRepositoryProtocol = MockOAuthRepository() + public static var testValue: OAuthRepositoryProtocol = MockOAuthRepository() +} + +public extension DependencyValues { + var oAuthRepository: OAuthRepositoryProtocol { + get { self[OAuthRepositoryDependency.self] } + set { self[OAuthRepositoryDependency.self] = newValue } + } } diff --git a/Domain/Sources/Repository/Profile/ProfileRepositoryProtocol.swift b/Domain/Sources/Repository/Profile/ProfileRepositoryProtocol.swift index e50d9c3c..6c423b5f 100644 --- a/Domain/Sources/Repository/Profile/ProfileRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Profile/ProfileRepositoryProtocol.swift @@ -6,8 +6,25 @@ // import Foundation +import Dependencies public protocol ProfileRepositoryProtocol { - func getProfile() async throws -> Profile - func editProfile(name: String?, avatarData: Data?, fileName: String?) async throws -> Profile + func getProfile() async throws -> Profile + func editProfile(name: String?, avatarData: Data?, fileName: String?) async throws -> Profile +} + +// MARK: - Dependencies +private struct ProfileRepositoryDependencyKey: DependencyKey { + public static var liveValue: ProfileRepositoryProtocol { + fatalError("ProfileRepositoryDependency liveValue not implemented") + } + public static var previewValue: ProfileRepositoryProtocol = MockProfileRepository() + public static var testValue: ProfileRepositoryProtocol = MockProfileRepository() +} + +public extension DependencyValues { + var profileRepository: ProfileRepositoryProtocol { + get { self[ProfileRepositoryDependencyKey.self] } + set { self[ProfileRepositoryDependencyKey.self] = newValue } + } } diff --git a/Domain/Sources/Repository/Session/SessionRepositoryProtocol.swift b/Domain/Sources/Repository/Session/SessionRepositoryProtocol.swift index 80dd480e..e2560b9f 100644 --- a/Domain/Sources/Repository/Session/SessionRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Session/SessionRepositoryProtocol.swift @@ -6,22 +6,25 @@ // import Foundation -import Dependencies +import Dependencies public protocol SessionRepositoryProtocol { - /// Validate a stored session id and return its status from backend. - func checkSession(sessionId: String) async throws -> SessionStatus + /// Validate a stored session id and return its status from backend. + func checkSession(sessionId: String) async throws -> SessionStatus } -public struct SessionRepositoryDependency: DependencyKey { - public static var liveValue: SessionRepositoryProtocol = MockSessionRepository() - public static var previewValue: SessionRepositoryProtocol = MockSessionRepository() - public static var testValue: SessionRepositoryProtocol = MockSessionRepository() +// MARK: - Dependencies +public struct SessionRepositoryDependencyKey: DependencyKey { + public static var liveValue: SessionRepositoryProtocol { + fatalError("SessionRepositoryDependency liveValue not implemented") + } + public static let previewValue: SessionRepositoryProtocol = MockSessionRepository() + public static let testValue: SessionRepositoryProtocol = MockSessionRepository() } public extension DependencyValues { - var sessionRepository: SessionRepositoryProtocol { - get { self[SessionRepositoryDependency.self] } - set { self[SessionRepositoryDependency.self] = newValue } - } + var sessionRepository: SessionRepositoryProtocol { + get { self[SessionRepositoryDependencyKey.self] } + set { self[SessionRepositoryDependencyKey.self] = newValue } + } } diff --git a/Domain/Sources/Repository/Mock/MockSettlementRepository.swift b/Domain/Sources/Repository/Settlement/Mock/MockSettlementRepository.swift similarity index 100% rename from Domain/Sources/Repository/Mock/MockSettlementRepository.swift rename to Domain/Sources/Repository/Settlement/Mock/MockSettlementRepository.swift diff --git a/Domain/Sources/Repository/Settlement/SettlementRepositoryProtocol.swift b/Domain/Sources/Repository/Settlement/SettlementRepositoryProtocol.swift new file mode 100644 index 00000000..53d14343 --- /dev/null +++ b/Domain/Sources/Repository/Settlement/SettlementRepositoryProtocol.swift @@ -0,0 +1,29 @@ +// +// SettlementRepositoryProtocol.swift +// Domain +// +// Created by 홍석현 on 12/4/25. +// + +import Foundation +import Dependencies + +public protocol SettlementRepositoryProtocol { + func fetchSettlement(travelId: String) async throws -> TravelSettlement +} + +// MARK: - Dependency +private enum SettlementRepositoryDepensencyKey: DependencyKey { + static let liveValue: SettlementRepositoryProtocol = { + fatalError("SettlementRepository liveValue not implemented") + }() + + static let testValue: SettlementRepositoryProtocol = MockSettlementRepository() +} + +extension DependencyValues { + public var settlementRepository: SettlementRepositoryProtocol { + get { self[SettlementRepositoryDepensencyKey.self] } + set { self[SettlementRepositoryDepensencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/SettlementRepositoryProtocol.swift b/Domain/Sources/Repository/SettlementRepositoryProtocol.swift deleted file mode 100644 index b769112d..00000000 --- a/Domain/Sources/Repository/SettlementRepositoryProtocol.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// SettlementRepositoryProtocol.swift -// Domain -// -// Created by 홍석현 on 12/4/25. -// - -import Foundation - -public protocol SettlementRepositoryProtocol { - func fetchSettlement(travelId: String) async throws -> TravelSettlement -} diff --git a/Domain/Sources/Repository/SignUp/SignUpRepositoryProtocol.swift b/Domain/Sources/Repository/SignUp/SignUpRepositoryProtocol.swift index 09310790..fcaad8ca 100644 --- a/Domain/Sources/Repository/SignUp/SignUpRepositoryProtocol.swift +++ b/Domain/Sources/Repository/SignUp/SignUpRepositoryProtocol.swift @@ -6,6 +6,7 @@ // import Foundation +import Dependencies public protocol SignUpRepositoryProtocol { func checkSignUp(input: OAuthUserInput) async throws -> OAuthCheckUser @@ -13,3 +14,18 @@ public protocol SignUpRepositoryProtocol { } +// MARK: - Dependencies +public struct SignUpRepositoryDependency: DependencyKey { + public static var liveValue: SignUpRepositoryProtocol { + fatalError("SignUpRepositoryDependency liveValue not implemented") + } + public static var previewValue: SignUpRepositoryProtocol = MockSignUpRepository() + public static var testValue: SignUpRepositoryProtocol = MockSignUpRepository() +} + +public extension DependencyValues { + var signUpRepository: SignUpRepositoryProtocol { + get { self[SignUpRepositoryDependency.self] } + set { self[SignUpRepositoryDependency.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/Travel/TravelMemberRepositoryProtocol.swift b/Domain/Sources/Repository/Travel/TravelMemberRepositoryProtocol.swift index 6b12e151..09959345 100644 --- a/Domain/Sources/Repository/Travel/TravelMemberRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Travel/TravelMemberRepositoryProtocol.swift @@ -6,6 +6,7 @@ // import Foundation +import Dependencies public protocol TravelMemberRepositoryProtocol { func deleteMember(travelId: String, memberId: String) async throws @@ -14,3 +15,19 @@ public protocol TravelMemberRepositoryProtocol { func leaveTravel(travelId: String) async throws func fetchMember(travelId: String) async throws -> MyTravelMember } + +// MARK: - Dependency +private enum TravelMemberRepositoryDepensencyKey: DependencyKey { + static let liveValue: TravelMemberRepositoryProtocol = { + fatalError("TravelMemberRepository liveValue not implemented") + }() + + static let testValue: TravelMemberRepositoryProtocol = MockTravelMemberRepository() +} + +extension DependencyValues { + public var travelMemberRepository: TravelMemberRepositoryProtocol { + get { self[TravelMemberRepositoryDepensencyKey.self] } + set { self[TravelMemberRepositoryDepensencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/Travel/TravelRepositoryProtocol.swift b/Domain/Sources/Repository/Travel/TravelRepositoryProtocol.swift index 8a9be017..ea4e8817 100644 --- a/Domain/Sources/Repository/Travel/TravelRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Travel/TravelRepositoryProtocol.swift @@ -6,6 +6,7 @@ // import Foundation +import Dependencies public protocol TravelRepositoryProtocol { func fetchTravels(input: FetchTravelsInput) async throws -> [Travel] @@ -16,3 +17,19 @@ public protocol TravelRepositoryProtocol { func loadCachedTravels(status: TravelStatus) async throws -> [Travel]? func loadCachedTravel(id: String) async throws -> Travel? } + +// MARK: - Dependency +private enum TravelRepositoryDepensencyKey: DependencyKey { + static let liveValue: TravelRepositoryProtocol = { + fatalError("TravelRepository liveValue not implemented") + }() + + static let testValue: TravelRepositoryProtocol = MockTravelRepository() +} + +extension DependencyValues { + public var travelRepository: TravelRepositoryProtocol { + get { self[TravelRepositoryDepensencyKey.self] } + set { self[TravelRepositoryDepensencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/Repository/Version/VersionRepositoryProtocol.swift b/Domain/Sources/Repository/Version/VersionRepositoryProtocol.swift index e0cc2054..53f2d334 100644 --- a/Domain/Sources/Repository/Version/VersionRepositoryProtocol.swift +++ b/Domain/Sources/Repository/Version/VersionRepositoryProtocol.swift @@ -6,7 +6,24 @@ // import Foundation +import Dependencies public protocol VersionRepositoryProtocol { func getVersion(bundleId: String, version: String) async throws -> Version } + +// MARK: - Dependencies +private struct VersionRepositoryDependencyKey: DependencyKey { + public static var liveValue: VersionRepositoryProtocol { + fatalError("VersionRepositoryDependency liveValue not implemented") + } + public static let previewValue: VersionRepositoryProtocol = MockVersionRepository() + public static let testValue: VersionRepositoryProtocol = MockVersionRepository() +} + +public extension DependencyValues { + var versionRepository: VersionRepositoryProtocol { + get { self[VersionRepositoryDependencyKey.self] } + set { self[VersionRepositoryDependencyKey.self] = newValue } + } +} diff --git a/Domain/Sources/UseCase/Analytics/AnalyticsUseCase.swift b/Domain/Sources/UseCase/Analytics/AnalyticsUseCase.swift index abf9bee6..23d71619 100644 --- a/Domain/Sources/UseCase/Analytics/AnalyticsUseCase.swift +++ b/Domain/Sources/UseCase/Analytics/AnalyticsUseCase.swift @@ -1,13 +1,12 @@ import Foundation import ComposableArchitecture +import Dependencies /// Analytics UseCase 구현체 public struct AnalyticsUseCase: AnalyticsUseCaseProtocol, Sendable { - private let repository: any AnalyticsRepositoryProtocol + @Dependency(\.analyticsRepository) private var repository: any AnalyticsRepositoryProtocol - public init(repository: any AnalyticsRepositoryProtocol) { - self.repository = repository - } + public init() {} public func track(_ event: AnalyticsEvent) { Task { @@ -19,8 +18,8 @@ public struct AnalyticsUseCase: AnalyticsUseCaseProtocol, Sendable { // MARK: - Dependency Key extension AnalyticsUseCase: DependencyKey { - public static let liveValue: any AnalyticsUseCaseProtocol = AnalyticsUseCase(repository: MockAnalyticsRepository()) - public static let testValue: any AnalyticsUseCaseProtocol = AnalyticsUseCase(repository: MockAnalyticsRepository()) + public static let liveValue: any AnalyticsUseCaseProtocol = AnalyticsUseCase() + public static let testValue: any AnalyticsUseCaseProtocol = AnalyticsUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Auth/AuthUseCase.swift b/Domain/Sources/UseCase/Auth/AuthUseCase.swift index 8929ff95..410cb236 100644 --- a/Domain/Sources/UseCase/Auth/AuthUseCase.swift +++ b/Domain/Sources/UseCase/Auth/AuthUseCase.swift @@ -7,41 +7,32 @@ import ComposableArchitecture +import Dependencies public struct AuthUseCase: AuthUseCaseProtocol { - @Shared(.appStorage("sessionId")) var sessionId: String? = "" - - private let repository: AuthRepositoryProtocol - public init( - repository: AuthRepositoryProtocol - ) { - self.repository = repository + @Shared(.appStorage("sessionId")) var sessionId: String? = "" + + @Dependency(\.authRepository) private var repository: AuthRepositoryProtocol + public init() {} + + // MARK: - 로그아웃 + public func logout() async throws -> LogoutStatus { + let sessionId = self.sessionId ?? "" + return try await repository.logout(sessionId: sessionId) + } + + public func deleteUser() async throws -> AuthDeleteStatus { + let result = try await repository.delete() + KeychainManager.shared.clearAll() + return result } - - // MARK: - 로그아웃 - public func logout() async throws -> LogoutStatus { - let sessionId = self.sessionId ?? "" - return try await repository.logout(sessionId: sessionId) - } - - public func deleteUser() async throws -> AuthDeleteStatus { - let result = try await repository.delete() - KeychainManager.shared.clearAll() - return result - } } extension AuthUseCase: DependencyKey { - public static var liveValue: AuthUseCaseProtocol { - return AuthUseCase(repository: MockAuthRepository()) - } - - public static var previewValue: any AuthUseCaseProtocol { liveValue } - - public static let testValue: AuthUseCaseProtocol = AuthUseCase( - repository: MockAuthRepository() - ) + public static let liveValue: AuthUseCaseProtocol = AuthUseCase() + public static let previewValue: any AuthUseCaseProtocol = AuthUseCase() + public static let testValue: AuthUseCaseProtocol = AuthUseCase() } diff --git a/Domain/Sources/UseCase/Country/FetchCountriesUseCaseProtocol.swift b/Domain/Sources/UseCase/Country/FetchCountriesUseCaseProtocol.swift index 00b9076c..8b8e4f43 100644 --- a/Domain/Sources/UseCase/Country/FetchCountriesUseCaseProtocol.swift +++ b/Domain/Sources/UseCase/Country/FetchCountriesUseCaseProtocol.swift @@ -13,28 +13,18 @@ public protocol FetchCountriesUseCaseProtocol { } public final class FetchCountriesUseCase: FetchCountriesUseCaseProtocol { - private let repository: CountryRepositoryProtocol + @Dependency(\.countryRepository) private var repository: CountryRepositoryProtocol - public init(repository: CountryRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute() async throws -> [Country] { try await repository.fetchCountries() } } extension FetchCountriesUseCase: DependencyKey { - public static var liveValue: FetchCountriesUseCaseProtocol = { - FetchCountriesUseCase(repository: MockCountriesRepository()) - }() - - public static var previewValue: FetchCountriesUseCaseProtocol = { - FetchCountriesUseCase(repository: MockCountriesRepository()) - }() - - public static var testValue: FetchCountriesUseCaseProtocol = { - FetchCountriesUseCase(repository: MockCountriesRepository()) - }() + public static var liveValue: FetchCountriesUseCaseProtocol = FetchCountriesUseCase() + public static var previewValue: FetchCountriesUseCaseProtocol = FetchCountriesUseCase() + public static var testValue: FetchCountriesUseCaseProtocol = FetchCountriesUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Country/FetchExchangeRateUseCaseProtocol.swift b/Domain/Sources/UseCase/Country/FetchExchangeRateUseCaseProtocol.swift index fefd442c..97e73a7e 100644 --- a/Domain/Sources/UseCase/Country/FetchExchangeRateUseCaseProtocol.swift +++ b/Domain/Sources/UseCase/Country/FetchExchangeRateUseCaseProtocol.swift @@ -13,28 +13,18 @@ public protocol FetchExchangeRateUseCaseProtocol { } public final class FetchExchangeRateUseCase: FetchExchangeRateUseCaseProtocol { - private let repository: ExchangeRateRepositoryProtocol + @Dependency(\.exchangeRateRepository) private var repository: ExchangeRateRepositoryProtocol - public init(repository: ExchangeRateRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(base: String) async throws -> ExchangeRate { try await repository.fetchExchangeRate(base: base) } } extension FetchExchangeRateUseCase: DependencyKey { - public static var liveValue: FetchExchangeRateUseCaseProtocol = { - FetchExchangeRateUseCase(repository: MockExchangeRateRepository()) - }() - - public static var previewValue: FetchExchangeRateUseCaseProtocol = { - FetchExchangeRateUseCase(repository: MockExchangeRateRepository()) - }() - - public static var testValue: FetchExchangeRateUseCaseProtocol = { - FetchExchangeRateUseCase(repository: MockExchangeRateRepository()) - }() + public static var liveValue: FetchExchangeRateUseCaseProtocol = FetchExchangeRateUseCase() + public static var previewValue: FetchExchangeRateUseCaseProtocol = FetchExchangeRateUseCase() + public static var testValue: FetchExchangeRateUseCaseProtocol = FetchExchangeRateUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Expense/CreateExpenseUseCase.swift b/Domain/Sources/UseCase/Expense/CreateExpenseUseCase.swift index b5a3fffd..b2d8a6e6 100644 --- a/Domain/Sources/UseCase/Expense/CreateExpenseUseCase.swift +++ b/Domain/Sources/UseCase/Expense/CreateExpenseUseCase.swift @@ -8,33 +8,28 @@ import Foundation import Dependencies -public struct CreateExpenseUseCase { - private let repository: ExpenseRepositoryProtocol - - public init(repository: ExpenseRepositoryProtocol) { - self.repository = repository - } +public protocol CreateExpenseUseCaseProtocol { + func execute(travelId: String, input: ExpenseInput) async throws +} +public struct CreateExpenseUseCase: CreateExpenseUseCaseProtocol { + @Dependency(\.expenseRepository) private var repository: ExpenseRepositoryProtocol + public func execute(travelId: String, input: ExpenseInput) async throws { try input.validate() try await repository.save(travelId: travelId, input: input) } } -extension CreateExpenseUseCase: DependencyKey { - public static var liveValue: CreateExpenseUseCase { - @Dependency(\.expenseRepository) var repository - return CreateExpenseUseCase(repository: repository) - } +public enum CreateExpenseUseCaseDependencyKey: DependencyKey { + public static var liveValue: CreateExpenseUseCaseProtocol = CreateExpenseUseCase() - public static var testValue: CreateExpenseUseCase { - CreateExpenseUseCase(repository: MockExpenseRepository()) - } + public static var testValue: CreateExpenseUseCaseProtocol = CreateExpenseUseCase() } extension DependencyValues { - public var createExpenseUseCase: CreateExpenseUseCase { - get { self[CreateExpenseUseCase.self] } - set { self[CreateExpenseUseCase.self] = newValue } + public var createExpenseUseCase: CreateExpenseUseCaseProtocol { + get { self[CreateExpenseUseCaseDependencyKey.self] } + set { self[CreateExpenseUseCaseDependencyKey.self] = newValue } } } diff --git a/Domain/Sources/UseCase/Expense/DeleteExpenseUseCase.swift b/Domain/Sources/UseCase/Expense/DeleteExpenseUseCase.swift index ed343e1c..5d505262 100644 --- a/Domain/Sources/UseCase/Expense/DeleteExpenseUseCase.swift +++ b/Domain/Sources/UseCase/Expense/DeleteExpenseUseCase.swift @@ -13,11 +13,7 @@ public protocol DeleteExpenseUseCaseProtocol { } public struct DeleteExpenseUseCase: DeleteExpenseUseCaseProtocol { - private let repository: ExpenseRepositoryProtocol - - public init(repository: ExpenseRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.expenseRepository) private var repository: ExpenseRepositoryProtocol public func execute(travelId: String, expenseId: String) async throws { try await repository.delete(travelId: travelId, expenseId: expenseId) @@ -26,7 +22,7 @@ public struct DeleteExpenseUseCase: DeleteExpenseUseCaseProtocol { // MARK: - DependencyKey public enum DeleteExpenseUseCaseDependencyKey: DependencyKey { - public static var liveValue: any DeleteExpenseUseCaseProtocol = MockDeleteExpenseUseCase() + public static var liveValue: any DeleteExpenseUseCaseProtocol = DeleteExpenseUseCase() public static var testValue: any DeleteExpenseUseCaseProtocol = MockDeleteExpenseUseCase() diff --git a/Domain/Sources/UseCase/Expense/FetchTravelExpenseUseCase.swift b/Domain/Sources/UseCase/Expense/FetchTravelExpenseUseCase.swift index 47c9aa56..8b476e45 100644 --- a/Domain/Sources/UseCase/Expense/FetchTravelExpenseUseCase.swift +++ b/Domain/Sources/UseCase/Expense/FetchTravelExpenseUseCase.swift @@ -13,11 +13,7 @@ public protocol FetchTravelExpenseUseCaseProtocol { } public struct FetchTravelExpenseUseCase: FetchTravelExpenseUseCaseProtocol { - private let repository: ExpenseRepositoryProtocol - - public init(repository: ExpenseRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.expenseRepository) private var repository: ExpenseRepositoryProtocol public func execute( travelId: String, @@ -54,7 +50,7 @@ public struct FetchTravelExpenseUseCase: FetchTravelExpenseUseCaseProtocol { // MARK: - DependencyKey public enum FetchTravelExpenseUseCaseDependencyKey: DependencyKey { - public static var liveValue: any FetchTravelExpenseUseCaseProtocol = MockFetchTravelExpenseUseCase() + public static var liveValue: any FetchTravelExpenseUseCaseProtocol = FetchTravelExpenseUseCase() public static var testValue: any FetchTravelExpenseUseCaseProtocol = MockFetchTravelExpenseUseCase() diff --git a/Domain/Sources/UseCase/Expense/UpdateExpenseUseCase.swift b/Domain/Sources/UseCase/Expense/UpdateExpenseUseCase.swift index cb49e9e4..2d243220 100644 --- a/Domain/Sources/UseCase/Expense/UpdateExpenseUseCase.swift +++ b/Domain/Sources/UseCase/Expense/UpdateExpenseUseCase.swift @@ -13,11 +13,7 @@ public protocol UpdateExpenseUseCaseProtocol { } public struct UpdateExpenseUseCase: UpdateExpenseUseCaseProtocol { - private let repository: ExpenseRepositoryProtocol - - public init(repository: ExpenseRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.expenseRepository) private var repository: ExpenseRepositoryProtocol public func execute(travelId: String, expenseId: String, input: ExpenseInput) async throws { try input.validate() @@ -27,7 +23,7 @@ public struct UpdateExpenseUseCase: UpdateExpenseUseCaseProtocol { // MARK: - DependencyKey public enum UpdateExpenseUseCaseDependencyKey: DependencyKey { - public static var liveValue: any UpdateExpenseUseCaseProtocol = MockUpdateExpenseUseCase() + public static var liveValue: any UpdateExpenseUseCaseProtocol = UpdateExpenseUseCase() public static var testValue: any UpdateExpenseUseCaseProtocol = MockUpdateExpenseUseCase() diff --git a/Domain/Sources/UseCase/OAuth/OAuthUseCase.swift b/Domain/Sources/UseCase/OAuth/OAuthUseCase.swift index b6087e7c..67235258 100644 --- a/Domain/Sources/UseCase/OAuth/OAuthUseCase.swift +++ b/Domain/Sources/UseCase/OAuth/OAuthUseCase.swift @@ -6,162 +6,138 @@ // import Foundation -import ComposableArchitecture +import Dependencies import LogMacro import AuthenticationServices public struct OAuthUseCase: OAuthUseCaseProtocol { - private let repository: OAuthRepositoryProtocol - private let googleRepository: GoogleOAuthRepositoryProtocol - private let appleRepository: AppleOAuthRepositoryProtocol - private let kakaoRepository: KakaoOAuthRepositoryProtocol - - public init( - repository: OAuthRepositoryProtocol, - googleRepository: GoogleOAuthRepositoryProtocol, - appleRepository: AppleOAuthRepositoryProtocol, - kakaoRepository: KakaoOAuthRepositoryProtocol - ) { - self.repository = repository - self.googleRepository = googleRepository - self.appleRepository = appleRepository - self.kakaoRepository = kakaoRepository - } - - public func signInWithApple( - credential: ASAuthorizationAppleIDCredential, - nonce: String - ) async throws -> UserProfile { - guard let identityTokenData = credential.identityToken, - let identityToken = String(data: identityTokenData, encoding: .utf8), - let authCode = String(data: credential.authorizationCode ?? Data(), encoding: .utf8) - else { - throw AuthError.missingIDToken + @Dependency(\.oAuthRepository) private var repository: OAuthRepositoryProtocol + @Dependency(\.googleOAuthRepository) private var googleRepository: GoogleOAuthRepositoryProtocol + @Dependency(\.appleOAuthRepository) private var appleRepository: AppleOAuthRepositoryProtocol + @Dependency(\.kakaoOAuthRepository) private var kakaoRepository: KakaoOAuthRepositoryProtocol + + public init() {} + + public func signInWithApple( + credential: ASAuthorizationAppleIDCredential, + nonce: String + ) async throws -> UserProfile { + guard let identityTokenData = credential.identityToken, + let identityToken = String(data: identityTokenData, encoding: .utf8), + let authCode = String(data: credential.authorizationCode ?? Data(), encoding: .utf8) + else { + throw AuthError.missingIDToken + } + + let displayName = formatDisplayName(credential.fullName) + Log.info("Apple sign-in credential received for \(displayName ?? "unknown user")") + + let profile = try await repository.signIn( + provider: .apple, + idToken: identityToken, + nonce: nonce, + displayName: displayName, + authorizationCode: authCode + ) + Log.info("Supabase sign-in with Apple succeeded") + return profile } - - let displayName = formatDisplayName(credential.fullName) - Log.info("Apple sign-in credential received for \(displayName ?? "unknown user")") - - let profile = try await repository.signIn( - provider: .apple, - idToken: identityToken, - nonce: nonce, - displayName: displayName, - authorizationCode: authCode - ) - Log.info("Supabase sign-in with Apple succeeded") - return profile - } - - // MARK: - Helper Methods - private func formatDisplayName( - _ components: PersonNameComponents? - ) -> String? { - guard let components else { return nil } - let formatter = PersonNameComponentsFormatter() - let name = formatter.string(from: components).trimmingCharacters(in: .whitespacesAndNewlines) - return name.isEmpty ? nil : name - } - + + // MARK: - Helper Methods + private func formatDisplayName( + _ components: PersonNameComponents? + ) -> String? { + guard let components else { return nil } + let formatter = PersonNameComponentsFormatter() + let name = formatter.string(from: components).trimmingCharacters(in: .whitespacesAndNewlines) + return name.isEmpty ? nil : name + } + public func signUp( - with provider: SocialType + with provider: SocialType ) async throws -> UserProfile { // Kakao는 Supabase OAuth를 거치지 않고 Kakao SDK 토큰을 그대로 사용 if provider == .kakao { let kakaoPayload = try await kakaoRepository.signIn() let tokens = AuthTokens( - authToken: kakaoPayload.authorizationCode ?? "", - accessToken: kakaoPayload.accessToken, - refreshToken: kakaoPayload.refreshToken ?? "", - sessionID: "" + authToken: kakaoPayload.authorizationCode ?? "", + accessToken: kakaoPayload.accessToken, + refreshToken: kakaoPayload.refreshToken ?? "", + sessionID: "" ) return UserProfile( - id: kakaoPayload.authorizationCode ?? UUID().uuidString, - email: nil, - displayName: kakaoPayload.displayName, - provider: .kakao, - tokens: tokens, - authCode: kakaoPayload.authorizationCode, - codeVerifier: kakaoPayload.codeVerifier + id: kakaoPayload.authorizationCode ?? UUID().uuidString, + email: nil, + displayName: kakaoPayload.displayName, + provider: .kakao, + tokens: tokens, + authCode: kakaoPayload.authorizationCode, + codeVerifier: kakaoPayload.codeVerifier ) } - - let payload = try await fetchPayload(for: provider) - Log.info("\(provider.rawValue) sign-in succeeded for \(payload.displayName ?? "unknown user")") - - let profile = try await repository.signIn( - provider: payload.provider, - idToken: payload.idToken, - nonce: payload.nonce, - displayName: payload.displayName, - authorizationCode: payload.authorizationCode - ) - Log.info("Supabase sign-in with \(provider.rawValue) succeeded") - - return profile - } - - private func fetchPayload( - for provider: SocialType - ) async throws -> OAuthSignInPayload { - switch provider { - case .apple: - let payload = try await appleRepository.signIn() - return OAuthSignInPayload( - provider: .apple, - idToken: payload.idToken, - nonce: payload.nonce, - displayName: payload.displayName, - authorizationCode: payload.authorizationCode + + let payload = try await fetchPayload(for: provider) + Log.info("\(provider.rawValue) sign-in succeeded for \(payload.displayName ?? "unknown user")") + + let profile = try await repository.signIn( + provider: payload.provider, + idToken: payload.idToken, + nonce: payload.nonce, + displayName: payload.displayName, + authorizationCode: payload.authorizationCode ) - case .google: - let payload = try await googleRepository.signIn() - return OAuthSignInPayload( - provider: .google, - idToken: payload.idToken, - nonce: nil, - displayName: payload.displayName, - authorizationCode: payload.authorizationCode - ) - case .kakao: - // Kakao는 SDK 토큰을 바로 사용하므로 여기서는 빈 페이로드 반환 - return OAuthSignInPayload( - provider: .kakao, - idToken: "", - nonce: nil, - displayName: nil, - authorizationCode: nil - ) - case .none: - throw AuthError.configurationMissing + Log.info("Supabase sign-in with \(provider.rawValue) succeeded") + + return profile + } + + private func fetchPayload( + for provider: SocialType + ) async throws -> OAuthSignInPayload { + switch provider { + case .apple: + let payload = try await appleRepository.signIn() + return OAuthSignInPayload( + provider: .apple, + idToken: payload.idToken, + nonce: payload.nonce, + displayName: payload.displayName, + authorizationCode: payload.authorizationCode + ) + case .google: + let payload = try await googleRepository.signIn() + return OAuthSignInPayload( + provider: .google, + idToken: payload.idToken, + nonce: nil, + displayName: payload.displayName, + authorizationCode: payload.authorizationCode + ) + case .kakao: + // Kakao는 SDK 토큰을 바로 사용하므로 여기서는 빈 페이로드 반환 + return OAuthSignInPayload( + provider: .kakao, + idToken: "", + nonce: nil, + displayName: nil, + authorizationCode: nil + ) + case .none: + throw AuthError.configurationMissing + } } - } } // MARK: - Dependencies extension OAuthUseCase: DependencyKey { - public static var liveValue: OAuthUseCaseProtocol = { - return OAuthUseCase( - repository: MockOAuthRepository(), - googleRepository: MockGoogleOAuthRepository(), - appleRepository: MockAppleOAuthRepository(), - kakaoRepository: MockKakaoOAuthRepository() - ) - }() - public static var previewValue: OAuthUseCaseProtocol = liveValue - public static var testValue: OAuthUseCaseProtocol = { - return OAuthUseCase( - repository: MockOAuthRepository(), - googleRepository: MockGoogleOAuthRepository(), - appleRepository: MockAppleOAuthRepository(), - kakaoRepository: MockKakaoOAuthRepository() - ) - }() + public static var liveValue: OAuthUseCaseProtocol = OAuthUseCase() + public static var previewValue: OAuthUseCaseProtocol = OAuthUseCase() + public static var testValue: OAuthUseCaseProtocol = OAuthUseCase() } public extension DependencyValues { - var oAuthUseCase: OAuthUseCaseProtocol { - get { self[OAuthUseCase.self] } - set { self[OAuthUseCase.self] = newValue } - } + var oAuthUseCase: OAuthUseCaseProtocol { + get { self[OAuthUseCase.self] } + set { self[OAuthUseCase.self] = newValue } + } } diff --git a/Domain/Sources/UseCase/OAuth/OAuthUseCaseProtocol.swift b/Domain/Sources/UseCase/OAuth/OAuthUseCaseProtocol.swift index d9609c93..3414780f 100644 --- a/Domain/Sources/UseCase/OAuth/OAuthUseCaseProtocol.swift +++ b/Domain/Sources/UseCase/OAuth/OAuthUseCaseProtocol.swift @@ -8,11 +8,13 @@ import Foundation import AuthenticationServices - public protocol OAuthUseCaseProtocol { - func signInWithApple( - credential: ASAuthorizationAppleIDCredential, - nonce: String - ) async throws -> UserProfile - func signUp(with provider: SocialType) async throws -> UserProfile + func signInWithApple( + credential: ASAuthorizationAppleIDCredential, + nonce: String + ) async throws -> UserProfile + + func signUp( + with provider: SocialType + ) async throws -> UserProfile } diff --git a/Domain/Sources/UseCase/OAuth/UnifiedOAuthUseCase.swift b/Domain/Sources/UseCase/OAuth/UnifiedOAuthUseCase.swift index 70966470..b664b86c 100644 --- a/Domain/Sources/UseCase/OAuth/UnifiedOAuthUseCase.swift +++ b/Domain/Sources/UseCase/OAuth/UnifiedOAuthUseCase.swift @@ -9,21 +9,16 @@ import Foundation import Dependencies import LogMacro import AuthenticationServices -import ComposableArchitecture /// 통합 OAuth UseCase - 로그인/회원가입 플로우를 하나로 통합 (AuthFacade 역할) public struct UnifiedOAuthUseCase { - private let oAuthUseCase: any OAuthUseCaseProtocol - private let authRepository: any AuthRepositoryProtocol + @Dependency(\.oAuthUseCase) private var oAuthUseCase: any OAuthUseCaseProtocol + @Dependency(\.authRepository) private var authRepository: AuthRepositoryProtocol private let sessionStoreRepository: any SessionStoreRepositoryProtocol - + public init( - oAuthUseCase: any OAuthUseCaseProtocol = OAuthUseCase.liveValue, - authRepository: any AuthRepositoryProtocol = MockAuthRepository(), sessionStoreRepository: any SessionStoreRepositoryProtocol = SessionStoreRepository() ) { - self.oAuthUseCase = oAuthUseCase - self.authRepository = authRepository self.sessionStoreRepository = sessionStoreRepository } } @@ -31,7 +26,7 @@ public struct UnifiedOAuthUseCase { // MARK: - Public Interface public extension UnifiedOAuthUseCase { - + /// OAuth Provider에서 토큰 획득 (Google/Apple SDK 호출) func socialLogin( with socialType: SocialType, @@ -44,34 +39,34 @@ public extension UnifiedOAuthUseCase { nonce: nonce ) } - + /// 회원가입 상태 확인 func checkSignUpUser( with oAuthData: AuthData ) async -> Result { return await checkUserRegistrationStatus(with: oAuthData) } - + /// 로그인 처리 func loginUser( with oAuthData: AuthData ) async -> Result { let loginResult = await attemptLogin(with: oAuthData) - + if case .success(let authEntity) = loginResult { saveTokensAndComplete(authEntity: authEntity) } - + return loginResult } - + /// 회원가입 처리 func signUpUser( with oAuthData: AuthData ) async -> Result { return await attemptSignUp(with: oAuthData) } - + /// 약관 동의 후 회원가입 처리 func signUpWithTermsAgreement( with oAuthData: AuthData @@ -79,7 +74,7 @@ public extension UnifiedOAuthUseCase { Log.info("✅ Terms agreement completed, proceeding with signup") return await attemptSignUp(with: oAuthData) } - + /// OAuth 플로우 처리 (AuthFlowOutcome 반환) func processOAuthFlow( with socialType: SocialType, @@ -87,7 +82,7 @@ public extension UnifiedOAuthUseCase { nonce: String? = nil ) async -> AuthFlowOutcome { Log.info("🔐 Starting OAuth flow for: \(socialType.rawValue)") - + // 1단계: OAuth Provider 인증 let oAuthData = await getOAuthCredentials( socialType: socialType, @@ -101,7 +96,7 @@ public extension UnifiedOAuthUseCase { return .failure(.unknownError("OAuth 인증 실패")) } } - + // 2단계: 사용자 등록 상태 확인 let registrationStatus = await checkUserRegistrationStatus(with: authData) guard case .success(let checkUser) = registrationStatus else { @@ -111,7 +106,7 @@ public extension UnifiedOAuthUseCase { return .failure(.unknownError("등록 상태 확인 실패")) } } - + // 3단계: 등록 여부에 따른 분기 처리 if checkUser.registered { // 이미 등록된 사용자 -> 로그인 진행 @@ -137,14 +132,14 @@ public extension UnifiedOAuthUseCase { } } } - + func loginOrSignUp( with socialType: SocialType, appleCredential: ASAuthorizationAppleIDCredential? = nil, nonce: String? = nil ) async -> Result { Log.info("🔐 Starting unified OAuth flow for: \(socialType.rawValue)") - + let oAuthData = await getOAuthCredentials( socialType: socialType, appleCredential: appleCredential, @@ -157,7 +152,7 @@ public extension UnifiedOAuthUseCase { return .failure(.unknownError("OAuth 인증 실패")) } } - + let registrationStatus = await checkUserRegistrationStatus(with: authData) guard case .success(let checkUser) = registrationStatus else { if case .failure(let error) = registrationStatus { @@ -166,9 +161,9 @@ public extension UnifiedOAuthUseCase { return .failure(.unknownError("등록 상태 확인 실패")) } } - + let authResult: Result - + if checkUser.registered { authResult = await attemptLogin(with: authData) } else { @@ -179,11 +174,11 @@ public extension UnifiedOAuthUseCase { authResult = await attemptSignUp(with: authData) } } - + if case .success(let authEntity) = authResult, checkUser.registered { saveTokensAndComplete(authEntity: authEntity) } - + return authResult } } @@ -191,7 +186,7 @@ public extension UnifiedOAuthUseCase { // MARK: - Private Methods private extension UnifiedOAuthUseCase { - + /// OAuth Provider에서 인증 정보 획득 func getOAuthCredentials( socialType: SocialType, @@ -208,12 +203,12 @@ private extension UnifiedOAuthUseCase { else { return .failure(.invalidCredential("Apple 자격정보가 없습니다")) } - + let profile = try await oAuthUseCase.signInWithApple( credential: credential, nonce: nonce ) - + let oAuthData = AuthData( socialType: profile.provider, accessToken: profile.tokens.accessToken, @@ -226,10 +221,10 @@ private extension UnifiedOAuthUseCase { sessionID: profile.tokens.sessionID, userId: profile.id ) - - + + return .success(oAuthData) - + case .google: let profile = try await oAuthUseCase.signUp(with: socialType) let oAuthData = AuthData( @@ -266,7 +261,7 @@ private extension UnifiedOAuthUseCase { userId: finalized.userId ) return .success(oAuthData) - + case .none: return .failure(.invalidCredential("잘못된 소셜 타입")) } @@ -275,7 +270,7 @@ private extension UnifiedOAuthUseCase { return .failure(authError) } } - + /// 로그인 시도 func attemptLogin( with oAuthData: AuthData @@ -297,7 +292,7 @@ private extension UnifiedOAuthUseCase { Log.info("✅ Kakao finalize-only login completed") return .success(authEntity) } - + let input = OAuthUserInput( accessToken: oAuthData.authToken , socialType: oAuthData.socialType, @@ -305,18 +300,18 @@ private extension UnifiedOAuthUseCase { codeVerifier: oAuthData.codeVerifier, redirectUri: oAuthData.redirectUri ) - + var authEntity = try await authRepository.login(input: input) authEntity.token.authToken = oAuthData.authToken Log.info("✅ Login successful for \(oAuthData.socialType.rawValue)") return .success(authEntity) - + } catch { Log.info("⚠️ Login failed: \(error.localizedDescription)") return .failure(.networkError(error.localizedDescription)) } } - + /// 회원가입 상태 확인 func checkUserRegistrationStatus( with oAuthData: AuthData @@ -325,7 +320,7 @@ private extension UnifiedOAuthUseCase { if oAuthData.socialType == .kakao { return .success(OAuthCheckUser(registered: true, needsTerms: false)) } - + let checkInput = OAuthUserInput( accessToken: oAuthData.authToken, socialType: oAuthData.socialType, @@ -340,7 +335,7 @@ private extension UnifiedOAuthUseCase { return .failure(authError) } } - + /// 회원가입 시도 func attemptSignUp( with oAuthData: AuthData @@ -354,7 +349,7 @@ private extension UnifiedOAuthUseCase { sessionID: oAuthData.sessionID ?? "" ) let authEntity = AuthResult( - userId: oAuthData.userId ?? "kakao-user", + userId: oAuthData.userId ?? "kakao-user", name: oAuthData.displayName ?? "", provider: .kakao, token: tokens @@ -362,7 +357,7 @@ private extension UnifiedOAuthUseCase { saveTokensAndComplete(authEntity: authEntity) return .success(authEntity) } - + let checkInput = OAuthUserInput( accessToken: oAuthData.authToken, socialType: oAuthData.socialType, @@ -379,7 +374,7 @@ private extension UnifiedOAuthUseCase { return .failure(authError) } } - + /// 토큰 저장 및 로깅 func saveTokensAndComplete( authEntity: AuthResult @@ -401,10 +396,8 @@ private extension UnifiedOAuthUseCase { extension UnifiedOAuthUseCase: DependencyKey { public static let liveValue = UnifiedOAuthUseCase() - + public static let testValue = UnifiedOAuthUseCase( - oAuthUseCase: OAuthUseCase.testValue, - authRepository: MockAuthRepository(), sessionStoreRepository: SessionStoreRepository() ) } diff --git a/Domain/Sources/UseCase/Profile/ProfileEditPayload.swift b/Domain/Sources/UseCase/Profile/ProfileEditPayload.swift index 7c78b4ba..18c6f174 100644 --- a/Domain/Sources/UseCase/Profile/ProfileEditPayload.swift +++ b/Domain/Sources/UseCase/Profile/ProfileEditPayload.swift @@ -8,17 +8,17 @@ import Foundation public struct ProfileEditPayload: Equatable { - public let name: String? - public let avatarData: Data? - public let fileName: String? - - public init( - name: String? = nil, - avatarData: Data? = nil, - fileName: String? = nil - ) { - self.name = name - self.avatarData = avatarData - self.fileName = fileName - } + public let name: String? + public let avatarData: Data? + public let fileName: String? + + public init( + name: String? = nil, + avatarData: Data? = nil, + fileName: String? = nil + ) { + self.name = name + self.avatarData = avatarData + self.fileName = fileName + } } diff --git a/Domain/Sources/UseCase/Profile/ProfileUseCase.swift b/Domain/Sources/UseCase/Profile/ProfileUseCase.swift index aadc1841..bf8be5c8 100644 --- a/Domain/Sources/UseCase/Profile/ProfileUseCase.swift +++ b/Domain/Sources/UseCase/Profile/ProfileUseCase.swift @@ -6,45 +6,37 @@ // import Foundation -import ComposableArchitecture +import Dependencies public struct ProfileUseCase: ProfileUseCaseProtocol { - private let repository: ProfileRepositoryProtocol - - public init(repository: ProfileRepositoryProtocol) { - self.repository = repository - } - - public func getProfile() async throws -> Profile { - return try await repository.getProfile() - } - - public func editProfile(_ payload: ProfileEditPayload) async throws -> Profile { - let resolvedFileName: String? = { - // 파일이 있을 때만 기본 파일명을 지정하고, 없으면 그대로 nil 전달 - guard payload.avatarData != nil else { return nil } - return payload.fileName ?? "avatar.jpg" - }() - - return try await repository.editProfile( - name: payload.name, - avatarData: payload.avatarData, - fileName: resolvedFileName - ) - } + @Dependency(\.profileRepository) private var repository: ProfileRepositoryProtocol + + public init() {} + + public func getProfile() async throws -> Profile { + return try await repository.getProfile() + } + + public func editProfile(_ payload: ProfileEditPayload) async throws -> Profile { + let resolvedFileName: String? = { + // 파일이 있을 때만 기본 파일명을 지정하고, 없으면 그대로 nil 전달 + guard payload.avatarData != nil else { return nil } + return payload.fileName ?? "avatar.jpg" + }() + + return try await repository.editProfile( + name: payload.name, + avatarData: payload.avatarData, + fileName: resolvedFileName + ) + } } extension ProfileUseCase: DependencyKey { - public static var liveValue: ProfileUseCaseProtocol { - return ProfileUseCase(repository: MockProfileRepository()) - } - - public static var previewValue: any ProfileUseCaseProtocol { liveValue } - - public static let testValue: ProfileUseCaseProtocol = ProfileUseCase( - repository: MockProfileRepository() - ) + public static let liveValue: ProfileUseCaseProtocol = ProfileUseCase() + public static let previewValue: any ProfileUseCaseProtocol = ProfileUseCase() + public static let testValue: ProfileUseCaseProtocol = ProfileUseCase() } diff --git a/Domain/Sources/UseCase/Profile/ProfileUseCaseProtocol.swift b/Domain/Sources/UseCase/Profile/ProfileUseCaseProtocol.swift index 561ab4da..aebd5d77 100644 --- a/Domain/Sources/UseCase/Profile/ProfileUseCaseProtocol.swift +++ b/Domain/Sources/UseCase/Profile/ProfileUseCaseProtocol.swift @@ -8,6 +8,6 @@ import Foundation public protocol ProfileUseCaseProtocol { - func getProfile() async throws -> Profile - func editProfile(_ payload: ProfileEditPayload) async throws -> Profile + func getProfile() async throws -> Profile + func editProfile(_ payload: ProfileEditPayload) async throws -> Profile } diff --git a/Domain/Sources/UseCase/Session/SessionUseCase.swift b/Domain/Sources/UseCase/Session/SessionUseCase.swift index fb632f2a..0c5aa98e 100644 --- a/Domain/Sources/UseCase/Session/SessionUseCase.swift +++ b/Domain/Sources/UseCase/Session/SessionUseCase.swift @@ -6,17 +6,12 @@ // import Foundation - -import ComposableArchitecture +import Dependencies public struct SessionUseCase: SessionUseCaseProtocol { - private let repository: SessionRepositoryProtocol + @Dependency(\.sessionRepository) private var repository: SessionRepositoryProtocol - public init( - repository: SessionRepositoryProtocol - ) { - self.repository = repository - } + public init() {} public func checkSession( sessionId: String @@ -25,17 +20,10 @@ public struct SessionUseCase: SessionUseCaseProtocol { } } - extension SessionUseCase: DependencyKey { - public static var liveValue: SessionUseCaseProtocol { - return SessionUseCase(repository: MockSessionRepository()) - } - - public static var previewValue: SessionUseCaseProtocol { liveValue } - - public static var testValue: SessionUseCaseProtocol { - return SessionUseCase(repository: MockSessionRepository()) - } + public static let liveValue: SessionUseCaseProtocol = SessionUseCase() + public static let previewValue: SessionUseCaseProtocol = SessionUseCase() + public static let testValue: SessionUseCaseProtocol = SessionUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Settlement/FetchSettlementUseCase.swift b/Domain/Sources/UseCase/Settlement/FetchSettlementUseCase.swift index 5195e38e..dd044f26 100644 --- a/Domain/Sources/UseCase/Settlement/FetchSettlementUseCase.swift +++ b/Domain/Sources/UseCase/Settlement/FetchSettlementUseCase.swift @@ -6,14 +6,15 @@ // import Foundation -import ComposableArchitecture +import Dependencies -public struct FetchSettlementUseCase: FetchSettlementUseCaseProtocol { - private let repository: SettlementRepositoryProtocol +public protocol FetchSettlementUseCaseProtocol { + func execute(travelId: String) async throws -> TravelSettlement +} - public init(repository: SettlementRepositoryProtocol) { - self.repository = repository - } + +public struct FetchSettlementUseCase: FetchSettlementUseCaseProtocol { + @Dependency(\.settlementRepository) private var repository: SettlementRepositoryProtocol public func execute(travelId: String) async throws -> TravelSettlement { return try await repository.fetchSettlement(travelId: travelId) @@ -22,7 +23,7 @@ public struct FetchSettlementUseCase: FetchSettlementUseCaseProtocol { // MARK: - DependencyKey public enum FetchSettlementUseCaseDependencyKey: DependencyKey { - public static var liveValue: any FetchSettlementUseCaseProtocol = MockFetchSettlementUseCase() + public static var liveValue: any FetchSettlementUseCaseProtocol = FetchSettlementUseCase() public static var testValue: any FetchSettlementUseCaseProtocol = MockFetchSettlementUseCase() diff --git a/Domain/Sources/UseCase/Settlement/FetchSettlementUseCaseProtocol.swift b/Domain/Sources/UseCase/Settlement/FetchSettlementUseCaseProtocol.swift deleted file mode 100644 index ffc911ba..00000000 --- a/Domain/Sources/UseCase/Settlement/FetchSettlementUseCaseProtocol.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// FetchSettlementUseCaseProtocol.swift -// Domain -// -// Created by 홍석현 on 12/4/25. -// - -import Foundation - -public protocol FetchSettlementUseCaseProtocol { - func execute(travelId: String) async throws -> TravelSettlement -} diff --git a/Domain/Sources/UseCase/Settlement/MockFetchSettlementUseCase.swift b/Domain/Sources/UseCase/Settlement/Mock/MockFetchSettlementUseCase.swift similarity index 100% rename from Domain/Sources/UseCase/Settlement/MockFetchSettlementUseCase.swift rename to Domain/Sources/UseCase/Settlement/Mock/MockFetchSettlementUseCase.swift diff --git a/Domain/Sources/UseCase/Travel/CreateTravelUseCase.swift b/Domain/Sources/UseCase/Travel/CreateTravelUseCase.swift index 5ddb9f34..2de58e6b 100644 --- a/Domain/Sources/UseCase/Travel/CreateTravelUseCase.swift +++ b/Domain/Sources/UseCase/Travel/CreateTravelUseCase.swift @@ -13,11 +13,9 @@ public protocol CreateTravelUseCaseProtocol { } public struct CreateTravelUseCase: CreateTravelUseCaseProtocol { - private let repository: TravelRepositoryProtocol + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(input: CreateTravelInput) async throws -> Travel { try await repository.createTravel(input: input) @@ -25,17 +23,9 @@ public struct CreateTravelUseCase: CreateTravelUseCaseProtocol { } extension CreateTravelUseCase: DependencyKey { - public static var liveValue: CreateTravelUseCaseProtocol = { - CreateTravelUseCase(repository: MockTravelRepository()) - }() - - public static var previewValue: CreateTravelUseCaseProtocol = { - CreateTravelUseCase(repository: MockTravelRepository()) - }() - - public static var testValue: CreateTravelUseCaseProtocol = { - CreateTravelUseCase(repository: MockTravelRepository()) - }() + public static var liveValue: CreateTravelUseCaseProtocol = CreateTravelUseCase() + public static var previewValue: CreateTravelUseCaseProtocol = CreateTravelUseCase() + public static var testValue: CreateTravelUseCaseProtocol = CreateTravelUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/DeleteTravelUseCase.swift b/Domain/Sources/UseCase/Travel/DeleteTravelUseCase.swift index 582d79c6..236973d0 100644 --- a/Domain/Sources/UseCase/Travel/DeleteTravelUseCase.swift +++ b/Domain/Sources/UseCase/Travel/DeleteTravelUseCase.swift @@ -13,11 +13,9 @@ public protocol DeleteTravelUseCaseProtocol { } public struct DeleteTravelUseCase: DeleteTravelUseCaseProtocol { - private let repository: TravelRepositoryProtocol + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(id: String) async throws { try await repository.deleteTravel(id: id) @@ -25,17 +23,9 @@ public struct DeleteTravelUseCase: DeleteTravelUseCaseProtocol { } extension DeleteTravelUseCase: DependencyKey { - public static var liveValue: DeleteTravelUseCaseProtocol = { - DeleteTravelUseCase(repository: MockTravelRepository()) - }() - - public static var previewValue: DeleteTravelUseCaseProtocol = { - DeleteTravelUseCase(repository: MockTravelRepository()) - }() - - public static var testValue: DeleteTravelUseCaseProtocol = { - DeleteTravelUseCase(repository: MockTravelRepository()) - }() + public static var liveValue: DeleteTravelUseCaseProtocol = DeleteTravelUseCase() + public static var previewValue: DeleteTravelUseCaseProtocol = DeleteTravelUseCase() + public static var testValue: DeleteTravelUseCaseProtocol = DeleteTravelUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/FetchTravelDetailUseCase.swift b/Domain/Sources/UseCase/Travel/FetchTravelDetailUseCase.swift index c7fddbd1..b61814aa 100644 --- a/Domain/Sources/UseCase/Travel/FetchTravelDetailUseCase.swift +++ b/Domain/Sources/UseCase/Travel/FetchTravelDetailUseCase.swift @@ -13,11 +13,9 @@ public protocol FetchTravelDetailUseCaseProtocol { } public struct FetchTravelDetailUseCase: FetchTravelDetailUseCaseProtocol { - private let repository: TravelRepositoryProtocol + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(id: String) async throws -> Travel { try await repository.fetchTravelDetail(id: id) @@ -27,11 +25,11 @@ public struct FetchTravelDetailUseCase: FetchTravelDetailUseCaseProtocol { // MARK: - DependencyKey public enum FetchTravelDetailUseCaseDependencyKey: DependencyKey { - public static var liveValue: any FetchTravelDetailUseCaseProtocol = MockFetchTravelDetailUseCase() + public static var liveValue: any FetchTravelDetailUseCaseProtocol = FetchTravelDetailUseCase() - public static var testValue: any FetchTravelDetailUseCaseProtocol = MockFetchTravelDetailUseCase() + public static var testValue: any FetchTravelDetailUseCaseProtocol = FetchTravelDetailUseCase() - public static var previewValue: any FetchTravelDetailUseCaseProtocol = MockFetchTravelDetailUseCase() + public static var previewValue: any FetchTravelDetailUseCaseProtocol = FetchTravelDetailUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/FetchTravelsUseCase.swift b/Domain/Sources/UseCase/Travel/FetchTravelsUseCase.swift index 49999368..1da84600 100644 --- a/Domain/Sources/UseCase/Travel/FetchTravelsUseCase.swift +++ b/Domain/Sources/UseCase/Travel/FetchTravelsUseCase.swift @@ -13,11 +13,9 @@ public protocol FetchTravelsUseCaseProtocol { } public struct FetchTravelsUseCase: FetchTravelsUseCaseProtocol { - private let repository: TravelRepositoryProtocol + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(input: FetchTravelsInput) async throws -> [Travel] { try await repository.fetchTravels(input: input) @@ -25,17 +23,9 @@ public struct FetchTravelsUseCase: FetchTravelsUseCaseProtocol { } extension FetchTravelsUseCase: DependencyKey { - public static var liveValue: FetchTravelsUseCaseProtocol = { - FetchTravelsUseCase(repository: MockTravelRepository()) - }() - - public static var previewValue: FetchTravelsUseCaseProtocol = { - FetchTravelsUseCase(repository: MockTravelRepository()) - }() - - public static var testValue: FetchTravelsUseCaseProtocol = { - FetchTravelsUseCase(repository: MockTravelRepository()) - }() + public static var liveValue: FetchTravelsUseCaseProtocol = FetchTravelsUseCase() + public static var previewValue: FetchTravelsUseCaseProtocol = FetchTravelsUseCase() + public static var testValue: FetchTravelsUseCaseProtocol = FetchTravelsUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/LoadTravelCacheUseCase.swift b/Domain/Sources/UseCase/Travel/LoadTravelCacheUseCase.swift index 2a67c136..76897714 100644 --- a/Domain/Sources/UseCase/Travel/LoadTravelCacheUseCase.swift +++ b/Domain/Sources/UseCase/Travel/LoadTravelCacheUseCase.swift @@ -13,11 +13,9 @@ public protocol LoadTravelCacheUseCaseProtocol { } public struct LoadTravelCacheUseCase: LoadTravelCacheUseCaseProtocol { - private let repository: TravelRepositoryProtocol - - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol + + public init() {} public func execute(status: TravelStatus) async throws -> [Travel]? { try await repository.loadCachedTravels(status: status) @@ -25,17 +23,9 @@ public struct LoadTravelCacheUseCase: LoadTravelCacheUseCaseProtocol { } extension LoadTravelCacheUseCase: DependencyKey { - public static var liveValue: LoadTravelCacheUseCaseProtocol = { - LoadTravelCacheUseCase(repository: MockTravelRepository()) - }() - - public static var previewValue: LoadTravelCacheUseCaseProtocol = { - LoadTravelCacheUseCase(repository: MockTravelRepository()) - }() - - public static var testValue: LoadTravelCacheUseCaseProtocol = { - LoadTravelCacheUseCase(repository: MockTravelRepository()) - }() + public static var liveValue: LoadTravelCacheUseCaseProtocol = LoadTravelCacheUseCase() + public static var previewValue: LoadTravelCacheUseCaseProtocol = LoadTravelCacheUseCase() + public static var testValue: LoadTravelCacheUseCaseProtocol = LoadTravelCacheUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/LoadTravelDetailCacheUseCase.swift b/Domain/Sources/UseCase/Travel/LoadTravelDetailCacheUseCase.swift index 400c4bd0..a471b81d 100644 --- a/Domain/Sources/UseCase/Travel/LoadTravelDetailCacheUseCase.swift +++ b/Domain/Sources/UseCase/Travel/LoadTravelDetailCacheUseCase.swift @@ -13,11 +13,9 @@ public protocol LoadTravelDetailCacheUseCaseProtocol { } public struct LoadTravelDetailCacheUseCase: LoadTravelDetailCacheUseCaseProtocol { - private let repository: TravelRepositoryProtocol + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(id: String) async throws -> Travel? { try await repository.loadCachedTravel(id: id) @@ -25,17 +23,9 @@ public struct LoadTravelDetailCacheUseCase: LoadTravelDetailCacheUseCaseProtocol } extension LoadTravelDetailCacheUseCase: DependencyKey { - public static var liveValue: any LoadTravelDetailCacheUseCaseProtocol = { - LoadTravelDetailCacheUseCase(repository: MockTravelRepository()) - }() - - public static var previewValue: any LoadTravelDetailCacheUseCaseProtocol = { - LoadTravelDetailCacheUseCase(repository: MockTravelRepository()) - }() - - public static var testValue: any LoadTravelDetailCacheUseCaseProtocol = { - LoadTravelDetailCacheUseCase(repository: MockTravelRepository()) - }() + public static let liveValue: any LoadTravelDetailCacheUseCaseProtocol = LoadTravelDetailCacheUseCase() + public static let previewValue: any LoadTravelDetailCacheUseCaseProtocol = LoadTravelDetailCacheUseCase() + public static let testValue: any LoadTravelDetailCacheUseCaseProtocol = LoadTravelDetailCacheUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/Member/DelegateOwnerUseCase.swift b/Domain/Sources/UseCase/Travel/Member/DelegateOwnerUseCase.swift index 9563dbe8..74db16b8 100644 --- a/Domain/Sources/UseCase/Travel/Member/DelegateOwnerUseCase.swift +++ b/Domain/Sources/UseCase/Travel/Member/DelegateOwnerUseCase.swift @@ -13,11 +13,7 @@ public protocol DelegateOwnerUseCaseProtocol { } public struct DelegateOwnerUseCase: DelegateOwnerUseCaseProtocol { - private let repository: TravelMemberRepositoryProtocol - - public init(repository: TravelMemberRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.travelMemberRepository) private var repository: TravelMemberRepositoryProtocol public func execute(travelId: String, newOwnerId: String) async throws -> Travel { try await repository.delegateOwner(travelId: travelId, newOwnerId: newOwnerId) @@ -25,17 +21,11 @@ public struct DelegateOwnerUseCase: DelegateOwnerUseCaseProtocol { } extension DelegateOwnerUseCase: DependencyKey { - public static var liveValue: DelegateOwnerUseCaseProtocol = { - DelegateOwnerUseCase(repository: MockTravelMemberRepository()) - }() + public static var liveValue: DelegateOwnerUseCaseProtocol = DelegateOwnerUseCase() - public static var previewValue: DelegateOwnerUseCaseProtocol = { - DelegateOwnerUseCase(repository: MockTravelMemberRepository()) - }() + public static var previewValue: DelegateOwnerUseCaseProtocol = DelegateOwnerUseCase() - public static var testValue: DelegateOwnerUseCaseProtocol = { - DelegateOwnerUseCase(repository: MockTravelMemberRepository()) - }() + public static var testValue: DelegateOwnerUseCaseProtocol = DelegateOwnerUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/Member/DeleteTravelMemberUseCase.swift b/Domain/Sources/UseCase/Travel/Member/DeleteTravelMemberUseCase.swift index 74a8b64e..cc8c29b8 100644 --- a/Domain/Sources/UseCase/Travel/Member/DeleteTravelMemberUseCase.swift +++ b/Domain/Sources/UseCase/Travel/Member/DeleteTravelMemberUseCase.swift @@ -13,11 +13,7 @@ public protocol DeleteTravelMemberUseCaseProtocol { } public struct DeleteTravelMemberUseCase: DeleteTravelMemberUseCaseProtocol { - private let repository: TravelMemberRepositoryProtocol - - public init(repository: TravelMemberRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.travelMemberRepository) private var repository: TravelMemberRepositoryProtocol public func execute(travelId: String, memberId: String) async throws { try await repository.deleteMember(travelId: travelId, memberId: memberId) @@ -25,17 +21,11 @@ public struct DeleteTravelMemberUseCase: DeleteTravelMemberUseCaseProtocol { } extension DeleteTravelMemberUseCase: DependencyKey { - public static var liveValue: DeleteTravelMemberUseCaseProtocol = { - DeleteTravelMemberUseCase(repository: MockTravelMemberRepository()) - }() + public static var liveValue: DeleteTravelMemberUseCaseProtocol = DeleteTravelMemberUseCase() - public static var previewValue: DeleteTravelMemberUseCaseProtocol = { - DeleteTravelMemberUseCase(repository: MockTravelMemberRepository()) - }() + public static var previewValue: DeleteTravelMemberUseCaseProtocol = DeleteTravelMemberUseCase() - public static var testValue: DeleteTravelMemberUseCaseProtocol = { - DeleteTravelMemberUseCase(repository: MockTravelMemberRepository()) - }() + public static var testValue: DeleteTravelMemberUseCaseProtocol = DeleteTravelMemberUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/Member/FetchMemberUseCase.swift b/Domain/Sources/UseCase/Travel/Member/FetchMemberUseCase.swift index 4ca11dd3..420f964d 100644 --- a/Domain/Sources/UseCase/Travel/Member/FetchMemberUseCase.swift +++ b/Domain/Sources/UseCase/Travel/Member/FetchMemberUseCase.swift @@ -13,11 +13,9 @@ public protocol FetchMemberUseCaseProtocol { } public struct FetchMemberUseCase: FetchMemberUseCaseProtocol { - private let repository: TravelMemberRepositoryProtocol + @Dependency(\.travelMemberRepository) private var repository: TravelMemberRepositoryProtocol - public init(repository: TravelMemberRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(travelId: String) async throws -> MyTravelMember { try await repository.fetchMember(travelId: travelId) @@ -25,17 +23,11 @@ public struct FetchMemberUseCase: FetchMemberUseCaseProtocol { } extension FetchMemberUseCase: DependencyKey { - public static var liveValue: FetchMemberUseCaseProtocol = { - FetchMemberUseCase(repository: MockTravelMemberRepository()) - }() + public static var liveValue: FetchMemberUseCaseProtocol = FetchMemberUseCase() - public static var previewValue: FetchMemberUseCaseProtocol = { - FetchMemberUseCase(repository: MockTravelMemberRepository()) - }() + public static var previewValue: FetchMemberUseCaseProtocol = FetchMemberUseCase() - public static var testValue: FetchMemberUseCaseProtocol = { - FetchMemberUseCase(repository: MockTravelMemberRepository()) - }() + public static var testValue: FetchMemberUseCaseProtocol = FetchMemberUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/Member/JoinTravelUseCase.swift b/Domain/Sources/UseCase/Travel/Member/JoinTravelUseCase.swift index 1b180ce8..487226b1 100644 --- a/Domain/Sources/UseCase/Travel/Member/JoinTravelUseCase.swift +++ b/Domain/Sources/UseCase/Travel/Member/JoinTravelUseCase.swift @@ -13,11 +13,9 @@ public protocol JoinTravelUseCaseProtocol { } public struct JoinTravelUseCase: JoinTravelUseCaseProtocol { - private let repository: TravelMemberRepositoryProtocol + @Dependency(\.travelMemberRepository) private var repository: TravelMemberRepositoryProtocol - public init(repository: TravelMemberRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(inviteCode: String) async throws -> Travel { try await repository.joinTravel(inviteCode: inviteCode) @@ -25,17 +23,11 @@ public struct JoinTravelUseCase: JoinTravelUseCaseProtocol { } extension JoinTravelUseCase: DependencyKey { - public static var liveValue: JoinTravelUseCaseProtocol = { - JoinTravelUseCase(repository: MockTravelMemberRepository()) - }() + public static var liveValue: JoinTravelUseCaseProtocol = JoinTravelUseCase() - public static var previewValue: JoinTravelUseCaseProtocol = { - JoinTravelUseCase(repository: MockTravelMemberRepository()) - }() + public static var previewValue: JoinTravelUseCaseProtocol = JoinTravelUseCase() - public static var testValue: JoinTravelUseCaseProtocol = { - JoinTravelUseCase(repository: MockTravelMemberRepository()) - }() + public static var testValue: JoinTravelUseCaseProtocol = JoinTravelUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/Member/LeaveTravelUseCase.swift b/Domain/Sources/UseCase/Travel/Member/LeaveTravelUseCase.swift index 7e1a0f60..32b49ac4 100644 --- a/Domain/Sources/UseCase/Travel/Member/LeaveTravelUseCase.swift +++ b/Domain/Sources/UseCase/Travel/Member/LeaveTravelUseCase.swift @@ -13,11 +13,9 @@ public protocol LeaveTravelUseCaseProtocol { } public struct LeaveTravelUseCase: LeaveTravelUseCaseProtocol { - private let repository: TravelMemberRepositoryProtocol + @Dependency(\.travelMemberRepository) private var repository: TravelMemberRepositoryProtocol - public init(repository: TravelMemberRepositoryProtocol) { - self.repository = repository - } + public init() {} public func execute(travelId: String) async throws { try await repository.leaveTravel(travelId: travelId) @@ -25,17 +23,11 @@ public struct LeaveTravelUseCase: LeaveTravelUseCaseProtocol { } extension LeaveTravelUseCase: DependencyKey { - public static var liveValue: LeaveTravelUseCaseProtocol = { - LeaveTravelUseCase(repository: MockTravelMemberRepository()) - }() + public static var liveValue: LeaveTravelUseCaseProtocol = LeaveTravelUseCase() - public static var previewValue: LeaveTravelUseCaseProtocol = { - LeaveTravelUseCase(repository: MockTravelMemberRepository()) - }() + public static var previewValue: LeaveTravelUseCaseProtocol = LeaveTravelUseCase() - public static var testValue: LeaveTravelUseCaseProtocol = { - LeaveTravelUseCase(repository: MockTravelMemberRepository()) - }() + public static var testValue: LeaveTravelUseCaseProtocol = LeaveTravelUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Travel/UpdateTravelUseCase.swift b/Domain/Sources/UseCase/Travel/UpdateTravelUseCase.swift index de063ff4..68a8d4a5 100644 --- a/Domain/Sources/UseCase/Travel/UpdateTravelUseCase.swift +++ b/Domain/Sources/UseCase/Travel/UpdateTravelUseCase.swift @@ -13,11 +13,9 @@ public protocol UpdateTravelUseCaseProtocol { } public struct UpdateTravelUseCase: UpdateTravelUseCaseProtocol { - private let repository: TravelRepositoryProtocol - - public init(repository: TravelRepositoryProtocol) { - self.repository = repository - } + @Dependency(\.travelRepository) private var repository: TravelRepositoryProtocol + + public init() {} public func execute(id: String, input: UpdateTravelInput) async throws -> Travel { try await repository.updateTravel(id: id, input: input) @@ -25,17 +23,9 @@ public struct UpdateTravelUseCase: UpdateTravelUseCaseProtocol { } extension UpdateTravelUseCase: DependencyKey { - public static var liveValue: UpdateTravelUseCaseProtocol = { - UpdateTravelUseCase(repository: MockTravelRepository()) - }() - - public static var previewValue: UpdateTravelUseCaseProtocol = { - UpdateTravelUseCase(repository: MockTravelRepository()) - }() - - public static var testValue: UpdateTravelUseCaseProtocol = { - UpdateTravelUseCase(repository: MockTravelRepository()) - }() + public static var liveValue: UpdateTravelUseCaseProtocol = UpdateTravelUseCase() + public static var previewValue: UpdateTravelUseCaseProtocol = UpdateTravelUseCase() + public static var testValue: UpdateTravelUseCaseProtocol = UpdateTravelUseCase() } public extension DependencyValues { diff --git a/Domain/Sources/UseCase/Version/VersionUseCase.swift b/Domain/Sources/UseCase/Version/VersionUseCase.swift index ca91a3d4..7b6b25b7 100644 --- a/Domain/Sources/UseCase/Version/VersionUseCase.swift +++ b/Domain/Sources/UseCase/Version/VersionUseCase.swift @@ -6,37 +6,28 @@ // import Foundation -import ComposableArchitecture +import Dependencies public struct VersionUseCase: VersionUseCaseProtocol { - private let repository: VersionRepositoryProtocol + @Dependency(\.versionRepository) private var repository: VersionRepositoryProtocol - public init(repository: VersionRepositoryProtocol) { - self.repository = repository - } + public init() {} public func getVersion(bundleId: String, version: String) async throws -> Version { return try await repository.getVersion(bundleId: bundleId, version: version) } } -extension VersionUseCase: DependencyKey { - public static var liveValue: VersionUseCaseProtocol { - return VersionUseCase(repository: MockVersionRepository()) - } - - public static var previewValue: VersionUseCaseProtocol { liveValue } - - public static let testValue: VersionUseCaseProtocol = VersionUseCase( - repository: MockVersionRepository() - ) +private struct VersionUseCaseDependencyKey: DependencyKey { + public static let liveValue: VersionUseCaseProtocol = VersionUseCase() + public static let previewValue: VersionUseCaseProtocol = VersionUseCase() + public static let testValue: VersionUseCaseProtocol = VersionUseCase() } - public extension DependencyValues { var versionUseCase : VersionUseCaseProtocol { - get { self[VersionUseCase.self] } - set { self[VersionUseCase.self] = newValue } + get { self[VersionUseCaseDependencyKey.self] } + set { self[VersionUseCaseDependencyKey.self] = newValue } } } diff --git a/Features/Splash/Sources/Reducer/SplashFeature.swift b/Features/Splash/Sources/Reducer/SplashFeature.swift index 63555b42..daf2af0d 100644 --- a/Features/Splash/Sources/Reducer/SplashFeature.swift +++ b/Features/Splash/Sources/Reducer/SplashFeature.swift @@ -83,7 +83,7 @@ public struct SplashFeature { @Dependency(SessionUseCase.self) var sessionUseCase @Dependency(\.continuousClock) var clock - @Dependency(VersionUseCase.self) var versionUseCase + @Dependency(\.versionUseCase) var versionUseCase public var body: some Reducer { BindingReducer() diff --git a/SseuDamApp/Sources/Application/LiveDependencies.swift b/SseuDamApp/Sources/Application/LiveDependencies.swift index e4d64a72..01a749a5 100644 --- a/SseuDamApp/Sources/Application/LiveDependencies.swift +++ b/SseuDamApp/Sources/Application/LiveDependencies.swift @@ -11,83 +11,49 @@ import Data import Domain public enum LiveDependencies { - @MainActor public static func register(_ dependencies: inout DependencyValues) { - // Repository 인스턴스 생성 (재사용) - let travelRepository = TravelRepository( + @MainActor + public static func register(_ dependencies: inout DependencyValues) { + // Auth & Session + dependencies.authRepository = AuthRepository() + dependencies.sessionRepository = SessionRepository() + + dependencies.oAuthRepository = OAuthRepository() + dependencies.googleOAuthRepository = GoogleOAuthRepository() + dependencies.appleOAuthRepository = AppleOAuthRepository() + dependencies.kakaoOAuthRepository = KakaoOAuthRepository( + presentationContextProvider: AppPresentationContextProvider() + ) + + // Analytics + dependencies.analyticsRepository = FirebaseAnalyticsRepository() + + // Travel + dependencies.travelRepository = TravelRepository( remote: TravelRemoteDataSource(), local: TravelLocalDataSource() ) - let expenseRepository = ExpenseRepository( + + // Expense + dependencies.expenseRepository = ExpenseRepository( remote: ExpenseRemoteDataSource(), local: ExpenseLocalDataSource() ) - let travelMemberRepository = TravelMemberRepository(remote: TravelMemberRemoteDataSource()) - let authRepository = AuthRepository() - let oAuthRepository = OAuthRepository() - let countryRepository = CountryRepository(remote: CountryRemoteDataSource()) - let exchangeRateRepository = ExchangeRateRepository(remote: ExchangeRateRemoteDataSource()) - let settlementRepository = SettlementRepository(remote: SettlementRemoteDataSource()) - let profileRepository = ProfileRepository() - let versionRepository = VersionRepository() - - // Auth & Session - let oAuthUseCase = makeOAuthUseCase(repository: oAuthRepository) - dependencies.oAuthUseCase = oAuthUseCase - dependencies.unifiedOAuthUseCase = UnifiedOAuthUseCase( - oAuthUseCase: oAuthUseCase, - authRepository: authRepository, - sessionStoreRepository: SessionStoreRepository() - ) - dependencies.sessionUseCase = SessionUseCase(repository: SessionRepository()) - dependencies.authUseCase = AuthUseCase(repository: authRepository) - dependencies.profileUseCase = ProfileUseCase(repository: profileRepository) - dependencies.versionUseCase = VersionUseCase(repository: versionRepository) - - // Analytics - dependencies.analyticsUseCase = AnalyticsUseCase(repository: FirebaseAnalyticsRepository()) - - // Travel - dependencies.fetchTravelsUseCase = FetchTravelsUseCase(repository: travelRepository) - dependencies.loadTravelCacheUseCase = LoadTravelCacheUseCase(repository: travelRepository) - dependencies.loadTravelDetailCacheUseCase = LoadTravelDetailCacheUseCase(repository: travelRepository) - dependencies.createTravelUseCase = CreateTravelUseCase(repository: travelRepository) - dependencies.fetchTravelDetailUseCase = FetchTravelDetailUseCase(repository: travelRepository) - dependencies.updateTravelUseCase = UpdateTravelUseCase(repository: travelRepository) - dependencies.deleteTravelUseCase = DeleteTravelUseCase(repository: travelRepository) - - // Expense - dependencies.expenseRepository = expenseRepository - dependencies.fetchTravelExpenseUseCase = FetchTravelExpenseUseCase(repository: expenseRepository) - dependencies.createExpenseUseCase = CreateExpenseUseCase(repository: expenseRepository) - dependencies.updateExpenseUseCase = UpdateExpenseUseCase(repository: expenseRepository) - dependencies.deleteExpenseUseCase = DeleteExpenseUseCase(repository: expenseRepository) // TravelMember - dependencies.joinTravelUseCase = JoinTravelUseCase(repository: travelMemberRepository) - dependencies.delegateOwnerUseCase = DelegateOwnerUseCase(repository: travelMemberRepository) - dependencies.deleteTravelMemberUseCase = DeleteTravelMemberUseCase(repository: travelMemberRepository) - dependencies.leaveTravelUseCase = LeaveTravelUseCase(repository: travelMemberRepository) - dependencies.fetchMemberUseCase = FetchMemberUseCase(repository: travelMemberRepository) + dependencies.travelMemberRepository = TravelMemberRepository(remote: TravelMemberRemoteDataSource()) // Country & Exchange - dependencies.fetchCountriesUseCase = FetchCountriesUseCase(repository: countryRepository) - dependencies.fetchExchangeRateUseCase = FetchExchangeRateUseCase(repository: exchangeRateRepository) - + dependencies.countryRepository = CountryRepository(remote: CountryRemoteDataSource()) + dependencies.exchangeRateRepository = ExchangeRateRepository(remote: ExchangeRateRemoteDataSource()) + // Settlement - dependencies.fetchSettlementUseCase = FetchSettlementUseCase(repository: settlementRepository) - dependencies.calculateSettlementUseCase = CalculateSettlementUseCase() - } - - // MARK: - Factory Methods - @MainActor - private static func makeOAuthUseCase(repository: OAuthRepository) -> OAuthUseCaseProtocol { - OAuthUseCase( - repository: repository, - googleRepository: GoogleOAuthRepository(), - appleRepository: AppleOAuthRepository(), - kakaoRepository: KakaoOAuthRepository( - presentationContextProvider: AppPresentationContextProvider() - ) - ) + dependencies.settlementRepository = SettlementRepository(remote: SettlementRemoteDataSource()) + + // Profile + dependencies.profileRepository = ProfileRepository() + + // AppVersion + dependencies.versionRepository = VersionRepository() + } }