Skip to content

Feat/#125 Flowstate, 시술 일정 추가 API 연결#128

Merged
wotjs020708 merged 8 commits intodevelopfrom
feat/#125-flowstate
Jan 21, 2026
Merged

Feat/#125 Flowstate, 시술 일정 추가 API 연결#128
wotjs020708 merged 8 commits intodevelopfrom
feat/#125-flowstate

Conversation

@wotjs020708
Copy link
Contributor

🔗 연결된 이슈

📄 작업 내용

  • FlowState를 통해 뷰에 데이터 전달
  • 네트워크 연결
스크린샷 2026-01-21 15 58 56

💻 주요 코드 설명

CalendarTreatmentFlowState.swift

  • Calendar와 Treatment 화면에서 공유할 데이터를 만들어준다.
final class CalendarTreatmentFlowState: ObservableObject {
    @Published var selectedDaet: Date?
}

PresentationDependencyAssembler.swift

  • DI 컨테이너에 등록, ViewModel 보다 먼저 선언해줘야함
 DIContainer.shared.register(type: CalendarTreatmentFlowState.self) {
            return CalendarTreatmentFlowState()
        }
  • 각 뷰모델에서 주입받아 사용
 private let calendarTreatmentFlowState: CalendarTreatmentFlowState
 
 init(
        calendarTreatmentFlowState: CalendarTreatmentFlowState,
    ) {
        self.calendarTreatmentFlowState = calendarTreatmentFlowState
    }
  • DI 컨테이너에 각 사용할 ViewModel에 주입
guard let calendarTreatmentFlowState = DIContainer.shared.resolve(type: CalendarTreatmentFlowState.self) else {
            CherrishLogger.error(CherrishError.DIFailedError)
            return
        }

DIContainer.shared.register(type: TreatmentViewModel.self) {
            return TreatmentViewModel(
                calendarTreatmentFlowState: calendarTreatmentFlowState,
            )
        }

@wotjs020708 wotjs020708 requested a review from a team January 21, 2026 07:13
@wotjs020708 wotjs020708 self-assigned this Jan 21, 2026
@wotjs020708 wotjs020708 requested review from soseoyo12, sum130 and y-eonee and removed request for a team January 21, 2026 07:13
@wotjs020708 wotjs020708 added 재선🐻 Feature 새로운 기능 구현 및 API 연결 labels Jan 21, 2026
@wotjs020708 wotjs020708 linked an issue Jan 21, 2026 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

캘린더 기반 시술 일정 생성 기능을 추가합니다. DTO/응답 모델, TreatmentAPI 엔드포인트, 저장소·도메인 유스케이스, 캘린더-시술 흐름 상태 및 뷰/뷰모델 연동을 포함해 전체 워크플로우를 구현합니다.

Changes

Cohort / File(s) 변경 요약
DTOs / Responses
Cherrish-iOS/Cherrish-iOS/Data/Model/CreateUserProcedureRequestDTO.swift, Cherrish-iOS/Cherrish-iOS/Data/Model/CreateUserProcedureResponseDTO.swift
요청/응답 DTO 추가: UserProcedureItemRequestDTO, CreateUserProcedureRequestDTO, CreateUserProcedureResponseDTO, CreateUserProceduresResponseDTO
Network Endpoints
Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/HomeAPI.swift, Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/TreatmentAPI.swift
HomeAPI.queryParameters 타입을 [String: Any]?로 변경; TreatmentAPIcreateUserProcedure(userId:request:) 케이스(POST, JSON 바디, /user-procedures) 추가
Repository
Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift
DefaultTreatmentRepositorycreateUserProcedure(...) async throws 구현 추가; MockTreatmentRepository에 스텁 추가
Domain 인터페이스 / 유스케이스
Cherrish-iOS/Cherrish-iOS/Domain/Interface/TreatmentInterface.swift, Cherrish-iOS/Cherrish-iOS/Domain/UseCase/CreateUserProcedureUseCase.swift
TreatmentInterface에 async createUserProcedure 메서드 추가; CreateUserProcedureUseCase 프로토콜과 DefaultCreateUserProcedureUseCase 구현 추가
도메인 모델
Cherrish-iOS/Cherrish-iOS/Domain/Model/TreatmentEntity.swift
TreatmentEntity 확장에 toRequestDTO() 추가 (다운타임이 있을 때 UserProcedureItemRequestDTO 반환)
프레젠테이션 상태/DI
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/CalendarTreatmentFlowState.swift, Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift, Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift
CalendarTreatmentFlowState 추가(@Published var selectedDate: Date?), DI에 flow state 및 CreateUserProcedureUseCase 등록 및 뷰모델 주입 변경
뷰 / 뷰모델 변경
.../CalendarView.swift, .../CalendarViewModel.swift, .../NoTreatmentView.swift, .../TreatmentView.swift, .../NoTreatmentViewModel.swift, .../TreatmentViewModel.swift
캘린더에서 날짜 전송 로직 추가 (sendDateToTreatmentView), NoTreatment/Treatment의 "다음" 버튼에서 상태별로 비동기 createUserProcedure() 호출 추가, 뷰모델에 flow state 및 use case 의존성 주입 및 메서드 추가
유틸 확장 / 기타
Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Date+.swift, Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Onboarding/SplashView.swift
Date 포맷/파서 추가 (toScheduledAtFormat, toRecoveryDateFormat, from(year:month:day:)); SplashView에 의존성 주입 초기화자 추가

Sequence Diagram

sequenceDiagram
    participant User as User
    participant CalView as CalendarView
    participant CalVM as CalendarViewModel
    participant FlowState as CalendarTreatmentFlowState
    participant TreatView as TreatmentView
    participant TreatVM as TreatmentViewModel
    participant UseCase as CreateUserProcedureUseCase
    participant Repo as TreatmentRepository
    participant API as TreatmentAPI
    participant Server as API_Server

    User->>CalView: 날짜 선택
    CalView->>CalVM: sendDateToTreatmentView()
    CalVM->>FlowState: selectedDate = Date

    User->>TreatView: 시술 선택 후 다음
    TreatView->>TreatVM: createUserProcedure()
    TreatVM->>FlowState: selectedDate 조회
    FlowState-->>TreatVM: selectedDate

    TreatVM->>UseCase: execute(scheduledDate, recoveryDate, treatments)
    UseCase->>Repo: createUserProcedure(...)
    Repo->>API: createUserProcedure(userId, requestDTO)
    API->>Server: POST /api/user-procedures (JSON body)
    Server-->>API: 200 OK (프로시저 생성 응답)
    API-->>Repo: 응답 전달
    Repo-->>UseCase: 완료
    UseCase-->>TreatVM: 완료
    TreatVM->>TreatView: 탭바 노출 및 루트로 네비게이션
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • sum130
  • y-eonee
  • soseoyo12
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
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.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 FlowState 도입과 시술 일정 추가 API 연결이라는 주요 변경사항을 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명은 FlowState를 통한 데이터 전달과 네트워크 연결 구현을 다루고 있으며, 주요 코드 설명과 스크린샷을 포함하고 있습니다.
Linked Issues check ✅ Passed PR은 FlowState 도입을 통해 Calendar와 Treatment 뷰 간 데이터 공유를 구현했으며, 시술 일정 추가 API 연동도 포함하여 이슈 #125의 목표를 충족합니다.
Out of Scope Changes check ✅ Passed 모든 변경사항은 FlowState 도입과 시술 일정 API 연동이라는 명확한 범위 내에 있으며, 관련 없는 변경사항은 발견되지 않습니다.

