diff --git a/docs/20261013_커뮤니티_딥링크_상세_이동/plan-task.md b/docs/20261013_커뮤니티_딥링크_상세_이동/plan-task.md new file mode 100644 index 00000000..78011b3a --- /dev/null +++ b/docs/20261013_커뮤니티_딥링크_상세_이동/plan-task.md @@ -0,0 +1,91 @@ +# 커뮤니티 딥링크 상세 이동 계획 + +| 항목 | 내용 | +|---|---| +| 상태 | 구현·자동 검증 완료, 실제 게시물 UI 확인 제한 | +| 작성일 | 2026-10-13 | +| 요구사항 | [prd.md](prd.md) CD-001~005 | +| API 기준 | 기존 상세 화면/조회 API 유지 | +| 현재 Phase | 1: postId 기반 상세 라우팅 | + +## 목표와 범위 +정상 community postId는 상세 화면으로 전달하고 누락·무효 값은 이동하지 않는다. 공통 handler와 기존 테스트만 변경하며 UI·API·다른 딥링크·기존 댓글 화면 정리는 제외한다. + +## Phase 1 +**결과:** 커뮤니티 딥링크가 사용자 ID와 무관하게 정확한 게시글 상세 route를 선택한다. +**선행조건:** 사용자 인터뷰 완료, 기존 딥링크 검사 22 assertions 통과. + +### Task 1.1 라우팅 변경과 회귀 검사 +**Goal P1-T1:** CD-001~005를 production handler 실행으로 검증한다. +**Files:** +- Modify: `SodaLive/Sources/App/AppDeepLinkHandler.swift` +- Test: `work/tests/AppDeepLinkGiftDetailCheck.swift` +- Run: `work/tests/check-app-deep-link-gift-detail.sh` +- Read: `SodaLive/Sources/App/AppStep.swift`, `SodaLive/Sources/ContentView.swift`, `SodaLive/Sources/Splash/SplashView.swift` +- Read: `SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift`, `CreatorChannelCommunityPostDetailViewModel.swift` (같은 디렉터리) +**Interfaces:** 기존 URL handler 입력 → 기존 `creatorChannelCommunityPostDetail(postId:)` route. +**완료 증거:** RED/GREEN 실행 결과, 유효·무효·스플래시·인접 라우팅 검사. + +- [x] **RED:** 정상 postId 상세 이동 및 누락·무효 값 이동 금지 회귀 검사 추가. +- [x] **RED 확인:** `bash work/tests/check-app-deep-link-gift-detail.sh`로 의도한 assertion 실패 확인. +- [x] **GREEN:** postId 단독 community action과 기존 상세 route 연결. +- [x] **GREEN 확인:** 같은 명령으로 신규·기존 검사 통과. +- [x] **REFACTOR:** 이번 변경이 만든 handler 내부 불필요 코드 제거 및 회귀 재검증. + +### Task 1.2 검증과 리뷰 +**Goal P1-GATE:** 변경 범위의 검증 결과와 확인 불가능한 환경 조건을 구분한다. +**Files:** 위 코드/테스트, 본 PRD/계획, `reviews/phase1-community-post-detail-links.md`. +**TDD 예외 사유:** 검증·리뷰 기록만 작성하는 Task. + +- [x] Swift 컴파일/구문 검사와 앱 빌드 실행. +- [x] 실제 handler 입력/결과 및 iOS UI 검증 가능 여부 기록. +- [x] 읽기 전용 리뷰 후 확정 문제가 있으면 신규 Task 등록, 없으면 발견 사항 없음 기록. +- [x] 변경 범위와 검증 결과를 Progress에 누적. + +## 시나리오와 검증 +| 시나리오 | 이진 성공 기준 | 실행 표면 | +|---|---|---| +| 정상 입력 | `voiceon://community?postId=12345`가 상세 12345로 이동, 목록/댓글 예약 없음 | production handler를 swiftc로 컴파일한 기존 하네스 | +| 잘못된 입력 | 누락·빈 값·문자·0·음수·범위 초과 입력은 route/pending 변경 없음 | 동일 하네스, 사용자 ID 0/양수와 path/query 변형 | +| 시작·진입점 | splash에서 저장 후 apply, notificationList에서도 상세 12345 | 동일 하네스 | +| 인접 회귀 | 기존 선물/콘텐츠 라우팅 유지 | 기존 22 assertions | + +명령: `bash work/tests/check-app-deep-link-gift-detail.sh`, `swiftc -frontend -parse SodaLive/Sources/App/AppDeepLinkHandler.swift work/tests/AppDeepLinkGiftDetailCheck.swift`, `xcodebuild -workspace SodaLive.xcworkspace -scheme SodaLive-dev -configuration Debug -destination 'generic/platform=iOS Simulator' CODE_SIGNING_ALLOWED=NO build`. +iOS 수동 QA는 개발 앱에서 `xcrun simctl openurl booted 'voiceon-test://community?postId=12345'`로 진입해 상세 화면/게시물을 확인해야 한다. 운영 앱의 등록 scheme은 `voiceon`, 개발 앱은 `voiceon-test`다. 빌드/앱 실행이 차단되면 handler 하네스를 UI 검증으로 대체했다고 주장하지 않는다. + +## 실행 순서와 중단 조건 +P1-T1 → P1-GATE. 검증과 리뷰가 끝나면 추가 정리 없이 종료한다. 현재 브랜치에서만 작업한다. + +## Progress +### 기준 확인 — 2026-10-13 +- 기존 딥링크 하네스: exit 0, 22 assertions 통과. +- 상세 화면은 받은 postId로 기존 상세 API를 조회함을 확인. +- Xcode 26.0, 실행 중 시뮬레이터 없음. +- 인터뷰 결과: postId 누락·잘못된 값은 기존 목록 fallback 대신 이동 금지. + +### P1-T1 RED — 2026-10-13 +- 기존 하네스에 정상 입력·사용자 ID 독립성·누락/무효·스플래시·알림 목록 검사를 추가했다. +- `swiftc -frontend -parse work/tests/AppDeepLinkGiftDetailCheck.swift`: exit 0. +- `bash work/tests/check-app-deep-link-gift-detail.sh`: `FAIL: community link accepted: voiceon://community?postId=12345, userId=0` assertion으로 실패. 기존 코드의 사용자 ID 의존성 때문에 발생한 의도된 RED다. + +### P1-T1 GREEN — 2026-10-13 +- community action은 postId만 보유하며 기존 상세 route에 전달한다. 사용자 ID fallback과 기존 목록/댓글 예약 호출을 handler에서 제거했다. +- 명시적인 community 경로의 누락·무효 postId는 다른 쿼리 route로 우회하지 않는다. +- `bash work/tests/check-app-deep-link-gift-detail.sh`: exit 0, 279 assertions 통과. +- `swiftc -frontend -parse SodaLive/Sources/App/AppDeepLinkHandler.swift work/tests/AppDeepLinkGiftDetailCheck.swift`: exit 0. +- `git diff --check`: exit 0. +- `for test_script in work/tests/check-*.sh; do bash "$test_script" || exit $?; done`: exit 0, 기존 스크립트 전체 통과. +- 첫 앱 빌드는 도구의 120초 제한으로 중단되어 실행 제한을 600초로 늘려 재실행했다. + +### P1-GATE — 2026-10-13 +- 앱 빌드: 위 `xcodebuild ... build` 재실행 결과 `BUILD SUCCEEDED`. 로그: `/var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/community-deeplink-build-retry.log`. +- 변경 handler의 빌드 경고/오류 없음. `lsp_diagnostics` 도구가 제공되지 않아 Swift 컴파일·구문 검사와 앱 빌드로 확인했다. +- Xcode test: `xcodebuild -workspace SodaLive.xcworkspace -scheme SodaLive-dev -configuration Debug -destination 'platform=iOS Simulator,id=E9FC7721-AA96-440F-8349-2DC4B85F40F5' CODE_SIGNING_ALLOWED=NO test`는 `Scheme SodaLive-dev is not currently configured for the test action`으로 실행 불가. 전체 검증 성공은 `work/tests/check-*.sh` 범위이며 XCTest 통과를 의미하지 않는다. +- 독립 읽기 전용 리뷰: 차단 결함 없음, handler 하네스 279 assertions 재확인. [리뷰](reviews/phase1-community-post-detail-links.md). +- 실제 QA: 작업 전용 iPhone 17 Pro/iOS 26.0 시뮬레이터 `9794D878-ABFB-48F6-9759-17C9C2EB48F8` 생성·부팅 후 빌드한 개발 앱 설치. 부팅/설치 명령은 120초 제한에 걸렸으나 `simctl get_app_container`로 설치 완료를 별도 확인했다. +- `xcrun simctl launch ... 9794D878-ABFB-48F6-9759-17C9C2EB48F8 kr.co.vividnext.sodalive.debug2`: PID 26019. `xcrun simctl openurl 9794D878-ABFB-48F6-9759-17C9C2EB48F8 'voiceon-test://community?postId=12345'` 실행. +- 스크린샷 `/var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/community-deeplink-valid.png`에서 첫 실행 추적 허용 팝업과 배경 홈 화면 확인. 재실행 캡처는 같은 디렉터리의 `community-deeplink-reopen.png`. +- [blocked] 실제 게시글 표시·접근 권한 및 푸시 탭 UI 검증: 첫 실행 시스템 팝업을 조작할 iOS UI 자동화 도구가 제공되지 않아 완료하지 못했다. 개발 앱에서 팝업을 처리한 뒤 접근 가능한 실제 postId로 확인해야 한다. handler 검사를 UI 검증 완료로 보고하지 않는다. +- 작업 중 `SodaLive.xcodeproj/project.pbxproj`에 별도 항목 정렬 diff가 관찰됐다. 직접 수정한 파일이 아니므로 임의 복구하지 않았으며 라우팅 변경 범위와 분리한다. +- QA 정리: `xcrun simctl terminate 9794D878-ABFB-48F6-9759-17C9C2EB48F8 kr.co.vividnext.sodalive.debug2 && xcrun simctl shutdown 9794D878-ABFB-48F6-9759-17C9C2EB48F8 && xcrun simctl delete 9794D878-ABFB-48F6-9759-17C9C2EB48F8` 성공. 작업 전용 앱/시뮬레이터를 정리했고 사용자 기존 기기/Preview는 변경하지 않았다. 테스트 임시 바이너리는 기존 스크립트의 EXIT trap으로 제거된다. +- 최종 딥링크 검사 279 assertions 및 `git diff --check` 재통과. 스크린샷·빌드 로그는 위 임시 경로에 검증 자료로 보존한다. diff --git a/docs/20261013_커뮤니티_딥링크_상세_이동/prd.md b/docs/20261013_커뮤니티_딥링크_상세_이동/prd.md new file mode 100644 index 00000000..33cb0d84 --- /dev/null +++ b/docs/20261013_커뮤니티_딥링크_상세_이동/prd.md @@ -0,0 +1,60 @@ +# PRD: 커뮤니티 딥링크 상세 이동 + +## 문서 정보 +| 항목 | 내용 | +|---|---| +| 상태 | 구현 완료, 실제 게시물 UI 확인 제한은 계획에 기록 | +| 작성일 | 2026-10-13 | +| 결정권자 | 사용자 | +| 관련 계획 | [plan-task.md](plan-task.md) | +| API | 기존 게시글 상세 API 재사용, 계약 변경 없음 | +| 리뷰 | [phase1-community-post-detail-links.md](reviews/phase1-community-post-detail-links.md) | + +## 1. Overview +`voiceon://community?postId=12345`를 실행하면 기존 `CreatorChannelCommunityPostDetailView`에서 해당 게시물을 표시한다. + +## 2. Problem Statement +기존 링크는 저장된 사용자 ID를 크리에이터 ID로 사용해 커뮤니티 목록과 댓글 시트를 연다. 게시글 상세를 바로 보여주지 않으며 사용자 ID가 없으면 정상 postId도 처리되지 않는다. + +## 3. Goals +- 유효한 postId만으로 해당 게시글 상세 route에 진입한다. +- postId 누락·잘못된 값이면 현재 화면과 대기 중 이동 상태를 바꾸지 않는다. + +## 4. Non-Goals +- 상세 화면 UI, API, 인증·구매·접근 권한 정책 변경. +- 관련 없는 기존 댓글 화면/상태의 일괄 정리. +- worktree 생성 또는 다른 브랜치로 전환. + +## 5. 사용자와 권한 +푸시 탭, 외부 URL, 앱 내 알림 목록의 공통 handler를 사용한다. 게시글 존재 여부와 접근 권한은 기존 상세 API와 화면의 오류 처리를 따른다. + +## 6. 핵심 흐름과 라우팅 +`community` 링크 → 양수 Int postId 해석 → `.creatorChannelCommunityPostDetail(postId:)` → 기존 상세 화면의 게시글 조회. +스플래시에서는 기존 pending action 전달을 유지한다. 기존 `post_id` 별칭, 크리에이터 경로형 및 `community_id` 쿼리형은 동일한 postId 상세 이동으로 처리한다. + +## 7. 기능 요구사항 +| ID | 상태 | 요구사항 | 수용 기준 | +|---|---|---|---| +| CD-001 | 확정 | postId로 상세 이동 | 12345 전달 시 상세 route에 정확히 12345 전달, 목록/댓글 시트 호출 없음 | +| CD-002 | 확정 | 누락·무효 값 거부 | 빈 값, 문자, 0, 음수, Int 범위 초과는 이동 및 pending 변경 없음 | +| CD-003 | 확정 | 사용자 ID 불필요 | 저장된 사용자 ID 0과 양수 모두 CD-001 성립 | +| CD-004 | 확정 | 공통 진입점과 시작 대기 유지 | external/notificationList 및 splash 후 apply가 같은 상세 route 생성 | +| CD-005 | 확정 | 인접 기능 유지 | 기존 선물/콘텐츠 딥링크 검사 통과 | + +## 8. 기술·운영 제약 +기존 Swift/앱 라우팅과 `work/tests` 하네스를 재사용한다. 신규 의존성·프로젝트 설정 변경 없이 현재 브랜치에서 작업한다. 실제 서버 데이터가 필요한 UI 검증과 독립 실행 가능한 handler 검증을 구분한다. + +## 9. 성공 기준 +- CD-001~005의 실제 production handler 실행 검사가 통과한다. +- 변경 Swift 구문/컴파일 검사와 가능한 앱 빌드를 수행하고 실패·환경 제한을 그대로 기록한다. +- 기기 UI 실행 미확인 상태를 정상 동작 확인으로 보고하지 않는다. + +## 10. Open Questions +없음. 사용자 인터뷰로 누락·잘못된 값은 이동하지 않는 것으로 확정했다. + +## 11. Decision Log +| 날짜 | 결정 | 근거 | +|---|---|---| +| 2026-10-13 | 목록 대신 기존 게시글 상세로 이동 | 사용자 구현 요청 | +| 2026-10-13 | 누락·잘못된 postId는 이동하지 않음 | 사용자 인터뷰 답변 | +| 2026-10-13 | 현재 브랜치 사용, worktree 금지 | 사용자 직접 지시 | diff --git a/docs/20261013_커뮤니티_딥링크_상세_이동/reviews/phase1-community-post-detail-links.md b/docs/20261013_커뮤니티_딥링크_상세_이동/reviews/phase1-community-post-detail-links.md new file mode 100644 index 00000000..5195c014 --- /dev/null +++ b/docs/20261013_커뮤니티_딥링크_상세_이동/reviews/phase1-community-post-detail-links.md @@ -0,0 +1,43 @@ +# 커뮤니티 상세 딥링크 리뷰 + +## 1. 리뷰 정보 +| 항목 | 내용 | +|---|---| +| 대상 | Phase 1 / 현재 브랜치 working tree | +| 일자 | 2026-10-13 | +| 리뷰어 | 독립 읽기 전용 에이전트, Sisyphus 검증 | +| 기준 | [PRD](../prd.md), [계획](../plan-task.md) | +| 상태 | 코드 리뷰 승인, 실제 UI 확인 제한 기록 | + +## 2. 목적과 범위 +공통 `AppDeepLinkHandler.swift`와 `work/tests/AppDeepLinkGiftDetailCheck.swift`의 변경, 기존 AppDelegate/알림 목록/Splash/AppStep/ContentView/상세 조회 연결을 검토했다. UI 디자인·API 계약·인증 정책 변경은 제외한다. + +## 3. 판정 기준 +정상 postId는 해당 상세 route에 전달되고, 누락·무효 postId는 현재 route와 pending action을 바꾸지 않아야 한다. 사용자 ID와 진입점에 따른 오동작 또는 기존 선물/콘텐츠 회귀는 차단 결함이다. + +## 4. 검토 근거와 검증 +- CD-001/003: community action은 postId만 보유한다. 기존 ContentView가 이를 상세 화면에 전달하고 ViewModel은 해당 postId로 기존 API를 호출한다. +- CD-002: 양수 Int 검증과 명시적 community 경로 fallback 차단을 확인했다. main/splash에서 현재 route와 기존 pending action 보존 검사가 통과했다. +- CD-004: 외부 URL/푸시/알림 목록이 같은 handler를 사용하며 스플래시 재적용도 동일 action을 사용한다. +- CD-005: 기존 선물/콘텐츠 assertion 22개를 유지했다. + +| 검증 | 결과 | +|---|---| +| 리뷰어의 딥링크 하네스 재실행 | PASS, 279 assertions | +| 전체 `work/tests/check-*.sh` | 모두 PASS | +| Swift 구문 검사 및 `git diff --check` | PASS | +| SodaLive-dev Debug 시뮬레이터 빌드 | BUILD SUCCEEDED | +| Xcode test action | 스킴에 test action이 구성되지 않아 실행 불가 | +| 실제 앱 설치/딥링크 실행 | 시도 완료, 첫 실행 추적 허용 팝업으로 상세 표시 확인 제한 | + +## 5. 발견 사항 요약 +확정 발견 사항 없음. 코드 리뷰는 승인한다. 실제 API 응답·게시물 표시·푸시 탭 E2E 검증은 하네스와 별개이며 완료로 판단하지 않는다. + +## 6. 발견 사항 상세 +차단 결함 없음. 개발 앱 수동 QA scheme은 `voiceon-test`, 운영 앱은 `voiceon`이다. 이 차이는 계획의 QA 명령에 반영했다. + +## 7. plan·goal 전환 +확정 결함이 없어 전환 항목 없음. + +## 8. 종료 판정 +요청 범위 코드와 테스트는 승인한다. 실제 UI 확인 제한 및 실행 증거는 [계획 Progress](../plan-task.md)에 기록했다. 추가 리팩터링 없이 종료한다.