Skip to content

[Feat-T3-134] 루틴 삭제 구현#35

Merged
choijungp merged 5 commits intodevelopfrom
feat/routine-delete
Aug 5, 2025
Merged

[Feat-T3-134] 루틴 삭제 구현#35
choijungp merged 5 commits intodevelopfrom
feat/routine-delete

Conversation

@choijungp
Copy link
Copy Markdown
Contributor

@choijungp choijungp commented Aug 5, 2025

🌁 Background

루틴 삭제를 구현하였습니다.

  • 당일 루틴인 경우 (온보딩에서 추가한 루틴) : Alert View 없이 바로 삭제
  • 반복 설정이 된 루틴인 경우 (루틴 등록에서 직접 등록한 루틴) : Alert View를 통해 당일만 삭제할지, 반복되는 루틴 전체 삭제할지 선택하여 삭제

📱 Screenshot

루틴 삭제 Alert View

iPhone SE3 iPhone 13 mini iPhone 16 Pro
Simulator Screenshot - iPhone SE (3rd generation) - 2025-08-05 at 00 55 58 Simulator Screenshot - iPhone 13 mini - 2025-08-05 at 00 53 48 Simulator Screenshot - iPhone 16 Pro - 2025-08-05 at 00 50 17

전체 흐름

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-08-05.at.00.23.41.mp4

👩‍💻 Contents

  • RoutineDeleteAlertView UI 구현
  • RoutineEndpoint에 루틴 당일 삭제, 루틴 전체 삭제 case 추가
  • RoutineRepository, RoutineUseCase, HomeViewModel에 삭제 로직 추가

✅ Testing

  • 온보딩을 통해 등록한 루틴 삭제
  • 반복 루틴의 당일 삭제
  • 반복 루틴의 전체 삭제

를 테스트 해보았습니다.

📝 Review Note

1. DTO <-> Entity

띵의 PR에서 말씀해주신 요 부분 .....
저도 마찬가지로 DIP 라고는 하지만 Entity가 DTO를 너무 알고 있어요 ㅠㅠ

배포 후 꼭 개선할게요 ....

그리고 일단 DTO -> Entity는 일단 현상 유지 했지만 ... Entity -> DTO는 repository에서 하게 했슴니다 !!!!

📣 Related Issue

  • close #T3-134

Summary by CodeRabbit

새로운 기능

  • 루틴 삭제 시 "당일만 삭제"와 "전체 루틴 삭제"를 선택할 수 있는 삭제 확인 알림창이 추가되었습니다.
  • 홈 화면에서 루틴 삭제 시 반복 루틴 여부에 따라 삭제 옵션을 안내합니다.
  • 루틴 및 서브루틴 정보에 삭제 관련 데이터가 확장되었습니다.
  • 루틴 삭제 기능이 도메인, 데이터 소스, 뷰모델, 유즈케이스 전반에 걸쳐 추가되어, 사용자가 루틴 전체 또는 당일 루틴만 선택적으로 삭제할 수 있습니다.

버그 수정

  • Apple 로그인 시 이메일 정보도 함께 요청하도록 개선되었습니다.

기타

  • 불필요한 파일이 정리되었습니다.

@choijungp choijungp requested a review from taipaise August 5, 2025 02:59
@choijungp choijungp self-assigned this Aug 5, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 5, 2025

Walkthrough

이 변경 사항은 루틴 삭제 기능을 도메인, 데이터 소스, 프레젠테이션 계층 전반에 걸쳐 추가 및 확장합니다. 새로운 DTO 및 Entity 구조체가 도입되었으며, 삭제 관련 UseCase, Repository, ViewModel, View가 연동되어 일관된 루틴/서브루틴 삭제 흐름을 구현합니다. 삭제 시 사용자 확인을 위한 커스텀 Alert UI도 추가되었습니다.

Changes

