Files
sodalive-backend-spring-boot/docs/20260929_크리에이터_선물하기/gift-list-page-prompt.md
T

14 KiB

선물함 리스트 페이지 생성 프롬프트

이 문서는 Android/iOS 앱의 선물함 리스트 페이지를 생성할 때 사용하는 프롬프트다.

참고 Figma:

  • 팬 모드, 신청한 내역이 있을 때: 2481:19382
  • 팬 모드, 신청한 내역이 없을 때: 2520:35587
  • 크리에이터 모드, 받은 선물 내역이 없을 때: 2531:36283
  • 크리에이터 모드, 받은 선물 내역이 있을 때: 2531:36194
  • 크리에이터 모드, 받은 선물 상태별 카드 표시: 2531:36237

전제:

  • Android/iOS 각각의 기존 디자인 시스템, 컴포넌트, API client, 상태 관리, toast/dialog, navigation 패턴을 재사용한다.
  • Figma의 visual structure를 기준으로 구현하되, 아래 사용자 요구사항을 Figma보다 우선한다.
  • 상단 뒤로가기 내비게이션 영역은 고정한다.
  • 상단 뒤로가기 내비게이션 영역을 제외한 전체 콘텐츠 영역은 스크롤되어야 한다.
  • 신청 내역, 선물 내역 섹션 타이틀은 표시하지 않는다.
  • 리스트는 신청일/취소일 최신순으로 보여야 한다.
  • request/response 설명은 모바일 공통 JSON 기준이다.

모바일 앱 구현 프롬프트

Android/iOS 앱의 선물함 리스트 페이지를 Figma 기준으로 생성하고 API 연동을 구현해줘.

Figma는 두 관점의 상태를 보여준다.
- 보낸 선물 관점: 사용자가 본인이 신청한 선물 내역을 확인하는 상태다. Figma `2481:19382`, `2520:35587`를 기준으로 한다.
- 받은 선물 관점: 사용자가 본인이 받을 선물 내역을 확인하는 상태다. Figma `2531:36283`, `2531:36194`, `2531:36237`를 기준으로 한다.
- 실제 선물함 API는 두 관점을 나누어 호출하지 않고 `type=ALL`로 한 번 호출한다.
- 응답 item의 `direction` 값이 `SENT`이면 보낸 선물 카드로, `RECEIVED`이면 받은 선물 카드로 렌더링한다.
- 각 카드에는 상대방 프로필 이미지와 닉네임을 표시한다.
  - `direction=SENT`: 상대방은 선물을 받는 크리에이터다.
  - `direction=RECEIVED`: 상대방은 선물을 보낸 팬이다.

중요 요구사항:
- 상단 뒤로가기 내비게이션은 고정한다.
- 상단 내비게이션 아래의 전체 콘텐츠만 스크롤되게 한다.
- Figma에 보이는 `신청 내역`, `선물 내역` 섹션 타이틀은 실제 구현에서 표시하지 않는다.
- 선물함 리스트는 신청일/취소일 최신순으로 정렬한다.
- 현재 API 응답만으로 취소일 기준 정렬/표시는 완전하지 않으므로, API가 취소일을 내려주지 않으면 서버 응답 순서를 우선 사용하고 취소 건 날짜 라벨은 `createdAt` 기준으로 표시한다. 취소일 표시가 필수이면 API 보강이 필요하다.

API 호출:
- 선물함 리스트는 항상 `GET /api/v2/gifts?type=ALL&page=0&size=20`로 조회한다.
- `SENT`, `RECEIVED`로 따로 호출하지 않는다.
- `items[].direction`으로 보낸 선물/받은 선물 UI를 결정한다.
- 페이지 진입 시 첫 페이지를 조회한다.
- `hasNext=true`이면 스크롤 하단에서 다음 page를 추가 조회한다.
- pull-to-refresh가 기존 앱에 있으면 page를 0으로 초기화하고 다시 조회한다.

공통 레이아웃:
1. 상단 고정 내비게이션
   - 타이틀: `선물함`
   - 뒤로가기 버튼은 기존 앱 패턴을 사용한다.
   - 이 영역은 스크롤되지 않는다.

