[FEAT] 그룹 종료 API 연동 및 홈 리스트 정리 - #106
Conversation
그룹 상세 메뉴에서 종료/나가기 확인 알럿을 노출하고
종료 시 PATCH /groups/{id}/close 호출 후 화면을 닫는다
GroupListStatus에 closed(CLOSED) 케이스를 도입하고 홈 그룹 리스트 조회 시 종료된 그룹을 필터링한다
InfoPlist가 참조하는 BUNDLE_DISPLAY_NAME이 정의되지 않아 CFBundleDisplayName이 비어 PRODUCT_NAME으로 폴백되던 문제를 수정
동작 미정의(no-op) 알림/마이페이지 버튼과 화면 미구현 리마인더 탭을 심사 리젝 방지를 위해 임시 숨김 처리
| case .groupsResponse(.success(let groups)): | ||
| state.groups = groups | ||
| if (1...2).contains(groups.count) { | ||
| let visibleGroups = groups.filter { $0.listStatus != .closed } |
There was a problem hiding this comment.
🟠 [P2] Major
'종료된 그룹은 홈 리스트에서 제외한다'는 규칙은 비즈니스 로직(Domain Rule)에 해당합니다. Presentation 레이어의 Reducer에서 데이터를 직접 필터링하기보다는, Domain 레이어의 UseCase 단에서 필터링된 데이터를 반환하거나 적절한 사양으로 가공하여 가져오는 것이 클린 아키텍처의 레이어별 책임 분리에 더 적합합니다.
향후 FetchGroupsUseCase 내부에서 이 필터링을 수행하거나, UseCase에서 별도의 Filter 파라미터를 지원하도록 변경하는 방향을 권장합니다.
| let groupId = state.home.group.id | ||
| let groupClient = groupClient | ||
| let dismiss = dismiss | ||
| return .run { _ in |
There was a problem hiding this comment.
🟡 [P3] Minor
API 호출 실패 시 단순히 Log.debug로 에러를 콘솔에만 출력하고 있어, 실제 사용자는 화면에서 아무런 피드백을 받지 못하고 멈춰 있는 현상을 겪게 됩니다. API 요청 실패 시 적절하게 에러 액션(closeGroupResponse(.failure(error)))을 호출하여 사용자에게 에러 얼럿이나 토스트 등을 보여주도록 대응 로직을 보완하는 것이 좋습니다.
| return .run { _ in | |
| return .run { send in | |
| do { | |
| try await groupClient.closeGroup(groupId) | |
| await dismiss() | |
| } catch { | |
| await send(.closeGroupResponse(.failure(error))) | |
| } | |
| } |
| @@ -0,0 +1,19 @@ | |||
| // | |||
There was a problem hiding this comment.
🔵 [P4] Readability
신규 추가된 파일 상단에 Xcode 기본 템플릿의 Boilerplate 주석이 그대로 포함되어 있습니다. 프로젝트 코드 일관성과 가독성을 위해 불필요한 파일 헤더 주석은 제거해 주세요.
| } | ||
| ] | ||
| ) | ||
| // FIXME: 알림/마이페이지 버튼은 동작이 정의되지 않아(탭 시 no-op) 심사 리젝 방지를 위해 임시 숨김. |
There was a problem hiding this comment.
🔵 [P4] Readability
심사 리젝 방지 및 미구현 기능 차단을 위해 코드들을 주석 처리한 것은 이해하지만, 주석으로 남겨진 대규모 코드 블록은 코드 복잡도를 높이고 유지보수를 어렵게 만듭니다. 주석 처리하여 남겨두기보다는 과감히 삭제하고, 추후 관련 기능을 다루는 이슈 및 PR에서 추가하는 것을 권장합니다.
| let groupId = state.home.group.id | ||
| let groupClient = groupClient | ||
| return .run { send in | ||
| await send(.groupClosed(Result { |
There was a problem hiding this comment.
🔴 [P1] Critical
Swift 표준 라이브러리의 Result(catching:) 초기화자는 동기(synchronous) 클로저만 지원하므로, 내부에서 try await과 같은 비동기 작업(Async/Await)을 호출하면 컴파일 에러가 발생합니다.
do-catch 블록을 활용하여 비동기 작업 결과를 처리하도록 수정해야 컴파일 에러를 방지할 수 있습니다.
| await send(.groupClosed(Result { | |
| return .run { send in | |
| do { | |
| try await groupClient.closeGroup(groupId) | |
| await send(.groupClosed(.success(()))) | |
| } catch { | |
| await send(.groupClosed(.failure(error))) | |
| } | |
| } |
| case kakaoShareTapped | ||
| case endGroupTapped | ||
| case leaveGroupTapped | ||
| case groupClosed(Result<Void, Error>) |
There was a problem hiding this comment.
🟡 [P3] Minor
TCA 컨벤션에 따라 API 요청에 대한 결과를 받는 Action은 단순히 상태를 표현하기보다 xxxResponse와 같이 사건의 성격을 서술하는 네이밍을 권장합니다.
groupClosed 대신 closeGroupResponse로 명명하여 일관성을 높이는 것을 추천합니다.
| case groupClosed(Result<Void, Error>) | |
| case closeGroupResponse(Result<Void, Error>) |
Summary
그룹(모임) 종료 API를 연동하고, 종료된 그룹이 홈 리스트에 노출되지 않도록 정리했습니다.
GroupDetail 상단 케밥 메뉴에 종료/나가기 액션을 붙여 종료 플로우를 완성했습니다.
Closes #101
주요 변경 사항
GroupClient에closeGroup메서드 추가 및 Domain UseCase / Repository / API Endpoint 조립(Factory)To Reviewer
develop입니다.