Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
59c7360
[CHORE]: Tuist 플러그인에 신규 모듈 정의 추가
khyeji98 May 5, 2026
08824ee
[CHORE]: 카메라/사진 권한 및 Kakao REST 키 plist 추가
khyeji98 May 5, 2026
ec84724
[FEAT]: AppEnvironment 환경값 헬퍼 추가
khyeji98 May 5, 2026
59cb98f
[FEAT]: 인터셉터 미적용 쿼리 파라미터 요청 추가
khyeji98 May 5, 2026
9a62c44
[FEAT]: Station 엔티티 및 검색 도메인 인터페이스 정의
khyeji98 May 5, 2026
1dc341f
[FEAT]: Kakao Local 출발지 검색 데이터 레이어 구현
khyeji98 May 5, 2026
60cc9a9
[FEAT]: SearchStationsClient TCA 의존성 정의
khyeji98 May 5, 2026
9659a93
[FEAT]: 회원가입 플로우 및 임시 홈 화면 구현
khyeji98 May 5, 2026
011947e
[REFACTOR]: Presentation 모듈을 Feature 재노출로 단순화
khyeji98 May 5, 2026
fa29d6b
[FEAT]: RootFeature 도입 및 앱 진입점 교체
khyeji98 May 5, 2026
4e5ed36
[CHORE]: Tuist 의존성 그래프 갱신
khyeji98 May 5, 2026
2ffc0c2
[REFACTOR]: RootFeature를 별도 Presentation 모듈로 분리
khyeji98 May 5, 2026
e7b2904
[CHORE]: Tuist 의존성 그래프 갱신
khyeji98 May 5, 2026
60d0918
[FIX]: 출발지 검색 시트 헤더 레이아웃 수정
khyeji98 May 5, 2026
e6a3876
[DOCS]: TCA Dependency 컨벤션 문서 추가
khyeji98 May 6, 2026
4a87de8
[DOCS]: 회원가입 플로우 스펙 문서 추가
khyeji98 May 6, 2026
f13c75c
[MERGE]: develop 브랜치 병합 및 충돌 해결
khyeji98 May 6, 2026
241f921
[REFACTOR]: 임시 로그인 화면을 통합 로그인 화면으로 교체
khyeji98 May 10, 2026
801ef3e
[REFACTOR]: Presentation 모듈 정리 및 RootFeature 재노출
khyeji98 May 10, 2026
978913a
[CHORE]: Tuist 의존성 그래프 갱신
khyeji98 May 10, 2026
9c184a8
[REFACTOR]: Project.swift settings 파라미터 불필요한 공백 제거
khyeji98 May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ Projects/
- CPU 작업은 Effect 내에서 처리
- 테스트: TestStore 패턴 사용

#### TCA Dependency Client
- TCA Client(`@DependencyClient` + `DependencyKey` + `DependencyValues`)는 `CoreDependencies` 한 파일에 둔다
- `liveValue` / `testValue`는 빈 `Self()`, `static func live(useCase:)` 팩토리는 Domain UseCase protocol만 받는다
- 실제 live 조립은 `App/Sources/Factory/*Factory.makeClient()`에서, 주입은 `BangawoApp.init()`의 `prepareDependencies`에서 한 번만
- Feature는 `@Dependency`만 사용, `Data` 계열(Repository/DataUseCase/Model/API/Service) import 금지
- 네이밍: Entity는 도메인명 그대로(`AuthToken`), DTO는 `*RequestDTO`/`*ResponseDTO`, Repository는 `*RepositoryProtocol`/`*RepositoryImpl`, UseCase는 `*UseCase`/`*UseCaseImpl`, TCA Client는 `*Client`, Composition Root 헬퍼는 `*Factory`
- 상세 예시·의존성 표·금지 사항은 [`docs/conventions/tca-dependency-convention.md`](docs/conventions/tca-dependency-convention.md) 참고

## Git Rules

### Branch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ public enum ModulePath {
case Domain(Domains)
case Data(Datas)
case Shared(Shareds)
case Core(Cores)
}