✏️ 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/#125-flowstate

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.

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

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/Domain/DomainDependencyAssembler.swift (1)

36-38: 중복된 homeRepository guard 문 발견

Lines 24-26에서 이미 homeRepository를 resolve하고 있습니다. 이 중복된 guard 문은 불필요하며 제거해야 합니다.

🧹 중복 guard 제거
         DIContainer.shared.register(type: FetchTodayProcedureListUseCase.self) {
             return DefaultFetchTodayProcedureUseCase(repository: calendarRepository)
         }
-        
-        guard let homeRepository = DIContainer.shared.resolve(type: HomeInterface.self) else {
-            return
-        }
         
         DIContainer.shared.register(type: FetchProcedureDowntimeUseCase.self) {
🤖 Fix all issues with AI agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Model/CreateUserProcedureRequestDTO.swift`:
- Around line 10-18: Replace the repeated Encodable, Decodable declarations with
the Codable typealias on the DTOs: update both UserProcedureItemRequestDTO and
CreateUserProcedureRequestDTO to conform to Codable instead of listing Encodable
and Decodable separately, keeping existing property names and types unchanged.
- Around line 1-6: 파일 헤더 주석의 파일명이 실제 파일명과 일치하지 않습니다: 현재 상단 주석에
`UserProcedureItemRequestDTO.swift`가 적혀 있으나 파일명은
`CreateUserProcedureRequestDTO.swift`입니다; 파일 상단의 주석 블록(헤더 코멘트)을 찾아
`UserProcedureItemRequestDTO.swift`를 `CreateUserProcedureRequestDTO.swift`로 수정하여
헤더와 실제 파일명이 일치하도록 고치세요.

In `@Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/TreatmentAPI.swift`:
- Around line 98-108: The manual dictionary construction in the TreatmentAPI
case .createUserProcedure should be replaced by encoding the existing
CreateUserProcedureRequestDTO to a Parameters-style dictionary to avoid
duplication; add an extension on CreateUserProcedureRequestDTO (or a helper)
that encodes self with JSONEncoder and converts to [String: Any] (e.g.,
asParameters) and then return request.asParameters from the createUserProcedure
case, or alternatively use Alamofire's JSONParameterEncoder when building the
request so the body is derived from the DTO rather than hand-constructed.

In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift`:
- Around line 51-53: MockTreatmentRepository.createUserProcedure has a different
signature than the protocol and DefaultTreatmentRepository; update
MockTreatmentRepository.createUserProcedure to match the protocol's declaration
by adding async throws to its signature (so it matches TreatmentInterface and
DefaultTreatmentRepository), and ensure its implementation returns/throws
appropriately for the mock behavior.
- Around line 38-46: createUserProcedure currently uses treatments.compactMap {
$0.toRequestDTO() } which drops any treatments whose setDowntime is nil and can
produce an empty procedures array; add validation in createUserProcedure to
check the resulting procedures array and throw (or return) a clear error before
calling networkService.request when procedures.isEmpty, and surface that error
to callers; replace the incorrect decodingType UserProcedureItemRequestDTO with
a dedicated response DTO (e.g., UserProcedureItemResponseDTO) that matches the
server response and update the request call (TreatmentAPI.createUserProcedure)
to decode that response type; finally, make
MockTreatmentRepository.createUserProcedure conform by adding the missing async
throws signature so it matches the TreatmentInterface protocol.

In `@Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift`:
- Around line 76-78: Remove the stray whitespace between DIContainer.shared and
.register in the registration call so it reads as
DIContainer.shared.register(...); locate the registration for
CreateUserProcedureUseCase that returns
DefaultCreateUserProcedureUseCase(repository: treatmentRepository) and fix the
spacing around the dot to match surrounding calls.

In `@Cherrish-iOS/Cherrish-iOS/Domain/UseCase/CreateUserProcedureUseCase.swift`:
- Around line 22-24: Rename the misspelled method excute to execute in
CreateUserProcedureUseCase by changing the function signature func excute(...)
to func execute(...), and update any conformance/overrides (e.g., protocol
requirements or callers that expect execute) so the implementation in
CreateUserProcedureUseCase and its references call
repository.createUserProcedure(...) the same way; ensure the method name change
is propagated to any protocol/interface that declared excute to avoid
mismatches.
- Around line 10-12: Rename the misspelled protocol method excute to execute in
CreateUserProcedureUseCase and update all call sites to the new name;
specifically change the protocol declaration (CreateUserProcedureUseCase) and
adjust any invocations in NoTreatmentViewModel and TreatmentViewModel to call
execute(scheduledDate:recoveryDate:treatments:) so signatures stay consistent
and compilation errors are resolved.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/CalendarMain/CalendarView.swift`:
- Around line 256-260: 해당 블록에서 viewModel.confirmDate() 호출 후
calendarCoordinator.push(.selectTreatment) 호출 다음에 있는 불필요한 공백 라인(현재 빈 줄)을 제거하세요;
즉 CalendarView.swift의 해당 코드 블록에서 calendarCoordinator.push(.selectTreatment) 뒤에
있는 빈 줄을 삭제하여 불필요한 공백을 없애면 됩니다.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/CalendarMain/CalendarViewModel.swift`:
- Around line 104-106: Two methods, sendDateToTreatmentView() and confirmDate(),
perform the same action (assigning selectedDate to
calendarTreatmentFlowState.selectedDaet); remove the duplication by keeping one
method (pick a clear name like sendDateToTreatmentView or confirmDate), delete
the other, and update all callers to invoke the retained method (search for
sendDateToTreatmentView and confirmDate usages). Also ensure the retained method
is accessible where needed and run tests/build to confirm no references remain
to the removed symbol.
- Around line 43-45: Rename the typo property selectedDaet to selectedDate in
CalendarTreatmentFlowState and update all references to the new name (search for
selectedDaet usages), then in CalendarViewModel change the assignment in
confirmDate() to use calendarTreatmentFlowState.selectedDate = selectedDate;
finally remove the duplicate method sendDateToTreatmentView() (or make it call
confirmDate()) so only one implementation remains (update any call sites to the
single method name to avoid breakage).

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/CalendarTreatmentFlowState.swift`:
- Around line 10-12: Rename the mistyped property selectedDaet to selectedDate
in CalendarTreatmentFlowState and update every reference to it across the
codebase (e.g., NoTreatmentViewModel, TreatmentViewModel and any other
consumers) to use CalendarTreatmentFlowState.selectedDate; ensure you update
both declaration and all usages (getters, setters, bindings, initializers) and
run the build to catch any remaining references.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/NoTreatment/NoTreatmentView.swift`:
- Around line 114-122: The Task block around viewModel.createUserProcedure()
lacks error handling so API failures give no user feedback; wrap the await call
in a do/catch inside the Task, handle errors by updating the view state (e.g.,
set an `@State` error/message or call a viewModel.showError method) and present an
alert/toast to the user, and only set tabBarCoordinator.isTabbarHidden = false
and call calendarCoordinator.popToRoot() on successful completion of
createUserProcedure(); reference viewModel.createUserProcedure(),
tabBarCoordinator.isTabbarHidden, and calendarCoordinator.popToRoot when
implementing the changes.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift`:
- Around line 113-121: The code calls try await viewModel.createUserProcedure()
inside a Task without error handling, so wrap that call in a do-catch inside the
Task and only run tabBarCoordinator.isTabbarHidden = false and
calendarCoordinator.popToRoot() after a successful createUserProcedure(); on
error catch and handle appropriately (e.g., call viewModel.handleError(_:) or
present an error alert and keep UI state unchanged), referencing
createUserProcedure() and the viewModel/state check in TreatmentView so failures
don't trigger the navigation changes.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`:
- Around line 90-104: The createUserProcedure() implementation silently returns
on nil dates and swallows errors; fix it by correcting the typos and surfacing
errors: rename calendarTreatmentFlowState.selectedDaet to selectedDate and call
createUserProcedureUseCase.execute(...) (fix excute→execute in the use
case/protocol), validate and throw a clear error when scheduledDate or
recoverDate is nil instead of returning, and in the do/catch rethrow the caught
error (or remove internal catch since the method is async throws) while logging
the actual error via CherrishLogger.network(error) rather than the generic
CherrishError.networkRequestFailed so callers can handle failures.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift`:
- Around line 71-85: The function createUserProcedure is declared async throws
but swallows errors and uses misspelled identifiers; change
calendarTreatmentFlowState.selectedDaet to selectedDate, rename
createUserProcedureUseCase.excute to execute, and propagate errors instead of
swallowing them: either remove the do-catch and call try await
createUserProcedureUseCase.execute(...) so failures bubble up, or if you need
logging, catch the error, log with CherrishLogger.network(error), then rethrow
the caught error; ensure you still pass scheduledDate.toScheduledAtFormat,
recoveryDate.toRecoveryDateFormat, and selectedTreatments unchanged.

In `@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Date`+.swift:
- Around line 49-60: The two computed properties toScheduledAtFormat and
toRecoveryDateFormat create new DateFormatter instances on each access which is
expensive; replace these per-access allocations by reusing static DateFormatter
singletons (e.g., static let scheduledAtFormatter and static let
recoveryDateFormatter) configured with the same formats ("yyyy-MM-dd'T'HH:mm:ss"
and "yyyy-MM-dd") and any needed locale/timeZone, and have the computed
properties call formatter.string(from: self) on those static formatters (or
reuse the existing shared dateFormatter already defined elsewhere if
appropriate) to improve performance and avoid duplication.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift`:
- Around line 76-80: The guard that resolves CreateUserProcedureUseCase via
DIContainer.shared.resolve currently returns silently on failure; update this
guard to log the same DI failure as other guards by calling
CherrishLogger.error(CherrishError.DIFailedError) before returning so failures
are consistently reported — locate the guard that checks
CreateUserProcedureUseCase and insert the error logging call above the return.
- Around line 91-97: The TreatmentViewModel registration closure contains an
unnecessary trailing comma after the last initializer argument
(`createUserProcedureUseCase:`) which can cause compile errors on some Swift
versions; edit the DIContainer.shared.register block and remove the trailing
comma following the `createUserProcedureUseCase` parameter in the
TreatmentViewModel(...) call so the final argument is not followed by a comma.

Comment on lines +1 to +6
//
// UserProcedureItemRequestDTO.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/21/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

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

주석에는 UserProcedureItemRequestDTO.swift로 되어 있으나, 실제 파일명은 CreateUserProcedureRequestDTO.swift입니다.

✏️ 수정 제안
 //
-//  UserProcedureItemRequestDTO.swift
+//  CreateUserProcedureRequestDTO.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
//
// UserProcedureItemRequestDTO.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/21/26.
//
//
// CreateUserProcedureRequestDTO.swift
// Cherrish-iOS
//
// Created by 어재선 on 1/21/26.
//
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Model/CreateUserProcedureRequestDTO.swift`
around lines 1 - 6, 파일 헤더 주석의 파일명이 실제 파일명과 일치하지 않습니다: 현재 상단 주석에
`UserProcedureItemRequestDTO.swift`가 적혀 있으나 파일명은
`CreateUserProcedureRequestDTO.swift`입니다; 파일 상단의 주석 블록(헤더 코멘트)을 찾아
`UserProcedureItemRequestDTO.swift`를 `CreateUserProcedureRequestDTO.swift`로 수정하여
헤더와 실제 파일명이 일치하도록 고치세요.

Copy link
Contributor

Choose a reason for hiding this comment

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

이거한번만봐주세염

Comment on lines 10 to 18
struct UserProcedureItemRequestDTO: Encodable, Decodable {
let procedureId: Int
let downtimeDays: Int
}

struct CreateUserProcedureRequestDTO: Encodable, Decodable {
let scheduledAt: String
let recoveryTargetDate: String
let procedures: [UserProcedureItemRequestDTO]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Codable 타입 별칭 사용을 권장합니다.

Encodable, Decodable을 명시적으로 나열하는 대신 Codable을 사용하면 더 간결합니다.

♻️ 리팩토링 제안
-struct UserProcedureItemRequestDTO: Encodable, Decodable {
+struct UserProcedureItemRequestDTO: Codable {
     let procedureId: Int
     let downtimeDays: Int
 }

-struct CreateUserProcedureRequestDTO: Encodable, Decodable {
+struct CreateUserProcedureRequestDTO: Codable {
     let scheduledAt: String
     let recoveryTargetDate: String
     let procedures: [UserProcedureItemRequestDTO]
 }
📝 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 UserProcedureItemRequestDTO: Encodable, Decodable {
let procedureId: Int
let downtimeDays: Int
}
struct CreateUserProcedureRequestDTO: Encodable, Decodable {
let scheduledAt: String
let recoveryTargetDate: String
let procedures: [UserProcedureItemRequestDTO]
struct UserProcedureItemRequestDTO: Codable {
let procedureId: Int
let downtimeDays: Int
}
struct CreateUserProcedureRequestDTO: Codable {
let scheduledAt: String
let recoveryTargetDate: String
let procedures: [UserProcedureItemRequestDTO]
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Model/CreateUserProcedureRequestDTO.swift`
around lines 10 - 18, Replace the repeated Encodable, Decodable declarations
with the Codable typealias on the DTOs: update both UserProcedureItemRequestDTO
and CreateUserProcedureRequestDTO to conform to Codable instead of listing
Encodable and Decodable separately, keeping existing property names and types
unchanged.

Comment on lines +98 to +108
case .createUserProcedure(_, let request):
return [
"scheduledAt": request.scheduledAt,
"recoveryTargetDate": request.recoveryTargetDate,
"procedures": request.procedures.map {
[
"procedureId": $0.procedureId,
"downtimeDays": $0.downtimeDays
]
}
]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

DTO의 Encodable 준수를 활용하는 것을 고려하세요

CreateUserProcedureRequestDTO가 이미 Encodable을 준수하므로, 수동으로 딕셔너리를 생성하는 대신 직접 인코딩하는 것이 더 안전하고 유지보수하기 쉽습니다. 현재 방식은 DTO 구조가 변경될 때 두 곳을 수정해야 합니다.

♻️ 대안 제안

Alamofire와 함께 사용할 수 있도록 DTO를 Parameters로 변환하는 헬퍼를 만들거나, JSONParameterEncoder를 사용하는 것을 고려하세요:

// 옵션 1: DTO에 extension 추가
extension CreateUserProcedureRequestDTO {
    var asParameters: Parameters {
        guard let data = try? JSONEncoder().encode(self),
              let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
            return [:]
        }
        return dict
    }
}