2. 스크롤 콘텐츠
   - nav 아래부터 시작한다.
   - 안내 배너, 빈 상태, 리스트, 하단 여백 또는 하단 문의 버튼까지 스크롤 영역에 포함한다.
   - iOS safe area와 Android navigation bar 여백은 기존 앱 패턴을 따른다.

보낸 선물 UI:
- `direction=SENT`인 item에 적용한다.
- 사용자가 신청한 선물 내역을 보여준다.
- 보낸 선물만 있는 상태는 Figma `2481:19382`를 따른다.
- 상단 안내 배너를 표시한다.
  - 제목: `사서함을 통해 안전하게 전달됩니다`
  - 본문: `크리에이터 및 팬의 주소는 공개되지 않습니다. 선물은 소다라이브 사서함에 도착한 뒤 크리에이터에게 전달됩니다.`
- `신청 내역` 섹션 타이틀은 표시하지 않는다.
- 카드 구성:
  - 상단 왼쪽: `statusName`
  - 상단 오른쪽: 날짜 라벨
    - 기본: `{createdAt} 신청`
    - 상태가 `CANCELED`이고 취소일 필드가 있으면 `{canceledAt} 취소`
    - 현재 리스트 API에는 `canceledAt`이 없으므로 기존 API만 사용할 때는 `{createdAt} 취소` 또는 `{createdAt} 신청` 중 제품 정책에 맞춰 하나로 통일한다.
  - 프로필 row 내부: `counterpartProfileImageUrl`, `counterpartNickname`을 사용해 받는 크리에이터 프로필을 표시한다.
  - 프로필 row 아래 보조 문구: `sizeName · categoryName`
  - 프로필 이미지가 없으면 기존 앱의 기본 프로필 이미지를 표시한다.
  - 우측 chevron
  - 탭 시 선물 상세 페이지로 이동하며 `applicationNo`를 전달한다.
- 리스트가 비어 있고 보낸 선물 관점으로 진입한 화면이면 Figma `2520:35587`를 따른다.
  - 상단 안내 배너만 표시한다.
  - 별도 empty title/body를 추가하지 않는다.

받은 선물 UI:
- `direction=RECEIVED`인 item에 적용한다.
- 사용자가 받을 선물 내역을 보여준다.
- 리스트가 비어 있고 받은 선물 관점으로 진입한 화면이면 Figma `2531:36283`를 따른다.
  - 가운데 empty title: `전달 예정인 선물이 없어요`
  - empty body: `베타 기간에는 팬이 선물을 보내는 기능만 제공돼요. 더 다양해진 선물 기능으로 곧 다시 만나요!`
  - 버튼: `의견 남기기`
  - 의견 남기기 동작은 기존 앱의 문의/피드백 이동 패턴을 사용한다.
- 받은 선물이 있는 상태는 Figma `2531:36194`, `2531:36237`를 따른다.
- 상단 안내 배너를 표시한다.
  - 제목: `배송지 입력 기간 안내`
  - 본문: `알림을 받은 날부터 7일 이내에 배송지를 입력해 주세요. 기한 내 입력하지 않으면 선물이 반송됩니다.`
- `선물 내역` 섹션 타이틀은 표시하지 않는다.
- 배송지 입력이 필요한 선물이 있으면 파란 안내 배너를 리스트 상단에 표시한다.
  - 제목: `팬이 보낸 선물이 있어요!`
  - 본문: `선물이 늦지 않게 전달될 수 있도록 배송지를 입력해 주세요.`
  - 보조 문구: `*n일 이내로 입력하지 않으면 선물이 사라져요.`
  - 현재 리스트 API에는 배송지 입력 마감일이 없으므로 정확한 n일 계산이 필요하면 API 보강이 필요하다.
  - 배너 탭 시 배송지 입력이 필요한 첫 번째 선물 상세로 이동한다.
- 카드 구성:
  - 상단 왼쪽 프로필 row 내부: `counterpartProfileImageUrl`, `counterpartNickname`을 사용해 보낸 팬 프로필을 표시한다.
  - 상단 오른쪽: `{createdAt} 신청`
  - 본문 메인: 상태 표시 문구
  - 본문 서브: 상태 보조 문구가 필요한 경우만 표시
  - 우측 chevron
  - 탭 시 선물 상세 페이지로 이동하며 `applicationNo`를 전달한다.
