Skip to content

[Feat] #132 - 작품 평가 피처 구현#144

Open
Naknakk wants to merge 32 commits into
developfrom
Feat/#132
Open

[Feat] #132 - 작품 평가 피처 구현#144
Naknakk wants to merge 32 commits into
developfrom
Feat/#132

Conversation

@Naknakk

@Naknakk Naknakk commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

💡 Issue

closed #132


💭 Summary

작품 상세에서 사용자가 작품을 평가할 수 있는 NovelReviewFeature를 새로 추가함.

이번 PR에서는 리뷰 화면의 기본 편집 흐름을 먼저 완성함. 진입 시 선택된 읽기 상태를 기준으로 기존 리뷰 초안을 불러오고, 사용자는 독서 기간·별점·매력 포인트를 수정한 뒤 저장 가능. 키워드 영역은 추후 탐색/선택 화면으로 연결하기 위한 진입 버튼까지만 배치함.


🔑 Key Changes

1. 작품 평가 화면 추가

  • NovelReviewFeature 모듈을 새로 만들고, 외부에서는 NovelReviewFactory.makeView(...)만 통해 화면을 생성하도록 구성함.

2. 독서 기간 입력 흐름

  • watching, watched, quit 상태별로 필요한 날짜만 부모 화면에 전달하고, 최종 ReadingPeriod 생성과 정규화는 Domain 쪽 정책에 맡김.
  • 미래 날짜로 굴린 경우 스크롤 중에는 강제로 끊지 않고, 스크롤이 멈춘 뒤 직전 유효 날짜로 되돌림.
  • 편집 중인 쪽을 기준으로 함. watched에서 시작이 종료를 넘으면 종료를, 종료가 시작보다 빠르면 시작을 끌어다 맞춤.

3. 저장 전 이탈 방어

  • 사용자가 내용을 수정한 뒤 뒤로가기를 누르면 “그만 작성” 확인 알럿을 띄움.
  • 로드 중 뒤로가기를 누르는 경우에는 로드 완료를 기다리지 않고 바로 닫음.
  • 닫기 이후 늦게 도착한 로드 결과가 현재 draft나 loading 상태를 다시 덮어쓰지 않도록 loadTask 취소와 isClosing 가드 추가함.
  • 로딩 화면은 루트 뷰를 교체하지 않고 overlay로 보여줌. 로드 완료 시점과 뒤로가기 dismiss가 겹칠 때 navigation pop이 취소되는 현상을 막기 위한 처리.

4. 도메인 정책과 서버 데이터 방어

  • ReadingPeriod에 미래 날짜를 허용하지 않는 불변식 추가함.
  • Data mapper에서도 서버에서 미래 날짜나 역전된 기간이 내려오면 조용히 보정하지 않고 매핑 실패로 처리함.
  • UI 휠은 사용자 입력을 막는 1차 방어선이고, Domain 불변식은 외부 데이터까지 막는 최종 방어선 역할.

5. 공용 UI와 에러 표현

  • 키워드 섹션에 사용할 WSSSearchBarButton 추가함. 실제 입력창은 아니고, 검색바처럼 보이는 탭 버튼.
  • 매력 포인트 초과처럼 사용자가 정상적으로 만날 수 있는 검증 에러는 토스트로 보여줌.
  • 그 외 네트워크/서버/예상 밖의 도메인 에러는 일반 에러 토스트로 묶고, 원인은 logger에 남김.
  • 필요한 디자인 에셋과 토스트 타입도 함께 보강함.

6. Demo와 테스트

  • NovelReviewFeature Demo 앱을 추가해 Mock 데이터와 실서버 연결을 전환하며 확인할 수 있게 함.

📱 Simulation

실서버 데모
Simulator Screen Recording - iPhone 17 Pro - 2026-06-13 at 01 02 05

mock 데모
Simulator Screen Recording - iPhone 17 Pro - 2026-06-13 at 01 03 12


🧑‍🧒‍🧒 To Reviewer

  • 키워드 탐색/선택 화면 연결은 아직 포함하지 않음. 이번 PR에서는 키워드 영역 진입 버튼까지만 작업함.

※ Reference