Cohort / File(s) Change Summary
DTO 및 Entity 추가
Projects/DataSource/Sources/DTO/DeleteRoutineDTO.swift, Projects/Domain/Sources/Entity/DeleteRoutineEntity.swift
루틴 및 서브루틴 삭제 정보를 담는 DTO, Entity 구조체 신설. Encodable 준수, 삭제에 필요한 식별자 및 메타데이터 포함.
Endpoint 및 Repository 확장
Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift, Projects/DataSource/Sources/Repository/RoutineRepository.swift
루틴 전체/당일 삭제를 위한 Endpoint 케이스 및 Repository 메서드 추가. 네트워크 요청에 DTO 변환 및 전송 로직 포함.
프로토콜 및 UseCase 확장
Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift, Projects/Domain/Sources/Protocol/UseCase/RoutineUseCaseProtocol.swift, Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift
루틴 전체/당일 삭제 메서드가 프로토콜 및 UseCase에 추가되어 계층 간 인터페이스 일관성 확보.
홈 뷰모델 및 UI 연동
Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift, Projects/Presentation/Sources/Home/View/HomeView.swift, Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift
루틴 삭제 액션, 선택 상태 관리, 삭제 결과 퍼블리셔 및 AlertView 연동. 삭제 시 사용자 확인 절차와 UI 상태 관리 추가.
모델 확장
Projects/Presentation/Sources/Home/Model/MainRoutine.swift, Projects/Presentation/Sources/Home/Model/SubRoutine.swift
루틴 및 서브루틴 모델에 삭제에 필요한 completionId, historySeq, routineType 등 속성 추가.
기타 사소한 변경
Projects/DataSource/Sources/Endpoint/EmotionEndpoint.swift, Projects/Domain/Sources/Entity/Untitled.swift, Projects/Presentation/Sources/Login/View/LoginView.swift
EmotionEndpoint 패턴 단순화, 불필요 파일 제거, Apple 로그인 시 email scope 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant HomeView
    participant RoutineDeleteAlertView
    participant HomeViewModel
    participant RoutineUseCase
    participant RoutineRepository
    participant NetworkService

    User->>HomeView: 루틴 삭제 버튼 클릭
    HomeView->>RoutineDeleteAlertView: 삭제 AlertView 표시
    User->>RoutineDeleteAlertView: "전체 루틴 삭제" 또는 "당일만 삭제" 선택
    RoutineDeleteAlertView->>HomeView: Delegate 콜백
    HomeView->>HomeViewModel: .deleteAllRoutine or .deleteDailyRoutine 액션
    HomeViewModel->>RoutineUseCase: deleteAllRoutine() 또는 deleteDailyRoutine()
    RoutineUseCase->>RoutineRepository: deleteAllRoutine() 또는 deleteDailyRoutine()
    RoutineRepository->>NetworkService: DELETE 요청 전송
    NetworkService-->>RoutineRepository: 응답 반환
    RoutineRepository-->>RoutineUseCase: 완료/에러 반환
    RoutineUseCase-->>HomeViewModel: 완료/에러 반환
    HomeViewModel-->>HomeView: deleteRoutineResultPublisher로 결과 알림
    HomeView->>HomeView: AlertView 닫기 및 루틴 목록 갱신
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40분

Suggested reviewers

  • taipaise

Poem

🐇
루틴 삭제, 오늘은 새로워
AlertView가 반짝이며 등장해
한 번만? 모두 다? 선택해봐
ViewModel이 바삐 움직이고
네트워크로 삭제 소식 전해
깔끔한 UI, 기분 좋은 변화
토끼도 박수 짝짝짝!

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 18a980f and e56623d.