- 리스트 하단에는 Figma처럼 `문의하기` 하단 버튼을 둘 수 있다. 기존 앱 정책상 고정 버튼이면 하단 safe area를 포함하고, 스크롤 콘텐츠 내부 버튼이면 콘텐츠 하단에 둔다.

상태 표시 매핑:

보낸 선물 카드:
| API status | 표시 문구 |
|---|---|
| `RECEIVED` | `운송장 등록 필요` |
| `TRACKING_REGISTERED` | `발송 확인` |
| `ARRIVED_AT_MAILBOX` | `사서함 도착` |
| `INSPECTION_COMPLETED` | `선물 검수 완료` |
| `DELIVERED` | `전달 완료` |
| `UNDELIVERABLE` | `전달 불가` |
| `CANCELED` | `신청 취소` |

받은 선물 카드:
| API status | 메인 문구 | 서브 문구 |
|---|---|---|
| `TRACKING_REGISTERED` | `배송지 입력 필요` | `전달 예정` |
| `ARRIVED_AT_MAILBOX` | `선물 검수` | `선물 확인 중` |
| `INSPECTION_COMPLETED` | `선물 검수 완료` | `배송 중` |
| `DELIVERED` | `전달 완료` | 없음 |
| `UNDELIVERABLE` | `전달 불가` | 없음 |

API 명세:

선물함 리스트 조회 API:
- Method: `GET`
- URL: `/api/v2/gifts`
- 인증: 로그인 필요
- Query:
  - `type`: `ALL`, `SENT`, `RECEIVED`
  - `page`: 0부터 시작
  - `size`: 페이지 크기. 기본 20