Naknakk and others added 28 commits June 8, 2026 22:51
- 첫 Feature 모듈 생성 (ModuleType.feature(.novelReview) 등록)
- MVVM 골격: Input/Output 프로토콜 + DefaultNovelReviewViewModel + 제네릭 View
- 읽기 상태 선택, 매력 포인트 토글(최대 3개) 구현
- public 진입점 NovelReviewFactory + Demo 앱 + Preview
- Feature 레이어/모듈 가이드 문서화 (docs/layers/Feature.md → Projects/Feature/CLAUDE.md)
- BaseDomain ReadingStatus·NovelGenre CaseIterable 채택

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- LoadNovelReviewDraftUseCase / SaveNovelReviewUseCase 주입 (Factory 파라미터)
- 화면 진입 시 load(), 완료 버튼에서 save()
- isLoading/isSaving/shouldDismiss 상태 + RepositoryError 메시지 매핑
- Demo는 인메모리 Mock UseCase로 흐름 시연

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 상태별 입력 분기: 보는 중=시작일, 봤어요=시작+종료(segment), 하차=종료일
- ReadingPeriodSheet (DatePicker + watched 시 시작/종료 segment)
- ViewModel: selectedPeriod 출력 + updatePeriod(start:end:) 입력
- 상태↔날짜 매핑은 도메인 ReadingPeriod.normalized(for:)에 일치

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 0.0~5.0 0.5단위 슬라이더, 0.0은 평점 없음(nil)으로 매핑
- 도메인 Rating(0.5~5.0)이 0.0을 표현 못 하는 제약 반영
- ViewModel: selectedRating 출력 + updateRating(_:) 입력

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ViewModel은 의미값(state)만 노출, 카피/포맷은 View가 담당
- 기간 표시는 status 분기 제거 → start/end 존재 여부로만 (도메인 normalize 신뢰)
- Date는 SwiftUI 네이티브 포맷으로 직접 렌더 (수동 DateFormatter 제거)
- load는 hasLoaded 가드로 최초 1회만 (재진입 시 편집 중 덮어쓰기 방지)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 검색바 룩이지만 TextField 없는 탭 버튼 (실제 검색 X)
- placeholder 정렬 옵션(leading/center), 전체 영역 탭 액션
- 키워드 진입 버튼 등 재사용 목적

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 키워드 섹션에 검색바 룩 탭 버튼 배치 (placeholder 가운데)
- 탭 액션은 훅만 연결, 키워드 탐색뷰 이동은 추후(TODO)
- icSearch 아이콘 갱신 반영

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 읽기 상태·매력포인트 아이콘 .template 틴팅 (선택 primary)
- 별점 탭/슬라이드 0.5 단위 StarRatingView 추가
- 네비게이션 타이틀 Factory 주입(title) + icNavigateLeft 뒤로가기 버튼
- icNavigateLeft 에셋 추가, wssGray80 색 토큰 추가

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
프로토콜(Input/Output) 폐기, 단일 state/handle로 전환. View·Factory 호출부 및 모듈 가이드 동기화.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
생성자가 notAfter(기본 오늘) 이후 날짜를 일 단위로 거부(.futureDate). 미래 독서 기간은 표현 불가능. 도메인 테스트 4건 추가.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NovelMapper가 ReadingPeriod 불변식 위반을 MappingError로 변환 → 레이어 규칙대로 로드 실패(fail-loud).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- WSSDateWheel에 maxDate(오늘) 추가. 미래로 굴러가도 date는 갱신하지 않고, settleTask 디바운스로 스크롤 정착을 감지한 뒤 오늘로 되돌림
- 되돌림 시 bounceToken→WheelColumn의 proxy.scrollTo로 물리 스크롤 강제 재정렬(.scrollPosition만으론 안 먹음)
- 연도 컬럼은 올해까지만 둬 미래 연도 차단
- VM: futureDate 에러 메시지 추가

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
watched에서 편집 중인 쪽을 기준으로 시작이 종료를 넘으면 종료를, 종료가 시작보다 빠르면 시작을 끌어다 맞춘다(입력 UX 정책).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WSSDateWheel 오버슈트→정착→되돌림 의도와 함정을 주의사항에 누적. 코드와 어긋난 시트 높이(362/436→320/394) 정정.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 매력 포인트 초과만 사용자 문구로 노출, 나머지는 '알 수 없는 에러' + 로그
- Core Logger를 옵셔널(nil 기본값)로 Factory→ViewModel 주입
- Feature 레이어 Core 의존(로깅 한정) 규칙 문서화

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- WSSToastType에 unknownError 케이스 추가(아이콘 icAlertWarning)
- ViewModel은 의미 에러(ReviewError)만 노출, View가 토스트 타입 매핑
- 매력 포인트 초과는 selectionOverLimit 재사용

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- onAppear+asyncAfter → .task(id:)로 교체해 퇴장 트랜지션 도중 재호출 시 토스트 잔류 해결
- move 트랜지션 제거하고 opacity 페이드만 유지
- 기본 표시 시간 3.0s → 1.5s

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- presentError에서 이미 표시 중인 에러가 있으면 새 에러로 덮어쓰지 않고 무시

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Naknakk Naknakk linked an issue Jun 12, 2026 that may be closed by this pull request
@Team-WSS Team-WSS deleted a comment from github-actions Bot Jun 12, 2026
@Naknakk Naknakk self-assigned this Jun 12, 2026
@Naknakk Naknakk requested review from Guryss and onesunny2 June 12, 2026 16:10
@Naknakk Naknakk marked this pull request as ready for review June 12, 2026 16:16
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.

[Feat] NovelReview Feature 구현

1 participant