// 옵션 2: bodyParameters에서 사용
case .createUserProcedure(_, let request):
    return request.asParameters
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/TreatmentAPI.swift` around
lines 98 - 108, The manual dictionary construction in the TreatmentAPI case
.createUserProcedure should be replaced by encoding the existing
CreateUserProcedureRequestDTO to a Parameters-style dictionary to avoid
duplication; add an extension on CreateUserProcedureRequestDTO (or a helper)
that encodes self with JSONEncoder and converts to [String: Any] (e.g.,
asParameters) and then return request.asParameters from the createUserProcedure
case, or alternatively use Alamofire's JSONParameterEncoder when building the
request so the body is derived from the DTO rather than hand-constructed.

Comment on lines 38 to 46
func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws {
let userId: Int = userDefaultService.load(key: .userID) ?? 1
let request = CreateUserProcedureRequestDTO(
scheduledAt: scheduledDate,
recoveryTargetDate: recoveryDate,
procedures: treatments.compactMap { $0.toRequestDTO() }
)
let _ = try await networkService.request(TreatmentAPI.createUserProcedure(userId: userId, request: request), decodingType: UserProcedureItemRequestDTO.self)
}
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:

# First, find and read the TreatmentRepository.swift file to understand the full context
find . -name "TreatmentRepository.swift" -type f

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 139


🏁 Script executed:

# Search for TreatmentInterface protocol definition
rg -n "protocol TreatmentInterface" --type swift -A 20

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 729


🏁 Script executed:

# Search for UserProcedureItemRequestDTO definition
rg -n "struct UserProcedureItemRequestDTO\|class UserProcedureItemRequestDTO" --type swift -A 5

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 52


🏁 Script executed:

# Search for response DTOs related to user procedures
rg -n "UserProcedure.*ResponseDTO\|UserProcedure.*Response\|.*ProcedureResponse" --type swift -A 5

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 52


🏁 Script executed:

# Search for TreatmentEntity and its toRequestDTO method
rg -n "func toRequestDTO" --type swift -B 2 -A 10

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1048


🏁 Script executed:

# Search for MockTreatmentRepository
rg -n "class MockTreatmentRepository\|struct MockTreatmentRepository" --type swift -A 30

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 52


🏁 Script executed:

# Find UserProcedureItemRequestDTO definition with broader search
rg -n "UserProcedureItemRequestDTO" --type swift -B 2 -A 5

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 3706


🏁 Script executed:

# Read the full TreatmentRepository.swift file
cat -n ./Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 3175


🏁 Script executed:

# Search for MockTreatmentRepository without exact class/struct syntax
rg -n "MockTreatmentRepository" --type swift -B 2 -A 20

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 2471


🏁 Script executed:

# Search for any DTO that contains "Procedure" in name
rg -n "struct.*Procedure.*DTO\|class.*Procedure.*DTO" --type swift -A 3

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 52


procedures 배열이 비어서 전송될 수 있습니다.

compactMap { $0.toRequestDTO() }setDowntime이 nil인 모든 treatment를 필터링합니다. 모든 treatment의 setDowntime이 nil이면 빈 procedures 배열이 생성되어 API 요청이 전송됩니다. 이에 대한 유효성 검사 또는 에러 처리를 추가해야 합니다.

또한 Line 45의 응답 타입으로 UserProcedureItemRequestDTO를 사용하고 있는데, 이는 요청용 DTO입니다. 서버 응답에 맞는 별도의 Response DTO를 정의하고 사용해야 합니다.

추가로 MockTreatmentRepository의 createUserProcedure 메서드(Line 51)에 async throws 키워드가 누락되어 있습니다. TreatmentInterface 프로토콜 요구사항과 일치시켜주세요.

🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift` around
lines 38 - 46, createUserProcedure currently uses treatments.compactMap {
$0.toRequestDTO() } which drops any treatments whose setDowntime is nil and can
produce an empty procedures array; add validation in createUserProcedure to
check the resulting procedures array and throw (or return) a clear error before
calling networkService.request when procedures.isEmpty, and surface that error
to callers; replace the incorrect decodingType UserProcedureItemRequestDTO with
a dedicated response DTO (e.g., UserProcedureItemResponseDTO) that matches the
server response and update the request call (TreatmentAPI.createUserProcedure)
to decode that response type; finally, make
MockTreatmentRepository.createUserProcedure conform by adding the missing async
throws signature so it matches the TreatmentInterface protocol.