- 이 페이지에서는 `type=ALL`만 사용한다.
- Response envelope 예시:
```json
{
  "success": true,
  "data": {
    "totalCount": 1,
    "items": [],
    "page": 0,
    "size": 20,
    "hasNext": false
  },
  "message": ""
}

Response data 예시:

{
  "totalCount": 2,
  "items": [
    {
      "applicationNo": "A-1002609300001",
      "direction": "SENT",
      "status": "RECEIVED",
      "statusName": "접수 완료",
      "priceCan": 80,
      "categoryName": "아크릴/스탠드",
      "sizeName": "소형",
      "counterpartMemberId": 200,
      "counterpartNickname": "달빛수집가",
      "counterpartProfileImageUrl": "https://example.com/profile.png",
      "createdAt": "2026-09-18T03:00:00Z"
    }
  ],
  "page": 0,
  "size": 20,
  "hasNext": false
}

Response data 필드:

필드 타입 설명
totalCount number 전체 개수
items array 선물함 리스트
items[].applicationNo string 선물 신청번호. 상세 이동 ID
items[].direction string SENT 또는 RECEIVED
items[].status string 선물 상태 코드
items[].statusName string 서버 상태 표시명
items[].priceCan number 사용된 캔
items[].categoryName string 카테고리명
items[].sizeName string 사이즈명
items[].counterpartMemberId number 상대방 회원 ID. SENT에서는 받는 크리에이터, RECEIVED에서는 보낸 팬
items[].counterpartNickname string 상대방 닉네임
items[].counterpartProfileImageUrl string 또는 null 상대방 프로필 이미지 URL. 없으면 기본 프로필 이미지 표시
items[].createdAt string 또는 null 신청일. UTC ISO 문자열
page number 현재 페이지
size number 페이지 크기
hasNext boolean 다음 페이지 존재 여부

정렬:

  • 현재 서버 API는 createdAt desc, id desc로 정렬한다.
  • 요구사항은 신청일/취소일 최신순이다.
  • 취소일 최신순까지 정확히 맞추려면 리스트 API가 canceledAt 또는 displayedAt 같은 정렬 기준 시각을 내려주고 그 기준으로 정렬해야 한다.
  • API 보강 전에는 서버 응답 순서를 그대로 사용하고, 클라이언트에서 임의 재정렬하지 않는다.

상대방 프로필 표시 규칙:

  • counterpartNickname은 카드의 프로필 row 이름으로 표시한다.
  • counterpartProfileImageUrl이 있으면 해당 이미지를 원형 프로필 이미지로 표시한다.
  • counterpartProfileImageUrl이 null이거나 빈 값이면 기존 앱의 기본 프로필 이미지를 표시한다.
  • direction=SENT에서는 받는 크리에이터 정보로 해석한다.
  • direction=RECEIVED에서는 보낸 팬 정보로 해석한다.

현재 API만으로 부족한 Figma 표시값:

  • 취소일 canceledAt
  • 배송지 입력 마감일 또는 남은 일수

추가 API 보강이 가능하면 리스트 item에 아래 필드를 추가해달라고 요청한다.

{
  "canceledAt": "2026-09-18T03:00:00Z",
  "recipientAddressDeadlineAt": "2026-09-25T03:00:00Z",
  "sortAt": "2026-09-18T03:00:00Z"
}
  • canceledAt: 취소 상태의 취소일 표시용
  • recipientAddressDeadlineAt: 크리에이터 배송지 입력 안내 배너의 남은 일수 계산용
  • sortAt: 신청/취소 최신순 정렬 기준. 취소 건은 취소일, 그 외에는 신청일

로딩/에러/빈 상태:

  • 최초 로딩 중에는 기존 앱 리스트 스켈레톤 또는 loading 패턴을 사용한다.
  • 실패 시 기존 앱 toast/dialog와 재시도 버튼을 사용한다.
  • 빈 상태는 진입 관점에 따라 다르게 표시한다.
  • 보낸 선물 관점으로 진입한 화면이면 안내 배너만 남긴다.
  • 받은 선물 관점으로 진입한 화면이면 중앙 empty UI와 의견 남기기 버튼을 표시한다.

테스트/검증:

  • 선물함 진입 시 type=ALL로 API를 한 번 호출하는지 확인한다.
  • direction=SENT item은 보낸 선물 카드 UI로 표시되는지 확인한다.
  • direction=RECEIVED item은 받은 선물 카드 UI로 표시되는지 확인한다.
  • 각 item의 counterpartNickname, counterpartProfileImageUrl이 프로필 row에 표시되는지 확인한다.
  • counterpartProfileImageUrl=null이면 기본 프로필 이미지가 표시되는지 확인한다.
  • 상단 내비게이션은 고정되고 아래 콘텐츠만 스크롤되는지 확인한다.
  • 신청 내역, 선물 내역 텍스트가 실제 화면에 노출되지 않는지 확인한다.
  • 리스트 item 탭 시 applicationNo로 상세 화면 이동이 되는지 확인한다.
  • 빈 상태가 진입 관점에 맞는 Figma 기준으로 표시되는지 확인한다.
  • hasNext=true일 때 다음 page를 추가 조회하는지 확인한다.
  • API 실패 시 입력/스크롤 상태를 깨지 않고 오류와 재시도를 제공하는지 확인한다.

---

## API 요약

| 목적 | Method | URL | Query | Response data |
|---|---|---|---|---|
| 선물함 리스트 조회 | GET | `/api/v2/gifts` | `type=ALL`, `page`, `size` | 선물 리스트, 페이지 정보 |

## Figma 반영 메모

- 보낸 선물 리스트 있음: 안내 배너 + 카드 리스트. 단, 실제 구현에서는 `신청 내역` 타이틀을 제거한다.
- 보낸 선물 관점 empty: 안내 배너만 표시한다.
- 받은 선물 관점 empty: 중앙 empty UI와 `의견 남기기` 버튼을 표시한다.
- 받은 선물 리스트 있음: 안내 배너 + 배송지 입력 CTA 배너 + 카드 리스트. 단, 실제 구현에서는 `선물 내역` 타이틀을 제거한다.
- 받은 선물 상태별 카드는 `배송지 입력 완료/전달 예정`, `전달 완료`, `전달 불가`, `선물 검수/선물 확인 중`, `선물 검수 완료/배송 중` 패턴을 사용한다.