// MARK: FeatureModule
public extension ModulePath {
enum Presentations: String, CaseIterable {
case Presentation
case AuthFlowFeature
case HomeFeature
case RootFeature


public static let name: String = "Presentation"
Expand All @@ -46,6 +50,7 @@ public extension ModulePath {
case Repository
case API
case Service
case DataUseCase

public static let name: String = "Data"
}
Expand All @@ -72,9 +77,19 @@ public extension ModulePath {
case Shared
case DesignSystem
case Utill

public static let name: String = "Shared"
}
}


//MARK: - CoreModule
public extension ModulePath {
enum Cores: String, CaseIterable {
case CoreDependencies

public static let name: String = "Core"
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,14 @@ public extension ProjectDescription.Path {
return .relativeToRoot("Projects/\(ModulePath.Datas.name)/\(module.rawValue)")
}
}

// MARK: - Core
public extension ProjectDescription.Path {
static var Core: Self {
return .relativeToRoot("Projects/\(ModulePath.Cores.name)")
}

static func Core(implementation module: ModulePath.Cores) -> Self {
return .relativeToRoot("Projects/\(ModulePath.Cores.name)/\(module.rawValue)")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,10 @@ public extension TargetDependency {
}
}

// Core
public extension TargetDependency {
static func Core(implements module: ModulePath.Cores) -> Self {
projectTarget(module.rawValue, path: .Core(implementation: module))
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ extension InfoPlistDictionary {
func setNSCameraUsageDescription(_ value: String) -> InfoPlistDictionary {
return self.merging(["NSCameraUsageDescription": .string(value)]) { (_, new) in new }
}

func setNSPhotoLibraryUsageDescription(_ value: String) -> InfoPlistDictionary {
return self.merging(["NSPhotoLibraryUsageDescription": .string(value)]) { (_, new) in new }
}

func setUILaunchScreens() -> InfoPlistDictionary {
let dict: InfoPlistDictionary = [
Expand Down Expand Up @@ -199,4 +203,8 @@ extension InfoPlistDictionary {
func setKakaoAppKey(_ value: String) -> InfoPlistDictionary {
return self.merging(["KAKAO_APP_KEY": .string(value)]) { (_, new) in new }
}

func setKakaoRestAPIKey(_ value: String) -> InfoPlistDictionary {
return self.merging(["KAKAO_REST_API_KEY": .string(value)]) { (_, new) in new }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public extension InfoPlist {
]
])
.setKakaoAppKey("$(KAKAO_APP_KEY)")
.setKakaoRestAPIKey("$(KAKAO_REST_API_KEY)")
.setNSCameraUsageDescription("프로필 사진 촬영을 위해 카메라 접근이 필요합니다")
.setNSPhotoLibraryUsageDescription("프로필 사진 선택을 위해 사진 접근이 필요합니다")
)

static let moduleInfoPlist: Self = .extendingDefault(
Expand Down
6 changes: 6 additions & 0 deletions Projects/App/Derived/InfoPlists/Bangawo-Debug-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<false/>
<key>KAKAO_APP_KEY</key>
<string>$(KAKAO_APP_KEY)</string>
<key>KAKAO_REST_API_KEY</key>
<string>$(KAKAO_REST_API_KEY)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaokompassauth</string>
Expand All @@ -46,6 +48,10 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>프로필 사진 촬영을 위해 카메라 접근이 필요합니다</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>프로필 사진 선택을 위해 사진 접근이 필요합니다</string>
<key>UIAppFonts</key>
<array>
<string>PretendardVariable.ttf</string>
Expand Down
6 changes: 6 additions & 0 deletions Projects/App/Derived/InfoPlists/Bangawo-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<false/>
<key>KAKAO_APP_KEY</key>
<string>$(KAKAO_APP_KEY)</string>
<key>KAKAO_REST_API_KEY</key>
<string>$(KAKAO_REST_API_KEY)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaokompassauth</string>
Expand All @@ -46,6 +48,10 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>프로필 사진 촬영을 위해 카메라 접근이 필요합니다</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>프로필 사진 선택을 위해 사진 접근이 필요합니다</string>
<key>UIAppFonts</key>
<array>
<string>PretendardVariable.ttf</string>
Expand Down
6 changes: 6 additions & 0 deletions Projects/App/Derived/InfoPlists/Bangawo-Prod-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<false/>
<key>KAKAO_APP_KEY</key>
<string>$(KAKAO_APP_KEY)</string>
<key>KAKAO_REST_API_KEY</key>
<string>$(KAKAO_REST_API_KEY)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaokompassauth</string>
Expand All @@ -46,6 +48,10 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>프로필 사진 촬영을 위해 카메라 접근이 필요합니다</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>프로필 사진 선택을 위해 사진 접근이 필요합니다</string>
<key>UIAppFonts</key>
<array>
<string>PretendardVariable.ttf</string>
Expand Down
6 changes: 6 additions & 0 deletions Projects/App/Derived/InfoPlists/Bangawo-Stage-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<false/>
<key>KAKAO_APP_KEY</key>
<string>$(KAKAO_APP_KEY)</string>
<key>KAKAO_REST_API_KEY</key>
<string>$(KAKAO_REST_API_KEY)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaokompassauth</string>
Expand All @@ -46,6 +48,10 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>프로필 사진 촬영을 위해 카메라 접근이 필요합니다</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>프로필 사진 선택을 위해 사진 접근이 필요합니다</string>
<key>UIAppFonts</key>
<array>
<string>PretendardVariable.ttf</string>
Expand Down
9 changes: 6 additions & 3 deletions Projects/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ let project = Project.makeAppModule(
scripts: [],
dependencies: [
.Presentation(implements: .Presentation),
.project(target: "CoreDependencies", path: .relativeToRoot("Projects/Core/Dependencies")),
.project(target: "DataUseCase", path: .relativeToRoot("Projects/Data/UseCase")),
.Domain(implements: .UseCase),
.Data(implements: .Repository),
.Data(implements: .Service),
.Data(implements: .DataUseCase),
.Core(implements: .CoreDependencies),
.Shared(implements: .Utill),
.SPM.kakaoMapsSDK,
.SPM.kakaoSDKCommon,
.SPM.kakaoSDKAuth,
.SPM.kakaoSDKUser
.SPM.kakaoSDKUser,
.SPM.composableArchitecture
],
sources: ["Sources/**"],
resources: ["Resources/**"],
Expand Down
36 changes: 16 additions & 20 deletions Projects/App/Sources/Application/BangawoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,36 @@ import SwiftUI
import ComposableArchitecture
import CoreDependencies
import Presentation
import Utill
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import Utill

@preconcurrency import KakaoMapsSDK


@main
struct BangawoApp: App {
private let store = Store(initialState: RootFeature.State()) {
RootFeature()
}

init() {
if let appKey = Bundle.main.infoDictionary?["KAKAO_APP_KEY"] as? String, !appKey.isEmpty {
SDKInitializer.InitSDK(appKey: appKey, phase: .real) // 카카오 지도 SDK 초기화
let appKey = AppEnvironment.kakaoAppKey
SDKInitializer.InitSDK(appKey: appKey, phase: .real)
KakaoSDK.initSDK(appKey: appKey)

KakaoSDK.initSDK(appKey: appKey)// 카카오 로그인/공유 SDK 초기화
Log.debug("👤 [Kakao] Login SDK 초기화 완료")
} else {
Log.debug("⚠️ [Kakao] Error: Info.plist에서 'KAKAO_APP_KEY'를 찾을 수 없거나 비어 있습니다.")
prepareDependencies {
$0.searchStationsClient = SearchStationsFactory.makeClient()
$0.socialAuthClient = AuthFactory.makeSocialAuthClient()
}
}

var body: some Scene {
WindowGroup {
LoginView( // 앱 시작점 임의로 로그인 뷰
store: Store(initialState: LoginFeature.State()) { // store 주입
LoginFeature()
} withDependencies: {
$0.socialAuthClient = AuthFactory.makeSocialAuthClient()
}
).onOpenURL(perform: { url in
if (AuthApi.isKakaoTalkLoginUrl(url)) { // 카카오 로그인 처리를 정상적으로 완료
AuthController.handleOpenUrl(url: url)
RootView(store: store)
.onOpenURL { url in
if AuthApi.isKakaoTalkLoginUrl(url) {
AuthController.handleOpenUrl(url: url)
}
}
})
}
}
}
15 changes: 0 additions & 15 deletions Projects/App/Sources/ContentView.swift

This file was deleted.

18 changes: 18 additions & 0 deletions Projects/App/Sources/Factory/SearchStationsFactory.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// SearchStationsFactory.swift
// App
//
// Repository → UseCase → TCA Client을 조립하는 Composition Root
//

import CoreDependencies
import DataUseCase
import Repository

enum SearchStationsFactory {
static func makeClient() -> SearchStationsClient {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

중요한건 아닌데, 해당 네이밍도 컨벤션을 맞추면 좋을것 같아요.
현재 makeClient는 너무 포괄적이니, 도메인을 포함한 네이밍은 어떠신가요? 예를들면 makeSearchStationsClient 처럼요.

Copy link
Copy Markdown
Collaborator Author

@khyeji98 khyeji98 May 6, 2026

Choose a reason for hiding this comment

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

Factory 객체 네이밍 자체가 특정 Client를 지칭하고 있어서 호출시 네이밍이 중복되는 것 같기도 해요..!
만약 제안해주신 방향대로 한다면, 공통 팩토리에서 각 Client 생성메서드에 따라 네이밍을 설정하는 것이 좋지 않을까용?

let repository = LocationSearchRepositoryImpl()
let useCase = SearchStationsUseCaseImpl(repository: repository)
return .live(useCase: useCase)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import DependencyPackagePlugin

let project = Project.makeModule(
name: "CoreDependencies",
bundleId: .appBundleID(name: ".Dependencies"),
bundleId: .appBundleID(name: ".CoreDependencies"),
product: .staticFramework,
settings: .settings(),
dependencies: [
.Domain(implements: .Entity),
.Domain(implements: .DomainInterface),
.Domain(implements: .UseCase),
.SPM.composableArchitecture
.SPM.composableArchitecture,
],
sources: ["Sources/**"],
hasTests: false
Expand Down
6 changes: 6 additions & 0 deletions Projects/Core/CoreDependencies/Sources/Base.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//
// Base.swift
// CoreDependencies
//

import Foundation
38 changes: 38 additions & 0 deletions Projects/Core/CoreDependencies/Sources/SearchStationsClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// SearchStationsClient.swift
// CoreDependencies
//
// Kakao Local 키워드 검색을 Feature에 노출하는 TCA struct-based client
//

import ComposableArchitecture
import Entity
import Foundation
import UseCase

@DependencyClient
public struct SearchStationsClient: Sendable {
public var searchStations: @Sendable (_ keyword: String) async throws -> [Station]
}

public extension SearchStationsClient {
static func live(useCase: SearchStationsUseCase) -> Self {
Self(
searchStations: { keyword in
try await useCase.execute(keyword: keyword)
}
)
}
}

extension SearchStationsClient: DependencyKey {
public static let liveValue: SearchStationsClient = SearchStationsClient()
public static let testValue: SearchStationsClient = SearchStationsClient()
}

public extension DependencyValues {
var searchStationsClient: SearchStationsClient {
get { self[SearchStationsClient.self] }
set { self[SearchStationsClient.self] = newValue }
}
}
1 change: 1 addition & 0 deletions Projects/Data/API/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ let project = Project.makeModule(
settings: .settings(),
dependencies: [
.Network(implements: .Foundations),
.Shared(implements: .Utill),
.Data(implements: .Model)
],
sources: ["Sources/**"],
Expand Down
Loading
Loading