📒 Files selected for processing (2)
  • Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift (1 hunks)
  • Projects/Presentation/Sources/Home/View/HomeView.swift (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift:0-0
Timestamp: 2025-07-16T10:57:16.559Z
Learning: choijungp는 추후 CustomAlertView를 만들어서 에러 처리를 UI로 해결하도록 수정할 계획을 가지고 있음.
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Domain/Sources/UseCase/Onboarding/OnboardingUseCase.swift:0-0
Timestamp: 2025-07-16T10:58:30.858Z
Learning: choijungp는 OnboardingUseCase의 convertToDictionary 함수에서 에러 처리 개선을 추후 고민하고 반영할 계획을 가지고 있음.
📚 Learning: baseviewcontroller의 viewdidload() 메서드에서 이미 configureattribute(), configurelayout(), bind()를 호출하므로, 하...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Login/View/TermsAgreementView.swift:44-46
Timestamp: 2025-07-16T09:09:13.869Z
Learning: BaseViewController의 viewDidLoad() 메서드에서 이미 configureAttribute(), configureLayout(), bind()를 호출하므로, 하위 클래스에서 super.viewDidLoad()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.

Applied to files:

  • Projects/Presentation/Sources/Home/View/HomeView.swift
📚 Learning: onboardingrecommendedroutineview에서 viewwillappear에 registeronboarding 호출하는 것이 적절한 이유: 사용자가 이전 페이지에서 ...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Onboarding/View/OnboardingRecommendedRoutineView.swift:57-59
Timestamp: 2025-07-16T09:21:15.038Z
Learning: OnboardingRecommendedRoutineView에서 viewWillAppear에 registerOnboarding 호출하는 것이 적절한 이유: 사용자가 이전 페이지에서 온보딩 선택지를 변경한 후 돌아올 때 새로운 선택지로 다시 등록해야 하기 때문. 홈 뷰에서는 이 뷰로 돌아올 수 없어서 중복 호출 문제가 발생하지 않음.

Applied to files:

  • Projects/Presentation/Sources/Home/View/HomeView.swift
📚 Learning: choijungp의 homeviewmodel에서 fetchroutines(for date: date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 ...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#31
File: Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift:97-103
Timestamp: 2025-08-01T06:38:18.687Z
Learning: choijungp의 HomeViewModel에서 fetchRoutines(for date: Date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 데이터 청크를 가져오기 위해 oldestDate와 latestDate를 모두 업데이트한다. 과거 날짜 요청 시에는 해당 날짜의 1주 전~1일 전, 미래 날짜 요청 시에는 해당 날짜의 1일 후~1주 후 범위로 설정한다.

Applied to files:

  • Projects/Presentation/Sources/Home/View/HomeView.swift
🔇 Additional comments (9)
Projects/Presentation/Sources/Home/View/HomeView.swift (9)

53-54: 레이아웃 상수 추가가 적절합니다.

삭제 알림 뷰의 크기를 정의하는 레이아웃 상수가 적절하게 추가되었습니다.


80-82: 삭제 알림 뷰 프로퍼티 선언이 올바릅니다.

상태 관리를 위한 isShowingDeleteAlertView 불린 플래그와 deleteAlertView 인스턴스가 적절하게 선언되었습니다.


192-194: 델리게이트 설정과 초기 상태 구성이 적절합니다.

삭제 알림 뷰의 델리게이트 설정과 초기 숨김 상태 처리가 올바르게 구현되었습니다.


217-218: 레이아웃 제약 조건이 올바르게 설정되었습니다.

삭제 알림 뷰가 화면 중앙에 정렬되고 적절한 크기로 설정되었습니다.

Also applies to: 306-311


344-356: 삭제 결과 처리 로직이 올바르게 구현되었습니다.

삭제 성공 시 알림 뷰를 숨기고 루틴 목록을 새로고침하는 로직이 적절합니다.


471-485: 삭제 알림 뷰 토글 메서드가 잘 구현되었습니다.

애니메이션과 상태 관리, 그리고 알림 뷰를 닫을 때 선택된 루틴을 초기화하는 로직이 적절합니다.


488-495: dimmed view 탭 처리가 개선되었습니다.

플로팅 메뉴와 삭제 알림 뷰 두 가지 상태를 모두 고려한 처리가 올바르게 구현되었습니다.


532-532: 루틴 선택 액션 추가가 적절합니다.

루틴 상세 뷰를 표시할 때 뷰모델에 선택된 루틴을 알리는 로직이 올바르게 추가되었습니다.


588-600: 루틴 삭제 로직이 올바르게 구현되었습니다.

반복 설정이 없는 루틴은 즉시 삭제하고, 반복 루틴은 알림 뷰를 표시하는 분기 처리가 적절합니다.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/routine-delete

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or @coderabbitai 요약 to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@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

🧹 Nitpick comments (3)
Projects/Presentation/Sources/Home/Model/MainRoutine.swift (1)

18-20: 삭제 기능을 위한 새로운 프로퍼티들이 적절히 추가되었습니다.

historySeq, completionId, routineType 프로퍼티들이 삭제 로직에 필요한 정보를 제공하도록 잘 구현되었습니다.

향후 개선 사항으로, routineTypeString 대신 enum으로 정의하는 것을 고려해보세요:

enum RoutineType: String, CaseIterable {
    case onboarding = "ONBOARDING"
    case regular = "REGULAR"
    // 기타 타입들
}
Projects/Domain/Sources/Entity/DeleteRoutineEntity.swift (1)

8-31: 도메인 엔티티에서 Encodable 준수에 대한 아키텍처 우려사항

엔티티 구조체는 잘 정의되어 있지만, 도메인 엔티티가 Encodable을 준수하는 것은 클린 아키텍처의 의존성 규칙을 위반할 수 있습니다. 도메인 계층은 외부 계층(직렬화 등)에 대해 알아서는 안 됩니다. 다만 PR 목표에서 이미 언급된 설계 우려사항으로, 배포 후 개선 예정인 것으로 이해합니다.

Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift (1)

161-174: 전체 루틴 삭제 로직이 잘 구현되었습니다!

Guard 문을 통한 안전한 언래핑과 삭제 후 선택 상태 초기화가 적절합니다. 다만, 에러 발생 시 사용자에게 구체적인 에러 정보를 전달하는 것을 고려해보세요.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d99a002 and 18a980f.

📒 Files selected for processing (15)
  • Projects/DataSource/Sources/DTO/DeleteRoutineDTO.swift (1 hunks)
  • Projects/DataSource/Sources/Endpoint/EmotionEndpoint.swift (1 hunks)
  • Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift (4 hunks)
  • Projects/DataSource/Sources/Repository/RoutineRepository.swift (1 hunks)
  • Projects/Domain/Sources/Entity/DeleteRoutineEntity.swift (1 hunks)
  • Projects/Domain/Sources/Entity/Untitled.swift (0 hunks)
  • Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift (1 hunks)
  • Projects/Domain/Sources/Protocol/UseCase/RoutineUseCaseProtocol.swift (1 hunks)
  • Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (1 hunks)
  • Projects/Presentation/Sources/Home/Model/MainRoutine.swift (2 hunks)
  • Projects/Presentation/Sources/Home/Model/SubRoutine.swift (2 hunks)
  • Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift (1 hunks)
  • Projects/Presentation/Sources/Home/View/HomeView.swift (9 hunks)
  • Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift (4 hunks)
  • Projects/Presentation/Sources/Login/View/LoginView.swift (1 hunks)
💤 Files with no reviewable changes (1)
  • Projects/Domain/Sources/Entity/Untitled.swift
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#30
File: Projects/DataSource/Sources/NetworkService/Plugin/RefreshTokenPlugin.swift:42-43
Timestamp: 2025-07-30T03:56:18.617Z
Learning: choijungp는 현재 테스트 단계에서 RefreshTokenPlugin의 토큰 갱신 로직 디버깅을 위해 액세스 토큰과 리프레시 토큰의 실제 값을 로그에 기록하는 것을 선호함.
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift:0-0
Timestamp: 2025-07-16T10:57:16.559Z
Learning: choijungp는 추후 CustomAlertView를 만들어서 에러 처리를 UI로 해결하도록 수정할 계획을 가지고 있음.
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Domain/Sources/UseCase/Onboarding/OnboardingUseCase.swift:0-0
Timestamp: 2025-07-16T10:58:30.858Z
Learning: choijungp는 OnboardingUseCase의 convertToDictionary 함수에서 에러 처리 개선을 추후 고민하고 반영할 계획을 가지고 있음.
📚 Learning: choijungp의 homeviewmodel에서 fetchroutines(for date: date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 ...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#31
File: Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift:97-103
Timestamp: 2025-08-01T06:38:18.687Z
Learning: choijungp의 HomeViewModel에서 fetchRoutines(for date: Date) 메서드는 기존 캐시 범위를 확장하는 것이 아니라, 요청된 날짜 주변의 새로운 데이터 청크를 가져오기 위해 oldestDate와 latestDate를 모두 업데이트한다. 과거 날짜 요청 시에는 해당 날짜의 1주 전~1일 전, 미래 날짜 요청 시에는 해당 날짜의 1일 후~1주 후 범위로 설정한다.

Applied to files:

  • Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift
  • Projects/DataSource/Sources/Repository/RoutineRepository.swift
  • Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift
  • Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift
  • Projects/Presentation/Sources/Home/View/HomeView.swift
📚 Learning: onboardingrecommendedroutineview에서 viewwillappear에 registeronboarding 호출하는 것이 적절한 이유: 사용자가 이전 페이지에서 ...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Onboarding/View/OnboardingRecommendedRoutineView.swift:57-59
Timestamp: 2025-07-16T09:21:15.038Z
Learning: OnboardingRecommendedRoutineView에서 viewWillAppear에 registerOnboarding 호출하는 것이 적절한 이유: 사용자가 이전 페이지에서 온보딩 선택지를 변경한 후 돌아올 때 새로운 선택지로 다시 등록해야 하기 때문. 홈 뷰에서는 이 뷰로 돌아올 수 없어서 중복 호출 문제가 발생하지 않음.

Applied to files:

  • Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift
  • Projects/Presentation/Sources/Home/View/HomeView.swift
📚 Learning: choijungp는 추후 customalertview를 만들어서 에러 처리를 ui로 해결하도록 수정할 계획을 가지고 있음....
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Common/PresentationDependencyAssembler.swift:0-0
Timestamp: 2025-07-16T10:57:16.559Z
Learning: choijungp는 추후 CustomAlertView를 만들어서 에러 처리를 UI로 해결하도록 수정할 계획을 가지고 있음.

Applied to files:

  • Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift
📚 Learning: baseviewcontroller의 viewdidload() 메서드에서 이미 configureattribute(), configurelayout(), bind()를 호출하므로, 하...
Learnt from: choijungp
PR: YAPP-Github/Bitnagil-iOS#19
File: Projects/Presentation/Sources/Login/View/TermsAgreementView.swift:44-46
Timestamp: 2025-07-16T09:09:13.869Z
Learning: BaseViewController의 viewDidLoad() 메서드에서 이미 configureAttribute(), configureLayout(), bind()를 호출하므로, 하위 클래스에서 super.viewDidLoad()를 호출하면 이 메서드들이 자동으로 호출된다. 따라서 하위 클래스에서 추가로 호출할 필요가 없다.

Applied to files:

  • Projects/Presentation/Sources/Home/View/HomeView.swift
🔇 Additional comments (26)
Projects/DataSource/Sources/Endpoint/EmotionEndpoint.swift (1)

25-27: 연관값을 사용하지 않는 패턴으로 간소화 👍
path의 switch 문에서 .registerEmotion 케이스에 연관값 바인딩을 제거해 필요 없는 변수 선언을 없앴습니다. 동일한 방법이 method에서도 이미 사용되고 있어 일관성이 향상되었습니다. 컴파일 결과에도 영향이 없으며 가독성도 좋아졌습니다.

Projects/Presentation/Sources/Home/Model/SubRoutine.swift (2)

15-15: 새로운 completionId 프로퍼티 추가가 적절합니다.

삭제 기능을 위해 필요한 완료 ID를 추적할 수 있는 옵셔널 프로퍼티가 잘 추가되었습니다.


27-27: Entity에서 Presentation 모델로의 매핑이 올바르게 업데이트되었습니다.

routineCompletionId를 completionId로 매핑하는 로직이 일관성 있게 구현되었습니다.

Projects/Presentation/Sources/Home/Model/MainRoutine.swift (1)

37-40: Entity에서 Presentation 모델로의 매핑이 일관성 있게 구현되었습니다.

새로 추가된 프로퍼티들이 Entity의 대응하는 필드들로부터 올바르게 초기화되고 있습니다.

Projects/Domain/Sources/Protocol/UseCase/RoutineUseCaseProtocol.swift (1)

21-23: 삭제 기능을 위한 UseCase 프로토콜 메서드들이 적절히 추가되었습니다.

  • deleteAllRoutine: 반복 루틴 전체 삭제를 위한 간단한 ID 기반 메서드
  • deleteDailyRoutine: 당일 루틴 삭제를 위한 Entity 기반 메서드

메서드 시그니처가 각각의 사용 목적에 맞게 잘 설계되었으며, async throws를 통한 비동기 에러 처리도 적절합니다.

Projects/DataSource/Sources/Endpoint/RoutineEndpoint.swift (4)

13-14: 삭제 기능을 위한 새로운 endpoint case들이 적절히 추가되었습니다.

두 가지 삭제 유형을 구분하여 적절한 endpoint를 정의했습니다.


26-29: endpoint path 설정이 RESTful 패턴을 잘 따르고 있습니다.

  • deleteAllRoutine: /routines/{routineId} - 특정 루틴 리소스 삭제
  • deleteDailyRoutine: /routines/day - 당일 루틴 삭제를 위한 별도 경로

경로 설계가 각각의 삭제 동작을 명확히 구분하도록 잘 구현되었습니다.


43-44: HTTP 메서드와 body 파라미터 설정이 적절합니다.

DELETE 메서드 사용과 deleteDailyRoutine에서만 request body를 포함하는 것이 각 endpoint의 특성에 맞게 올바르게 구현되었습니다.


73-74: body 파라미터 처리가 올바르게 구현되었습니다.

deleteDailyRoutine에서 DeleteRoutineDTO의 dictionary를 사용하여 적절한 request body를 생성하고 있습니다.

Projects/Domain/Sources/Protocol/Repository/RoutineRepositoryProtocol.swift (1)

33-39: Repository 프로토콜에 삭제 메서드들이 적절히 추가되었습니다.

  • 명확한 한국어 주석으로 각 메서드의 목적이 잘 설명되어 있습니다
  • deleteAllRoutine: 반복 루틴 전체 삭제
  • deleteDailyRoutine: 당일 루틴만 삭제

메서드 시그니처가 UseCase 계층과 일치하며, Repository 패턴의 추상화 역할을 잘 수행하고 있습니다.

Projects/Domain/Sources/UseCase/Routine/RoutineUseCase.swift (1)

74-80: 구현이 올바르게 되었습니다!

두 삭제 메서드 모두 repository로의 위임 패턴을 올바르게 따르고 있으며, 기존 UseCase 메서드들과 일관된 구조를 유지하고 있습니다.

Projects/DataSource/Sources/Repository/RoutineRepository.swift (2)

66-69: 전체 루틴 삭제 구현이 적절합니다.

간단한 routineId 기반 삭제 로직이 올바르게 구현되어 있습니다.


71-86: Entity to DTO 변환 로직이 올바르게 구현되었습니다.

PR 목표에서 언급한 대로 Repository에서 Entity to DTO 변환을 처리하고 있으며, 모든 필수 필드가 적절히 매핑되고 있습니다. 다만 PR에서 언급한 대로 Entity가 DTO에 대해 너무 많은 지식을 가지고 있는 설계 우려사항은 배포 후 개선 예정인 것으로 이해합니다.

Projects/DataSource/Sources/DTO/DeleteRoutineDTO.swift (1)

8-20: DTO 구조체 정의가 적절합니다.

삭제 작업에 필요한 모든 필드가 포함되어 있고, Encodable 프로토콜 준수로 네트워크 요청에 적합하게 설계되었습니다. optional routineCompletionId 필드는 다양한 루틴 상태를 유연하게 처리할 수 있게 해줍니다.

Projects/Domain/Sources/Entity/DeleteRoutineEntity.swift (1)

33-41: 서브루틴 삭제 엔티티 구현이 적절합니다.

필요한 식별자 정보가 포함되어 있고 public 초기화 메서드가 제공되어 있습니다.

Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift (3)

16-41: CustomAlertView 구현이 잘 되었습니다.

이전 학습 내용에서 언급된 CustomAlertView 계획이 잘 실행되었습니다. 깔끔한 UI 구성과 적절한 초기화 패턴을 사용하고 있습니다.


43-83: UI 구성과 액션 처리가 적절합니다.

버튼 스타일링과 액션 처리가 잘 구현되어 있으며, weak self 패턴으로 메모리 누수도 방지하고 있습니다. 다만 위에서 언급한 메서드명 오타만 수정하면 됩니다.


85-115: 레이아웃 구성이 체계적입니다.

SnapKit을 사용한 Auto Layout 설정이 적절하고, Layout enum으로 상수를 관리하는 것도 좋은 패턴입니다.

Projects/Presentation/Sources/Home/ViewModel/HomeViewModel.swift (4)

18-20: Input 케이스 추가가 적절합니다!

루틴 선택 및 삭제를 위한 새로운 Input 케이스들이 명확하게 정의되었습니다.


28-28: Publisher 타입 선택이 적절합니다!

선택된 루틴 상태 관리를 위한 CurrentValueSubject와 삭제 결과 이벤트를 위한 PassthroughSubject 사용이 올바릅니다.

Also applies to: 36-38


79-86: Action 처리가 깔끔하게 구현되었습니다!

각 Input 케이스에 대한 처리가 명확하게 분리되어 있습니다.


176-198: 일일 루틴 삭제 로직이 올바르게 구현되었습니다!

DeleteRoutineEntity 생성 및 서브루틴 매핑이 적절합니다.

Projects/Presentation/Sources/Home/View/HomeView.swift (4)

80-82: 삭제 알림 뷰 속성이 적절하게 추가되었습니다!

기존 플로팅 메뉴 패턴과 일관성 있게 구현되었습니다.

Also applies to: 192-193


344-355: 삭제 결과 처리가 올바르게 구현되었습니다!

메인 큐에서의 UI 업데이트와 성공 시 루틴 새로고침 로직이 적절합니다.


471-485: 토글 메서드가 일관성 있게 구현되었습니다!

알림 뷰를 숨길 때 선택 상태를 초기화하는 것이 좋은 구현입니다.


588-599: 루틴 타입별 삭제 로직이 PR 요구사항대로 구현되었습니다!

반복 설정이 없는 루틴은 즉시 삭제, 반복 루틴은 알림 뷰를 표시하는 로직이 정확합니다.

Comment thread Projects/Presentation/Sources/Home/View/Component/RoutineDeleteAlertView.swift Outdated
Comment thread Projects/Presentation/Sources/Home/View/HomeView.swift
Comment on lines 132 to 136
private func appleLogin() {
let provider = ASAuthorizationAppleIDProvider()
let request = provider.createRequest()
request.requestedScopes = [.fullName]
request.requestedScopes = [.fullName, .email]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

email 스코프를 요청한 만큼, credential.email 처리 로직도 함께 추가하세요
request.requestedScopes.email을 포함했지만 authorizationController(_:didCompleteWithAuthorization:)에서는 credential.email을 전혀 사용하지 않고 있습니다.

  • Apple ID 로그인 최초 1회에 한해 credential.email 값이 반환되며, 이후에는 nil이 리턴됩니다. 값을 놓치면 재요청이 불가능하므로 사용자 이메일이 필요한 비즈니스 로직이 있다면 반드시 저장·전달해야 합니다.
  • ViewModel의 .appleLogin 액션 파라미터에 이메일을 추가하거나, 이메일 저장 책임을 별도 컴포넌트로 위임하는 방안을 검토해 주세요.

예시 패치:

-        let givenName = credential.fullName?.givenName
-        let familyName = credential.fullName?.familyName
+        let givenName   = credential.fullName?.givenName
+        let familyName  = credential.fullName?.familyName
+        let email       = credential.email       // 신규 요청 스코프

@@
-        self.viewModel.action(input: .appleLogin(nickname: nickname, authToken: authToken))
+        self.viewModel.action(
+            input: .appleLogin(
+                nickname: nickname,
+                authToken: authToken,
+                email: email
+            )
+        )

위 변경 없이 스코프만 늘리면 사용자에게 추가 권한을 요구하면서도 실제로는 활용하지 못해 UX‧개발 일관성 측면에서 좋지 않습니다.


추가 검증을 위해 authorizationController(_:didCompleteWithAuthorization:) 구현부에서 credential.email 처리 여부를 확인합니다.


🏁 Script executed:

#!/bin/bash
# LoginView.swift에서 authorizationController 메서드 위치 및 주변 로직 조회
rg -n -C3 "func authorizationController" Projects/Presentation/Sources/Login/View/LoginView.swift

Length of output: 707


추가 확인을 위해 authorizationController(_:didCompleteWithAuthorization:) 구현부를 전체적으로 살펴봅니다.


🏁 Script executed:

#!/bin/bash
sed -n '140,180p' Projects/Presentation/Sources/Login/View/LoginView.swift

Length of output: 1584


Apple 로그인 시 이메일 처리 로직 추가 필요

  • 파일: Projects/Presentation/Sources/Login/View/LoginView.swift
    • private func appleLogin()에서 .email 스코프를 요청하고 있음에도
    • authorizationController(_:didCompleteWithAuthorization:)에서 credential.email을 전혀 사용하지 않고 있습니다.
  • Apple ID 로그인 최초 1회에만 반환되는 이메일을 놓치면 재요청이 불가능하므로, 필요한 비즈니스 로직이 있다면 이메일을 저장·전달하도록 꼭 반영해 주세요.

예시 수정안:

@@ extension LoginView: ASAuthorizationControllerDelegate {
-        let givenName = credential.fullName?.givenName
-        let familyName = credential.fullName?.familyName
+        let givenName   = credential.fullName?.givenName
+        let familyName  = credential.fullName?.familyName
+        let email       = credential.email       // 신규: 이메일 스코프 처리

-        self.viewModel.action(input: .appleLogin(nickname: nickname, authToken: authToken))
+        self.viewModel.action(
+            input: .appleLogin(
+                nickname: nickname,
+                authToken: authToken,
+                email: email              // 전달된 이메일 포함
+            )
+        )
🤖 Prompt for AI Agents
In Projects/Presentation/Sources/Login/View/LoginView.swift around lines 132 to
136, the appleLogin function requests the user's email scope but the
authorizationController(_:didCompleteWithAuthorization:) method does not handle
or store the returned email. To fix this, update the
authorizationController(_:didCompleteWithAuthorization:) method to extract the
email from the credential on the first login and save or pass it as needed for
your business logic, ensuring the email is not lost since it is only provided
once by Apple.

Copy link
Copy Markdown
Collaborator

@taipaise taipaise left a comment

Choose a reason for hiding this comment

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

루삭도 고생많으셨습니다!!! 빛나길 그 자체 조이 만세 만세 만세입니다

// Created by 최정인 on 8/4/25.
//

public struct DeleteRoutineEntity: Encodable {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

아직 정리도 못했고, 굉장히 막연한 생각이지만, Routine이라는 Entity 하나만으로 굴러가게 하기는 힘들까요?
저도 루틴 추가/수정을 하며 새로운 엔티티를 만들었는데요, 뭔가 루틴에 대한 정책이 바뀌거나 하면 수정할 사항이 굉장히 많아질 것 같다는 생각이 듭니다..!
그리고 '루틴'에 대한 엔티티라 하면, 루틴이 가지고 있는 속성들을 다 가지고 있기 때문에, 추가/수정이든 삭제든 해당 엔티티로 처리할 수 있어야 하지 않을까? 싶기도 하구요!

다만 엔티티 하나로 통일하게 되면, RoutineEntity 내의 프로퍼티들이 옵셔널로 선언되는 경우가 많을것 같아 고민입니다.
오늘 회의에서 가볍게라도 짚고 넘어가면 좋을것 같습니다~!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

사실 서버에서 Routine에 관련된 Response 를 받을 때 DTO에 모든 값들을 저장하고 Entity로 변환할 때에도 모든 값을 다 갖고 있어서 하나의 Entity로만 굴러가게 할 수 있을 것 같아요 !!

하지만 ...... 흠 네네네 !!!! 오늘 회의에서 마저 이야기 해부아요 ㅠㅠ !!!

Comment on lines +79 to +82
deleteAllRoutineButton.addAction(UIAction { [weak self] _ in
guard let self else { return }
self.delegate?.routineDeleteAlertViewDidTapDeleteAllRoutine(self)
}, for: .touchUpInside)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
deleteAllRoutineButton.addAction(UIAction { [weak self] _ in
guard let self else { return }
self.delegate?.routineDeleteAlertViewDidTapDeleteAllRoutine(self)
}, for: .touchUpInside)
deleteAllRoutineButton.addAction(
UIAction { [weak self] _ in
guard let self else { return }
self.delegate?.routineDeleteAlertViewDidTapDeleteAllRoutine(self)
},
for: .touchUpInside)

정말 사소한 부분이긴하지만, 요런 형식이 컨벤션에 맞는것 같습니다!

Comment on lines +481 to +483
UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseOut]) {
self.dimmedView.alpha = self.isShowingDeleteAlertView ? 1 : 0
self.deleteAlertView.alpha = self.isShowingDeleteAlertView ? 1 : 0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

띡 하고 나오는게 아니라 애니메이션이 추가 되는군요 bbb

@choijungp choijungp merged commit 0315ddb into develop Aug 5, 2025
2 checks passed
@choijungp choijungp deleted the feat/routine-delete branch August 5, 2025 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants