♻️ :: (#441) 모집의뢰서 필터 Repository/UseCase 기반 수정#442
Conversation
Flow가 네비게이션 스택에서 ViewController를 찾아 Reactor에 직접 이벤트를 주입하던 구조(클린아키텍처 위배)를 제거하고, 필터를 Repository/UseCase 경계로 옮겨 저장/로드하도록 리팩터링. - RecruitmentFilterEntity/Repository/Save·LoadUseCase 추가 (Domain) - RecruitmentFilterDTO/LocalDataSource(UserDefaults)/RepositoryImpl 추가 (Data) - 적용 시 Repository에 저장, 화면 노출 시 UseCase로 로드(viewWillAppear 변경 감지) - RecruitmentFilterStep payload 제거, Flow는 순수 pop만 수행 - 모집의뢰서/체험형현장실습 필터 공유, dead code(updateFilterOptions) 제거 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Walkthrough채용 필터 상태를 Changes채용 필터 퍼시스턴스 아키텍처
Sequence Diagram(s)sequenceDiagram
rect rgba(173, 216, 230, 0.5)
Note over RecruitmentFilterReactor,SaveRecruitmentFilterUseCase: 필터 적용 흐름
end
participant RFC as RecruitmentFilterReactor
participant SaveUC as SaveRecruitmentFilterUseCase
participant Repo as RecruitmentFilterRepositoryImpl
participant DS as LocalRecruitmentFilterDataSourceImpl
participant UD as UserDefaults
participant Flow as RecruitmentFilterFlow
RFC->>RFC: filterApplyButtonDidTap → build RecruitmentFilterEntity
RFC->>SaveUC: execute(filter:)
SaveUC->>Repo: saveRecruitmentFilter(filter)
Repo->>DS: saveFilter(filter)
DS->>UD: JSONEncoder → set(data, forKey:)
RFC->>Flow: steps.accept(.popToRecruitment)
Flow->>Flow: navigationController.popViewController
rect rgba(144, 238, 144, 0.5)
Note over RecruitmentReactor,FetchRecruitmentFilterUseCase: 화면 복귀 후 필터 로드 흐름
end
participant RRC as RecruitmentReactor
participant FetchUC as FetchRecruitmentFilterUseCase
RRC->>RRC: viewWillAppear
RRC->>FetchUC: execute()
FetchUC->>Repo: fetchRecruitmentFilter()
Repo->>DS: fetchFilter()
DS->>UD: data(forKey:) → JSONDecoder → toDomain()
DS-->>FetchUC: RecruitmentFilterEntity
FetchUC-->>RRC: RecruitmentFilterEntity
RRC->>RRC: fetchListMutations(filter:) → setFilterOptions + fetchRecruitmentList
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
Projects/Presentation/Sources/Recruitment/RecruitmentViewController.swift (2)
204-204:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win린팅 위반: 라인 길이를 130자 이하로 줄이세요.
현재 140자로 프로젝트 제한(130자)을 초과합니다. 파라미터를 여러 줄로 분리하거나 메서드 이름을 줄여주세요.
제안하는 수정 예시
- public func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) -> ReusableCellIdentifier { + public func collectionSkeletonView( + _ skeletonView: UITableView, + cellIdentifierForRowAt indexPath: IndexPath + ) -> ReusableCellIdentifier {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Projects/Presentation/Sources/Recruitment/RecruitmentViewController.swift` at line 204, The method signature collectionSkeletonView(_:cellIdentifierForRowAt:) exceeds the 130-char line limit; break the declaration across multiple lines to wrap parameters (e.g., place the first parameter on its own line and the second parameter on the next line) or shorten the method name if appropriate so the full signature for public func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt indexPath: IndexPath) fits under 130 characters while preserving the same parameter types and access level.
173-173:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win린팅 위반: 세로 공백을 제거하세요.
파이프라인에서 감지한 대로 연속된 빈 줄이 2개 있습니다. 1개로 줄여주세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Projects/Presentation/Sources/Recruitment/RecruitmentViewController.swift` at line 173, There are two consecutive blank lines detected in RecruitmentViewController.swift (around the RecruitmentViewController class near the area flagged ~line 173); remove one of the blank lines so there is only a single empty line between the surrounding code blocks (e.g., between the preceding and following methods/properties) to satisfy the linter.
🧹 Nitpick comments (3)
Projects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swift (1)
15-18: ⚡ Quick win인코딩 실패를 로깅하는 것을 권장합니다.
현재 인코딩 실패 시 조용히 반환하여 저장이 실패했는지 확인할 방법이 없습니다. 디버깅을 위해 최소한 로그를 남기는 것이 좋습니다.
📝 개선안
public func saveFilter(_ filter: RecruitmentFilterEntity) { - guard let data = try? JSONEncoder().encode(RecruitmentFilterDTO(entity: filter)) else { return } + guard let data = try? JSONEncoder().encode(RecruitmentFilterDTO(entity: filter)) else { + print("⚠️ Failed to encode RecruitmentFilterEntity") + return + } userDefaults.set(data, forKey: key) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Projects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swift` around lines 15 - 18, The saveFilter(_:) method in RecruitmentFilterLocal silently returns when JSONEncoder().encode(RecruitmentFilterDTO(entity: filter)) fails; modify saveFilter(_:) to catch the encoding error instead of using try? and log the failure (including the error and the RecruitmentFilterDTO or filter identifier) before returning so callers and debuggers can see why the save failed; update the code around RecruitmentFilterDTO(entity: filter), JSONEncoder(), and userDefaults.set(..., forKey: key) to handle and log the thrown error (using your app's Logger/print/os_log) while keeping the current behavior of not crashing.Projects/Domain/Sources/UseCases/Recruitments/SaveRecruitmentFilterUseCase.swift (1)
1-11: ⚡ Quick win프로퍼티 선언 위치를 init 앞으로 이동하세요.
LoadRecruitmentFilterUseCase와 동일하게, Line 6의recruitmentFilterRepository프로퍼티가 Lines 2-4의 init 메서드 뒤에 선언되어 있습니다. Swift 컨벤션에 따라 프로퍼티를 init 앞에 선언해 주세요.♻️ 제안하는 프로퍼티 순서 수정
public struct SaveRecruitmentFilterUseCase { + private let recruitmentFilterRepository: RecruitmentFilterRepository + public init(recruitmentFilterRepository: RecruitmentFilterRepository) { self.recruitmentFilterRepository = recruitmentFilterRepository } - private let recruitmentFilterRepository: RecruitmentFilterRepository - public func execute(filter: RecruitmentFilterEntity) { recruitmentFilterRepository.saveRecruitmentFilter(filter) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Projects/Domain/Sources/UseCases/Recruitments/SaveRecruitmentFilterUseCase.swift` around lines 1 - 11, Move the private property declaration for recruitmentFilterRepository so it appears before the init in the SaveRecruitmentFilterUseCase struct (match the ordering used in LoadRecruitmentFilterUseCase); specifically, declare private let recruitmentFilterRepository: RecruitmentFilterRepository above the public init(recruitmentFilterRepository: RecruitmentFilterRepository) initializer and keep the execute(filter:) method unchanged.Projects/Domain/Sources/UseCases/Recruitments/LoadRecruitmentFilterUseCase.swift (1)
1-11: ⚡ Quick win프로퍼티 선언 위치를 init 앞으로 이동하세요.
Swift 코딩 컨벤션에 따르면 프로퍼티는 일반적으로 init 메서드보다 앞에 선언됩니다. 현재 Line 6의
recruitmentFilterRepository프로퍼티가 Lines 2-4의 init 메서드 뒤에 선언되어 있어 일반적인 구조와 다릅니다.♻️ 제안하는 프로퍼티 순서 수정
public struct LoadRecruitmentFilterUseCase { + private let recruitmentFilterRepository: RecruitmentFilterRepository + public init(recruitmentFilterRepository: RecruitmentFilterRepository) { self.recruitmentFilterRepository = recruitmentFilterRepository } - private let recruitmentFilterRepository: RecruitmentFilterRepository - public func execute() -> RecruitmentFilterEntity { recruitmentFilterRepository.fetchRecruitmentFilter() }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Projects/Domain/Sources/UseCases/Recruitments/LoadRecruitmentFilterUseCase.swift` around lines 1 - 11, Move the property declaration for recruitmentFilterRepository to appear before the init within the LoadRecruitmentFilterUseCase struct: locate the private let recruitmentFilterRepository: RecruitmentFilterRepository declaration and place it above public init(recruitmentFilterRepository: RecruitmentFilterRepository) so properties are declared before initializers; leave execute() and other logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Projects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swift`:
- Line 4: 프로토콜 LocalRecruitmentFilterDataSource의 접근 수준을 public으로 변경하세요: 파일 내
protocol 선언을 internal에서 public으로 바꾸고, 필요하다면 해당 프로토콜이 선언한 모든 메서드/프로퍼티 시그니처도
public으로 노출하여 구현체 LocalRecruitmentFilterDataSourceImpl 및 RepositoryAssembly에서
정상적으로 resolve될 수 있게 만드세요.
- Line 10: The property userDefaults is being instantiated inline
(UserDefaults.standard) — change LocalRecruitmentFilterDataSourceImpl (or the
type in RecruitmentFilterLocal.swift) to accept a UserDefaults instance via its
initializer and store it as a dependency instead of creating it inside the
class; then register and inject the dependency from DataSourceAssembly (e.g.,
container.register(...){ _ in LocalRecruitmentFilterDataSourceImpl(userDefaults:
.standard) }) so tests can provide a mock UserDefaults.
In `@Projects/Domain/Sources/Repositories/RecruitmentFilterRepository.swift`:
- Around line 1-4: Update the RecruitmentFilterRepository protocol to use
Rx-style reactive return types: change saveRecruitmentFilter(_ filter:
RecruitmentFilterEntity) to return a Completable (or equivalent reactive void)
and change fetchRecruitmentFilter() to return Single<RecruitmentFilterEntity>;
locate these members on the RecruitmentFilterRepository protocol and adjust any
conforming implementations and imports (e.g., RxSwift) to return the reactive
types so callers and UseCases remain consistent with the project's
Single/Completable conventions.
In `@Projects/Presentation/Sources/Recruitment/RecruitmentReactor.swift`:
- Around line 148-176: fetchListMutations is missing error handling so a network
failure from fetchRecruitmentListUseCase.execute(...) can leave loading stuck;
update fetchListMutations to mirror updateSortOption by adding a catch (or
catchError) on the execute() observable that returns .just(.setLoading(false))
(or a concat of .setLoading(false) and an optional error mutation) so that
.setLoading(false) is always emitted on failure after the
.setRecruitmentList/.setLoading(false) success path; reference
fetchListMutations and fetchRecruitmentListUseCase.execute(...) when making the
change.
---
Outside diff comments:
In `@Projects/Presentation/Sources/Recruitment/RecruitmentViewController.swift`:
- Line 204: The method signature
collectionSkeletonView(_:cellIdentifierForRowAt:) exceeds the 130-char line
limit; break the declaration across multiple lines to wrap parameters (e.g.,
place the first parameter on its own line and the second parameter on the next
line) or shorten the method name if appropriate so the full signature for public
func collectionSkeletonView(_ skeletonView: UITableView, cellIdentifierForRowAt
indexPath: IndexPath) fits under 130 characters while preserving the same
parameter types and access level.
- Line 173: There are two consecutive blank lines detected in
RecruitmentViewController.swift (around the RecruitmentViewController class near
the area flagged ~line 173); remove one of the blank lines so there is only a
single empty line between the surrounding code blocks (e.g., between the
preceding and following methods/properties) to satisfy the linter.
---
Nitpick comments:
In `@Projects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swift`:
- Around line 15-18: The saveFilter(_:) method in RecruitmentFilterLocal
silently returns when JSONEncoder().encode(RecruitmentFilterDTO(entity: filter))
fails; modify saveFilter(_:) to catch the encoding error instead of using try?
and log the failure (including the error and the RecruitmentFilterDTO or filter
identifier) before returning so callers and debuggers can see why the save
failed; update the code around RecruitmentFilterDTO(entity: filter),
JSONEncoder(), and userDefaults.set(..., forKey: key) to handle and log the
thrown error (using your app's Logger/print/os_log) while keeping the current
behavior of not crashing.
In
`@Projects/Domain/Sources/UseCases/Recruitments/LoadRecruitmentFilterUseCase.swift`:
- Around line 1-11: Move the property declaration for
recruitmentFilterRepository to appear before the init within the
LoadRecruitmentFilterUseCase struct: locate the private let
recruitmentFilterRepository: RecruitmentFilterRepository declaration and place
it above public init(recruitmentFilterRepository: RecruitmentFilterRepository)
so properties are declared before initializers; leave execute() and other logic
unchanged.
In
`@Projects/Domain/Sources/UseCases/Recruitments/SaveRecruitmentFilterUseCase.swift`:
- Around line 1-11: Move the private property declaration for
recruitmentFilterRepository so it appears before the init in the
SaveRecruitmentFilterUseCase struct (match the ordering used in
LoadRecruitmentFilterUseCase); specifically, declare private let
recruitmentFilterRepository: RecruitmentFilterRepository above the public
init(recruitmentFilterRepository: RecruitmentFilterRepository) initializer and
keep the execute(filter:) method unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c1b9df61-5d26-49d3-ba8d-f83d66ed7459
📒 Files selected for processing (17)
Projects/Core/Sources/Steps/RecruitmentFilterStep.swiftProjects/Data/Sources/DI/DataSourceAssembly.swiftProjects/Data/Sources/DI/RepositoryAssembly.swiftProjects/Data/Sources/DI/UseCaseAssembly.swiftProjects/Data/Sources/DTO/Recruitments/RecruitmentFilterDTO.swiftProjects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swiftProjects/Data/Sources/Repositories/RecruitmentFilterRepositoryImpl.swiftProjects/Domain/Sources/Entities/Recruitments/RecruitmentFilterEntity.swiftProjects/Domain/Sources/Repositories/RecruitmentFilterRepository.swiftProjects/Domain/Sources/UseCases/Recruitments/LoadRecruitmentFilterUseCase.swiftProjects/Domain/Sources/UseCases/Recruitments/SaveRecruitmentFilterUseCase.swiftProjects/Flow/Sources/Recruitment/RecruitmentFilterFlow.swiftProjects/Presentation/Sources/DI/Assembly/MainPresentationAssembly.swiftProjects/Presentation/Sources/Recruitment/RecruitmentReactor.swiftProjects/Presentation/Sources/Recruitment/RecruitmentViewController.swiftProjects/Presentation/Sources/RecruitmentFilter/RecruitmentFilterReactor.swiftProjects/Presentation/Sources/WinterIntern/WinterInternReactor.swift
| import Foundation | ||
| import Domain | ||
|
|
||
| protocol LocalRecruitmentFilterDataSource { |
There was a problem hiding this comment.
Protocol 접근 레벨을 public으로 변경하세요.
구현체 LocalRecruitmentFilterDataSourceImpl은 public인데 protocol은 internal입니다. RepositoryAssembly에서 이 타입을 resolve하려면 protocol도 public이어야 합니다.
🔧 수정안
-protocol LocalRecruitmentFilterDataSource {
+public protocol LocalRecruitmentFilterDataSource {
func saveFilter(_ filter: RecruitmentFilterEntity)
func fetchFilter() -> RecruitmentFilterEntity
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Projects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swift` at line
4, 프로토콜 LocalRecruitmentFilterDataSource의 접근 수준을 public으로 변경하세요: 파일 내 protocol
선언을 internal에서 public으로 바꾸고, 필요하다면 해당 프로토콜이 선언한 모든 메서드/프로퍼티 시그니처도 public으로 노출하여
구현체 LocalRecruitmentFilterDataSourceImpl 및 RepositoryAssembly에서 정상적으로 resolve될 수
있게 만드세요.
| } | ||
|
|
||
| public struct LocalRecruitmentFilterDataSourceImpl: LocalRecruitmentFilterDataSource { | ||
| private let userDefaults = UserDefaults.standard |
There was a problem hiding this comment.
UserDefaults를 직접 생성하지 말고 생성자를 통해 주입하세요.
코딩 가이드라인에 따르면 모든 의존성은 Assembly 클래스에서 등록하고 Container를 통해 주입해야 하며, inline으로 생성하지 말아야 합니다. UserDefaults.standard를 프로퍼티에서 직접 생성하면 테스트 시 목(mock) 객체로 대체할 수 없습니다.
🛠️ 권장 수정안
public struct LocalRecruitmentFilterDataSourceImpl: LocalRecruitmentFilterDataSource {
- private let userDefaults = UserDefaults.standard
+ private let userDefaults: UserDefaults
private let key = "RECRUITMENT_FILTER"
- public init() {}
+ public init(userDefaults: UserDefaults = .standard) {
+ self.userDefaults = userDefaults
+ }그리고 DataSourceAssembly.swift에서 다음과 같이 등록:
container.register(LocalRecruitmentFilterDataSource.self) { _ in
LocalRecruitmentFilterDataSourceImpl(userDefaults: .standard)
}As per coding guidelines: Register all dependencies in Assembly classes and inject through Container, do not create dependencies inline
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Projects/Data/Sources/DataSource/Local/RecruitmentFilterLocal.swift` at line
10, The property userDefaults is being instantiated inline
(UserDefaults.standard) — change LocalRecruitmentFilterDataSourceImpl (or the
type in RecruitmentFilterLocal.swift) to accept a UserDefaults instance via its
initializer and store it as a dependency instead of creating it inside the
class; then register and inject the dependency from DataSourceAssembly (e.g.,
container.register(...){ _ in LocalRecruitmentFilterDataSourceImpl(userDefaults:
.standard) }) so tests can provide a mock UserDefaults.
| public protocol RecruitmentFilterRepository { | ||
| func saveRecruitmentFilter(_ filter: RecruitmentFilterEntity) | ||
| func fetchRecruitmentFilter() -> RecruitmentFilterEntity | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: 프로젝트 내 다른 Repository 프로토콜의 메서드 시그니처 패턴 확인
# Test: Repository 프로토콜들의 메서드 반환 타입 조사
rg -n -A 2 'protocol.*Repository' --type swift Projects/Domain/Sources/Repositories/Repository: Team-return/JOBIS-DSM-iOS-v2
Length of output: 6544
Repository 동기 시그니처를 Rx 패턴(Single/Completable)으로 맞추세요
RecruitmentFilterRepository의 saveRecruitmentFilter(void) / fetchRecruitmentFilter(동기 Entity 반환)가 프로젝트의 다른 Repository 프로토콜들과 불일치합니다. (예: 대부분 Single<...> / Completable 반환)
saveRecruitmentFilter는Completable(또는 동일 의미의 반응형 반환)fetchRecruitmentFilter는Single<RecruitmentFilterEntity>로 변경해 UseCase의 sync/async 동작 컨벤션과 일관성을 확보하고, 향후 UserDefaults 외 네트워크/DB 확장 시에도 API 전환 비용을 줄이세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Projects/Domain/Sources/Repositories/RecruitmentFilterRepository.swift`
around lines 1 - 4, Update the RecruitmentFilterRepository protocol to use
Rx-style reactive return types: change saveRecruitmentFilter(_ filter:
RecruitmentFilterEntity) to return a Completable (or equivalent reactive void)
and change fetchRecruitmentFilter() to return Single<RecruitmentFilterEntity>;
locate these members on the RecruitmentFilterRepository protocol and adjust any
conforming implementations and imports (e.g., RxSwift) to return the reactive
types so callers and UseCases remain consistent with the project's
Single/Completable conventions.
| private func fetchListMutations(filter: RecruitmentFilterEntity) -> Observable<Mutation> { | ||
| return .concat([ | ||
| .just(.setFilterOptions( | ||
| jobCode: filter.jobCode, | ||
| techCode: filter.techCode, | ||
| years: filter.years, | ||
| region: filter.region, | ||
| status: filter.status | ||
| )), | ||
| .just(.resetPageCount), | ||
| .just(.setLoading(true)), | ||
| fetchRecruitmentListUseCase.execute( | ||
| page: 1, | ||
| jobCode: filter.jobCode, | ||
| techCode: filter.techCode, | ||
| years: filter.years, | ||
| region: filter.region, | ||
| status: filter.status, | ||
| sortType: currentState.sortType?.rawValue | ||
| ) | ||
| .asObservable() | ||
| .flatMap { list -> Observable<Mutation> in | ||
| .concat([ | ||
| .just(.setRecruitmentList(list)), | ||
| .just(.setLoading(false)) | ||
| ]) | ||
| } | ||
| ]) | ||
| } |
There was a problem hiding this comment.
fetchListMutations에 에러 핸들링 누락으로 로딩 상태가 stuck될 수 있습니다.
fetchRecruitmentListUseCase.execute() 호출 시 네트워크 오류가 발생하면 .setLoading(false) mutation이 방출되지 않아 UI가 로딩 상태에 고정됩니다. 동일 파일 내 updateSortOption (line 143)에서는 .catch { _ in .just(.setLoading(false)) }로 처리하고 있습니다.
🐛 에러 핸들링 추가 제안
fetchRecruitmentListUseCase.execute(
page: 1,
jobCode: filter.jobCode,
techCode: filter.techCode,
years: filter.years,
region: filter.region,
status: filter.status,
sortType: currentState.sortType?.rawValue
)
.asObservable()
.flatMap { list -> Observable<Mutation> in
.concat([
.just(.setRecruitmentList(list)),
.just(.setLoading(false))
])
}
+ .catch { _ in .just(.setLoading(false)) }
])
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Projects/Presentation/Sources/Recruitment/RecruitmentReactor.swift` around
lines 148 - 176, fetchListMutations is missing error handling so a network
failure from fetchRecruitmentListUseCase.execute(...) can leave loading stuck;
update fetchListMutations to mirror updateSortOption by adding a catch (or
catchError) on the execute() observable that returns .just(.setLoading(false))
(or a concat of .setLoading(false) and an optional error mutation) so that
.setLoading(false) is always emitted on failure after the
.setRecruitmentList/.setLoading(false) success path; reference
fetchListMutations and fetchRecruitmentListUseCase.execute(...) when making the
change.
.xcworkspace의 macOS 기본 실행 앱이 VSCode로 등록되어 있고, Xcode/Xcode-beta가 동일 bundle identifier(com.apple.dt.Xcode)를 공유해 시스템 기본앱 설정만으로는 구분이 안 됨. tuist generate --no-open 후 Xcode-beta 경로를 명시적으로 open하도록 변경. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ase로 리네임 프로젝트의 읽기 UseCase는 전부 Fetch* 접두사를 쓰는데(FetchRecruitmentListUseCase, FetchCodeListUseCase 등) 새로 추가된 필터 조회 UseCase만 Load*였음. 네이밍 컨벤션 일관성을 위해 Fetch*로 통일. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Core/Steps와 Presentation/CompanyDetail에 동일한 이름의 public enum이 각각 선언되어 있어 Core+Presentation을 동시에 import하는 Flow 타겟에서 'CompanyDetailPreviousViewType' is ambiguous for type lookup 에러 발생. 과거 (#421) PreviousViewType enum을 Core로 옮기면서 Presentation 쪽 파일을 삭제하지 않고 남겨둔 게 원인. Presentation 쪽엔 있던 home 케이스가 Core 쪽엔 빠져있어서 Core 버전에 추가하고 Presentation 중복 파일을 삭제. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Xcode 27 beta가 최소 배포 타겟을 15.0으로 올리면서, 그보다 낮은 배포 타겟을 선언한 서드파티 SPM 의존성(Alamofire, RxSwift, Moya, Lottie 등) 전체에서 빌드가 깨지는 문제. Package.swift 설정으로 override 가능할 거라 가정했으나 실제로는 Tuist 자체의 버그였음(tuist/tuist#11163, PR #11169로 수정, 4.198.0부터 정상화). 기존 핀 버전(4.119.2)이 그보다 훨씬 오래돼 버그를 그대로 갖고 있어 4.200.5로 업그레이드. tuist install && tuist generate 재생성 정상 완료, 일반 Xcode 빌드도 회귀 없이 BUILD SUCCEEDED 확인. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentFilterUseCase.swift (1)
1-11:⚠️ Potential issue | 🟠 Major
execute()메서드의 반환 타입을 프로젝트 컨벤션에 맞춰Single<RecruitmentFilterEntity>로 변경하세요.프로젝트의 모든 Fetch*UseCase(예:
FetchStudentInfoUseCase,FetchRecruitmentDetailUseCase,FetchCodeListUseCase,FetchNotificationListUseCase등)는 RxSwift의Single<T>또는Completable을 반환합니다.FetchRecruitmentFilterUseCase만 동기적으로 직접RecruitmentFilterEntity를 반환하고 있어 불일치합니다. UserDefaults 기반이므로 동기 처리이더라도Single로 래핑하여 프로젝트의 표준 반응형 패턴을 준수해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentFilterUseCase.swift` around lines 1 - 11, The execute() method in FetchRecruitmentFilterUseCase currently returns RecruitmentFilterEntity directly, but it should return Single<RecruitmentFilterEntity> to match the project's RxSwift reactive pattern convention used by other Fetch*UseCase classes. Change the return type of the execute() method from RecruitmentFilterEntity to Single<RecruitmentFilterEntity>, and wrap the result from recruitmentFilterRepository.fetchRecruitmentFilter() in a Single.just() call to conform to the project's standard reactive return pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Makefile`:
- Around line 3-4: Replace the hardcoded Xcode-beta path in the Makefile with a
configurable environment variable approach. Define an XCODE_APP variable that
accepts environment variable input with a sensible default (the standard Xcode
installation path), then modify the open command to use this variable. Add a
check to verify the specified Xcode application path exists before attempting to
open it, and provide a clear error message if the path cannot be found, allowing
developers to override the path by setting XCODE_APP environment variable when
running make generate.
---
Outside diff comments:
In
`@Projects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentFilterUseCase.swift`:
- Around line 1-11: The execute() method in FetchRecruitmentFilterUseCase
currently returns RecruitmentFilterEntity directly, but it should return
Single<RecruitmentFilterEntity> to match the project's RxSwift reactive pattern
convention used by other Fetch*UseCase classes. Change the return type of the
execute() method from RecruitmentFilterEntity to
Single<RecruitmentFilterEntity>, and wrap the result from
recruitmentFilterRepository.fetchRecruitmentFilter() in a Single.just() call to
conform to the project's standard reactive return pattern.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 54adf0ca-1399-4cbf-9666-913ec1472072
📒 Files selected for processing (9)
.mise.tomlMakefileProjects/Core/Sources/Steps/CompanyDetailPreviousViewType.swiftProjects/Data/Sources/DI/UseCaseAssembly.swiftProjects/Domain/Sources/UseCases/Recruitments/FetchRecruitmentFilterUseCase.swiftProjects/Presentation/Sources/CompanyDetail/CompanyDetailPreviousViewType.swiftProjects/Presentation/Sources/DI/Assembly/MainPresentationAssembly.swiftProjects/Presentation/Sources/Recruitment/RecruitmentReactor.swiftProjects/Presentation/Sources/WinterIntern/WinterInternReactor.swift
💤 Files with no reviewable changes (1)
- Projects/Presentation/Sources/CompanyDetail/CompanyDetailPreviousViewType.swift
✅ Files skipped from review due to trivial changes (1)
- .mise.toml
🚧 Files skipped from review as they are similar to previous changes (4)
- Projects/Data/Sources/DI/UseCaseAssembly.swift
- Projects/Presentation/Sources/DI/Assembly/MainPresentationAssembly.swift
- Projects/Presentation/Sources/WinterIntern/WinterInternReactor.swift
- Projects/Presentation/Sources/Recruitment/RecruitmentReactor.swift
| tuist generate --no-open | ||
| open -a /Applications/Xcode-beta.app *.xcworkspace |
There was a problem hiding this comment.
Xcode-beta 경로 하드코딩이 팀 전체의 개발 환경을 제약합니다.
/Applications/Xcode-beta.app 경로가 하드코딩되어 있어 다음 문제가 발생할 수 있습니다:
- Xcode-beta가 설치되지 않은 팀원의
make generate실패 - 안정 버전 Xcode를 사용하려는 팀원의 선택권 제한
- CI/CD 환경에서 예상치 못한 실패 가능성
- 오류 발생 시 명확한 피드백 부재
환경 변수를 통해 Xcode 경로를 설정하거나, 경로 존재 여부를 확인한 후 폴백하는 방식으로 개선하는 것을 권장합니다.
🔧 설정 가능한 Xcode 경로 개선안
+XCODE_APP ?= /Applications/Xcode.app
+
generate:
tuist install
tuist generate --no-open
- open -a /Applications/Xcode-beta.app *.xcworkspace
+ `@if` [ -d "$(XCODE_APP)" ]; then \
+ open -a "$(XCODE_APP)" *.xcworkspace; \
+ else \
+ echo "Error: Xcode not found at $(XCODE_APP)"; \
+ echo "Set XCODE_APP environment variable to your Xcode path"; \
+ exit 1; \
+ fi사용 예시:
# 기본 Xcode 사용
make generate
# Xcode-beta 사용
XCODE_APP=/Applications/Xcode-beta.app make generate📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| tuist generate --no-open | |
| open -a /Applications/Xcode-beta.app *.xcworkspace | |
| XCODE_APP ?= /Applications/Xcode.app | |
| generate: | |
| tuist install | |
| tuist generate --no-open | |
| `@if` [ -d "$(XCODE_APP)" ]; then \ | |
| open -a "$(XCODE_APP)" *.xcworkspace; \ | |
| else \ | |
| echo "Error: Xcode not found at $(XCODE_APP)"; \ | |
| echo "Set XCODE_APP environment variable to your Xcode path"; \ | |
| exit 1; \ | |
| fi |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Makefile` around lines 3 - 4, Replace the hardcoded Xcode-beta path in the
Makefile with a configurable environment variable approach. Define an XCODE_APP
variable that accepts environment variable input with a sensible default (the
standard Xcode installation path), then modify the open command to use this
variable. Add a check to verify the specified Xcode application path exists
before attempting to open it, and provide a clear error message if the path
cannot be found, allowing developers to override the path by setting XCODE_APP
environment variable when running make generate.
개요
문제 사항
RecruitmentFilterStep.popToRecruitment(jobCode:techCode:...)라는 payload를 가진 Step으로 필터값이 네비게이션 계층을 타고 흐름RecruitmentFilterFlow가 네비게이션 스택에서RecruitmentViewController/WinterInternViewController를 직접 찾아reactor.action.onNext(.updateFilterOptions(...))로 Presentation Reactor 내부에 직접 이벤트를 주입작업사항
RecruitmentFilterEntity)로 만들고 Repository/UseCase 경계를 통해 저장/로드확인 및 결정 필요한사항
프로젝트 규칙있다면 비동기로 통일 or 동기 선택 필요
Summary by CodeRabbit
릴리스 노트
New Features
Chores