Repository navigation
클래스 참여 화면을 Figma 코드 입력 시안에 맞춤 - #74
Conversation
6칸 참여 코드 입력과 중앙 제목을 적용하고 시안에 없는 안내 영역과 클래스 생성 버튼을 제거합니다.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c12965fd5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
클래스 참여 화면의 Figma 가이드라인 준수를 위한 UI/UX 변경 사항을 검토했습니다. 내비게이션 제목 및 클래스 참여 코드 입력 UI 변경, 안내 문구 조정 등 전반적으로 Figma 시안에 맞춰 잘 구현되었습니다.
새롭게 추가된 6자리 참여 코드 입력 UI는 SwiftUI의 ZStack과 투명 TextField를 활용하는 일반적인 패턴을 따르고 있으며, 에러 및 포커스 상태에 따른 시각적 피드백도 잘 처리되었습니다. codeCharacter(at:), codeBorderColor(at:)와 같은 헬퍼 함수들은 가독성이 좋고 안전하게 구현되었습니다.
전반적으로 프로젝트의 아키텍처 및 코딩 컨벤션을 잘 준수하고 있으며, 큰 문제점은 발견되지 않았습니다.
| switch mode { | ||
| case .code: return nil | ||
| case .nickname: return "클래스 참여" | ||
| case .code, .nickname: return "클래스 참여" |
There was a problem hiding this comment.
🔵 [P4] Readability
code와 nickname 모드의 내비게이션 중앙 제목을 "클래스 참여"로 통합하여 간결하게 표현한 것은 좋은 개선입니다.
|
|
||
| public var navigationLeadingTitle: String? { | ||
| mode == .code ? "클래스 참여" : nil | ||
| nil |
There was a problem hiding this comment.
🔵 [P4] Readability
code 모드에서 내비게이션 선행 제목을 nil로 설정하여 Figma 시안과 일치시킨 변경입니다.
|
|
||
| ScrollView { | ||
| VStack(alignment: .leading, spacing: store.mode == .code ? 26 : 24) { | ||
| VStack(alignment: .leading, spacing: store.mode == .code ? 20 : 24) { |
There was a problem hiding this comment.
🔵 [P4] Readability
code 모드에서의 VStack 간격을 조정하여 Figma 시안에 맞춘 UI 변경입니다.
| .scrollBounceBehavior(.basedOnSize) | ||
|
|
||
| bottomActions() | ||
| bottomAction |
There was a problem hiding this comment.
🔵 [P4] Readability
단일 버튼을 포함하는 하단 액션 뷰를 @ViewBuilder func bottomActions()에서 var bottomAction: some View로 변경한 것은 SwiftUI 컨벤션에 부합하며, 코드를 더 깔끔하게 만듭니다. 이는 프로젝트의 SubView 분리 규칙(func 또는 var 형태가 정식)을 준수합니다.
| @ViewBuilder | ||
| func titleSection() -> some View { | ||
| VStack(alignment: .leading, spacing: store.mode == .code ? 14 : 8) { | ||
| VStack(alignment: .leading, spacing: store.mode == .code ? 6 : 8) { |
There was a problem hiding this comment.
🔵 [P4] Readability
code 모드에서의 제목 섹션 간격을 조정하여 Figma 시안에 맞춘 UI 변경입니다.
| errorLabel(message) | ||
| } | ||
| .foregroundStyle(.clear) | ||
| .tint(.clear) |
There was a problem hiding this comment.
🔵 [P4] Readability
TextField의 틴트 색상(커서)을 clear로 설정하여 기본 커서가 표시되지 않도록 한 것은 커스텀 코드 입력 UI의 완성도를 높이는 좋은 디테일입니다.
| Text("클래스를 만든 선생님이나 모임장에게\n참여 코드를 확인해 주세요.") | ||
| .pretendardFont(.bodySmall) | ||
| .foregroundStyle(.gray400) | ||
| if let message = store.errorMessage { |
There was a problem hiding this comment.
🔵 [P4] Readability
에러 메시지를 코드 입력 필드 아래에 배치하여 시각적으로 명확하게 사용자에게 전달하도록 변경되었습니다.
| } | ||
| } | ||
|
|
||
| func codeCharacter(at index: Int) -> String { |
There was a problem hiding this comment.
🔵 [P4] Readability
코드 문자를 안전하게 추출하고, 비어 있는 칸에 "-"를 표시하는 헬퍼 함수를 추가하여 코드를 명확하고 간결하게 만들었습니다. 이는 프로젝트의 SubView 분리 규칙(func 또는 var 형태가 정식)을 준수합니다.
| return characters.indices.contains(index) ? String(characters[index]) : "-" | ||
| } | ||
|
|
||
| func codeBorderColor(at index: Int) -> Color { |
There was a problem hiding this comment.
🔵 [P4] Readability
에러 상태 및 현재 포커스 된 입력 위치에 따라 테두리 색상을 동적으로 변경하는 헬퍼 함수를 추가하여 UI의 시각적 피드백을 개선했습니다. 이는 프로젝트의 SubView 분리 규칙(func 또는 var 형태가 정식)을 준수합니다.
| .ctaButtonStyle(.primary, size: .large, height: 52) | ||
| .disabled(store.isLoading) | ||
| } | ||
| var bottomAction: some View { |
There was a problem hiding this comment.
🔵 [P4] Readability
bottomActions() 함수를 단일 버튼을 나타내는 bottomAction 변수로 변경하여 코드를 간결하게 만들었습니다. 이는 SwiftUI 컨벤션과 프로젝트의 SubView 분리 규칙(func 또는 var 형태가 정식)을 잘 따릅니다.
리뷰 의견에 따라 여섯 자리 표시값을 상태의 파생값으로 옮기고 뷰는 이를 그대로 렌더링합니다.
|
전반적으로 Figma 디자인 변경 사항과 기존 아키텍처 및 코딩 컨벤션을 잘 준수하여 구현되었습니다. 특히 Reducer에 추가된 |
ClassInterface 하나로 계약을 통합하고 Repository와 UseCase 구현을 정리합니다. 클래스 API를 API·APIEndpoint 모듈로 옮기고 Entity와 DTO 변환 파일을 기능별로 배치합니다.
ClassRepositoryImpl과 ClassUseCaseImpl 타입은 각각 하나로 유지하고 메서드를 역할별 파일로 배치합니다.
Class 서비스와 요청 모델을 Room, Battle, Member, Debate, Result, Ticket, TopicDraft 폴더에 배치합니다.
APIEndpoint의 폴더 구조와 맞춰 Class 경로 정의를 역할별로 배치합니다.
참여 화면 배경과 입력 칸 상태 및 키보드 초점을 확정 시안에 맞춥니다. AI 피드백 DTO의 중첩 투표 선택지 타입을 명시합니다.
There was a problem hiding this comment.
클래스 도메인 모듈에 대한 대규모 리팩토링이 잘 진행되었습니다.
주요 변경 사항:
- 인터페이스 분리 원칙(ISP) 적용: 기존의 단일
ClassInterface를ClassRoomInterface,ClassBattleInterface등 여러 개의 작고 명확한 인터페이스로 분리하여 역할별 책임을 명확히 했습니다.ClassInterface는 이제 이들을 합성하는 형태로 변경되었습니다. - 구현체 통합:
ClassUseCaseImpl과ClassRepositoryImpl이 분리된 모든 인터페이스를 준수하도록 확장(extension)을 통해 코드를 통합했습니다. 이로써 의존성 주입 시 단일한ClassUseCase또는ClassRepository인스턴스를 활용할 수 있게 되어 클라이언트 코드의 복잡성을 줄였습니다. - 네트워크 서비스 정의 분리:
ClassDomain내에 있던 네트워크 서비스 정의(ClassBattleService.swift등)를APIEndpoint모듈로 옮겨, 도메인 레이어에서 네트워크 관련 구현 세부 사항을 제거하고 의존성을 정리했습니다. - Mock 전략 개선:
MockClassRepository가 모든 새로운 개별 인터페이스의 테스트 값을 제공하도록 업데이트되어, 테스트 환경 구성이 더욱 일관성 있게 되었습니다. - UI/UX 개선: Figma 디자인 가이드라인에 맞춰 클래스 참여 화면의 6자리 코드 입력 UI를 개선하고, 레이아웃 및 텍스트를 조정했습니다.
개선이 필요한 주요 사항은 다음과 같습니다:
- 모듈 아키텍처 위반: DTO(Data Transfer Object)와 Entity 간의 매핑 로직(
toDomain()확장)이 여전히ClassDomain모듈 내에 존재합니다. 이는 "DTO-to-Entity 매핑은 Data 레이어에 유지되어야 한다"는 프로젝트 아키텍처 지침을 위반합니다. DTO와 매핑 로직은Data레이어로 이동해야 합니다. - 매직 넘버 사용: 일부 코드에서
20,1,3,50과 같은 숫자가 직접 사용되고 있어 가독성과 유지보수성이 저하될 수 있습니다. 이들은 명명된 상수로 추출하는 것이 좋습니다. - 의존성 속성 접근 제어자:
@Dependency로 주입되는 속성(client,repository)에private접근 제어자가 누락되어 있습니다. 캡슐화를 위해private으로 선언하는 것이 좋습니다.
전반적으로 대규모 리팩토링이 체계적으로 잘 수행되었습니다. 지적된 사항들을 개선하면 더욱 견고하고 유지보수하기 쉬운 아키텍처를 가질 수 있을 것입니다.
| classID: Int, | ||
| optionID: Int | ||
| ) async throws -> ClassVoteReceipt | ||
| func submitPreVote(classID: Int, optionID: Int) async throws -> ClassVoteReceipt |
There was a problem hiding this comment.
🔵 [P4] Readability
함수 인자 라벨이 한 줄로 정리되어 Swift API Design Guideline에 부합하게 변경되었습니다. 잘하셨습니다.
| classID: Int, | ||
| optionID: Int | ||
| ) async throws -> ClassVoteReceipt | ||
| func submitPostVote(classID: Int, optionID: Int) async throws -> ClassVoteReceipt |
There was a problem hiding this comment.
🔵 [P4] Readability
함수 인자 라벨이 한 줄로 정리되어 Swift API Design Guideline에 부합하게 변경되었습니다. 잘하셨습니다.
| classID: Int, | ||
| content: String | ||
| ) async throws -> ClassPerspectiveReceipt | ||
| func publishPerspective(classID: Int, content: String) async throws -> ClassPerspectiveReceipt |
There was a problem hiding this comment.
🔵 [P4] Readability
함수 인자 라벨이 한 줄로 정리되어 Swift API Design Guideline에 부합하게 변경되었습니다. 잘하셨습니다.
|
|
||
| extension ClassRepositoryImpl { | ||
| public func fetchRecommendedBattles(filter: ClassTopicFilter) async throws -> [ClassBattleSummary] { | ||
| guard (1 ... 3).contains(filter.categories.count), filter.keyword.count <= 50 else { |
There was a problem hiding this comment.
🔵 [P4] Readability
카테고리 개수 범위 1...3과 키워드 길이 제한 50이 하드코딩되어 있습니다. 이 값들은 상수로 정의하여 사용하는 것이 가독성과 유지보수성에 좋습니다.
| guard (1 ... 3).contains(filter.categories.count), filter.keyword.count <= 50 else { | |
| private enum ClassRecommendationMetric { | |
| static let minCategories = 1 | |
| static let maxCategories = 3 | |
| static let maxKeywordLength = 50 | |
| } | |
| // ... | |
| guard (ClassRecommendationMetric.minCategories...ClassRecommendationMetric.maxCategories).contains(filter.categories.count), filter.keyword.count <= ClassRecommendationMetric.maxKeywordLength else { |
| private static let unavailableMessage = "클래스 서버 API가 연결되지 않았습니다." | ||
| @Dependency(\.networkClient) private var client | ||
| public final class ClassRepositoryImpl: ClassInterface { | ||
| @Dependency(\.networkClient) var client |
There was a problem hiding this comment.
🔵 [P4] Readability
@Dependency 속성에는 일반적으로 private 접근 제어자를 사용하는 것이 캡슐화에 좋습니다. final class 내부에서 var로 선언된 client는 외부에서 접근하여 변경될 가능성이 있습니다.
| @Dependency(\.networkClient) var client | |
| @Dependency(\.networkClient) private var client |
| @ViewBuilder | ||
| func titleSection() -> some View { | ||
| VStack(alignment: .leading, spacing: store.mode == .code ? 14 : 8) { | ||
| VStack(alignment: .leading, spacing: store.mode == .code ? 6 : 8) { |
There was a problem hiding this comment.
🔵 [P4] Readability
하드코딩된 숫자 6과 8은 매직 넘버로, 가독성과 유지보수성을 저해할 수 있습니다. UI 레이아웃 관련 상수들은 별도의 private enum (예: Metric)으로 관리하는 것이 좋습니다.
| VStack(alignment: .leading, spacing: store.mode == .code ? 6 : 8) { | |
| private extension ClassJoinView.Metric { | |
| static let codeTitleSectionSpacing: CGFloat = 6 | |
| static let defaultTitleSectionSpacing: CGFloat = 8 | |
| } | |
| // ... | |
| VStack(alignment: .leading, spacing: store.mode == .code ? Metric.codeTitleSectionSpacing : Metric.defaultTitleSectionSpacing) { |
| ) | ||
| VStack(alignment: .leading, spacing: 8) { | ||
| ZStack { | ||
| HStack(spacing: 14) { |
There was a problem hiding this comment.
🔵 [P4] Readability
하드코딩된 숫자 14는 매직 넘버로, 가독성과 유지보수성을 저해할 수 있습니다. UI 레이아웃 관련 상수들은 별도의 private enum (예: Metric)으로 관리하는 것이 좋습니다.
| HStack(spacing: 14) { | |
| private extension ClassJoinView.Metric { | |
| static let codeInputCharacterSpacing: CGFloat = 14 | |
| } | |
| // ... | |
| HStack(spacing: Metric.codeInputCharacterSpacing) { |
| .pretendardFont(.headingMedium) | ||
| .foregroundStyle(.gray800) | ||
| .frame(maxWidth: .infinity) | ||
| .frame(height: 50) |
There was a problem hiding this comment.
🔵 [P4] Readability
하드코딩된 숫자 50은 매직 넘버로, 가독성과 유지보수성을 저해할 수 있습니다. UI 레이아웃 관련 상수들은 별도의 private enum (예: Metric)으로 관리하는 것이 좋습니다.
| .frame(height: 50) | |
| private extension ClassJoinView.Metric { | |
| static let codeInputCharacterHeight: CGFloat = 50 | |
| } | |
| // ... | |
| .frame(height: Metric.codeInputCharacterHeight) |
| } | ||
| } | ||
|
|
||
| TextField("", text: $store.joinCode) |
There was a problem hiding this comment.
🔵 [P4] Readability
이 TextField에는 characterLimit: 6과 같은 최대 문자열 길이 제한이 명시적으로 적용되어 있지 않습니다. 현재 codeCharacters 계산에서 prefix(6)으로 잘라내지만, TextField 자체의 입력 길이를 제한하는 로직이 필요합니다. Reducer에서 joinCode의 길이를 제한해야 합니다.
| TextField("", text: $store.joinCode) | |
| // ClassJoinFeature.swift의 Reducer 내 BindingReducer() 아래에 추가 | |
| BindingReducer() | |
| .onChange(of: \.joinCode) { | |
| newValue = String(newValue.prefix(6)) | |
| } |
| .tint(.clear) | ||
| .frame(maxWidth: .infinity, maxHeight: .infinity) | ||
| } | ||
| .frame(height: 50) |
There was a problem hiding this comment.
🔵 [P4] Readability
하드코딩된 숫자 50은 매직 넘버로, 가독성과 유지보수성을 저해할 수 있습니다. UI 레이아웃 관련 상수들은 별도의 private enum (예: Metric)으로 관리하는 것이 좋습니다.
| .frame(height: 50) | |
| private extension ClassJoinView.Metric { | |
| static let codeInputContainerHeight: CGFloat = 50 | |
| } | |
| // ... | |
| .frame(height: Metric.codeInputContainerHeight) |
숨겨둔 TabView 탭바를 다시 표시하고 별도 커스텀 탭바를 제거합니다. 키보드 및 상세 화면에서 탭바를 숨기는 기존 상태 조건을 유지합니다.
There was a problem hiding this comment.
클래스 관련 모듈을 인터페이스 분리 원칙(ISP)에 따라 ClassInterface를 여러 개의 작은 인터페이스로 분할하고, 이를 ClassUseCaseImpl 및 ClassRepositoryImpl에서 합성하도록 리팩터링한 PR입니다. 이는 아키텍처 관점에서 매우 긍정적인 변화입니다.
하지만 DTO-Entity 매핑 로직의 위치와 모듈 간 의존성 방향에서 아키텍처 원칙 위반 사항이 발견되었습니다. 이는 클린 아키텍처의 핵심 원칙을 위반하므로 즉시 수정해야 합니다.
| settings: .settings(), | ||
| dependencies: [ | ||
| .serviceAssembly, | ||
| .service(.apiEndpoint), |
There was a problem hiding this comment.
🟠 [P2] Major
Domain 모듈(ClassDomain)이 Service 레이어의 APIEndpoint에 직접 의존하고 있습니다. 클린 아키텍처에서 Domain 레이어는 비즈니스 로직과 엔티티를 정의하며, 외부 레이어(Data, Service)에 대한 의존성을 가져서는 안 됩니다. DTO-Entity 매핑은 Data 레이어에서 담당해야 하며, Domain은 순수한 Entity만 받아야 합니다.
APIEndpoint가 ClassDomainInterface의 Entity를 사용하여 Request Body를 구성하고 있는 것이 원인으로 보입니다. APIEndpoint는 Domain Layer의 추상화(Interface)를 모르고, 독립적인 Request DTO를 정의하고 사용해야 합니다. Domain Layer는 Data Layer를 통해서만 Entity를 전달받고, Data Layer는 APIEndpoint의 DTO를 Domain Entity로 변환하는 책임을 가집니다.
이를 해결하기 위해서는 APIEndpoint에서 ClassDomainInterface의 Entity 타입을 사용하지 않도록 수정하고, ClassDomain이 APIEndpoint에 의존하지 않도록 ClassRepositoryImpl에서 매핑 로직을 처리해야 합니다. 매핑 로직은 ClassDomain 외부, 즉 Data 레이어의 ClassRepositoryImpl 내부에 있어야 합니다.
| .service(.apiEndpoint), | |
| // .service(.apiEndpoint), // ClassDomain은 Service 레이어에 의존해서는 안 됩니다. | |
| ], | |
| testDependencies: [ | |
| // .service(.apiEndpoint), // ClassDomain은 Service 레이어에 의존해서는 안 됩니다. | |
| ], |
| @@ -0,0 +1,102 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassAIFeedbackDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,40 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassBattleRecommendationDataDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,61 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassBattleSessionDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,37 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassDebateDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,18 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassTicketPreviewDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,72 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassTopicDraftDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,58 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassVoteDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| @@ -0,0 +1,108 @@ | |||
| import ClassDomainInterface | |||
There was a problem hiding this comment.
🟠 [P2] Major
.toDomain() 매핑 로직이 ClassDomain 모듈 내부에 위치하고 있습니다. 클린 아키텍처에서 DTO(Data Transfer Object)를 Domain Entity로 변환하는 책임은 Data 레이어에 있습니다. Domain 레이어는 순수한 비즈니스 로직과 Entity를 포함해야 하며, Data 레이어의 DTO 구조를 알아서는 안 됩니다.
이 매핑 파일들은 Data 모듈(Projects/Data/ClassData)로 이동해야 합니다. Data 모듈에서 API로부터 받은 DTO를 Domain Entity로 변환하여 UseCase(Domain)에 전달하는 흐름이 올바른 아키텍처입니다.
| import ClassDomainInterface | |
| // 이 파일은 Projects/Data/ClassData/Sources/Model/Mapper/ClassroomDataDTO+.swift 와 같이 Data 모듈로 이동해야 합니다. | |
| import ClassDomainInterface | |
| // ... 매핑 로직 ... |
| .service(.api), | ||
| // Auth 엔드포인트가 SocialType 을 경로에 쓴다. | ||
| .domain(.auth, .interface), | ||
| .domain(.classroom, .interface), |
There was a problem hiding this comment.
🟠 [P2] Major
APIEndpoint 모듈이 ClassDomainInterface에 의존하고 있습니다. APIEndpoint는 Service 레이어에 해당하며, DomainInterface는 Domain 레이어의 추상화입니다. 클린 아키텍처에서 Service 레이어는 Domain 레이어를 몰라야 하며, Presentation → Domain ← Data, Network is only referenced by Data 의존성 방향 원칙을 위반합니다.
APIEndpoint는 자체적인 Request/Response DTO를 정의하고 사용해야 하며, Domain Entity를 직접 참조해서는 안 됩니다. Domain Entity를 활용해야 하는 경우, ClassRepositoryImpl(Data 레이어)에서 Domain Entity를 APIEndpoint의 Request DTO로 변환하여 사용하도록 변경해야 합니다.
| .domain(.classroom, .interface), | |
| // .domain(.classroom, .interface), // APIEndpoint는 DomainInterface에 의존해서는 안 됩니다. | |
| .core(.coreUtility), |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e5c7de9a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| @Dependency(\.uuid) private var uuid | ||
| @Dependency(\.classBattleUseCase) private var classBattleUseCase | ||
| @Dependency(\.classUseCase) private var classUseCase |
There was a problem hiding this comment.
Migrate test dependency overrides alongside the unified use case
The existing ClassBattleFlowTests still inject classBattleUseCase (for example, lines 27–34 of ClassBattleFlowTests.swift), but this reducer now reads the independent classUseCase key. Consequently, those tests use the default MockClassRepository, whose fetchBattle throws, instead of their configured session and spy, so the expected successful progress responses no longer occur. Update the affected test overrides and fixtures as part of this migration; the same mismatch also exists in the vote, recommendation, ticket, and report feature tests.
Useful? React with 👍 / 👎.
| } | ||
| } | ||
|
|
||
| public func updateName(id: Int, name: String) async throws -> ClassRoom { |
There was a problem hiding this comment.
Expand new multi-parameter method signatures
The new updateName(id:name:) declaration puts both parameters on one line, violating the mandatory signature convention in AGENTS.md, which explicitly applies to ordinary methods as well as View and reducer helpers. Put each parameter on its own line here and in the corresponding new use-case and mock declarations so this addition follows the repository's required convention.
AGENTS.md reference: AGENTS.md:L218-L221
Useful? React with 👍 / 👎.
변경 내용
12378:24376클래스 참여 코드 화면에 맞춰 6칸 입력 UI를 적용했습니다.클래스 참여제목을 중앙에 배치하고 안내 문구와 간격을 조정했습니다.클래스 새로 만들기버튼을 화면에서 제거했습니다.검증
Picke-Preview-375대상으로Class모듈 빌드 통과Picke-Stage전체 앱 빌드 통과git diff --check통과관련 사항
1.1.2 (2610260925)에는 이 수정이 들어 있지 않습니다. 해당 빌드의 실행 직후 종료 문제도 별도로 확인이 필요합니다.