Comment on lines +51 to +53
func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) {

}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

MockTreatmentRepository.createUserProcedure 메서드 시그니처가 프로토콜과 불일치합니다.

DefaultTreatmentRepositorycreateUserProcedureasync throws로 선언되어 있으나, Mock 구현체는 이를 누락하고 있습니다. 프로토콜 TreatmentInterface의 요구사항과 일치시켜야 합니다.

🐛 수정 제안
-    func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) {
-        
+    func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws {
+        // Mock implementation - no-op
     }
📝 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
func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) {
}
func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws {
// Mock implementation - no-op
}
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift` around
lines 51 - 53, MockTreatmentRepository.createUserProcedure has a different
signature than the protocol and DefaultTreatmentRepository; update
MockTreatmentRepository.createUserProcedure to match the protocol's declaration
by adding async throws to its signature (so it matches TreatmentInterface and
DefaultTreatmentRepository), and ensure its implementation returns/throws
appropriately for the mock behavior.

Comment on lines 90 to 104
func createUserProcedure() async throws {
guard let scheduledDate = calendarTreatmentFlowState.selectedDaet else {
return
}

guard let recoverDate = Date.from(year: year, month: month, day: day) else {
return
}

do {
try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
} catch {
CherrishLogger.network(CherrishError.networkRequestFailed)
}
}
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
# Find the NoTreatmentViewModel file and check its content
find . -name "NoTreatmentViewModel.swift" -type f

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 196


🏁 Script executed:

#!/bin/bash
# Find CreateUserProcedureUseCase to check the method name (excute vs execute)
find . -name "*CreateUserProcedureUseCase*" -type f

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 145


🏁 Script executed:

#!/bin/bash
# Search for the excute method across the codebase
rg "func excute" --type swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 429


🏁 Script executed:

#!/bin/bash
# Search for the execute method across the codebase
rg "func execute" --type swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 2267


🏁 Script executed:

#!/bin/bash
# Search for selectedDaet or selectedDate property
rg "selectedDa" --type swift -A 2 -B 2

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 6880


에러 처리 개선 및 오타 수정 필요

이 메서드에서 여러 문제가 있습니다:

  1. async throws로 선언되었지만 에러를 throw하지 않고 내부에서 모두 catch합니다.
  2. scheduledDaterecoverDate가 nil일 때 조용히 반환하여 호출자에게 피드백이 없습니다.
  3. 실제 에러를 무시하고 generic networkRequestFailed 에러만 로깅합니다.
  4. selectedDaet 는 CalendarTreatmentFlowState의 프로퍼티명 오타입니다 (올바른 철자: selectedDate).
  5. excute 메서드는 CreateUserProcedureUseCase의 오타입니다 (올바른 철자: execute).
🔧 수정 제안
    func createUserProcedure() async throws {
-       guard let scheduledDate = calendarTreatmentFlowState.selectedDaet else {
-           return
+       guard let scheduledDate = calendarTreatmentFlowState.selectedDate else {
+           CherrishLogger.debug("scheduledDate is nil")
+           throw CherrishError.invalidInput
        }
        
        guard let recoverDate = Date.from(year: year, month: month, day: day) else {
+           CherrishLogger.debug("Invalid recovery date")
+           throw CherrishError.invalidInput
-           return
        }
        
-       do {
-           try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
-       } catch {
-           CherrishLogger.network(CherrishError.networkRequestFailed)
-       }
+       try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
    }

주의: selectedDaetselectedDate 변경 시 CalendarTreatmentFlowState.swift와 이를 참조하는 다른 파일들도 함께 수정해야 합니다. excuteexecute 변경은 CreateUserProcedureUseCase.swift에서 메서드명과 프로토콜 정의를 모두 수정해야 합니다.

🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift`
around lines 90 - 104, The createUserProcedure() implementation silently returns
on nil dates and swallows errors; fix it by correcting the typos and surfacing
errors: rename calendarTreatmentFlowState.selectedDaet to selectedDate and call
createUserProcedureUseCase.execute(...) (fix excute→execute in the use
case/protocol), validate and throw a clear error when scheduledDate or
recoverDate is nil instead of returning, and in the do/catch rethrow the caught
error (or remove internal catch since the method is async throws) while logging
the actual error via CherrishLogger.network(error) rather than the generic
CherrishError.networkRequestFailed so callers can handle failures.

