21 KiB
21 KiB
보낸 선물 상세 및 운송장 등록 페이지 생성 프롬프트
이 문서는 Android/iOS 앱의 선물함 리스트에서 보낸 선물 상세 페이지와 운송장 등록 페이지를 생성할 때 사용하는 프롬프트다.
참고 Figma:
- 선물 보내기 신청 상세 운송장 등록 전 UI:
2481:19011 - 선물 보내기 신청 상세 운송장 등록 후 UI:
2481:19152 - 선물 보내기 신청 상세 전달 완료 UI:
2481:19320 - 전달 불가 UI:
2481:19456 - 취소 버튼 다이얼로그 UI:
2481:19500 - 취소 완료 페이지 UI:
2481:19521 - 운송장 등록 UI:
2481:19066 - 운송장 정보를 채우고 난 후 UI:
2481:19109
전제:
- 선물함 리스트 item 탭 시
applicationNo를 전달받아 상세 페이지로 이동한다. - 새 디자인 시스템을 만들지 말고 Android/iOS 각각의 기존 디자인 시스템, 컴포넌트, API client, 상태 관리, toast/dialog, navigation 패턴을 재사용한다.
- 모든 API 응답은 공통 envelope를 사용하며 실제 payload는
response.data다. - Figma의 진행 상태는 4단계처럼 보이지만 실제 구현은 서버의
statusTimeline5개 상태를 모두 사용한다. - 운송장 등록의 택배사 선택지는 서버 API가 없으므로 앱 로컬 상수로 관리한다.
- 취소 확인 팝업은 앱의
v2 dialog컴포넌트를 기본으로 사용한다.
모바일 앱 구현 프롬프트
Android/iOS 앱의 선물 상세 페이지와 운송장 등록 페이지를 Figma 기준으로 생성하고 API 연동을 구현해줘.
범위:
- 선물함 리스트에서 `applicationNo`를 받아 선물 상세 페이지로 이동한다.
- 상세 페이지는 `GET /api/v2/gifts/{applicationNo}` 응답으로 렌더링한다.
- `trackingRequired=true`인 보낸 선물 상세에서는 운송장 등록 CTA를 표시하고 운송장 등록 페이지로 이동한다.
- 운송장 등록 페이지는 같은 상세 API를 조회해 신청 요약과 보낼 주소를 표시한 뒤 `POST /api/v2/gifts/{applicationNo}/tracking`으로 운송장 정보를 등록한다.
중요 전제:
- Figma의 visual structure와 문구를 우선 따르되, 상태 개수와 데이터 노출은 API 계약을 우선한다.
- 상세 진행 단계는 Figma처럼 4단계로 고정하지 말고 API `statusTimeline`의 5개 정상 진행 상태를 모두 렌더링한다.
- 택배사 목록은 API로 조회하지 않는다. 앱 로컬 상수로 관리하고 선택한 한글 표시명을 `courierCompanyName`으로 전송한다.
- 운송장 등록 완료 후 수정 기능은 만들지 않는다.
상세 페이지 진입:
- 선물함 리스트 item에서 받은 `applicationNo`로 진입한다.
- 화면 진입 시 `GET /api/v2/gifts/{applicationNo}`를 호출한다.
- 조회 결과 `status=CANCELED`이면 일반 신청 상세 화면을 렌더링하지 말고 취소 완료 페이지 UI를 보여준다.
- 로딩 중에는 기존 앱 상세 화면 로딩/스켈레톤 패턴을 사용한다.
- 실패 시 기존 앱 toast/dialog와 재시도 패턴을 사용한다.
상세 페이지 공통 레이아웃:
1. 상단 고정 내비게이션
- 타이틀: `신청 상세`
- 뒤로가기 버튼은 기존 앱 패턴을 사용한다.
2. 스크롤 콘텐츠
- 배송 상태 hero
- 진행 상태 progress
- 상태별 action button 영역
- 선물 정보
- 필요한 경우 보내는 사람, 받는 사서함, 사유 섹션
3. 하단 safe area
- 기존 앱 패턴을 따른다.
상태별 hero 문구:
| status | chip | title | body |
|---|---|---|---|
| `RECEIVED` | 없음 또는 `접수 완료` | `선물 신청 완료!` | `선물이 정상적으로 접수되었어요!` |
| `TRACKING_REGISTERED` | `발송 확인` | `사서함으로 이동 중이에요` | 없음 |
| `ARRIVED_AT_MAILBOX` | `사서함 도착` | `선물이 사서함에 도착했어요` | 없음 |
| `INSPECTION_COMPLETED` | `검수 완료` | `선물 검수를 완료했어요` | 없음 |
| `DELIVERED` | `전달 완료` | `크리에이터에게 선물을 전달했어요` | 없음 |
| `UNDELIVERABLE` | `전달 불가` | `전달할 수 없는 품목입니다` | `보내주신 선물은 SODALIVE 선물 정책에 따라 크리에이터에게 전달할 수 없는 품목으로 확인되었습니다.` |
| `CANCELED` | `신청 취소` | `선물 신청이 취소되었어요` | `사용한 캔은 환불 처리됩니다.` |
진행 상태 progress:
- `statusTimeline` 배열을 그대로 사용한다.
- 항상 아래 5개 단계를 이 순서로 표시한다.
1. `RECEIVED`: `신청 접수`
2. `TRACKING_REGISTERED`: `발송 확인`
3. `ARRIVED_AT_MAILBOX`: `사서함 도착`
4. `INSPECTION_COMPLETED`: `검수 완료`
5. `DELIVERED`: `전달 완료`
- `occurredAt`이 있으면 해당 단계는 완료 색상으로 표시하고 `MM.DD`를 표시한다.
- `occurredAt`이 null이면 비활성 색상으로 표시하고 날짜는 표시하지 않는다.
- `UNDELIVERABLE`, `CANCELED`는 정상 진행 단계가 아니므로 progress step으로 추가하지 않는다.
- 종료 상태에서도 `statusTimeline`에 있는 정상 진행 이력은 그대로 표시한다.
상세 페이지 섹션 표시 규칙:
- `선물 정보`는 항상 표시한다.
- `direction=SENT`이면 크리에이터명은 `giftInfo.recipientCreatorNickname`을 사용한다.
- `direction=RECEIVED`이면 보낸 팬명은 `giftInfo.senderNickname`을 사용한다.
- `senderInfo`가 있으면 `보내는 사람` 섹션을 표시한다.
- `mailbox`가 있으면 `받는 사서함` 또는 `보내실 주소` 섹션을 표시한다.
- `recipientAddress`가 있으면 `받는 사람` 또는 `배송지` 섹션을 표시한다.
- `delivery.undeliverableReason`이 있으면 `사유` 섹션을 표시한다.
선물 정보 표시 필드:
- 크리에이터 또는 보낸 팬 닉네임
- 선물 사이즈: `giftInfo.sizeName`
- 카테고리: `giftInfo.categoryName`
- 신청번호: `applicationNo` 또는 `giftInfo.applicationNo`
- 캔: `giftInfo.paidCan`이 null이 아닐 때만 표시
- 운송장 번호: `giftInfo.tracking`이 null이 아닐 때 표시
- 검수일: `statusTimeline`에서 `INSPECTION_COMPLETED.occurredAt`이 있으면 표시
- 전달 완료일: `statusTimeline`에서 `DELIVERED.occurredAt`이 있으면 표시
- 취소일: `delivery.canceledAt`이 있으면 표시
받는 사서함/보내실 주소 표시:
- `mailbox.name`을 사서함/받는 분으로 표시한다.
- `mailbox.address`를 주소로 표시한다.
- `mailbox.phoneNumber`를 연락처로 표시한다.
- `mailbox`는 관리자가 등록한 전역 단일 주소다. 상대방 주소가 아니다.
- `mailbox`는 `direction=SENT`이고 `status`가 `RECEIVED`, `TRACKING_REGISTERED`, `ARRIVED_AT_MAILBOX`, `INSPECTION_COMPLETED`일 때 내려온다.
- `DELIVERED`, `UNDELIVERABLE`, `CANCELED` 또는 `direction=RECEIVED`에서는 `mailbox=null`이다.
- `mailbox=null`이면 해당 섹션을 표시하지 않는다.
보내는 사람 표시:
- `senderInfo.name`
- `senderInfo.phoneNumber`
- `senderInfo.address`
- 이 정보는 보낸 팬 본인이 신청 시 입력한 정보다.
전달 불가 표시:
- `status=UNDELIVERABLE`이면 Figma `2481:19456` 패턴을 따른다.
- 사유 섹션의 제목은 `delivery.undeliverableReason`을 사용한다.
- `delivery.undeliverableReason`이 null이면 사유 섹션 제목은 `전달 불가`로 표시한다.
- 안내 문구는 `해당 선물은 정책에 따라 폐기되며 반송되지 않습니다.`를 사용한다.
상세 페이지 action:
- `trackingRequired=true`이면 하단 주요 CTA `운송장 작성하기`를 표시하고 운송장 등록 페이지로 이동한다.
- `direction=SENT && status=RECEIVED`이면 보조 action `신청 취소`를 표시할 수 있다.
- 신청 취소 버튼을 누르면 즉시 API를 호출하지 말고 `v2 dialog` 확인 팝업을 먼저 표시한다.
- `status=DELIVERED && direction=SENT`이면 `리뷰 남기기` 버튼을 표시하고 기존 리뷰 작성 화면/플로우로 이동한다.
- `문의하기`, `선물 정책 확인` 버튼은 기존 앱에 해당 이동 경로가 있으면 연결하고, 없으면 기존 정책에 맞춰 숨기거나 비활성 처리한다.
신청 취소 확인 다이얼로그:
- Figma `2481:19500`을 참고한다.
- 앱의 기본 `v2 dialog` 컴포넌트를 사용한다. 새 dialog 컴포넌트를 만들지 않는다.
- 제목: `신청 취소`
- 본문:
- `{크리에이터}에게 보내는 선물을 취소할까요?`
- `선물 보내기 규정에 따라 선물 취소 및 사용한 캔이 모두 환불됩니다.`
- 왼쪽 action: `나가기`
- dialog만 닫고 상세/운송장 등록 화면 상태를 유지한다.
- 오른쪽 destructive action: `취소하기`
- `POST /api/v2/gifts/{applicationNo}/cancel`을 호출한다.
- 호출 중에는 중복 탭을 막고 loading 상태를 표시한다.
- 실패 시 dialog를 닫지 말고 기존 앱 에러 toast/dialog 패턴으로 안내한다.
- 성공 시 취소 완료 페이지로 replace navigation 한다.
취소 완료 페이지:
- Figma `2481:19521`을 참고한다.
- 취소 API 성공 직후뿐 아니라 상세 페이지 접근 시 `GET /api/v2/gifts/{applicationNo}` 응답이 `status=CANCELED`인 경우에도 이 화면을 보여준다.
- 상단 타이틀: `취소 완료`
- hero chip: `취소 완료`
- hero title: `선물 신청이 취소되었어요`
- hero body: `{크리에이터}에게 보내는 선물 신청({applicationNo})이 취소되었습니다. 취소한 신청은 되돌릴 수 없으며, 다시 보내려면 새로 신청해 주세요.`
- 섹션 제목: `취소 상세`
- 취소 상세 카드 표시 필드:
- 크리에이터: `giftInfo.recipientCreatorNickname`
- 선물 사이즈: `giftInfo.sizeName`
- 카테고리: `giftInfo.categoryName`
- 신청번호: `applicationNo`
- 신청일: `statusTimeline`의 `RECEIVED.occurredAt`
- 취소일: 취소 API response의 `canceledAt` 또는 상세 API 조회 시 `delivery.canceledAt`
- 환불 캔: 취소 API response의 `priceCan` 또는 상세 API의 `giftInfo.paidCan`
- 하단 또는 카드 아래에 `문의하기` 버튼을 표시한다.
- 뒤로가기 동작은 취소 전 상세/운송장 등록 화면으로 돌아가지 않게 한다. 기존 앱 navigation 정책에 맞춰 선물함 리스트 또는 이전 안전 화면으로 이동한다.
운송장 등록 페이지 진입:
- 상세 페이지에서 `trackingRequired=true`일 때만 진입시킨다.
- 진입 시 `GET /api/v2/gifts/{applicationNo}`를 다시 조회한다.
- 조회 결과에서 `trackingRequired=false`이면 이미 등록 불가 상태이므로 기존 오류 처리 후 상세 페이지로 돌아간다.
운송장 등록 페이지 레이아웃:
1. 상단 고정 내비게이션
- 타이틀: `운송장 등록`
2. 신청 건 요약 카드
- `applicationNo`
- 크리에이터 닉네임: `giftInfo.recipientCreatorNickname`
- `giftInfo.sizeName · giftInfo.categoryName · 신청일`
- 신청일은 `statusTimeline`의 `RECEIVED.occurredAt`을 `YYYY.MM.DD`로 표시한다.
3. 보내실 주소
- `mailbox`를 사용한다.
- `mailbox=null`이면 운송장 등록을 막고 `받을 주소가 등록되어 있지 않습니다.` 오류를 표시한다.
4. 운송장 정보
- 택배사 select
- 운송장 번호 input
5. 등록 안내
- Figma의 안내 문구를 유지한다.
6. 하단 action bar
- 왼쪽: `신청 취소`
- 오른쪽: `등록 완료`
택배사 로컬 상수:
- 서버에서 택배사 옵션을 조회하지 않는다.
- 앱에 아래 로컬 옵션을 둔다. 이미 앱 공통 택배사 상수가 있으면 그것을 우선 사용한다.
```ts
const giftCourierCompanyNames = [
"CJ대한통운",
"우체국택배",
"GS25 편의점택배",
"CU 편의점택배",
"한진택배",
"롯데택배",
"로젠택배",
"경동택배",
"대신택배",
"일양로지스",
"천일택배",
"합동택배",
"건영택배",
"농협택배"
];
- 선택 UI는 기존 앱의 bottom sheet, picker, dialog 중 이미 쓰는 방식을 사용한다.
- API에는 선택된 한글 표시명을 그대로
courierCompanyName으로 보낸다.
운송장 등록 CTA 활성 조건:
- 택배사를 선택했다.
- 운송장 번호를 입력했다.
- 운송장 번호는 공백만 입력할 수 없다.
- submit 중에는 중복 탭을 막고 loading 상태를 표시한다.
- 비활성 상태는 Figma
2481:19066, 활성 상태는 Figma2481:19109를 따른다.
운송장 등록 성공 처리:
POST /api/v2/gifts/{applicationNo}/tracking성공 후 성공 toast를 표시한다.- 상세 페이지로 돌아가거나 replace navigation으로 상세 페이지를 다시 연다.
- 상세 페이지는
GET /api/v2/gifts/{applicationNo}를 다시 호출해TRACKING_REGISTERED상태를 표시한다.
API 명세:
선물 상세 조회:
- Method:
GET - URL:
/api/v2/gifts/{applicationNo} - 인증: 로그인 필요
- Response envelope 예시:
{
"success": true,
"data": {
"applicationNo": "A-1002609300001",
"direction": "SENT",
"status": "RECEIVED",
"statusName": "접수 완료",
"giftInfo": {
"recipientCreatorNickname": "달빛수집가",
"senderNickname": null,
"sizeName": "소형",
"categoryName": "잡화",
"applicationNo": "A-1002609300001",
"paidCan": 100,
"tracking": null,
"shippingRequestedAt": null
},
"senderInfo": {
"name": "김소다",
"phoneNumber": "01012345678",
"address": "(04030) 서울특별시 마포구 양화로 000, 3층"
},
"recipientAddress": null,
"mailbox": {
"name": "소다라이브 사서함",
"address": "(06174) 서울특별시 강남구 테헤란로108길 8, 유민빌딩 4층",
"phoneNumber": "02-2055-1477"
},
"trackingRequired": true,
"recipientAddressRequired": false,
"recipientAddressDeadlineAt": null,
"delivery": {
"canceledAt": null,
"undeliverableAt": null,
"undeliverableReason": null
},
"statusTimeline": [
{
"status": "RECEIVED",
"statusName": "접수 완료",
"occurredAt": "2026-09-18T03:00:00Z"
},
{
"status": "TRACKING_REGISTERED",
"statusName": "발송 확인",
"occurredAt": null
},
{
"status": "ARRIVED_AT_MAILBOX",
"statusName": "사서함 도착",
"occurredAt": null
},
{
"status": "INSPECTION_COMPLETED",
"statusName": "검수완료",
"occurredAt": null
},
{
"status": "DELIVERED",
"statusName": "전달완료",
"occurredAt": null
}
]
},
"message": ""
}
Response data 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
applicationNo |
string | 선물 신청번호 |
direction |
string | SENT 또는 RECEIVED |
status |
string | 선물 상태 코드 |
statusName |
string | 서버 상태 표시명 |
giftInfo |
object | 선물 기본 정보 |
giftInfo.recipientCreatorNickname |
string 또는 null | 보낸 선물 관점에서 받는 크리에이터 닉네임 |
giftInfo.senderNickname |
string 또는 null | 받은 선물 관점에서 보낸 팬 닉네임 |
giftInfo.sizeName |
string | 선물 사이즈명 |
giftInfo.categoryName |
string | 카테고리명 |
giftInfo.applicationNo |
string 또는 null | 보낸 선물 관점 신청번호 |
giftInfo.paidCan |
number 또는 null | 보낸 선물 관점 사용 캔 |
giftInfo.tracking |
string 또는 null | 운송장 표시 문자열. 예: 한진택배_123456789012 |
giftInfo.shippingRequestedAt |
string 또는 null | 받은 선물 관점 배송신청일. UTC ISO 문자열 |
senderInfo |
object 또는 null | 보낸 팬 본인이 신청 시 입력한 보내는 사람 정보 |
senderInfo.name |
string | 이름 |
senderInfo.phoneNumber |
string | 휴대폰 번호 |
senderInfo.address |
string | (우편번호) 주소, 상세주소 형식 주소 |
recipientAddress |
object 또는 null | 받는 크리에이터 본인이 입력한 배송지 |
mailbox |
object 또는 null | 관리자가 등록한 전역 선물 받을 주소. 보낸 선물의 DELIVERED 전 정상 진행 상태에서만 값이 있다 |
mailbox.name |
string | 사서함/받는 분 이름 |
mailbox.address |
string | (우편번호) 주소, 상세주소 형식 주소 |
mailbox.phoneNumber |
string | 연락처 |
trackingRequired |
boolean | 보낸 팬이 운송장 등록을 해야 하는 상태인지 여부 |
recipientAddressRequired |
boolean | 받는 크리에이터가 배송지를 입력해야 하는 상태인지 여부 |
recipientAddressDeadlineAt |
string 또는 null | 배송지 입력 마감일. UTC ISO 문자열 |
delivery.canceledAt |
string 또는 null | 취소일. UTC ISO 문자열 |
delivery.undeliverableAt |
string 또는 null | 전달 불가 처리일. UTC ISO 문자열 |
delivery.undeliverableReason |
string 또는 null | 전달 불가 사유 |
statusTimeline |
array | 정상 진행 5단계 타임라인 |
statusTimeline[].status |
string | 단계 상태 코드 |
statusTimeline[].statusName |
string | 단계 표시명 |
statusTimeline[].occurredAt |
string 또는 null | 해당 단계 도달 시각. UTC ISO 문자열 |
운송장 등록:
- Method:
POST - URL:
/api/v2/gifts/{applicationNo}/tracking - 인증: 로그인 필요
- Request:
{
"courierCompanyName": "한진택배",
"trackingNumber": "123456789012"
}
- Response envelope 예시:
{
"success": true,
"data": {
"applicationNo": "A-1002609300001",
"status": "TRACKING_REGISTERED",
"statusName": "발송 확인",
"courierCompanyName": "한진택배",
"trackingNumber": "123456789012",
"trackingRegisteredAt": "2026-09-19T03:00:00Z",
"recipientAddressDeadlineAt": "2026-09-26T03:00:00Z"
},
"message": ""
}
운송장 등록 response data 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
applicationNo |
string | 선물 신청번호 |
status |
string | 등록 후 상태. TRACKING_REGISTERED |
statusName |
string | 서버 상태 표시명 |
courierCompanyName |
string | 선택한 택배사 한글명 |
trackingNumber |
string | 운송장 번호 |
trackingRegisteredAt |
string | 운송장 등록일. UTC ISO 문자열 |
recipientAddressDeadlineAt |
string | 크리에이터 배송지 입력 마감일. UTC ISO 문자열 |
선물 보내기 취소:
- Method:
POST - URL:
/api/v2/gifts/{applicationNo}/cancel - Request: 없음
- 용도:
direction=SENT && status=RECEIVED에서만신청 취소action에 사용한다. - Response envelope 예시:
{
"success": true,
"data": {
"applicationNo": "A-1002609300001",
"status": "CANCELED",
"statusName": "신청 취소",
"priceCan": 100,
"canceledAt": "2026-09-18T04:00:00Z"
},
"message": ""
}
선물 보내기 취소 response data 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
applicationNo |
string | 선물 신청번호 |
status |
string | 취소 후 상태. CANCELED |
statusName |
string | 서버 상태 표시명 |
priceCan |
number | 환불되는 캔 수량 |
canceledAt |
string | 취소일. UTC ISO 문자열 |
테스트/검증:
- 리스트 item 탭 시
applicationNo로 상세 페이지가 열리는지 확인한다. - 상세 진입 시
GET /api/v2/gifts/{applicationNo}가 호출되는지 확인한다. - 상세 조회 결과
status=CANCELED이면 일반 상세가 아니라 취소 완료 페이지가 표시되는지 확인한다. statusTimeline5개 단계가 모두 표시되는지 확인한다.- Figma처럼 4단계로 하드코딩하지 않았는지 확인한다.
trackingRequired=true이면운송장 작성하기가 표시되는지 확인한다.- 신청 취소 버튼 탭 시
v2 dialog확인 팝업이 뜨고 즉시 API를 호출하지 않는지 확인한다. - 취소 확인 dialog에서
나가기를 누르면 dialog만 닫히는지 확인한다. - 취소 확인 dialog에서
취소하기를 누르면POST /api/v2/gifts/{applicationNo}/cancel을 호출하는지 확인한다. - 취소 성공 후 취소 완료 페이지가 표시되고 취소 전 상세/등록 화면으로 돌아가지 않는지 확인한다.
mailbox가 있을 때만 사서함 주소 섹션이 표시되는지 확인한다.direction=SENT의RECEIVED,TRACKING_REGISTERED,ARRIVED_AT_MAILBOX,INSPECTION_COMPLETED상태에서mailbox가 표시되는지 확인한다.DELIVERED,UNDELIVERABLE,CANCELED,direction=RECEIVED에서는mailbox가 표시되지 않는지 확인한다.UNDELIVERABLE이면 전달 불가 hero와 사유 섹션이 표시되는지 확인한다.- 운송장 등록 페이지에서 택배사/운송장 번호 누락 시 API를 호출하지 않는지 확인한다.
- 운송장 등록 시 선택한 택배사 한글명과 운송장 번호가 request body로 전송되는지 확인한다.
- 운송장 등록 성공 후 상세 페이지가 재조회되어
TRACKING_REGISTERED상태로 보이는지 확인한다. - 모든 날짜는 UTC ISO 문자열을 앱 표시 형식으로 변환해 표시하는지 확인한다.