Skip to content

Comments

Feat/#91 challengeviewapi#110

Closed
sum130 wants to merge 62 commits intodevelopfrom
feat/#91-challengeviewapi
Closed

Feat/#91 challengeviewapi#110
sum130 wants to merge 62 commits intodevelopfrom
feat/#91-challengeviewapi

Conversation

@sum130
Copy link
Contributor

@sum130 sum130 commented Jan 19, 2026

No description provided.

@sum130 sum130 linked an issue Jan 19, 2026 that may be closed by this pull request
2 tasks
@sum130 sum130 requested review from a team, soseoyo12, wotjs020708 and y-eonee and removed request for a team January 19, 2026 15:37
@coderabbitai
Copy link

coderabbitai bot commented Jan 19, 2026

📝 Walkthrough

Walkthrough

프로젝트 공통 xcconfig를 연결하고, 챌린지 및 시술(Treatment) 도메인·DTO·엔드포인트·레포지토리·유스케이스·DI를 추가/조정해 SelectRoutine과 캘린더/시술 관련 뷰·뷰모델을 리포지토리/유스케이스 기반으로 리팩터링하고 여러 뷰의 레이아웃을 정리했습니다.

Changes

Cohort / File(s) Summary
프로젝트 구성
Cherrish-iOS/Cherrish-iOS.xcodeproj/project.pbxproj, Cherrish-iOS/Cherrish-iOS/Core/Config.xcconfig
Debug/Release XCBuildConfiguration에 baseConfigurationReferenceAnchor/baseConfigurationReferenceRelativePath 추가; Core/Config.xcconfig 추가 및 BASE_URL 정의
챌린지 도메인 & API
Cherrish-iOS/Cherrish-iOS/Domain/Interface/ChallengeInterface.swift, Cherrish-iOS/Cherrish-iOS/Domain/Model/RoutineEntity.swift, Cherrish-iOS/Cherrish-iOS/Data/Model/ChallengeRoutineDTO.swift, Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/ChallengeAPI.swift
ChallengeInterface 프로토콜과 RoutineEntity 추가; ChallengeRoutineDTO + toEntity() 추가; ChallengeAPI 엔드포인트(.homecareRoutines) 추가
챌린지 리포지토리 / DI
Cherrish-iOS/Cherrish-iOS/Data/Repository/ChallengeRepository.swift, Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift
DefaultChallengeRepository 구현(네트워크 요청 → DTO 디코드 → Entity 매핑) 추가 및 DI에 ChallengeInterface 등록; TreatmentInterfaceMockTreatmentRepository 바인딩 추가
시술(Treatment) 도메인 / DTO / 리포지토리 / 유스케이스
Cherrish-iOS/Cherrish-iOS/Domain/Interface/TreatmentInterface.swift, .../Domain/Model/TreatmentCategoryEntity.swift, .../Data/Model/TreatmentCategoryResponseDTO.swift, .../Data/Repository/TreatmentRepository.swift, .../Domain/UseCase/FetchTreatmentCategoriesUseCase.swift
TreatmentInterfaceTreatmentCategoryEntity/DTO 추가; DefaultTreatmentRepository(빈 결과) 및 MockTreatmentRepository(샘플 카테고리) 추가; FetchTreatmentCategoriesUseCase 및 구현 추가
Domain/Presentation DI 등록 & ViewFactory
Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift, Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift, Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift
Treatment 관련 UseCase DI 등록 추가; Presentation에 NoTreatmentViewModel 등록; ViewFactory에 makeNoTreatmentView()/makeTreatmentView() 등 팩토리 메서드 추가 및 일부 뷰 초기화 DI로 변경
SelectRoutine (챌린지) — ViewModel / View
.../Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectRoutineViewModel.swift, .../Presentation/Feature/ChallengeView/SelectRoutineView.swift, .../ChallengeMainViewModel.swift, .../SelectMissionViewModel.swift
SelectRoutineViewModelRoutineEntity 기반으로 전환, ChallengeInterface 주입 및 fetchRoutines() 추가; View에서 onAppear로 fetch 호출 및 UI 타입 변경; 두 파일은 헤더만 추가
캘린더 / 시술 플로우 — 모델·뷰·뷰모델 리팩터링
.../Presentation/Feature/Calendar/** (여러 파일, 하위 폴더 다수)
기존 Enum 기반 타입(Treatment/NoTreatment/TreatmentCategory 등) 제거 또는 대체하고 StepNavigatable 프로토콜 및 TreatmentStep/NoTreatmentStep 추가; 여러 뷰에서 @StateObject@ObservedObject 전환, SelectedTreatmentView → SelectedTreatmentSheetView 교체, 뷰 패딩/레이아웃 조정, NoTreatmentViewModel에 카테고리 로드/선택 로직 및 유스케이스 주입 추가
글로벌 유틸 / 프로토콜
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Model/StepNavigatable.swift
StepNavigatable 프로토콜 및 기본 구현(identifiable, isFirst/isLast, next/previous) 추가

Sequence Diagram(s)

sequenceDiagram
    participant View as SelectRoutineView
    participant VM as SelectRoutineViewModel
    participant Repo as DefaultChallengeRepository
    participant Network as NetworkService
    participant API as ChallengeAPI

    View->>VM: onAppear -> fetchRoutines()
    VM->>Repo: fetchHomecareRoutines(completion:)
    Repo->>Network: AF.request(ChallengeAPI.homecareRoutines.url)
    Network->>API: HTTP GET /api/challenges/homecare-routines
    Network-->>Repo: response (data / error)
    Repo->>Repo: decode BaseResponseDTO<[ChallengeRoutineDTO]> → map to [RoutineEntity]
    Repo-->>VM: completion(.success([RoutineEntity])) or .failure(error)
    VM->>VM: Dispatch to main thread, publish routines
    VM-->>View: UI updates via binding
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested labels

재선🐻

Suggested reviewers

  • y-eonee
  • wotjs020708
  • soseoyo12
🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 대부분의 변경사항은 #91의 범위 내에 있으나, NoTreatment/Treatment 관련 변경사항들(StepNavigatable 프로토콜, NoTreatmentStep/TreatmentStep 생성, 기존 모델 삭제, ViewModel/View 리팩토링)은 제시된 이슈 범위를 벗어납니다. NoTreatment/Treatment 관련 변경사항들을 별도 PR로 분리하거나, 해당 범위를 포함하는 이슈와 연결하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive PR 제목이 주요 변경사항(챌린지 뷰 API 연결)과 관련이 있지만, 구체성이 부족하고 'challengeviewapi'는 기술적으로 명확하지 않습니다. 제목을 '챌린지 홈케어 루틴 목록 API 연결' 또는 'Challenge homecare routines API integration'으로 변경하여 더 구체적으로 수정하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명이 변경사항과 관련이 있으며, 아키텍처 구조, 구현 내용, 스크린샷을 포함하고 있습니다.
Linked Issues check ✅ Passed PR이 #91의 두 가지 To-Do 항목(챌린지뷰 뷰모델 설정, 네트워크 연결)을 모두 충족합니다. SelectRoutineViewModel이 구현되었고, ChallengeAPI와 DefaultChallengeRepository를 통해 네트워크가 연결되었습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#91-challengeviewapi

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sum130 sum130 self-assigned this Jan 19, 2026
@sum130 sum130 added 수민🐶 Feature 새로운 기능 구현 및 API 연결 labels Jan 19, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 Fix all issues with AI agents
In `@Cherrish-iOS/Cherrish-iOS/Core/Config.xcconfig`:
- Line 11: 현재 Config.xcconfig의 BASE_URL이 하드코딩되어 있어 환경별 분리가 필요합니다; 해결하려면
Config.xcconfig에서 BASE_URL을 제거하거나 기본값만 남기고 별도의 환경별 xcconfig 파일(Debug.xcconfig,
Staging.xcconfig, Release.xcconfig)을 생성하여 각 파일에 BASE_URL 값을 설정하고 Xcode 프로젝트의
Build Configuration 또는 Scheme에 해당 xcconfig를 연결해(예: Debug → Debug.xcconfig,
Release → Release.xcconfig, 스테이징용 스킴 → Staging.xcconfig) 빌드 시 올바른 BASE_URL이
주입되도록 구성하세요; 변경 대상 식별자: BASE_URL 속성과 Config.xcconfig 및 새로 생성할
Debug.xcconfig/Staging.xcconfig/Release.xcconfig, 그리고 Xcode의 Build Settings에서의
Config 연결입니다.

In `@Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift`:
- Around line 25-28: The new DI registration for ChallengeInterface uses an
implicit return while other registrations use explicit "return"; update the
closure in DIContainer.shared.register(type: ChallengeInterface.self) to use an
explicit return (i.e., return DefaultChallengeRepository(networkService:
self.networkService)) so it matches the style of the other register closures and
keeps code consistency in DataDependencyAssembler.swift.

In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/ChallengeRepository.swift`:
- Around line 25-38: Remove the redundant parentheses around url in the
AF.request call (currently written as AF.request((url), ...)) and ensure the
request has a timeout: either build a URLRequest with timeoutInterval set and
pass it to AF.request or create an Alamofire Session with a
URLSessionConfiguration that sets
timeoutIntervalForRequest/timeoutIntervalForResource, then use that Session to
perform the same responseDecodable handling (preserving the decoded -> entities
mapping and completion(.success/entities)/completion(.failure/error) logic in
ChallengeRepository's request).
- Around line 12-18: DefaultChallengeRepository currently ignores the injected
networkService and calls AF.request directly (see AF.request usage), breaking
abstraction and making testing hard; refactor the fetch method(s) in
DefaultChallengeRepository to call the injected networkService (use its async
throws API) instead of AF.request, convert the existing
callback/completion-based method to async throws (or provide an async wrapper)
so it awaits networkService.request/performRequest, map the networkService
response into the existing Challenge model and propagate errors via throws
rather than completion, and remove direct Alamofire references from
DefaultChallengeRepository so unit tests can mock NetworkService.

In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/ChallengeInterface.swift`:
- Around line 10-13: Update the ChallengeInterface protocol to offer an
async/await API instead of a completion handler: replace the current
fetchHomecareRoutines(completion: `@escaping` (Result<[RoutineEntity], Error>) ->
Void) signature with an async throws variant so callers can use Swift
Concurrency; update any conforming types (e.g., repositories implementing
ChallengeInterface.fetchHomecareRoutines) and callers (ViewModel/unit tests) to
await the new fetchHomecareRoutines() and handle thrown errors accordingly,
ensuring RoutineEntity remains the return type and keeping compatibility only if
the project minimum deployment target is iOS 15 or newer.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/ChallengeMainViewModel.swift`:
- Around line 1-7: 이 파일(ChallengeMainViewModel.swift)이 헤더 주석만 포함한 빈 플레이스홀더로 노이즈를
유발하므로 커밋에서 제거하거나 최소한의 스켈레톤을 추가하세요: 삭제 선택 시 파일을 git에서 제거하면 되고, 추가 선택 시
ChallengeMainViewModel이라는 명시적 타입(예: final class ChallengeMainViewModel 또는 struct
ChallengeMainViewModel)과 기본 이니셜라이저와 TODO 주석(또는 // MARK: - placeholder)만 포함해 실제
구현이 준비될 때까지 빌드/타입 체크에 통과하게 만드세요.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectMissionViewModel.swift`:
- Around line 1-7: The file SelectMissionViewModel.swift currently contains only
a header comment and no implementation; remove it from the commit (or add a
minimal TODO stub/placeholder type with a clear FIXME and documentation comment)
so empty placeholder files aren't checked in — locate
SelectMissionViewModel.swift and either delete the file from the commit or
replace its header-only contents with a small, clearly marked stub (e.g., a
commented TODO and a placeholder SelectMissionViewModel declaration) until the
real implementation is ready.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectRoutineViewModel.swift`:
- Around line 38-50: Add loading and error state to SelectRoutineViewModel by
introducing `@Published` properties (e.g., isLoading: Bool and errorMessage:
String?) and updating fetchRoutines to set isLoading = true and clear
errorMessage before calling challengeRepository.fetchHomecareRoutines, then set
isLoading = false on completion; on success assign routines, on failure log via
CherrishLogger.error, set routines = [] and set errorMessage to a user-facing
string (e.g., "루틴을 불러올 수 없습니다."). Ensure these new properties are used instead
of only mutating routines in the fetchRoutines method so the UI can show loading
and error states.
- Around line 23-28: The initializer for SelectRoutineViewModel currently falls
back to constructing DefaultChallengeRepository(DefaultNetworkService()) when
DIContainer.shared.resolve(...) returns nil; instead, remove the ad-hoc
instantiation and make the failure explicit so missing DI registration is caught
early — replace the fallback with a forced unwrap or a fatalError that includes
a clear message (e.g., resolve(... )! or guard let challengeRepository =
DIContainer.shared.resolve(...) else { fatalError("ChallengeInterface not
registered in DI") }) inside the init of SelectRoutineViewModel so tests and app
startup surface configuration errors immediately.
- Around line 10-14: 현재 파일에 정의된 Routine 구조체가 실제로 사용되지 않으므로 Routine 구조체 선언을
삭제하세요: 제거 대상은 struct Routine: Identifiable, Decodable, Equatable { let id: Int;
let name: String; let description: String }. 코드베이스에서 대신 사용 중인 RoutineEntity를
유지하고, Routine을 참조하는 곳이 없는지(예: SelectRoutineViewModel, 관련 뷰/모듈) 빌드/검색으로 확인한 뒤
불필요한 임포트나 의존성도 정리하세요.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift`:
- Around line 56-58: 현재 SelectRoutineView의 LazyVGrid에 붙어있는 .onAppear {
viewModel.fetchRoutines() }를 최상위 컨테이너로 이동하세요: LazyVGrid에서 해당 .onAppear 블록을 제거하고
대신 body 끝(또는 최상위 VStack)에 .onAppear { viewModel.fetchRoutines() }를 붙여 뷰 계층 변경 시
중복 호출을 방지합니다. Ensure you update references in SelectRoutineView so only the
top-level VStack/body triggers viewModel.fetchRoutines().

// Configuration settings file format documentation can be found at:
// https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project

BASE_URL = https:/$()/api.cherrish.kro.kr
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

환경별 설정 분리를 고려해 주세요.

현재 BASE_URL이 단일 값으로 하드코딩되어 있습니다. 개발(dev), 스테이징(staging), 프로덕션(prod) 환경별로 다른 API 엔드포인트를 사용해야 할 경우, 환경별 xcconfig 파일(예: Debug.xcconfig, Release.xcconfig)을 분리하거나, 빌드 스킴별로 다른 설정을 적용하는 것을 권장합니다.

🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Core/Config.xcconfig` at line 11, 현재
Config.xcconfig의 BASE_URL이 하드코딩되어 있어 환경별 분리가 필요합니다; 해결하려면 Config.xcconfig에서
BASE_URL을 제거하거나 기본값만 남기고 별도의 환경별 xcconfig 파일(Debug.xcconfig, Staging.xcconfig,
Release.xcconfig)을 생성하여 각 파일에 BASE_URL 값을 설정하고 Xcode 프로젝트의 Build Configuration
또는 Scheme에 해당 xcconfig를 연결해(예: Debug → Debug.xcconfig, Release →
Release.xcconfig, 스테이징용 스킴 → Staging.xcconfig) 빌드 시 올바른 BASE_URL이 주입되도록 구성하세요;
변경 대상 식별자: BASE_URL 속성과 Config.xcconfig 및 새로 생성할
Debug.xcconfig/Staging.xcconfig/Release.xcconfig, 그리고 Xcode의 Build Settings에서의
Config 연결입니다.

Comment on lines +12 to +18
struct DefaultChallengeRepository: ChallengeInterface {

private let networkService: NetworkService

init(networkService: NetworkService) {
self.networkService = networkService
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, locate and read the ChallengeRepository.swift file
find . -name "ChallengeRepository.swift" -type f

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 139


🏁 Script executed:

#!/bin/bash
# Get the full content of ChallengeRepository.swift to see the actual implementation
find . -name "ChallengeRepository.swift" -type f -exec cat -n {} \;

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1405


🏁 Script executed:

#!/bin/bash
# Search for NetworkService protocol/interface definition
rg -n "protocol NetworkService" -A 10 --type swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1047


🏁 Script executed:

#!/bin/bash
# Search for AF.request usage in Swift files related to Challenge
rg -n "AF\.request" --type swift -B 2 -A 2

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1513


🏁 Script executed:

#!/bin/bash
# Search for DefaultNetworkService implementation
rg -n "class DefaultNetworkService|struct DefaultNetworkService" -A 15 --type swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1575


주입된 networkService가 사용되지 않습니다.

networkService가 주입되었지만 전혀 사용되지 않고 있습니다. Line 25에서 AF.request를 직접 호출하여 추상화 계층을 무시하고 있으며, 이는 테스트 시 모킹을 어렵게 만들고 네트워크 레이어의 일관성을 해칩니다.

NetworkService 인터페이스를 활용하여 리팩토링하세요. 또한 NetworkServiceasync throws 패턴을 사용하므로, 현재 콜백 기반의 completion 패턴과의 불일치도 함께 해결되어야 합니다.

🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/ChallengeRepository.swift` around
lines 12 - 18, DefaultChallengeRepository currently ignores the injected
networkService and calls AF.request directly (see AF.request usage), breaking
abstraction and making testing hard; refactor the fetch method(s) in
DefaultChallengeRepository to call the injected networkService (use its async
throws API) instead of AF.request, convert the existing
callback/completion-based method to async throws (or provide an async wrapper)
so it awaits networkService.request/performRequest, map the networkService
response into the existing Challenge model and propagate errors via throws
rather than completion, and remove direct Alamofire references from
DefaultChallengeRepository so unit tests can mock NetworkService.

Comment on lines +25 to +38
AF.request((url), method: .get)
.validate()
.responseDecodable(
of: BaseResponseDTO<[ChallengeRoutineDTO]>.self
) { response in
switch response.result {
case .success(let decoded):
let entities: [RoutineEntity] = decoded.data?.map { $0.toEntity()} ?? []
completion(.success(entities))

case .failure(let error):
completion(.failure(error))
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

불필요한 괄호 제거 및 타임아웃 설정을 고려해 주세요.

  1. AF.request((url), ...) 에서 url 주변의 불필요한 괄호가 있습니다.
  2. 타임아웃 미설정 시 네트워크 지연으로 인해 요청이 무한 대기할 수 있습니다.
♻️ 불필요한 괄호 제거
-        AF.request((url), method: .get)
+        AF.request(url, method: .get)
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/ChallengeRepository.swift` around
lines 25 - 38, Remove the redundant parentheses around url in the AF.request
call (currently written as AF.request((url), ...)) and ensure the request has a
timeout: either build a URLRequest with timeoutInterval set and pass it to
AF.request or create an Alamofire Session with a URLSessionConfiguration that
sets timeoutIntervalForRequest/timeoutIntervalForResource, then use that Session
to perform the same responseDecodable handling (preserving the decoded ->
entities mapping and completion(.success/entities)/completion(.failure/error)
logic in ChallengeRepository's request).

Comment on lines +10 to +13
protocol ChallengeInterface {
func fetchHomecareRoutines(completion: @escaping (Result<[RoutineEntity], Error>) -> Void
)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

프로토콜 설계가 적절합니다.

의존성 역전 원칙(DIP)을 따르는 좋은 설계입니다. ViewModel이 구체적인 Repository 대신 이 인터페이스에 의존하므로 테스트 용이성이 향상됩니다.

프로젝트의 최소 배포 타겟이 iOS 15 이상이라면, completion handler 대신 Swift Concurrency(async/await)를 사용하는 것도 고려해 보세요. 이는 코드 가독성과 에러 핸들링을 개선할 수 있습니다.

// async/await 버전 예시
func fetchHomecareRoutines() async throws -> [RoutineEntity]
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/ChallengeInterface.swift` around
lines 10 - 13, Update the ChallengeInterface protocol to offer an async/await
API instead of a completion handler: replace the current
fetchHomecareRoutines(completion: `@escaping` (Result<[RoutineEntity], Error>) ->
Void) signature with an async throws variant so callers can use Swift
Concurrency; update any conforming types (e.g., repositories implementing
ChallengeInterface.fetchHomecareRoutines) and callers (ViewModel/unit tests) to
await the new fetchHomecareRoutines() and handle thrown errors accordingly,
ensuring RoutineEntity remains the return type and keeping compatibility only if
the project minimum deployment target is iOS 15 or newer.

Comment on lines +1 to +7
//
// SelectMissionViewModel.swift
// Cherrish-iOS
//
// Created by sumin Kong on 1/19/26.
//

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

빈 플레이스홀더 파일입니다.

ChallengeMainViewModel.swift와 마찬가지로 이 파일도 헤더 주석만 포함하고 있습니다. 실제 구현이 준비되기 전까지는 커밋에서 제외하는 것을 고려해 주세요.

🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectMissionViewModel.swift`
around lines 1 - 7, The file SelectMissionViewModel.swift currently contains
only a header comment and no implementation; remove it from the commit (or add a
minimal TODO stub/placeholder type with a clear FIXME and documentation comment)
so empty placeholder files aren't checked in — locate
SelectMissionViewModel.swift and either delete the file from the commit or
replace its header-only contents with a small, clearly marked stub (e.g., a
commented TODO and a placeholder SelectMissionViewModel declaration) until the
real implementation is ready.

Comment on lines +10 to 14
struct Routine: Identifiable, Decodable, Equatable {
let id: Int
let name: String
let description: String
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

사용되지 않는 Routine 구조체를 제거해 주세요.

Routine 구조체가 정의되어 있지만 실제 코드에서는 RoutineEntity만 사용되고 있습니다. 이는 불필요한 코드이므로 제거하는 것이 좋습니다.

🗑️ 제안된 수정
-struct Routine: Identifiable, Decodable, Equatable {
-    let id: Int
-    let name: String
-    let description: String
-}
-
 final class SelectRoutineViewModel: ObservableObject {
📝 Committable suggestion

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

Suggested change
struct Routine: Identifiable, Decodable, Equatable {
let id: Int
let name: String
let description: String
}
final class SelectRoutineViewModel: ObservableObject {
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectRoutineViewModel.swift`
around lines 10 - 14, 현재 파일에 정의된 Routine 구조체가 실제로 사용되지 않으므로 Routine 구조체 선언을
삭제하세요: 제거 대상은 struct Routine: Identifiable, Decodable, Equatable { let id: Int;
let name: String; let description: String }. 코드베이스에서 대신 사용 중인 RoutineEntity를
유지하고, Routine을 참조하는 곳이 없는지(예: SelectRoutineViewModel, 관련 뷰/모듈) 빌드/검색으로 확인한 뒤
불필요한 임포트나 의존성도 정리하세요.

Comment on lines +23 to +28
init(
challengeRepository: ChallengeInterface = DIContainer.shared.resolve(type: ChallengeInterface.self) ?? DefaultChallengeRepository(networkService: DefaultNetworkService()
)
){
self.challengeRepository = challengeRepository
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

DI 해결 실패 시 폴백 로직 재검토가 필요합니다.

DI 컨테이너에서 해결 실패 시 새로운 DefaultChallengeRepositoryDefaultNetworkService 인스턴스를 직접 생성하면 DI의 이점(테스트 용이성, 의존성 일관성)이 사라집니다. DI 설정이 올바르다면 해결 실패 시 fatalError로 빠르게 실패하는 것이 디버깅에 유리합니다.

♻️ 제안된 수정
     init(
-        challengeRepository: ChallengeInterface = DIContainer.shared.resolve(type: ChallengeInterface.self) ?? DefaultChallengeRepository(networkService: DefaultNetworkService()
-        )
-    ){
+        challengeRepository: ChallengeInterface? = nil
+    ) {
+        self.challengeRepository = challengeRepository ?? DIContainer.shared.resolve(type: ChallengeInterface.self)!
-        self.challengeRepository = challengeRepository
     }

또는 앱 시작 시 DI 등록이 완료되었다고 가정하고 강제 언래핑을 사용하여 등록 누락을 즉시 감지할 수 있습니다.

🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectRoutineViewModel.swift`
around lines 23 - 28, The initializer for SelectRoutineViewModel currently falls
back to constructing DefaultChallengeRepository(DefaultNetworkService()) when
DIContainer.shared.resolve(...) returns nil; instead, remove the ad-hoc
instantiation and make the failure explicit so missing DI registration is caught
early — replace the fallback with a forced unwrap or a fatalError that includes
a clear message (e.g., resolve(... )! or guard let challengeRepository =
DIContainer.shared.resolve(...) else { fatalError("ChallengeInterface not
registered in DI") }) inside the init of SelectRoutineViewModel so tests and app
startup surface configuration errors immediately.

Comment on lines +38 to +50
func fetchRoutines() {
challengeRepository.fetchHomecareRoutines { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let routines):
self?.routines = routines
case .failure(let error):
CherrishLogger.error(error)
self?.routines = []
}
}
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

로딩 및 에러 상태 관리를 추가하는 것을 권장합니다.

네트워크 요청 중 사용자에게 피드백을 제공하기 위한 로딩 상태가 없습니다. 또한 에러 발생 시 빈 배열만 설정되어 사용자가 데이터 부재 원인을 알 수 없습니다.

♻️ 제안된 개선
`@Published` var isLoading: Bool = false
`@Published` var errorMessage: String?

func fetchRoutines() {
    isLoading = true
    errorMessage = nil
    
    challengeRepository.fetchHomecareRoutines { [weak self] result in
        DispatchQueue.main.async {
            self?.isLoading = false
            switch result {
            case .success(let routines):
                self?.routines = routines
            case .failure(let error):
                CherrishLogger.error(error)
                self?.routines = []
                self?.errorMessage = "루틴을 불러올 수 없습니다."
            }
        }
    }
}
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/Coordinator/ViewModel/SelectRoutineViewModel.swift`
around lines 38 - 50, Add loading and error state to SelectRoutineViewModel by
introducing `@Published` properties (e.g., isLoading: Bool and errorMessage:
String?) and updating fetchRoutines to set isLoading = true and clear
errorMessage before calling challengeRepository.fetchHomecareRoutines, then set
isLoading = false on completion; on success assign routines, on failure log via
CherrishLogger.error, set routines = [] and set errorMessage to a user-facing
string (e.g., "루틴을 불러올 수 없습니다."). Ensure these new properties are used instead
of only mutating routines in the fetchRoutines method so the UI can show loading
and error states.

Comment on lines +56 to +58
.onAppear {
viewModel.fetchRoutines()
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

onAppear를 상위 컨테이너로 이동하는 것을 권장합니다.

현재 onAppearLazyVGrid에 적용되어 있어, 뷰 계층 구조 변경 시 의도치 않게 여러 번 호출될 수 있습니다. 최상위 VStack이나 body 끝에 배치하면 더 안정적입니다.

♻️ 제안된 수정
         }
         .ignoresSafeArea(edges: .bottom)
+        .onAppear {
+            viewModel.fetchRoutines()
+        }
     }

그리고 기존 위치의 .onAppear 블록을 제거:

                 }
                 .padding(.horizontal, 33.adjustedW)
                 .padding(.top, 40.adjustedH)
-                .onAppear {
-                    viewModel.fetchRoutines()
-                }
             }
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift`
around lines 56 - 58, 현재 SelectRoutineView의 LazyVGrid에 붙어있는 .onAppear {
viewModel.fetchRoutines() }를 최상위 컨테이너로 이동하세요: LazyVGrid에서 해당 .onAppear 블록을 제거하고
대신 body 끝(또는 최상위 VStack)에 .onAppear { viewModel.fetchRoutines() }를 붙여 뷰 계층 변경 시
중복 호출을 방지합니다. Ensure you update references in SelectRoutineView so only the
top-level VStack/body triggers viewModel.fetchRoutines().

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (1)

74-82: 선택 비교를 id 기준으로 고정하는 것을 권장
현재 viewModel.selectedRoutine == routine는 전체 값 비교이므로 서버 리프레시로 필드가 바뀌면 선택 상태가 풀릴 수 있습니다. id 기반 비교(또는 Equatable을 id만 비교하도록 보장)로 변경하는 편이 안정적입니다.

♻️ Duplicate comments (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (1)

56-58: onAppear 위치로 인한 중복 호출 위험
Line 56-58의 onAppear가 LazyVGrid 내부에 있어 뷰 계층 변화 시 여러 번 호출될 수 있습니다. 최상위 컨테이너(예: body 끝 또는 최상위 VStack)로 이동하는 편이 안정적입니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (5)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/ChallengeProgressView.swift (1)

18-31: 경계값 처리 고려

progressRate가 100을 초과하거나 0 미만일 경우 default로 빠져서 .mong(최저 레벨)을 반환합니다. 의도된 동작인지 확인이 필요합니다.

만약 100 초과 시 최고 레벨을 유지하는 것이 적절하다면:

♻️ 경계값 처리 개선 제안
 static func from(progressRate: Double) -> CherryLevel {
     switch progressRate {
-    case 0.0..<25.0:
+    case ..<25.0:
         return .mong
     case 25.0..<50.0:
         return .bbo
     case 50.0..<75.0:
         return .pang
-    case 75.0...100.0:
-        return .ggu
     default:
-        return .mong
+        return .ggu
     }
 }
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TreatmentSearchBarTextField.swift (1)

27-34: 비활성 상태에서도 키보드 제출이 동작합니다.

isDisabled가 true여도 onSubmitenter()를 호출해 버튼 비활성화를 우회합니다. 제출 시점을 동일하게 통제하도록 가드(또는 TextField에도 disabled)를 적용하세요.

✅ 제안 수정안
-        .onSubmit {
-            enter()
-        }
+        .onSubmit {
+            if !isDisabled { enter() }
+        }
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/SelectedTreatmentSheetView.swift (1)

1-6: 파일 헤더 주석을 새로운 구조체명과 일치시켜 주세요.

구조체가 SelectedTreatmentSheetView로 이름이 변경되었지만, 헤더 주석은 여전히 SelectedTreatmentView.swift입니다.

🔧 제안된 수정
 //
-//  SelectedTreatmentView.swift
+//  SelectedTreatmentSheetView.swift
 //  Cherrish-iOS
 //
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (1)

15-15: DIContainer를 통해 ViewModel을 의존성 주입해야 합니다.

SelectRoutineViewModelPresentationDependencyAssembler에 등록되지 않았으며, SelectRoutineView에서 직접 인스턴스화하고 있습니다. 이는 HomeView를 포함한 다른 View들과 다른 패턴입니다.

프로젝트의 일관된 DI 패턴을 따르려면:

  1. PresentationDependencyAssemblerSelectRoutineViewModel 등록
  2. SelectRoutineView에서 DIContainer를 통해 resolve
♻️ 권장 수정

PresentationDependencyAssembler.swift에 추가:

DIContainer.shared.register(type: SelectRoutineViewModel.self) {
    return SelectRoutineViewModel()
}

SelectRoutineView.swift 수정:

-    `@StateObject` private var viewModel = SelectRoutineViewModel()
+    `@StateObject` private var viewModel = DIContainer.shared.resolve(type: SelectRoutineViewModel.self)!

이는 HomeView의 패턴과 동일합니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift (1)

29-33: 단계별 콘텐츠가 화면에 표시되지 않습니다.
Line 29-33에서 contentView() 호출이 누락되어, 현재 화면에는 bottomView만 보일 가능성이 큽니다. 아래처럼 contentView()를 다시 삽입해 주세요.

🧩 제안 수정
             VStack(spacing: 0) {
                 Spacer()
+                contentView()
                 bottomView()
                 Spacer().frame(height: 38.adjustedH)
             }
🤖 Fix all issues with AI agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Model/TreatmentCategoryResponseDTO.swift`:
- Around line 1-6: The file header comment at the top of
TreatmentCategoryResponseDTO.swift shows the wrong filename
("TreatmentCategoryDTO.swift"); update the header block so the filename line
matches the actual file name (TreatmentCategoryResponseDTO.swift) and keep other
metadata (author/date) unchanged to ensure consistency when locating the DTO
definition (TreatmentCategoryResponseDTO).

In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift`:
- Around line 10-14: DefaultTreatmentRepository currently returns an empty array
and is unused; either implement its fetchCategories() to call the real API
client (e.g., inject a TreatmentAPI/NetworkService, parse response into
TreatmentCategoryEntity inside DefaultTreatmentRepository.fetchCategories()) or
remove the entire DefaultTreatmentRepository type and any DI registrations
referencing it so only MockTreatmentRepository remains; also update DI bindings
and unit tests that reference TreatmentInterface to use MockTreatmentRepository
or the new implementation accordingly.

In `@Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift`:
- Around line 40-46: The guard that resolves TreatmentInterface currently
returns silently on failure; update the block in DomainDependencyAssembler so
that when DIContainer.shared.resolve(type: TreatmentInterface.self) fails you
log an error via the same pattern used in PresentationDependencyAssembler (e.g.,
CherrishLogger.error) before returning; keep the existing registration of
FetchTreatmentCategoriesUseCase / DefaultFetchTreatmentCategoriesUseCase
unchanged but ensure the log message includes context like "Failed to resolve
TreatmentInterface for FetchTreatmentCategoriesUseCase".

In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/TreatmentInterface.swift`:
- Around line 1-6: The file header comment currently says
"TreatmentCategoryInterface.swift" but the actual file is
TreatmentInterface.swift; update the header block comment at the top of the file
so the filename line matches "TreatmentInterface.swift" (and optionally adjust
any Created by/date lines if needed) to keep header metadata consistent with the
file name and avoid confusion when locating the interface definitions such as
the TreatmentInterface type.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentFilterView.swift`:
- Around line 21-25: Fix the typo in the user-facing string inside the
TypographyText call in TreatmentFilterView by replacing "빅테이터" with "빅데이터"
(update the literal passed to TypographyText in the
TreatmentFilterView/TreatmentFilterView.swift view); ensure the rest of the
string and styling parameters (style: .body3_r_12, color: .gray600) remain
unchanged.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TreatmentSearchBarTextField.swift`:
- Around line 36-37: Replace the fixed height on the search text field to avoid
clipping under Dynamic Type: in TreatmentSearchBarTextField (the view that
currently uses .frame(height: 20.adjustedH) followed by .padding(.vertical,
8.adjustedH)), change the frame call to use a minimum height (e.g.,
.frame(minHeight: 20.adjustedH)) or otherwise remove the hard-coded height so
the field can grow with larger accessibility fonts while preserving the vertical
padding.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`:
- Around line 60-67: loadCategories의 빈 catch 블록이 에러를 무시하므로
fetchCategoriesUseCase.execute 실패 시 에러를 처리하도록 수정하세요; loadCategories 내 catch에서
에러를 로깅(예: print 또는 Logger), 뷰 상태 업데이트(예: errorMessage 또는 isLoading 플래그) 및 사용자
피드백 트리거(예: showError 바인딩 또는 delegate 호출)를 추가하고, 필요하면 categories를 빈 배열로 설정하거나 기존
상태를 유지하도록 명시적으로 처리해 주세요. 참조: loadCategories(), categories,
fetchCategoriesUseCase.execute().

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift`:
- Around line 46-50: 현재 DIContainer.shared.register 블록에서
MockTreatmentRepository와 DefaultFetchTreatmentCategoriesUseCase를 직접 생성하여
DomainDependencyAssembler에 등록된 FetchTreatmentCategoriesUseCase를 우회하고 있습니다;
NoTreatmentViewModel을 등록할 때는 직접 인스턴스 생성 대신 DIContainer에서
FetchTreatmentCategoriesUseCase를 resolve(예: DIContainer.shared.resolve(type:
FetchTreatmentCategoriesUseCase.self))하여 전달하도록 수정하고,
DefaultFetchTreatmentCategoriesUseCase와 MockTreatmentRepository 생성 코드는 제거해 주세요
so that DIContainer.shared.register(type: NoTreatmentViewModel.self) constructs
NoTreatmentViewModel(fetchCategoriesUseCase: resolvedUseCase) using the resolved
FetchTreatmentCategoriesUseCase.
♻️ Duplicate comments (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ChallengeView/SelectRoutineView.swift (1)

56-58: onAppear를 상위 컨테이너로 이동하는 것을 권장합니다.

현재 onAppearLazyVGrid에 적용되어 있어, 뷰 계층 구조 변경 시 의도치 않게 여러 번 호출될 수 있습니다.

Comment on lines +1 to +6
//
// TreatmentCategoryDTO.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/19/26.
//
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

파일 헤더 주석의 파일명이 실제 파일명과 불일치합니다.

헤더에는 TreatmentCategoryDTO.swift로 되어 있지만, 실제 파일명은 TreatmentCategoryResponseDTO.swift입니다.

🔧 제안된 수정
 //
-//  TreatmentCategoryDTO.swift
+//  TreatmentCategoryResponseDTO.swift
 //  Cherrish-iOS
 //
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Model/TreatmentCategoryResponseDTO.swift`
around lines 1 - 6, The file header comment at the top of
TreatmentCategoryResponseDTO.swift shows the wrong filename
("TreatmentCategoryDTO.swift"); update the header block so the filename line
matches the actual file name (TreatmentCategoryResponseDTO.swift) and keep other
metadata (author/date) unchanged to ensure consistency when locating the DTO
definition (TreatmentCategoryResponseDTO).

Comment on lines +10 to +14
struct DefaultTreatmentRepository: TreatmentInterface {
func fetchCategories() async throws -> [TreatmentCategoryEntity] {
return []
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

rg -n "TreatmentInterface|TreatmentRepository" --type swift -C 3

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 5811


DefaultTreatmentRepository는 불완전한 상태이며 현재 사용되지 않습니다.

DefaultTreatmentRepository가 빈 배열을 반환하고 있으나, DI 설정에서 TreatmentInterface 구현체로 MockTreatmentRepository가 등록되어 있으므로 현재 실제 영향은 없습니다. DefaultTreatmentRepository는 현재 코드베이스에서 사용되지 않는 상태입니다.

이 클래스가 향후 실제 API 연동을 위해 필요하다면 구현을 완료해야 하고, 그렇지 않다면 제거하는 것이 좋습니다. 미사용 코드로 남겨두는 것을 피하세요.

🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift` around
lines 10 - 14, DefaultTreatmentRepository currently returns an empty array and
is unused; either implement its fetchCategories() to call the real API client
(e.g., inject a TreatmentAPI/NetworkService, parse response into
TreatmentCategoryEntity inside DefaultTreatmentRepository.fetchCategories()) or
remove the entire DefaultTreatmentRepository type and any DI registrations
referencing it so only MockTreatmentRepository remains; also update DI bindings
and unit tests that reference TreatmentInterface to use MockTreatmentRepository
or the new implementation accordingly.

Comment on lines +40 to +46
guard let treatmentCategoryRepository = DIContainer.shared.resolve(type: TreatmentInterface.self) else {
return
}

DIContainer.shared.register(type: FetchTreatmentCategoriesUseCase.self) {
return DefaultFetchTreatmentCategoriesUseCase(repository: treatmentCategoryRepository)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM, 하지만 에러 로깅 추가를 권장합니다.

DI 패턴이 파일 내 다른 등록과 일관성 있게 구현되었습니다. 다만, 의존성 resolve 실패 시 조용히 반환하면 디버깅이 어려울 수 있습니다. PresentationDependencyAssemblerCherrishLogger.error 패턴처럼 에러 로깅 추가를 고려해 주세요.

♻️ 수정 제안
         guard let treatmentCategoryRepository = DIContainer.shared.resolve(type: TreatmentInterface.self) else {
+            CherrishLogger.error(CherrishError.DIFailedError)
             return
         }
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift` around
lines 40 - 46, The guard that resolves TreatmentInterface currently returns
silently on failure; update the block in DomainDependencyAssembler so that when
DIContainer.shared.resolve(type: TreatmentInterface.self) fails you log an error
via the same pattern used in PresentationDependencyAssembler (e.g.,
CherrishLogger.error) before returning; keep the existing registration of
FetchTreatmentCategoriesUseCase / DefaultFetchTreatmentCategoriesUseCase
unchanged but ensure the log message includes context like "Failed to resolve
TreatmentInterface for FetchTreatmentCategoriesUseCase".

Comment on lines +1 to +6
//
// TreatmentCategoryInterface.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/19/26.
//
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

파일 헤더 주석이 파일명과 일치하지 않습니다.

헤더 주석에는 TreatmentCategoryInterface.swift로 되어 있지만, 실제 파일명은 TreatmentInterface.swift입니다.

📝 수정 제안
 //
-//  TreatmentCategoryInterface.swift
+//  TreatmentInterface.swift
 //  Cherrish-iOS
 //
📝 Committable suggestion

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

Suggested change
//
// TreatmentCategoryInterface.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/19/26.
//
//
// TreatmentInterface.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/19/26.
//
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Domain/Interface/TreatmentInterface.swift` around
lines 1 - 6, The file header comment currently says
"TreatmentCategoryInterface.swift" but the actual file is
TreatmentInterface.swift; update the header block comment at the top of the file
so the filename line matches "TreatmentInterface.swift" (and optionally adjust
any Created by/date lines if needed) to keep header metadata consistent with the
file name and avoid confusion when locating the interface definitions such as
the TreatmentInterface type.

Comment on lines +21 to +25
TypographyText(
"본 정보는 인터넷 빅테이터 검색 및 분석을 통해 수집된 정보이며,공식적인 의료 정보가 아닙니다. ",
style: .body3_r_12,
color: .gray600
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

사용자에게 표시되는 텍스트에 오타가 있습니다.

"빅테이터"는 "빅데이터"로 수정해야 합니다.

📝 수정 제안
                     TypographyText(
-                            "본 정보는 인터넷 빅테이터 검색 및 분석을 통해 수집된 정보이며,공식적인 의료 정보가 아닙니다. ",
+                            "본 정보는 인터넷 빅데이터 검색 및 분석을 통해 수집된 정보이며, 공식적인 의료 정보가 아닙니다.",
                             style: .body3_r_12,
                             color: .gray600
                         )
📝 Committable suggestion

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

Suggested change
TypographyText(
"본 정보는 인터넷 빅테이터 검색 및 분석을 통해 수집된 정보이며,공식적인 의료 정보가 아닙니다. ",
style: .body3_r_12,
color: .gray600
)
TypographyText(
"본 정보는 인터넷 빅데이터 검색 및 분석을 통해 수집된 정보이며, 공식적인 의료 정보가 아닙니다.",
style: .body3_r_12,
color: .gray600
)
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentFilterView.swift`
around lines 21 - 25, Fix the typo in the user-facing string inside the
TypographyText call in TreatmentFilterView by replacing "빅테이터" with "빅데이터"
(update the literal passed to TypographyText in the
TreatmentFilterView/TreatmentFilterView.swift view); ensure the rest of the
string and styling parameters (style: .body3_r_12, color: .gray600) remain
unchanged.

Comment on lines +36 to 37
.frame(height: 20.adjustedH)
.padding(.vertical, 8.adjustedH)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

고정 높이로 Dynamic Type에서 텍스트가 잘릴 수 있습니다.

height 고정은 큰 글자 크기에서 클리핑 위험이 있습니다. 최소 높이로 완화하는 편이 안전합니다.

♻️ 제안 수정안
-        .frame(height: 20.adjustedH)
+        .frame(minHeight: 20.adjustedH)
📝 Committable suggestion

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

Suggested change
.frame(height: 20.adjustedH)
.padding(.vertical, 8.adjustedH)
.frame(minHeight: 20.adjustedH)
.padding(.vertical, 8.adjustedH)
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/TreatmentSearchBarTextField.swift`
around lines 36 - 37, Replace the fixed height on the search text field to avoid
clipping under Dynamic Type: in TreatmentSearchBarTextField (the view that
currently uses .frame(height: 20.adjustedH) followed by .padding(.vertical,
8.adjustedH)), change the frame call to use a minimum height (e.g.,
.frame(minHeight: 20.adjustedH)) or otherwise remove the hard-coded height so
the field can grow with larger accessibility fonts while preserving the vertical
padding.

Comment on lines +60 to +67
@MainActor
func loadCategories() async {
do {
categories = try await fetchCategoriesUseCase.execute()
} catch {

}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

빈 catch 블록으로 에러가 무시됩니다.

네트워크 요청 실패 시 에러가 조용히 무시되어 사용자에게 피드백이 제공되지 않습니다. 에러 상태를 추적하거나 최소한 로깅을 추가해야 합니다.

🔧 에러 처리 추가 제안
+    `@Published` var errorMessage: String?
+    
     `@MainActor`
     func loadCategories() async {
             do {
                 categories = try await fetchCategoriesUseCase.execute()
             } catch {
-                
+                print("Failed to load categories: \(error)")
+                errorMessage = "카테고리를 불러오는데 실패했습니다."
             }
         }
📝 Committable suggestion

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

Suggested change
@MainActor
func loadCategories() async {
do {
categories = try await fetchCategoriesUseCase.execute()
} catch {
}
}
`@Published` var errorMessage: String?
`@MainActor`
func loadCategories() async {
do {
categories = try await fetchCategoriesUseCase.execute()
} catch {
print("Failed to load categories: \(error)")
errorMessage = "카테고리를 불러오는데 실패했습니다."
}
}
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`
around lines 60 - 67, loadCategories의 빈 catch 블록이 에러를 무시하므로
fetchCategoriesUseCase.execute 실패 시 에러를 처리하도록 수정하세요; loadCategories 내 catch에서
에러를 로깅(예: print 또는 Logger), 뷰 상태 업데이트(예: errorMessage 또는 isLoading 플래그) 및 사용자
피드백 트리거(예: showError 바인딩 또는 delegate 호출)를 추가하고, 필요하면 categories를 빈 배열로 설정하거나 기존
상태를 유지하도록 명시적으로 처리해 주세요. 참조: loadCategories(), categories,
fetchCategoriesUseCase.execute().

Comment on lines +46 to +50
DIContainer.shared.register(type: NoTreatmentViewModel.self) {
let repository = MockTreatmentRepository()
let useCase = DefaultFetchTreatmentCategoriesUseCase(repository: repository)
return NoTreatmentViewModel(fetchCategoriesUseCase: useCase)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

DI 패턴 불일치: DIContainer에서 의존성을 resolve하세요.

다른 ViewModel 등록(CalendarViewModel, HomeViewModel)에서는 DIContainer에서 use case를 resolve하여 사용하고 있습니다. 그러나 여기서는 MockTreatmentRepository와 UseCase를 직접 생성하고 있어 DomainDependencyAssembler에서 등록한 FetchTreatmentCategoriesUseCase가 무시됩니다.

♻️ 수정 제안
-        DIContainer.shared.register(type: NoTreatmentViewModel.self) {
-            let repository = MockTreatmentRepository()
-            let useCase = DefaultFetchTreatmentCategoriesUseCase(repository: repository)
-            return NoTreatmentViewModel(fetchCategoriesUseCase: useCase)
+        guard let fetchCategoriesUseCase = DIContainer.shared.resolve(type: FetchTreatmentCategoriesUseCase.self) else {
+            CherrishLogger.error(CherrishError.DIFailedError)
+            return
+        }
+        
+        DIContainer.shared.register(type: NoTreatmentViewModel.self) {
+            return NoTreatmentViewModel(fetchCategoriesUseCase: fetchCategoriesUseCase)
         }
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift`
around lines 46 - 50, 현재 DIContainer.shared.register 블록에서
MockTreatmentRepository와 DefaultFetchTreatmentCategoriesUseCase를 직접 생성하여
DomainDependencyAssembler에 등록된 FetchTreatmentCategoriesUseCase를 우회하고 있습니다;
NoTreatmentViewModel을 등록할 때는 직접 인스턴스 생성 대신 DIContainer에서
FetchTreatmentCategoriesUseCase를 resolve(예: DIContainer.shared.resolve(type:
FetchTreatmentCategoriesUseCase.self))하여 전달하도록 수정하고,
DefaultFetchTreatmentCategoriesUseCase와 MockTreatmentRepository 생성 코드는 제거해 주세요
so that DIContainer.shared.register(type: NoTreatmentViewModel.self) constructs
NoTreatmentViewModel(fetchCategoriesUseCase: resolvedUseCase) using the resolved
FetchTreatmentCategoriesUseCase.

@sum130 sum130 closed this Jan 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature 새로운 기능 구현 및 API 연결 수민🐶

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 챌린지뷰 네트워크 연결

2 participants