From 89c070875cbeea8395c1e90cb9f47ff80df5d90f Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Tue, 4 Aug 2026 01:03:24 +0900 Subject: [PATCH] =?UTF-8?q?fix(main):=20=ED=98=84=EC=9E=AC=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=B8=8C=20=EC=A0=84=EC=B2=B4=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=EC=9D=84=20=EA=B3=A0=EC=A0=95=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/MainHomeLiveSection.swift | 17 +-- .../plan-task.md | 70 +++++++++++ docs/20260602_메인_홈_추천_UI_API_연동/prd.md | 19 +++ .../reviews/phase8-live-all-fixed.md | 116 ++++++++++++++++++ 4 files changed, 215 insertions(+), 7 deletions(-) create mode 100644 docs/20260602_메인_홈_추천_UI_API_연동/reviews/phase8-live-all-fixed.md diff --git a/SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift b/SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift index 411fe6a5..598fdb90 100644 --- a/SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift +++ b/SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift @@ -7,15 +7,18 @@ struct MainHomeLiveSection: View { var body: some View { if !items.isEmpty { - ScrollView(.horizontal, showsIndicators: false) { - LazyHStack(alignment: .top, spacing: SodaSpacing.s12) { - ForEach(items, id: \.self) { item in - MainHomeLiveItemView(item: item, onTapLive: onTapLive) + HStack(alignment: .top, spacing: SodaSpacing.s12) { + ScrollView(.horizontal, showsIndicators: false) { + LazyHStack(alignment: .top, spacing: SodaSpacing.s12) { + ForEach(items, id: \.self) { item in + MainHomeLiveItemView(item: item, onTapLive: onTapLive) + } } - - MainHomeLiveAllItemView(onTapAll: onTapAll) + .padding(.leading, SodaSpacing.s20) } - .padding(.horizontal, SodaSpacing.s20) + .frame(maxWidth: .infinity, alignment: .leading) + + MainHomeLiveAllItemView(onTapAll: onTapAll) } } } diff --git a/docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md b/docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md index 4c5380f0..b1efae11 100644 --- a/docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md +++ b/docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md @@ -85,6 +85,46 @@ - `plutil -lint SodaLive.xcodeproj/project.pbxproj` 실행, `OK` - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, `BUILD SUCCEEDED` +### 2026-08-03 Phase 8.3 현재 라이브 `전체` 우측 고정 + +**Goal 실행 `P8-T3`:** 현재 라이브 아이템만 가로로 스크롤하고 `전체` 버튼은 섹션 오른쪽 끝에 고정한다. + +- **시작 조건:** PRD 8.5와 2026-08-03 Decision Log 확정. +- **완료 증거:** 정적 RED/GREEN, `SodaLive-dev` 빌드, 여러 아이템 렌더에서 스크롤 전후 `전체` 위치 확인. +- **범위 밖:** API, 모델, ViewModel, 라우팅, `전체` 버튼 스타일 변경. +- **TDD 대체 사유:** 프로젝트에 XCTest 번들 타깃이 없으므로 기존 Preview를 실제 렌더 harness로 사용하고 레이아웃 구조를 정적 RED/GREEN으로 검증한다. + +**Files:** + +- Modify: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift` +- Verify: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift`의 `MainHomeLiveSection_Previews` + +- [x] **RED:** `MainHomeLiveAllItemView`가 `LazyHStack` 내부 마지막 항목으로 포함된 현재 구조를 확인한다. +- [x] **RED 확인:** `rg -n '^ {20}MainHomeLiveAllItemView\\(onTapAll' SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift`가 `LazyHStack` 내부 들여쓰기의 기존 스크롤 종속 구조를 찾는지 확인한다. +- [x] **GREEN:** `HStack`에서 라이브 목록 `ScrollView`와 `MainHomeLiveAllItemView`를 형제 뷰로 분리하고 기존 가장자리 여백을 유지한다. +- [x] **GREEN 확인:** `MainHomeLiveAllItemView`가 `ScrollView` 밖에 한 번만 존재하고 `onTapLive`, `onTapAll`, 빈 배열 guard가 유지되는지 확인한다. +- [x] **REFACTOR:** 추가 abstraction 없이 변경 파일의 diff와 빌드를 검증한다. +- [x] **SURFACE:** iPhone 16 Pro 시뮬레이터에서 추천 홈을 캡처했으나 dev 응답의 `lives`가 비어 대상 섹션은 표시되지 않았다. 두 독립 리뷰에서 제품 결함 없음과 non-empty 상태 증거 부족을 확인했고, 사용자가 이 증거 제한을 명시적으로 수용했다. + +### 2026-08-04 Phase 8.4 현재 라이브 `전체` 우측 여백 제거 + +**Goal 실행 `P8-R1`:** `전체` 버튼의 중복 trailing padding을 제거해 버튼 자체 프레임이 화면 오른쪽 끝에 붙도록 한다. + +- **시작 조건:** 사용자 피드백과 `REV-P8-002` 확정. +- **완료 증거:** 정적 RED/GREEN, `git diff --check`, `SodaLive-dev` Debug 빌드. +- **범위 밖:** 라이브 목록의 왼쪽 여백, 목록·버튼 간격, 버튼 프레임·스타일·콜백 변경. + +**Files:** + +- Modify: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift` +- Review: `reviews/phase8-live-all-fixed.md` + +- [x] **RED:** `.padding(.trailing, SodaSpacing.s20)`이 존재해 버튼 외부 우측 여백이 중복 적용됨을 확인한다. +- [x] **RED 확인:** focused `rg`가 기존 22행과 `RED LIVE-ALL-TRAILING-INSET`을 출력한다. +- [x] **GREEN:** `MainHomeLiveAllItemView`의 별도 trailing padding만 제거한다. +- [x] **GREEN 확인:** focused `rg`가 trailing padding을 찾지 못하고 왼쪽 `s20`, `HStack`의 `s12`, 콜백이 유지되는지 확인한다. +- [x] **REFACTOR:** 추가 변경 없이 diff와 빌드를 검증한다. + ### 2026-07-12 장르 크리에이터 섹션 미표시 반영 - 목적: 메인 홈 추천 탭에서 서버 응답의 `genreCreators` 기반 장르(카테고리)별 크리에이터 UI를 표시하지 않는다. @@ -2101,3 +2141,33 @@ - `rg "createdAt|Capsule\(\)|onChange\(of: proxy.size.height\)" SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift SodaLive/Sources/V2/Component/Text/ExpandableTextView.swift` 실행, 생성 시간 입력/표시, pay capsule, 높이 변화 감지 검색 확인 - `git diff --check` 실행, 출력 없이 성공 확인 - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, `BUILD SUCCEEDED` 확인 + +### P8-T3 1차 실행 — 2026-08-03 + +- 상태: 완료 +- 무엇을: `MainHomeLiveSection`의 라이브 목록 `ScrollView`와 `전체` 버튼을 `HStack`의 형제 뷰로 분리해 `전체`를 오른쪽 끝에 고정했다. +- 왜: 기존에는 `전체`가 `LazyHStack` 마지막 항목이라 라이브 목록과 함께 스크롤됐다. +- 어떻게: + - RED 정적 검증 — 기존 16행에서 `MainHomeLiveAllItemView`가 `LazyHStack` 내부에 있음을 확인했다. + - GREEN 정적 검증 — `MainHomeLiveAllItemView`가 `ScrollView` 밖으로 이동하고 빈 배열 guard, `onTapLive`, `onTapAll`, 좌우 `SodaSpacing.s20`, 간격 `SodaSpacing.s12`가 유지됨을 확인했다. + - `git diff --check` — 출력 없이 성공했다. + - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` — `BUILD SUCCEEDED`. + - iPhone 16 Pro(iOS 18.3) simulator build — 초기 전체 Pods 컴파일이 600초 제한으로 중단됐으나 동일 DerivedData의 `ONLY_ACTIVE_ARCH=YES` 증분 재실행은 `BUILD SUCCEEDED`. + - simulator 설치/실행 — 성공, 추천 홈의 1206x2622 RGBA PNG 캡처가 정상 합성됨을 확인했다. dev 응답의 `lives`가 비어 대상 섹션은 표시되지 않았다. + - 독립 시각 QA 2건 — 제품 결함 없음, non-empty 라이브 상태의 스크롤 전후 캡처 부재만 evidence blocker로 판정했다. 사용자가 해당 증거 제한을 수용했다. + - teardown — iPhone 16 Pro simulator를 종료하고 임시 QA DerivedData와 캡처 디렉터리를 제거했다. +- 남은 항목: 없음. non-empty 상태의 자동 시각 회귀는 테스트 타깃 또는 deterministic fixture가 도입될 때 추가한다. +- 리뷰: `reviews/phase8-live-all-fixed.md` + +### P8-R1 1차 실행 — 2026-08-04 + +- 상태: 완료 +- 무엇을: 고정된 `전체` 버튼의 `.padding(.trailing, SodaSpacing.s20)` 한 줄을 제거했다. +- 왜: 버튼의 70pt 프레임 자체에 좌우 간격이 포함되어 외부 trailing padding이 우측 간격을 중복시켰다. +- 어떻게: + - RED — focused `rg`가 기존 22행의 trailing `s20`과 `RED LIVE-ALL-TRAILING-INSET`을 출력했다. + - GREEN — 같은 `rg`가 trailing padding을 찾지 못했고, 스크롤 목록의 leading `s20`, `HStack`의 `s12`, 빈 상태와 콜백이 유지됨을 확인했다. + - `git diff --check` — 출력 없이 성공했다. + - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` — `BUILD SUCCEEDED`. +- 남은 항목: 없음. +- 리뷰: `reviews/phase8-live-all-fixed.md`의 `REV-P8-002` 수정 완료. diff --git a/docs/20260602_메인_홈_추천_UI_API_연동/prd.md b/docs/20260602_메인_홈_추천_UI_API_연동/prd.md index b7b0e6b3..4c9158b5 100644 --- a/docs/20260602_메인_홈_추천_UI_API_연동/prd.md +++ b/docs/20260602_메인_홈_추천_UI_API_연동/prd.md @@ -321,6 +321,12 @@ MainHomeView - 여러 페이지에서 재사용 가능한 Card/Banner/Text/Button/Creator widget: `SodaLive/Sources/V2/Component/**` - 기존 로직 수정이 아닌 신규 View/ViewModel/Repository는 `SodaLive/Sources/V2/**` 아래에 둔다. +### 8.5 현재 라이브 `전체` 고정 배치 +- 현재 라이브 아이템 목록만 가로로 스크롤한다. +- `전체` 버튼은 스크롤 위치와 관계없이 섹션 오른쪽 끝에 고정한다. +- 라이브 스크롤 목록의 왼쪽 20pt 여백은 유지하고, `전체` 버튼에는 별도 오른쪽 여백을 적용하지 않는다. +- 라이브 목록이 비어 있으면 기존처럼 현재 라이브 섹션과 `전체` 버튼을 표시하지 않는다. + ## 9. Technical Constraints - 앱 소스 변경은 `SodaLive/Sources/**`에서 수행한다. - `Pods/**`, `generated/**`, `build/**`는 직접 수정하지 않는다. @@ -340,6 +346,7 @@ MainHomeView - 추천 탭에서 `GET /api/v2/home/recommendations`를 호출하고 `success == true` 응답 데이터를 섹션별로 렌더링한다. - 응답 배열이 비어 있는 섹션은 화면에 표시하지 않는다. - 현재 라이브 섹션의 마지막 `전체` 항목은 배경 없이 medium 14 텍스트, `soda400` 색상, 세로 가운데 정렬로 표시된다. +- 현재 라이브 섹션의 `전체` 버튼은 라이브 아이템의 가로 스크롤과 관계없이 오른쪽 끝에 고정된다. - 현재 라이브 `전체` 진입 화면의 상단 제목은 `On Air`로 표시하고, 라이브 아이템은 Figma `185:4509`의 리스트형 구조를 따른다. - 현재 라이브 `전체` 진입 화면의 유료 라이브는 `ic_bar_cash`와 가격을 표시하고, 무료 라이브는 가격과 캔 아이콘 대신 `무료`만 표시한다. - `추천 필모그래피`, `또 다른 모습`은 코드와 화면에 포함하지 않는다. @@ -376,6 +383,7 @@ MainHomeView - 기능 검증: 추천 API 성공/실패, 빈 섹션, 활동 타입 I18n, 상세 진입 guard, 최근 활동 `LIVE`의 `targetId` 유무별 이동, `creatorId` 양수 검사, `LIVE_REPLAY`의 콘텐츠 상세 이동, 다른 활동 타입의 회귀 여부, 커뮤니티 카드 상태, 사업자 정보 더보기/접기를 확인한다. - 모두 팔로우 기능 검증: 로그인/비로그인 상태를 구분해 Dialog 표시 여부를 확인하고, 확인 전·취소·dimmed 영역 터치에는 API 요청이 0회이며 `팔로우 하기` 선택 시에만 요청이 1회인지 확인한다. - 다국어 검증: 앱 언어를 ko/en/ja로 전환해 모두 팔로우 Dialog의 제목, 설명, 확인, 취소 문구를 확인한다. +- 현재 라이브 고정 배치 검증: 여러 라이브 아이템이 표시된 상태에서 목록을 가로로 스크롤해 라이브 아이템만 이동하고 `전체` 버튼의 오른쪽 위치가 유지되는지 확인한다. ## 13. Decision Log @@ -386,3 +394,14 @@ MainHomeView - 로그인 사용자는 `팔로우 하기`를 명시적으로 선택한 경우에만 API를 호출한다. - `취소`와 dimmed 영역 터치는 모두 보류 action 폐기 및 API 미호출로 처리한다. - Dialog 문구는 7.6의 ko/en/ja 문구로 확정하며 관련 열린 질문은 없다. + +### 2026-08-03 현재 라이브 `전체` 고정 배치 + +- `MainHomeLiveSection`에서 라이브 목록 `ScrollView`와 `전체` 버튼을 형제 뷰로 분리한다. +- 오버레이 방식은 항목 가림과 터치 충돌 방지 여백이 추가로 필요하므로 사용하지 않는다. +- API, 모델, ViewModel, 라우팅과 `전체` 버튼 스타일은 변경하지 않는다. + +### 2026-08-04 현재 라이브 `전체` 우측 여백 제거 + +- `전체` 버튼 자체 프레임에 좌우 간격이 포함되어 있으므로 별도 trailing padding을 제거한다. +- 라이브 스크롤 목록의 왼쪽 `SodaSpacing.s20`과 목록·버튼 사이 `SodaSpacing.s12`는 유지한다. diff --git a/docs/20260602_메인_홈_추천_UI_API_연동/reviews/phase8-live-all-fixed.md b/docs/20260602_메인_홈_추천_UI_API_연동/reviews/phase8-live-all-fixed.md new file mode 100644 index 00000000..db0936d4 --- /dev/null +++ b/docs/20260602_메인_홈_추천_UI_API_연동/reviews/phase8-live-all-fixed.md @@ -0,0 +1,116 @@ +# Phase 8 현재 라이브 `전체` 우측 고정 리뷰 + +## 1. 리뷰 정보 + +| 항목 | 내용 | +|---|---| +| 리뷰 대상 | Phase 8.3 / `P8-T3` | +| 기준 commit 또는 working tree | working tree | +| 리뷰 일자 | 2026-08-03 | +| 리뷰어 | Sisyphus, 독립 Oracle 2건 | +| 기준 문서 | `../prd.md`, `../plan-task.md` | +| 리뷰 상태 | 판정 완료 | + +## 2. 리뷰 목적과 범위 + +### 목적 + +- 현재 라이브 아이템만 가로로 스크롤하고 `전체` 버튼이 오른쪽 끝에 고정되는지 검토한다. +- 빈 상태, 탭 callback, 기존 스타일과 여백에 회귀가 없는지 검토한다. + +### 포함 범위 + +- 코드: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift` +- 문서: PRD 8.5, Success Criteria, Verification Plan, `P8-T3` +- 검증: 정적 RED/GREEN, device/simulator 빌드, simulator 실행, 독립 시각 QA + +### 제외 범위 + +- API, 모델, ViewModel, 라우팅, `전체` 버튼 스타일 변경 + +## 3. 판정 기준 + +- `MainHomeLiveAllItemView`가 수평 `ScrollView` 밖에 있어야 한다. +- 스크롤 영역과 고정 버튼이 겹치지 않고 기존 `SodaSpacing` 토큰을 유지해야 한다. +- 빈 배열 guard와 `onTapLive`, `onTapAll` 경로가 유지되어야 한다. +- 컴파일과 앱 실행이 성공해야 한다. + +## 4. 검토한 근거 + +| 명령 또는 수동 검증 | 결과 | 핵심 증거 | +|---|---|---| +| RED 정적 검증 | 의도한 실패 | 기존 16행의 `전체`가 `LazyHStack` 내부에 있음 | +| GREEN 정적 검증 | 성공 | `전체`가 `ScrollView` 밖 형제 뷰로 이동 | +| `git diff --check` | 성공 | 출력 없음 | +| `SodaLive-dev` Debug device build | 성공 | `BUILD SUCCEEDED` | +| iPhone 16 Pro simulator build | 성공 | 증분 재실행 `BUILD SUCCEEDED` | +| simulator 설치·실행·캡처 | 제한적 성공 | 앱 정상 실행, 캡처 정상; `lives`가 비어 대상 섹션 미표시 | +| 독립 기능 무결성 리뷰 | REVISE | 제품 blocker 없음, non-empty 캡처만 evidence blocker | +| 독립 시각/CJK 리뷰 | REVISE | 제품 결함 없음, 노출된 한글 clipping 없음, 대상 상태 증거 부족 | + +## 5. 발견 사항 요약 + +확정 제품 발견 사항 없음. + +| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal | +|---|---|---|---|---|---| +| REV-P8-001 | Low | 보류 | non-empty 라이브 상태의 스크롤 전후 캡처 부재 | `P8-T3` | 사용자 증거 제한 수용으로 종료 | +| REV-P8-002 | Medium | 수정 완료 | `전체` 버튼 외부 trailing 여백 중복 | `P8-R1` | Phase 8.4에서 수정 및 빌드 검증 완료 | + +## 6. 발견 사항 상세 + +### REV-P8-001 — non-empty 라이브 상태 시각 증거 부재 + +- **심각도:** Low +- **상태:** 보류 +- **관련 요구사항:** PRD 8.5 +- **소유 Task:** `P8-T3` + +**관찰 내용** + +dev 서버의 추천 응답에서 `lives`가 비어 있어 빈 상태는 확인했지만 `전체` 버튼이 표시되는 상태는 캡처하지 못했다. GUI 자동화 권한이 없고 별도 touch driver도 설치되어 있지 않았다. + +**근거** + +- 코드는 `전체` 버튼을 `ScrollView` 밖 형제 뷰로 배치한다. +- 두 독립 리뷰 모두 제품 결함 없이 실제 non-empty 캡처 부재만 evidence blocker로 판정했다. +- 사용자가 2026-08-03 해당 증거 제한을 명시적으로 수용했다. + +**영향** + +구현과 빌드의 완료 판정에는 영향이 없지만, non-empty 상태의 자동 시각 회귀 증거는 남지 않는다. + +**권장 조치** + +향후 테스트 타깃 또는 deterministic fixture가 도입되면 overflow 라이브 아이템의 스크롤 전후 캡처를 추가한다. + +## 7. 확정 항목의 plan·goal 전환 + +`REV-P8-002`를 `plan-task.md`의 Phase 8.4 `P8-R1`으로 전환했다. + +## 8. 리뷰 종료 판정 + +| 판정 항목 | 결과 | 근거 | +|---|---|---| +| 리뷰 범위 전체 확인 | 충족 | 코드, 문서, build, simulator 실행 검토 | +| 후보 항목 판정 완료 | 충족 | 제품 결함 없음, evidence 제한만 분리 | +| 확정 항목 plan 반영 | 충족 | Phase 8.4 `P8-R1` | +| 보류 항목의 담당·재개 조건 기록 | 충족 | 테스트 타깃 또는 fixture 도입 시 재개 | +| 검증 명령과 결과 기록 | 충족 | `P8-T3` Progress와 본 문서에 기록 | + +**최종 결론:** 수정 검증 완료 + +**남은 항목:** 없음. non-empty 시각 증거 제한은 기존 사용자 수용을 유지한다. + +## 9. 수정 후 검증 기록 + +### 1차 수정 검증 — 2026-08-04 + +- 무엇을: `REV-P8-002`의 `MainHomeLiveAllItemView` 외부 trailing `s20`을 제거했다. +- 왜: 버튼 자체 70pt 프레임과 외부 padding이 우측 간격을 중복시켰다. +- 어떻게: + - RED focused `rg` — 기존 trailing padding과 실패 메시지 확인. + - GREEN focused `rg` — trailing padding 없음, leading `s20`과 `HStack` `s12` 유지 확인. + - `git diff --check` — 출력 없이 성공. + - `SodaLive-dev` Debug build — `BUILD SUCCEEDED`. +- 남은 항목: 없음.