From c6b5f9c86787a51e5dc0a74f47419a6200746e69 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 2 Oct 2026 13:20:25 +0900 Subject: [PATCH] =?UTF-8?q?docs(gift):=20=EB=B0=9B=EC=9D=80=20=EC=84=A0?= =?UTF-8?q?=EB=AC=BC=20=EC=83=81=EC=84=B8=20=EA=B5=AC=ED=98=84=20=ED=94=84?= =?UTF-8?q?=EB=A1=AC=ED=94=84=ED=8A=B8=EB=A5=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gift-detail-tracking-page-prompt.md | 4 +- .../gift-received-detail-page-prompt.md | 421 ++++++++++++++++++ 2 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 docs/20260929_크리에이터_선물하기/gift-received-detail-page-prompt.md diff --git a/docs/20260929_크리에이터_선물하기/gift-detail-tracking-page-prompt.md b/docs/20260929_크리에이터_선물하기/gift-detail-tracking-page-prompt.md index 127baf12..d3e5546f 100644 --- a/docs/20260929_크리에이터_선물하기/gift-detail-tracking-page-prompt.md +++ b/docs/20260929_크리에이터_선물하기/gift-detail-tracking-page-prompt.md @@ -1,6 +1,6 @@ -# 선물 상세 및 운송장 등록 페이지 생성 프롬프트 +# 보낸 선물 상세 및 운송장 등록 페이지 생성 프롬프트 -이 문서는 Android/iOS 앱의 `선물함` 리스트에서 진입하는 선물 상세 페이지와 운송장 등록 페이지를 생성할 때 사용하는 프롬프트다. +이 문서는 Android/iOS 앱의 `선물함` 리스트에서 보낸 선물 상세 페이지와 운송장 등록 페이지를 생성할 때 사용하는 프롬프트다. 참고 Figma: diff --git a/docs/20260929_크리에이터_선물하기/gift-received-detail-page-prompt.md b/docs/20260929_크리에이터_선물하기/gift-received-detail-page-prompt.md new file mode 100644 index 00000000..deff17c7 --- /dev/null +++ b/docs/20260929_크리에이터_선물하기/gift-received-detail-page-prompt.md @@ -0,0 +1,421 @@ +# 받은 선물 상세 및 배송지 입력 페이지 생성 프롬프트 + +이 문서는 Android/iOS 앱의 `선물함` 리스트에서 받은 선물 상세 페이지와 배송지 입력 UI를 생성할 때 사용하는 프롬프트다. + +참고 Figma: + +- 배송지 입력 전 상세 UI: `2531:36290` +- 배송지 입력 완료 후 상세 UI: `2531:36399` +- 선물 전달 완료시 상세 UI: `2531:36330` +- 선물 전달 불가시 상세 UI: `2531:36422` + +전제: + +- 선물함 리스트 item 탭 시 `applicationNo`를 전달받아 상세 페이지로 이동한다. +- 새 디자인 시스템을 만들지 말고 Android/iOS 각각의 기존 디자인 시스템, 컴포넌트, API client, 상태 관리, toast/dialog, navigation 패턴을 재사용한다. +- 모든 API 응답은 공통 envelope를 사용하며 실제 payload는 `response.data`다. +- 이 프롬프트는 받는 크리에이터 관점(`direction=RECEIVED`)만 다룬다. +- API 예시는 TypeScript 타입이 아니라 JSON으로 작성한다. + +--- + +## 모바일 앱 구현 프롬프트 + +```text +Android/iOS 앱의 받은 선물 상세 페이지와 배송지 입력 UI를 Figma 기준으로 생성하고 API 연동을 구현해줘. + +범위: +- 선물함 리스트에서 `applicationNo`를 받아 받은 선물 상세 페이지로 이동한다. +- 상세 페이지는 `GET /api/v2/gifts/{applicationNo}` 응답으로 렌더링한다. +- `direction=RECEIVED && recipientAddressRequired=true`이면 배송지 입력 UI를 표시한다. +- 배송지 입력은 `POST /api/v2/gifts/{applicationNo}/recipient-address`로 연결한다. +- 배송지 입력 완료 후에는 상세를 다시 조회해 배송지 입력 완료 상태 UI를 표시한다. + +중요 전제: +- Figma의 visual structure와 문구를 우선 따르되, 데이터 노출과 CTA 조건은 API 계약을 우선한다. +- `direction=RECEIVED` 화면에서 `senderInfo`, `mailbox`, `giftInfo.applicationNo`, `giftInfo.paidCan`, `giftInfo.tracking`은 표시하지 않는다. +- `recipientAddress`가 null이면 받는 주소 섹션 자체를 표시하지 않는다. 전달 완료 후 배송지 정보가 삭제될 예정이므로 빈 섹션, skeleton, `-` 값도 표시하지 않는다. +- 전달 불가 화면의 `문의하기`는 기존 앱의 카카오 채널 문의 연결과 동일하게 연결한다. +- 전달 불가 화면의 `선물 정책 확인`은 버튼/action만 만들어두고 실제 외부 페이지 연결은 하지 않는다. 임의 URL을 연결하지 않는다. + +상세 페이지 진입: +- 화면 진입 시 `GET /api/v2/gifts/{applicationNo}`를 호출한다. +- 조회 결과 `direction`이 `RECEIVED`가 아니면 이 화면을 렌더링하지 말고 기존 앱의 잘못된 접근/상세 재라우팅 정책을 따른다. +- 로딩 중에는 기존 앱 상세 화면 로딩/스켈레톤 패턴을 사용한다. +- 실패 시 기존 앱 toast/dialog와 재시도 패턴을 사용한다. + +배송지 입력 전 UI: +- 적용 조건: `direction=RECEIVED && recipientAddressRequired=true`. +- Figma `2531:36290`을 따른다. +- 상단 타이틀: `선물 받기`. +- 개인정보 이용 안내 배너를 표시한다. + - 제목: `개인정보 이용 안내` + - 본문: `크리에이터 및 팬의 주소는 공개되지 않습니다. 입력한 배송지는 선물 전달 및 필요한 사고 처리에서 사용되며, 전달 완료 후 파기됩니다.` +- `전달 예정 선물` 섹션을 표시한다. + - 발송인: `giftInfo.senderNickname` + - 사이즈: `giftInfo.sizeName` + - 카테고리: `giftInfo.categoryName` +- `배송지 입력` 섹션을 표시한다. + - 이름 input: `recipientName` + - 휴대폰 번호 input: `recipientPhoneNumber` + - 우편번호 input: `recipientZipCode` + - 우편번호 검색 버튼: 기존 페이지와 동일하게 Kakao 우편번호 서비스를 사용한다. + - 주소 input: `recipientAddress` + - 상세 주소 input: `recipientAddressDetail` +- `이용 약관 동의` 섹션을 표시한다. + - `소다라이브 크리에이터 상품 전달 이용약관 및 전달 가능 제한 품목을 확인하고 동의합니다.(필수)` + - `상품 전달을 위해 수령인 성명·연락처·주소 등 필요한 개인정보를 일시적으로 수집·이용하는 것에 동의합니다.(필수)` + - 두 항목 모두 체크해야 제출 가능하다. + - 약관 상세 링크는 앱에 기존 약관/webview 경로가 있으면 연결하고, 없으면 새 페이지를 만들지 않는다. +- 하단 주요 CTA: `선물 받기`. +- CTA 활성 조건: + - 이름, 휴대폰 번호, 우편번호, 주소가 공백이 아니다. + - 상세 주소는 선택 입력이다. + - 약관 2개가 모두 체크됐다. + - submit 중에는 중복 탭을 막고 loading 상태를 표시한다. + +배송지 입력 API 연결: +- CTA 탭 시 `POST /api/v2/gifts/{applicationNo}/recipient-address`를 호출한다. +- request body에는 화면 입력값과 약관 동의 boolean을 그대로 전송한다. +- 성공 시 성공 toast를 표시하고 상세 페이지를 다시 조회하거나 replace navigation으로 상세를 다시 연다. +- 실패 시 기존 앱 form error/toast/dialog 패턴을 따른다. 실패 상태에서 입력값은 유지한다. + +주소 검색 구현: +- 기존 앱/페이지에 Kakao 우편번호 서비스 래퍼가 있으면 반드시 재사용한다. +- 신규 연결이 필요하면 Kakao 우편번호 서비스 공식 가이드 `https://postcode.map.kakao.com/guide`를 따른다. +- SDK script는 공식 가이드의 `//t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js`를 사용한다. 임의 수정본이나 별도 주소 검색 API를 만들지 않는다. +- Android/iOS WebView 또는 모바일웹 환경에서는 `window.open` 팝업이 막힐 수 있으므로, 기존 페이지와 같은 방식이 없다면 Kakao 가이드의 `embed()` 기반 레이어/페이지 삽입 방식을 우선 검토한다. +- 검색 결과 선택 시: + - `data.zonecode`를 `recipientZipCode`에 넣는다. + - `data.userSelectedType === "R"`이면 `data.roadAddress`를, 그 외에는 `data.jibunAddress`를 `recipientAddress`에 넣는다. + - 주소 선택 후 `recipientAddressDetail` 입력으로 포커스를 이동한다. +- 상세 주소는 Kakao 결과에서 채우지 않고 사용자가 직접 입력하게 한다. +- 주소 검색 실패/취소 시 입력 중이던 이름, 휴대폰 번호, 약관 체크 상태를 초기화하지 않는다. + +배송지 입력 완료 후 상세 UI: +- 적용 조건: `direction=RECEIVED && recipientAddressRequired=false && status`가 `TRACKING_REGISTERED`, `ARRIVED_AT_MAILBOX`, `INSPECTION_COMPLETED` 중 하나이며 `recipientAddress`가 있다. +- Figma `2531:36399`를 따른다. +- 상단 타이틀: `선물 상세`. +- hero title: `배송지 입력 완료!` +- hero body: `빠른 시일 내로 선물을 전달 드릴게요.` +- `문의하기` 버튼을 표시하고 기존 카카오 채널 문의로 연결한다. +- `선물 정보` 섹션을 표시한다. + - 발송인: `giftInfo.senderNickname` + - 사이즈: `giftInfo.sizeName` + - 카테고리: `giftInfo.categoryName` + - 배송 신청일: `giftInfo.shippingRequestedAt` +- `받는 주소` 섹션은 `recipientAddress`가 있을 때만 표시한다. + - 이름: `recipientAddress.name` + - 휴대폰 번호: `recipientAddress.phoneNumber` + - 주소: `recipientAddress.address` + +선물 전달 완료 상세 UI: +- 적용 조건: `direction=RECEIVED && status=DELIVERED`. +- Figma `2531:36330`을 따른다. +- 상단 타이틀: `선물 상세`. +- hero title: `선물 전달 완료!` +- hero body: `팬이 보낸 선물이 도착했어요. 선물이 도착하지 않은 경우, 문의해 주세요.` +- `문의하기` 버튼을 표시하고 기존 카카오 채널 문의로 연결한다. +- `선물 정보` 섹션을 표시한다. + - 발송인: `giftInfo.senderNickname` + - 사이즈: `giftInfo.sizeName` + - 카테고리: `giftInfo.categoryName` + - 배송 신청일: `giftInfo.shippingRequestedAt` + - 배송 완료일: `statusTimeline`에서 `DELIVERED.occurredAt` +- `받는 주소` 섹션은 `recipientAddress`가 있을 때만 표시한다. + - 섹션 보조 문구: `배송 완료 3일 후 해당 정보는 사라져요` + - 이름: `recipientAddress.name` + - 휴대폰 번호: `recipientAddress.phoneNumber` + - 주소: `recipientAddress.address` +- `recipientAddress=null`이면 `받는 주소` 섹션 전체를 숨긴다. + +선물 전달 불가 상세 UI: +- 적용 조건: `direction=RECEIVED && status=UNDELIVERABLE`. +- Figma `2531:36422`를 따른다. +- 상단 타이틀: `선물 상세`. +- chip: `전달 불가` +- hero title: `전달할 수 없는 품목입니다` +- hero body: `해당 선물은 SODALIVE 선물 정책에 따라 크리에이터에게 전달할 수 없는 품목으로 확인되었습니다.` +- action button: + - `문의하기`: 기존 카카오 채널 문의로 연결한다. + - `선물 정책 확인`: action handler만 연결하고 실제 외부 페이지/URL은 연결하지 않는다. 기존 앱 정책상 no-op이 금지되어 있으면 `준비 중입니다.` toast만 표시한다. +- `사유` 섹션을 표시한다. + - 사유 제목: `delivery.undeliverableReason`이 있으면 그 값을 사용한다. + - `delivery.undeliverableReason`이 null이면 `전달 불가`로 표시한다. + - 안내 문구: `해당 선물은 정책에 따라 폐기되며 반송되지 않습니다.` +- 전달 불가 상태에서는 배송지 입력 UI를 표시하지 않는다. +- `recipientAddress`가 응답에 있더라도 전달 불가 Figma에는 받는 주소 섹션이 없으므로 표시하지 않는다. + +날짜 표시: +- API의 모든 날짜는 UTC ISO 문자열이다. +- 앱 공통 날짜 formatter가 있으면 재사용한다. +- Figma처럼 상세 필드 날짜는 `YYYY.MM.DD`로 표시한다. +- 값이 null이면 해당 row를 숨긴다. + +API 명세: + +선물 상세 조회: +- Method: `GET` +- URL: `/api/v2/gifts/{applicationNo}` +- 인증: 로그인 필요 +- Response envelope 예시 - 배송지 입력 전: +```json +{ + "success": true, + "data": { + "applicationNo": "A-1002609300001", + "direction": "RECEIVED", + "status": "TRACKING_REGISTERED", + "statusName": "발송 확인", + "giftInfo": { + "recipientCreatorNickname": null, + "senderNickname": "팬닉네임이들어가는부분", + "sizeName": "소형", + "categoryName": "신규 전자굿즈", + "applicationNo": null, + "paidCan": null, + "tracking": null, + "shippingRequestedAt": "2026-10-12T03:00:00Z" + }, + "senderInfo": null, + "recipientAddress": null, + "mailbox": null, + "trackingRequired": false, + "recipientAddressRequired": true, + "recipientAddressDeadlineAt": "2026-10-19T03:00:00Z", + "delivery": { + "canceledAt": null, + "undeliverableAt": null, + "undeliverableReason": null + }, + "statusTimeline": [ + { + "status": "RECEIVED", + "statusName": "접수 완료", + "occurredAt": "2026-10-11T03:00:00Z" + }, + { + "status": "TRACKING_REGISTERED", + "statusName": "발송 확인", + "occurredAt": "2026-10-12T03:00:00Z" + }, + { + "status": "ARRIVED_AT_MAILBOX", + "statusName": "사서함 도착", + "occurredAt": null + }, + { + "status": "INSPECTION_COMPLETED", + "statusName": "검수완료", + "occurredAt": null + }, + { + "status": "DELIVERED", + "statusName": "전달완료", + "occurredAt": null + } + ] + }, + "message": "" +} +``` + +Response envelope 예시 - 배송지 입력 완료/전달 완료: +```json +{ + "success": true, + "data": { + "applicationNo": "A-1002609300001", + "direction": "RECEIVED", + "status": "DELIVERED", + "statusName": "전달완료", + "giftInfo": { + "recipientCreatorNickname": null, + "senderNickname": "팬닉네임이들어가는부분", + "sizeName": "소형", + "categoryName": "신규 전자굿즈", + "applicationNo": null, + "paidCan": null, + "tracking": null, + "shippingRequestedAt": "2026-10-12T03:00:00Z" + }, + "senderInfo": null, + "recipientAddress": { + "name": "크리에이터이름", + "phoneNumber": "01012345678", + "address": "(04030) 서울특별시 마포구 양화로 000, 3층" + }, + "mailbox": null, + "trackingRequired": false, + "recipientAddressRequired": false, + "recipientAddressDeadlineAt": "2026-10-19T03:00:00Z", + "delivery": { + "canceledAt": null, + "undeliverableAt": null, + "undeliverableReason": null + }, + "statusTimeline": [ + { + "status": "RECEIVED", + "statusName": "접수 완료", + "occurredAt": "2026-10-11T03:00:00Z" + }, + { + "status": "TRACKING_REGISTERED", + "statusName": "발송 확인", + "occurredAt": "2026-10-12T03:00:00Z" + }, + { + "status": "ARRIVED_AT_MAILBOX", + "statusName": "사서함 도착", + "occurredAt": "2026-10-14T03:00:00Z" + }, + { + "status": "INSPECTION_COMPLETED", + "statusName": "검수완료", + "occurredAt": "2026-10-16T03:00:00Z" + }, + { + "status": "DELIVERED", + "statusName": "전달완료", + "occurredAt": "2026-10-22T03:00:00Z" + } + ] + }, + "message": "" +} +``` + +Response envelope 예시 - 전달 불가: +```json +{ + "success": true, + "data": { + "applicationNo": "A-1002609300001", + "direction": "RECEIVED", + "status": "UNDELIVERABLE", + "statusName": "전달불가", + "giftInfo": { + "recipientCreatorNickname": null, + "senderNickname": "팬닉네임이들어가는부분", + "sizeName": "소형", + "categoryName": "신규 전자굿즈", + "applicationNo": null, + "paidCan": null, + "tracking": null, + "shippingRequestedAt": "2026-10-12T03:00:00Z" + }, + "senderInfo": null, + "recipientAddress": null, + "mailbox": null, + "trackingRequired": false, + "recipientAddressRequired": false, + "recipientAddressDeadlineAt": "2026-10-19T03:00:00Z", + "delivery": { + "canceledAt": null, + "undeliverableAt": "2026-10-16T03:00:00Z", + "undeliverableReason": "음식물 또는 보관이 어려운 품목" + }, + "statusTimeline": [ + { + "status": "RECEIVED", + "statusName": "접수 완료", + "occurredAt": "2026-10-11T03:00:00Z" + }, + { + "status": "TRACKING_REGISTERED", + "statusName": "발송 확인", + "occurredAt": "2026-10-12T03:00:00Z" + }, + { + "status": "ARRIVED_AT_MAILBOX", + "statusName": "사서함 도착", + "occurredAt": "2026-10-14T03:00:00Z" + }, + { + "status": "INSPECTION_COMPLETED", + "statusName": "검수완료", + "occurredAt": null + }, + { + "status": "DELIVERED", + "statusName": "전달완료", + "occurredAt": null + } + ] + }, + "message": "" +} +``` + +선물 상세 response `data` 필드: + +| 필드 | 설명 | +|---|---| +| `applicationNo` | 선물 신청번호. 화면 진입 key로 사용한다. | +| `direction` | 이 프롬프트에서는 `RECEIVED`만 렌더링한다. | +| `status` | `TRACKING_REGISTERED`, `ARRIVED_AT_MAILBOX`, `INSPECTION_COMPLETED`, `DELIVERED`, `UNDELIVERABLE` 등을 상태별 UI 분기에 사용한다. | +| `giftInfo.senderNickname` | 받은 선물 관점의 발송인 팬 닉네임. | +| `giftInfo.sizeName` | 선물 사이즈명. | +| `giftInfo.categoryName` | 카테고리명. | +| `giftInfo.shippingRequestedAt` | 배송 신청일. UTC ISO 문자열. | +| `recipientAddress` | 크리에이터 본인이 입력한 배송지. null이면 받는 주소 섹션을 숨긴다. | +| `recipientAddressRequired` | 배송지 입력 UI 표시 여부. | +| `recipientAddressDeadlineAt` | 배송지 입력 마감일. 필요하면 안내 문구에 사용한다. | +| `delivery.undeliverableReason` | 전달 불가 사유. | +| `statusTimeline` | 배송 완료일 등 상태별 날짜를 찾는 데 사용한다. | + +배송지 입력: +- Method: `POST` +- URL: `/api/v2/gifts/{applicationNo}/recipient-address` +- 인증: 로그인 필요 +- Request: +```json +{ + "recipientName": "크리에이터이름", + "recipientPhoneNumber": "01012345678", + "recipientZipCode": "04030", + "recipientAddress": "서울특별시 마포구 양화로 000", + "recipientAddressDetail": "3층", + "recipientTermsAgreed": true, + "recipientPrivacyAgreed": true +} +``` +- Response envelope 예시: +```json +{ + "success": true, + "data": { + "applicationNo": "A-1002609300001", + "status": "TRACKING_REGISTERED", + "statusName": "발송 확인", + "recipientAddressRegisteredAt": "2026-10-13T03:00:00Z" + }, + "message": "" +} +``` + +배송지 입력 response `data` 필드: + +| 필드 | 설명 | +|---|---| +| `applicationNo` | 선물 신청번호 | +| `status` | 등록 후 상태. 일반적으로 기존 진행 상태 유지 | +| `statusName` | 서버 상태 표시명 | +| `recipientAddressRegisteredAt` | 배송지 입력 완료 시각. UTC ISO 문자열 | + +테스트/검증: +- 리스트 item 탭 시 `applicationNo`로 받은 선물 상세 페이지가 열리는지 확인한다. +- 상세 진입 시 `GET /api/v2/gifts/{applicationNo}`가 호출되는지 확인한다. +- `direction=RECEIVED && recipientAddressRequired=true`이면 배송지 입력 UI가 표시되는지 확인한다. +- 배송지 입력 필수값 또는 약관 동의가 누락되면 `POST /recipient-address`를 호출하지 않는지 확인한다. +- 배송지 입력 submit 시 request body가 API 명세와 일치하는지 확인한다. +- 배송지 입력 성공 후 상세가 재조회되고 배송지 입력 완료 UI가 표시되는지 확인한다. +- 배송지 입력 완료/전달 완료 상태에서 `recipientAddress`가 있으면 받는 주소 섹션이 표시되는지 확인한다. +- `recipientAddress=null`이면 받는 주소 섹션 자체가 표시되지 않는지 확인한다. +- `status=DELIVERED`이면 전달 완료 UI와 배송 완료일이 표시되는지 확인한다. +- `status=UNDELIVERABLE`이면 전달 불가 UI, 사유, 폐기/반송 불가 안내가 표시되는지 확인한다. +- 전달 불가 화면의 `문의하기`는 기존 카카오 채널 문의로 연결되는지 확인한다. +- 전달 불가 화면의 `선물 정책 확인`은 버튼 action만 있고 실제 외부 URL을 열지 않는지 확인한다. +- 모든 날짜는 UTC ISO 문자열을 앱 표시 형식으로 변환해 표시하는지 확인한다. +```