# 이벤트 상세 딥링크 및 OneLink 연동 PRD ## 문서 정보 | 항목 | 내용 | |---|---| | 문서 상태 | 클라이언트 구현·로컬 검증 완료, 실제 단축 URL 성공 검증은 비차단 후속 항목 | | 작성일 / 최종 수정일 | 2026-10-29 | | 대상 제품 | SodaLive iOS 이벤트 상세 진입 | | 작성자·결정권자 | 사용자 승인 범위, 실행자는 게이트 이후 구현 | | 관련 API Contract | [api-contract.md](api-contract.md) | | 관련 구현 계획 | [plan-task.md](plan-task.md) | | 관련 review | [최종 구현 리뷰](reviews/phase2-event-detail-links.md), [실제 SDK 검증](reviews/phase1-onelink-sdk-runtime.md) | ## 1. Overview와 문제 OS/SDK가 전달하는 이벤트 URI·OneLink와 앱 내부 알림 입력을 기존 `AppStep.eventDetail(eventId:)`로 연결한다. 비로그인 및 cold start에서도 기존 pending 경로를 재사용한다. SDK 6.17.5에서 `performOnAppAttribution(with:)`가 UDL 활성 시 `didResolveDeepLink`로 긴 URL의 이벤트 값을 반환함을 실제로 확인했고 이를 구현에 사용한다. 정상 단축 URL의 서버 해석은 사용자 결정에 따라 비차단 후속 검증으로 남긴다. ## 2. 목표와 성공 기준 - 커스텀 URL, OneLink, push, Notifly URL, 알림 목록 진입을 한 이벤트 ID 처리 경로로 연결한다. - cold start 및 로그인 전에는 기존 공통 pending queue를 사용하고, 잘못된 ID가 현재 화면이나 pending 목적지를 변경하지 않게 한다. - 동일 pending/current/delivery의 중복만 억제한다. 이후 사용자가 다시 탭한 동일 링크는 새 탐색으로 허용한다. - 실제 SDK 공존 증거와 DEC-004의 사용자 후속 결정으로 구현 진입 조건을 충족했다. 단축 URL의 실제 서버 성공을 로컬 테스트 결과와 혼동하지 않는다. ## 3. Non-Goals 새 이벤트 화면/API, 새 이벤트 ID 라우트 별칭, `pushEventId`, 전역 router 재작성, SDK 업그레이드, share button, OneLink 생성·AppsFlyer/AASA/실제 push 전달 설정은 제외한다. 실백엔드 검증과 실제 공급자 연동 검증도 이 작업에서 하지 않는다. ## 4. 라우팅 및 동작 요구사항 | ID | 상태 | 요구사항 | 수용 기준 | Contract / Goal | |---|---|---|---|---| | LINK-001 | 확정 | 프로덕션 URI는 `voiceon://event-detail/{id}`, 개발 URI는 `voiceon-test://event-detail/{id}`만 허용한다. | 이벤트 alias 없음. ID는 양수 signed 64-bit 정수. | Contract §1, P2-T1 | | LINK-002 | 확정 | OneLink는 정확한 HTTPS host `voiceon.onelink.me`의 short/long URL이며 `deep_link_value=event-detail`, `deep_link_sub5={id}`를 사용한다. | `deep_link_sub1`~`deep_link_sub4` 기존 마케팅 값은 건드리지 않는다. | Contract §2, P2-T1 | | LINK-003 | 확정 | 표준 push `deep_link`, Notifly `url`, 알림 목록 `deepLink`는 커스텀 URI 또는 HTTPS OneLink를 받는다. | shortlink는 SDK가 해석해야 한다. query만 직접 읽어 shortlink를 우회하지 않는다. | Contract §3, P2-T2 | | LINK-004 | 확정 | SDK push 경로는 `addPushNotificationDeepLinkPath([deep_link])`를 SDK 시작 전에 등록하고 실제 `userInfo`로 `handlePushNotification`을 호출한다. | HTTPS OneLink만 SDK push handler로 전달한다. Notifly marker와 URL이 함께 있으면 소유자 하나만 라우팅한다. 같은 payload를 `deep_link`나 AppsFlyer push로 중복 전달하지 않는다. | Contract §3, P2-T2 | | LINK-005 | 확정 | 목적지는 기존 `AppStep.eventDetail(eventId:)`다. | 기존 상세 UI/API 계약과 route 이름은 유지한다. 공통 pending queue를 사용하며 cold start 및 로그인 전에도 보존한다. | Contract §4, P2-T1 | | LINK-006 | 확정 | 비양수, 숫자 아님, overflow ID는 무시한다. | 잘못된 입력은 기존 current 또는 pending 목적지를 바꾸지 않는다. 같은 pending/current/delivery만 억제하며 이후 새 사용자 탭은 허용한다. | Contract §1, P2-T1 | | LINK-007 | 확정 | 기존 live 종료 확인을 보존한다. | 확인 취소 시 탐색하지 않는다. 기존 GCD와 route는 유지한다. | Contract §4, P2-T1 | ## 5. 초기 SDK 게이트 기록(후속 DEC-004로 구현 차단 해제) - `P1-GATE`가 `P2` 전체의 선행조건이다. 설치된 SDK 6.17.5의 공개 계약 조사와 실행 격리 사전 점검을 마쳤으나 gate를 통과하지 못했다. 제품 코드는 수정하지 않는다. - `performOnAppAttribution(with:)`는 URL-only legacy resolver이며 공개 계약이 존재한다. 다만 UDL delegate가 동시에 설정된 상태에서의 콜백 선택을 확인하지 못했다. 합성 activity나 가짜 SDK callback의 성공만으로 실제 SDK 동작을 입증한 것으로 취급하지 않는다. - gate 실패 시 지원 API를 추측하거나 구현하지 않는다. 공급자 지원 확인 또는 별도 승인된 실제 SDK 테스트를 요청하고 정지한다. - 기존 SDK 초기화, GCD 처리, 라우트 및 pending queue를 존중한다. 새 alias·의존성·프로젝트 설정 변경을 만들지 않는다. ## 6. 추적 및 결정 | 날짜 | ID | 상태 | 결정 | 영향 | |---|---|---|---|---| | 2026-10-29 | DEC-001 | 확정 | 사용자 승인 범위는 딥링크/OneLink이며 SDK feasibility gate 통과 전 구현 금지 | P1-GATE, P2 | | 2026-10-29 | DEC-002 | 확정 | 기존 `AppStep.eventDetail(eventId:)`와 공통 queue 재사용 | LINK-005 | | 2026-10-29 | DEC-003 | 확정 | 현재 branch에서 작업, 승인 없는 commit 및 worktree 생성 없음 | 실행 범위 | ## 7. 제외 범위 기존 완료 문서 [이벤트 상세 API 연동](../20261029_이벤트_상세_API_연동/prd.md)은 별개이며 수정하지 않는다. 실제 AppsFlyer/Notifly/AASA/push 전달과 backend 검증은 별도 승인 대상이다. ### 추가 승인 - 2026-10-29 사용자가 AppsFlyer 테스트 OneLink의 실제 SDK 해석에 한해 검증을 허용했다. 기존 UDL과 manual URL resolver의 공존 동작 확인만 수행한다. 이벤트 API/앱 서버 호출, 푸시 발송, 운영 앱 실행, 공급자 콘솔 설정 변경은 계속 제외한다. 제품 구현 gate는 검증 결과 전까지 유지한다. ### 실제 SDK 검증 결과 - 2026-10-29 긴 HTTPS OneLink는 현재 SDK 6.17.5에서 UDL delegate가 설정된 상태의 수동 resolver 호출 후 `didResolveDeepLink(found)`로 event-detail/123을 반환했다. legacy-only 대조군도 확인해 콜백 선택의 이전 불확실성을 해소했다. 공식 단축 URL 예시는 해석에 실패했으며 정상 short fixture의 양성 검증은 남았다. 당시 gate 유지 판정과 제한은 [실행 기록](reviews/phase1-onelink-sdk-runtime.md)에 보존한다. ### 사용자 후속 결정: 단축 URL 없이 구현 진행 - 2026-10-29 - 사용자: "단축 URL을 만들어 둔 것이 없다. 요구사항대로 진행한다." - DEC-004: 정상 단축 URL의 실연결 양성 검증을 구현 차단 조건에서 제외한다. 이미 실제로 확인한 `performOnAppAttribution(with:)` → UDL 경로를 사용해 긴/단축 HTTPS OneLink를 SDK에 전달한다. 실연결 성공을 추정하거나 단축 링크를 직접 생성하지 않는다. - 로컬 SDK 경계 대역으로 short/long 전달, UDL 성공/실패, 이벤트 ID, 중복·cold start·live 취소 및 push owner를 검증한다. SDK 자체 short 서버 해석은 후속 검증으로 명시한다. 추가 인터뷰나 fixture 요청 없이 구현·빌드·리뷰를 진행한다. ### 최종 클라이언트 검증 - 2026-10-29 이벤트 딥링크 345 assertion, 기존 deep-link 279 assertion 및 전체 로컬 회귀 15개가 통과했다. SodaLive/SodaLive-dev Debug 시뮬레이터 빌드도 통과했고, 단일 리뷰의 비동기 경합 지적을 RED/GREEN으로 수정한 뒤 delta APPROVE를 받았다. 실제 정상 short 링크·실제 푸시/Notifly 전달·앱 서버 및 전체 기기 UI 동작은 이번 완료 주장에 포함하지 않는다.