Comment on lines 71 to 85
func createUserProcedure() async throws {
guard let scheduledDate = calendarTreatmentFlowState.selectedDaet else {
return
}

guard let recoverDate = Date.from(year: year, month: month, day: day) else {
return
}

do {
try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
} catch {
CherrishLogger.network(CherrishError.networkRequestFailed)
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -n "selectedDa" --type swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 1889


🏁 Script executed:

rg -n "excute|execute" --type swift -B 2 -A 2

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 17254


🏁 Script executed:

rg -n "CalendarTreatmentFlowState" --type swift -A 5 | head -50

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 6320


🏁 Script executed:

fd "CalendarTreatmentFlowState" --type swift

Repository: TEAM-Cherrish/Cherrish-iOS

Length of output: 242


throws 선언과 에러 처리 로직이 불일치합니다.

함수가 async throws로 선언되어 있지만, 내부에서 에러를 catch하고 로깅만 수행합니다. 이로 인해 호출자가 실패 여부를 알 수 없습니다. 에러를 re-throw하거나 함수 시그니처에서 throws를 제거해 주세요.

또한 Line 72의 selectedDaet는 오타입니다 (selectedDate가 올바른 표기). CreateUserProcedureUseCase의 메서드명도 excute에서 execute로 수정이 필요합니다.

♻️ 에러 전파 방식 수정 제안
     func createUserProcedure() async throws {
-        guard let scheduledDate = calendarTreatmentFlowState.selectedDaet else {
+        guard let scheduledDate = calendarTreatmentFlowState.selectedDate else {
             return
         }
         
         guard let recoverDate = Date.from(year: year, month: month, day: day) else {
             return
         }
         
-        do {
-            try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
-        } catch {
-            CherrishLogger.network(CherrishError.networkRequestFailed)
-        }
+        try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
     }
📝 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
func createUserProcedure() async throws {
guard let scheduledDate = calendarTreatmentFlowState.selectedDaet else {
return
}
guard let recoverDate = Date.from(year: year, month: month, day: day) else {
return
}
do {
try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
} catch {
CherrishLogger.network(CherrishError.networkRequestFailed)
}
}
func createUserProcedure() async throws {
guard let scheduledDate = calendarTreatmentFlowState.selectedDate else {
return
}
guard let recoverDate = Date.from(year: year, month: month, day: day) else {
return
}
try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
}
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift`
around lines 71 - 85, The function createUserProcedure is declared async throws
but swallows errors and uses misspelled identifiers; change
calendarTreatmentFlowState.selectedDaet to selectedDate, rename
createUserProcedureUseCase.excute to execute, and propagate errors instead of
swallowing them: either remove the do-catch and call try await
createUserProcedureUseCase.execute(...) so failures bubble up, or if you need
logging, catch the error, log with CherrishLogger.network(error), then rethrow
the caught error; ensure you still pass scheduledDate.toScheduledAtFormat,
recoveryDate.toRecoveryDateFormat, and selectedTreatments unchanged.

Copy link
Contributor

Choose a reason for hiding this comment

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

network -> error

Comment on lines +76 to 80


guard let createUserProcedureUseCase = DIContainer.shared.resolve(type: CreateUserProcedureUseCase.self) else {
return
}
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

에러 로깅이 누락되었습니다.

다른 guard 문들은 실패 시 CherrishLogger.error(CherrishError.DIFailedError)를 호출하지만, 이 블록은 로깅 없이 return만 합니다. 일관성을 위해 에러 로깅을 추가해 주세요.

✏️ 수정 제안
         guard let createUserProcedureUseCase = DIContainer.shared.resolve(type: CreateUserProcedureUseCase.self) else {
+            CherrishLogger.error(CherrishError.DIFailedError)
             return
         }
📝 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
guard let createUserProcedureUseCase = DIContainer.shared.resolve(type: CreateUserProcedureUseCase.self) else {
return
}
guard let createUserProcedureUseCase = DIContainer.shared.resolve(type: CreateUserProcedureUseCase.self) else {
CherrishLogger.error(CherrishError.DIFailedError)
return
}
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift`
around lines 76 - 80, The guard that resolves CreateUserProcedureUseCase via
DIContainer.shared.resolve currently returns silently on failure; update this
guard to log the same DI failure as other guards by calling
CherrishLogger.error(CherrishError.DIFailedError) before returning so failures
are consistently reported — locate the guard that checks
CreateUserProcedureUseCase and insert the error logging call above the return.

Copy link
Contributor

@y-eonee y-eonee left a comment

Choose a reason for hiding this comment

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

flowState 좋아요
리뷰 한번만 봐주세요 !!!
IMG_3888

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

Choose a reason for hiding this comment

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

이거한번만봐주세염

Comment on lines 10 to 15
struct UserProcedureItemRequestDTO: Encodable, Decodable {
let procedureId: Int
let downtimeDays: Int
}

struct CreateUserProcedureRequestDTO: Encodable, Decodable {
Copy link
Contributor

Choose a reason for hiding this comment

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

리퀘스트니까 encodable만 쓰면 되겟져 ~~ ?

Comment on lines 10 to 12
protocol CreateUserProcedureUseCase {
func excute(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws
}
Copy link
Contributor

Choose a reason for hiding this comment

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

오타 고쳐주세욤

Comment on lines 22 to 24
func excute(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws {
return try await repository.createUserProcedure(scheduledDate: scheduledDate, recoveryDate: recoveryDate, treatments: treatments)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

개행 한번만요!

Comment on lines 43 to 45
func confirmDate() {
calendarTreatmentFlowState.selectedDaet = selectedDate
}
Copy link
Contributor

Choose a reason for hiding this comment

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

이거 한번만 봐주세용

Comment on lines 114 to 122
if viewModel.state == .downTimeSetting {
Task {
try await viewModel.createUserProcedure()
tabBarCoordinator.isTabbarHidden = false
calendarCoordinator.popToRoot()
}
} else {
viewModel.next()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

do {
try await ~
} catch {
CherrishLogger.error(error)
} 이렇게 써주면 조을것 같아요

Comment on lines 113 to 121
if viewModel.state == .downTimeSetting {
Task {
try await viewModel.createUserProcedure()
tabBarCoordinator.isTabbarHidden = false
calendarCoordinator.popToRoot()
}
} else {
viewModel.next()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

여기도~

Comment on lines 100 to 102
try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
} catch {
CherrishLogger.network(CherrishError.networkRequestFailed)
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. 개행
  2. network 말고 CherrishLogger.error(error)로 찍어주세여

Comment on lines 71 to 85
func createUserProcedure() async throws {
guard let scheduledDate = calendarTreatmentFlowState.selectedDaet else {
return
}

guard let recoverDate = Date.from(year: year, month: month, day: day) else {
return
}

do {
try await createUserProcedureUseCase.excute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
} catch {
CherrishLogger.network(CherrishError.networkRequestFailed)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

network -> error

Comment on lines +12 to +18

private let userDefaultService: UserDefaultService

init(userDefaultService: UserDefaultService = DefaultUserDefaultService()) {
self.userDefaultService = userDefaultService
}

Copy link
Contributor

Choose a reason for hiding this comment

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

이거는 롤백부탁드려여

Copy link
Contributor

@soseoyo12 soseoyo12 left a comment

Choose a reason for hiding this comment

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

수고하셨습니당

Comment on lines 10 to 12
final class CalendarTreatmentFlowState: ObservableObject {
@Published var selectedDaet: Date?
}
Copy link
Contributor

Choose a reason for hiding this comment

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

확인해주세영

Comment on lines -77 to +106
let monthInt = Int(month), monthInt >= 1, monthInt <= 12,
let dayInt = Int(day), dayInt >= 1, dayInt <= 31 else {
let monthInt = Int(month), (1...12).contains(monthInt),
let dayInt = Int(day), (1...31).contains(dayInt) else {
Copy link
Contributor

Choose a reason for hiding this comment

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

굳입니당

Copy link
Contributor

@sum130 sum130 left a comment

Choose a reason for hiding this comment

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

오타 한 번씩 확인해주세용 어푸푸!

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

🤖 Fix all issues with AI agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/NoTreatment/NoTreatmentView.swift`:
- Around line 117-130: The navigation lines run regardless of API success; wrap
tabBarCoordinator.isTabbarHidden = false and calendarCoordinator.popToRoot() so
they only execute on successful createUserProcedure(): inside the Task's do
block, after await viewModel.createUserProcedure(), perform the two navigation
calls; in the catch block log the error (CherrishLogger.error(error)) and
present or propagate an error UI/state instead of allowing the function to
continue to navigation; ensure viewModel.next() remains in the else branch for
non-.downTimeSetting flows.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift`:
- Around line 113-126: The screen transition is executed even when the API call
fails because tabBarCoordinator.isTabbarHidden = false and
calendarCoordinator.popToRoot() are outside the do block; update the Task in
TreatmentView so that those two calls are moved inside the do block immediately
after successful await viewModel.createUserProcedure(), and keep the catch block
to call CherrishLogger.error(error) without performing the transitions; ensure
the else branch still calls viewModel.next() as before.

In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift`:
- Around line 61-68: fetchTreatments() is declared async throws but swallows
errors internally; either remove throws from the signature or rethrow the caught
error so callers can handle it. To fix: in TreatmentViewModel.update the
function fetchTreatments() adjust the error handling around
fetchTreatmentsUseCase.execute(id:keyword:)—option A: remove throws from func
signature and keep the do/catch that sets treatments = [] on error (handling
locally); option B: if you want callers to observe failures, rethrow the error
in the catch (i.e., catch { treatments = []; throw error } or simply remove the
do/catch and let try await propagate). Ensure the signature and internal
behavior for fetchTreatments() are consistent.

In `@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Date`+.swift:
- Around line 69-79: Date.from(year:month:day:) uses Calendar.current which can
vary by user settings; change it to create and use a dedicated Calendar (e.g.,
Calendar(identifier: .gregorian)) configured with TimeZone(identifier:
"Asia/Seoul") and a consistent Locale (matching
scheduledAtFormatter/dateFormatter) before calling date(from:), so the date
construction is timezone/locale deterministic; update the method to build
components with that calendar instead of Calendar.current.
♻️ Duplicate comments (7)
Cherrish-iOS/Cherrish-iOS/Data/Model/CreateUserProcedureRequestDTO.swift (1)

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

주석에는 UserProcedureItemRequestDTO.swift로 되어 있으나, 실제 파일명은 CreateUserProcedureRequestDTO.swift입니다.

Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/CalendarMain/CalendarView.swift (1)

256-260: 네비게이션 전 상태 동기화가 잘 적용되었습니다.

sendDateToTreatmentView() 호출이 일관되게 적용되었습니다. Line 260의 불필요한 공백은 제거하는 것이 좋습니다.

Cherrish-iOS/Cherrish-iOS/Data/Repository/TreatmentRepository.swift (2)

64-66: MockTreatmentRepository.createUserProcedure 메서드 시그니처가 프로토콜과 불일치합니다.

DefaultTreatmentRepositorycreateUserProcedureasync throws로 선언되어 있으나, Mock 구현체는 이를 누락하고 있습니다. 프로토콜 TreatmentInterface의 요구사항과 일치시켜야 컴파일 에러가 발생하지 않습니다.

🐛 수정 제안
-    func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) {
-        
+    func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws {
+        // Mock implementation - no-op
     }

45-59: procedures 배열이 비어있을 때의 검증이 필요합니다.

treatments.compactMap { $0.toRequestDTO() }setDowntime이 nil인 모든 treatment를 필터링합니다. 모든 treatment의 downtime이 설정되지 않았다면 빈 procedures 배열로 API 요청이 전송됩니다.

🔧 수정 제안
     func createUserProcedure(scheduledDate: String, recoveryDate: String, treatments: [TreatmentEntity]) async throws {
         let userId: Int = userDefaultService.load(key: .userID) ?? 1
+        let procedures = treatments.compactMap { $0.toRequestDTO() }
+        guard !procedures.isEmpty else {
+            throw CherrishError.invalidInput
+        }
         let request = CreateUserProcedureRequestDTO(
             scheduledAt: scheduledDate,
             recoveryTargetDate: recoveryDate,
-            procedures: treatments.compactMap { $0.toRequestDTO() }
+            procedures: procedures
         )
Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift (1)

76-79: 에러 로깅이 누락되었습니다.

다른 guard 문들은 실패 시 CherrishLogger.error(CherrishError.DIFailedError)를 호출하지만, 이 블록은 로깅 없이 return만 합니다.

✏️ 수정 제안
     guard let createUserProcedureUseCase = DIContainer.shared.resolve(type: CreateUserProcedureUseCase.self) else {
+        CherrishLogger.error(CherrishError.DIFailedError)
         return
     }
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/NoTreatment/NoTreatmentViewModel.swift (1)

90-103: async throws로 선언되었지만 에러를 throw하지 않습니다.

메서드가 async throws로 선언되었지만, 내부에서 모든 에러를 catch하여 로깅만 하고 있습니다. 호출자(NoTreatmentView)에서 에러 처리를 할 수 있도록 에러를 전파하거나, throws를 제거하는 것이 좋습니다.

또한 이전 리뷰 피드백에 따라 CherrishLogger.network(error) 대신 CherrishLogger.error(error)를 사용해 주세요.

🔧 수정 제안
     func createUserProcedure() async throws {
         guard let scheduledDate = calendarTreatmentFlowState.selectedDate else {
+            CherrishLogger.debug("scheduledDate is nil")
             return
         }
         
         guard let recoverDate = Date.from(year: year, month: month, day: day) else {
+            CherrishLogger.debug("Invalid recovery date")
             return
         }
         
-        do {
-            try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
-        } catch {
-            CherrishLogger.network(error)
-        }
+        try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
     }
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift (1)

71-85: throws 선언과 에러 처리 로직이 여전히 불일치합니다.

이전 리뷰에서 지적된 오타(selectedDaet, excute)는 수정되었으나, 함수가 async throws로 선언되어 있으면서 에러를 catch 후 로깅만 수행하고 re-throw하지 않는 문제가 그대로 남아 있습니다. 호출자가 실패 여부를 알 수 없습니다.

♻️ 에러 전파 방식 수정 제안

옵션 1: 에러를 전파 (권장)

     func createUserProcedure() async throws {
         guard let scheduledDate = calendarTreatmentFlowState.selectedDate else {
             return
         }
         
         guard let recoverDate = Date.from(year: year, month: month, day: day) else {
             return
         }
         
-        do {
-            try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
-        } catch {
-            CherrishLogger.network(error)
-        }
+        try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
     }

옵션 2: 로깅 후 re-throw

         do {
             try await createUserProcedureUseCase.execute(scheduledDate: scheduledDate.toScheduledAtFormat, recoveryDate: recoverDate.toRecoveryDateFormat, treatments: selectedTreatments)
         } catch {
             CherrishLogger.network(error)
+            throw error
         }

옵션 3: throws 제거 (에러 무시가 의도적인 경우)

-    func createUserProcedure() async throws {
+    func createUserProcedure() async {

Comment on lines +117 to +130
if viewModel.state == .downTimeSetting {
Task {
do {
try await viewModel.createUserProcedure()
} catch {
CherrishLogger.error(error)
}

tabBarCoordinator.isTabbarHidden = false
calendarCoordinator.popToRoot()
}
} else {
viewModel.next()
}
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

API 실패 시에도 화면이 전환됩니다.

do/catch 블록이 추가되었지만, tabBarCoordinator.isTabbarHidden = falsecalendarCoordinator.popToRoot()do 블록 외부에 있어 API 호출 실패 시에도 화면이 전환됩니다. 사용자에게 에러 피드백 없이 화면이 닫히면 혼란을 줄 수 있습니다.

🔧 수정 제안
 if viewModel.state == .downTimeSetting {
     Task {
         do {
             try await viewModel.createUserProcedure()
+            tabBarCoordinator.isTabbarHidden = false
+            calendarCoordinator.popToRoot()
         } catch {
             CherrishLogger.error(error)
+            // TODO: 사용자에게 에러 표시 (예: Alert, Toast 등)
         }
-      
-        tabBarCoordinator.isTabbarHidden = false
-        calendarCoordinator.popToRoot()
     }
 } else {
     viewModel.next()
 }
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/NoTreatment/NoTreatmentView.swift`
around lines 117 - 130, The navigation lines run regardless of API success; wrap
tabBarCoordinator.isTabbarHidden = false and calendarCoordinator.popToRoot() so
they only execute on successful createUserProcedure(): inside the Task's do
block, after await viewModel.createUserProcedure(), perform the two navigation
calls; in the catch block log the error (CherrishLogger.error(error)) and
present or propagate an error UI/state instead of allowing the function to
continue to navigation; ensure viewModel.next() remains in the else branch for
non-.downTimeSetting flows.

Comment on lines +113 to +126
if viewModel.state == .downTimeSetting {
Task {
do {
try await viewModel.createUserProcedure()
} catch {
CherrishLogger.error(error)
}

tabBarCoordinator.isTabbarHidden = false
calendarCoordinator.popToRoot()
}
} else {
viewModel.next()
}
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

API 호출 성공 시에만 화면 전환이 실행되어야 합니다.

do-catch 블록이 추가되었지만, tabBarCoordinator.isTabbarHidden = falsecalendarCoordinator.popToRoot()do 블록 외부에 있어서 API 호출 실패 시에도 화면 전환이 실행됩니다.

🐛 수정 제안
 if viewModel.state == .downTimeSetting {
     Task {
         do {
             try await viewModel.createUserProcedure()
+            tabBarCoordinator.isTabbarHidden = false
+            calendarCoordinator.popToRoot()
         } catch {
             CherrishLogger.error(error)
+            // TODO: 사용자에게 에러 상태 표시
         }
-        
-        tabBarCoordinator.isTabbarHidden = false
-        calendarCoordinator.popToRoot()
     }
 } else {
     viewModel.next()
 }
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/View/Treatment/TreatmentView.swift`
around lines 113 - 126, The screen transition is executed even when the API call
fails because tabBarCoordinator.isTabbarHidden = false and
calendarCoordinator.popToRoot() are outside the do block; update the Task in
TreatmentView so that those two calls are moved inside the do block immediately
after successful await viewModel.createUserProcedure(), and keep the catch block
to call CherrishLogger.error(error) without performing the transitions; ensure
the else branch still calls viewModel.next() as before.

Comment on lines 61 to 68
@MainActor
func fetchTreatments() async throws {
do {
treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
} catch {
treatments = []
}
}
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

함수 시그니처와 에러 처리의 불일치

fetchTreatments()async throws로 선언되어 있지만, 내부에서 에러를 catch하고 빈 배열로 대체합니다. 호출자에게 에러가 전파되지 않으므로 throws를 제거하거나, 에러를 re-throw하는 것이 좋습니다.

♻️ 제안
     `@MainActor`
-    func fetchTreatments() async throws {
+    func fetchTreatments() async {
         do {
             treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
         } catch {
             treatments = []
         }
     }
📝 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 fetchTreatments() async throws {
do {
treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
} catch {
treatments = []
}
}
`@MainActor`
func fetchTreatments() async {
do {
treatments = try await fetchTreatmentsUseCase.execute(id: nil, keyword: searchText)
} catch {
treatments = []
}
}
🤖 Prompt for AI Agents
In
`@Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/ViewModel/Treatment/TreatmentViewModel.swift`
around lines 61 - 68, fetchTreatments() is declared async throws but swallows
errors internally; either remove throws from the signature or rethrow the caught
error so callers can handle it. To fix: in TreatmentViewModel.update the
function fetchTreatments() adjust the error handling around
fetchTreatmentsUseCase.execute(id:keyword:)—option A: remove throws from func
signature and keep the do/catch that sets treatments = [] on error (handling
locally); option B: if you want callers to observe failures, rethrow the error
in the catch (i.e., catch { treatments = []; throw error } or simply remove the
do/catch and let try await propagate). Ensure the signature and internal
behavior for fetchTreatments() are consistent.

Comment on lines +69 to +79
static func from(year: String, month: String, day: String) -> Date? {
guard let y = Int(year),
let m = Int(month),
let d = Int(day) else { return nil }

var components = DateComponents()
components.year = y
components.month = m
components.day = d
return Calendar.current.date(from: components)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Calendar의 locale/timeZone 설정 누락 가능성

Date.from(year:month:day:)에서 Calendar.current를 사용하면 사용자 기기 설정에 따라 다른 결과가 나올 수 있습니다. scheduledAtFormatterdateFormatter에서 Asia/Seoul 타임존을 명시한 것과 일관성을 유지하려면 Calendar도 동일하게 설정하는 것이 좋습니다.

♻️ 타임존 일관성 적용 제안
 static func from(year: String, month: String, day: String) -> Date? {
     guard let y = Int(year),
           let m = Int(month),
           let d = Int(day) else { return nil }
     
+    var calendar = Calendar.current
+    calendar.timeZone = TimeZone(identifier: "Asia/Seoul") ?? .current
+    
     var components = DateComponents()
     components.year = y
     components.month = m
     components.day = d
-    return Calendar.current.date(from: components)
+    return calendar.date(from: components)
 }
📝 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
static func from(year: String, month: String, day: String) -> Date? {
guard let y = Int(year),
let m = Int(month),
let d = Int(day) else { return nil }
var components = DateComponents()
components.year = y
components.month = m
components.day = d
return Calendar.current.date(from: components)
}
static func from(year: String, month: String, day: String) -> Date? {
guard let y = Int(year),
let m = Int(month),
let d = Int(day) else { return nil }
var calendar = Calendar.current
calendar.timeZone = TimeZone(identifier: "Asia/Seoul") ?? .current
var components = DateComponents()
components.year = y
components.month = m
components.day = d
return calendar.date(from: components)
}
🤖 Prompt for AI Agents
In `@Cherrish-iOS/Cherrish-iOS/Presentation/Global/Extension/Date`+.swift around
lines 69 - 79, Date.from(year:month:day:) uses Calendar.current which can vary
by user settings; change it to create and use a dedicated Calendar (e.g.,
Calendar(identifier: .gregorian)) configured with TimeZone(identifier:
"Asia/Seoul") and a consistent Locale (matching
scheduledAtFormatter/dateFormatter) before calling date(from:), so the date
construction is timezone/locale deterministic; update the method to build
components with that calendar instead of Calendar.current.

@wotjs020708 wotjs020708 merged commit 18c3313 into develop Jan 21, 2026
5 checks passed
@wotjs020708 wotjs020708 deleted the feat/#125-flowstate branch January 21, 2026 11:49
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] FlowState

4 participants

Comments