diff --git a/docs/20260929_크리에이터_선물하기/admin-page-prompts.md b/docs/20260929_크리에이터_선물하기/admin-page-prompts.md index 22312c5d..9953be7e 100644 --- a/docs/20260929_크리에이터_선물하기/admin-page-prompts.md +++ b/docs/20260929_크리에이터_선물하기/admin-page-prompts.md @@ -1,11 +1,12 @@ # 선물 관리자 페이지 구현 프롬프트 -이 문서는 관리자 페이지의 선물 관련 3개 화면을 프론트엔드 구현 에이전트에게 전달하기 위한 프롬프트 모음이다. +이 문서는 관리자 페이지의 선물 관련 4개 화면을 프론트엔드 구현 에이전트에게 전달하기 위한 프롬프트 모음이다. 공통 전제: -- 관리자 메뉴에는 parent 메뉴 `선물함 관리` 아래에 다음 3개 하위 메뉴가 있다. +- 관리자 메뉴에는 parent 메뉴 `선물함 관리` 아래에 다음 4개 하위 메뉴가 있다. - `선물함 리스트` → `/gift/list` + - `받을 주소` → `/gift/mailbox` - `선물 카테고리` → `/gift/category` - `선물 사이즈` → `/gift/size` - 모든 API 응답은 기존 공통 envelope를 사용한다. 화면에서는 `response.data`를 실제 payload로 사용한다. @@ -237,7 +238,84 @@ type AdminGiftOperationStatusResponse = { --- -## 2. 선물 카테고리 CRUD 페이지 프롬프트 +## 2. 받을 주소 설정 페이지 프롬프트 + +```text +관리자 선물 받을 주소 설정 페이지를 구현해줘. + +목표: +- 관리자 메뉴 `선물함 관리 > 받을 주소`에서 팬이 선물을 보낼 전역 단일 주소를 조회하고 저장한다. +- 이 주소는 팬의 선물 상세 API에서 운송장 등록 전 상태일 때 `mailbox`로 노출된다. +- 기존 관리자 페이지의 폼, 저장 버튼, 토스트, 에러 표시 패턴을 그대로 따른다. + +라우트: +- `/gift/mailbox` + +필수 화면 구성: +- 상단 제목: `받을 주소` +- 설명 문구: `팬이 선물을 발송할 때 확인하는 받을 주소입니다.` +- 입력 폼: + - 받을 사람 이름 `name` + - 연락처 `phoneNumber` + - 우편번호 `zipCode` + - 주소 `address` + - 상세주소 `addressDetail` +- 저장 버튼: `저장` + +초기 조회 API: +- Method: `GET` +- URL: `/api/v2/admin/gift-mailbox` +- response `data`: +```ts +type AdminGiftMailboxResponse = { + name: string; + address: string; + phoneNumber: string; +} | null; +``` +- `data`가 null이면 빈 폼을 표시한다. + +저장 API: +- Method: `PUT` +- URL: `/api/v2/admin/gift-mailbox` +- Request: +```ts +type AdminGiftMailboxRequest = { + name: string; + phoneNumber: string; + zipCode: string; + address: string; + addressDetail: string | null; +}; +``` +- Response `data`: +```ts +type AdminGiftMailboxResponse = { + name: string; + address: string; + phoneNumber: string; +}; +``` + +Validation: +- `name`, `phoneNumber`, `zipCode`, `address`는 필수다. +- 공백만 입력할 수 없다. +- 저장 실패 시 기존 관리자 페이지의 공통 에러 표시 방식을 따른다. + +저장 성공 UX: +- 성공 토스트를 표시한다. +- 저장 API response 기준으로 화면 값을 갱신한다. +- `address`는 서버가 조립한 `(우편번호) 주소, 상세주소` 형식으로 표시해도 되고, 입력 필드는 사용자가 입력한 값을 유지해도 된다. + +테스트/검증: +- 초기 조회 시 null이면 빈 폼을 표시하는지 확인한다. +- 저장 시 PUT body가 정확히 전달되는지 확인한다. +- 필수값 공백 validation을 확인한다. +``` + +--- + +## 3. 선물 카테고리 CRUD 페이지 프롬프트 ```text 관리자 선물 카테고리 CRUD 페이지를 구현해줘. @@ -345,7 +423,7 @@ UX 요구사항: --- -## 3. 선물 사이즈 가격 CRUD 페이지 프롬프트 +## 4. 선물 사이즈 가격 CRUD 페이지 프롬프트 ```text 관리자 선물 사이즈 가격 CRUD 페이지를 구현해줘. @@ -464,7 +542,8 @@ type GiftSize = "SMALL" | "MEDIUM" | "LARGE"; 1. API client 함수와 TypeScript 타입을 먼저 추가한다. 2. `/gift/list` 선물함 리스트와 상세/상태변경 모달을 구현한다. -3. `/gift/category` 카테고리 CRUD를 구현한다. -4. `/gift/size` 사이즈 가격 수정 화면을 구현한다. -5. 기존 관리자 메뉴의 `선물함 관리` 하위 route와 연결되는지 확인한다. -6. 각 페이지별 loading/empty/error/success 상태를 확인한다. +3. `/gift/mailbox` 받을 주소 설정 화면을 구현한다. +4. `/gift/category` 카테고리 CRUD를 구현한다. +5. `/gift/size` 사이즈 가격 수정 화면을 구현한다. +6. 기존 관리자 메뉴의 `선물함 관리` 하위 route와 연결되는지 확인한다. +7. 각 페이지별 loading/empty/error/success 상태를 확인한다. diff --git a/docs/20260929_크리에이터_선물하기/plan-task.md b/docs/20260929_크리에이터_선물하기/plan-task.md index 21c0a614..9b77549c 100644 --- a/docs/20260929_크리에이터_선물하기/plan-task.md +++ b/docs/20260929_크리에이터_선물하기/plan-task.md @@ -1309,6 +1309,48 @@ P7은 FCM 확장 후 전체 상태 전이를 연결하고 최종 회귀로 종 - Gate 확인: Phase 9 focused suite, `./gradlew ktlintCheck`, `git diff --check` 모두 성공 - 남은 항목: 없음 +## Phase 11: 선물 받을 주소 설정 + +**Phase 결과:** 관리자는 전역 단일 선물 받을 주소를 등록/수정하고, 팬은 운송장 등록 전 상세에서 해당 주소를 확인할 수 있다. + +**선행조건:** `P3-GATE`, `P10-GATE` 완료. + +### 구현 항목 + +#### Task 11.1 받을 주소 관리자 설정 API 구현 + +**Goal 실행 `P11-T1`:** 전역 단일 받을 주소 조회/저장 API를 구현한다. + +- **Files:** Create `GiftMailbox.kt`, `GiftMailboxRepository.kt`; Modify `GiftAdminService.kt`, `AdminGiftController.kt`, `AdminGiftRequest.kt`, `AdminGiftResponse.kt`, `gift-schema.sql`; Test `GiftAdminServiceTest.kt`, `AdminGiftControllerTest.kt`. +- [x] **RED:** 설정 미등록 시 `GET /api/v2/admin/gift-mailbox`가 `data=null`을 반환하는 실패 test를 작성한다. +- [x] **RED:** `PUT /api/v2/admin/gift-mailbox`가 전역 단일 주소를 생성하고, 재호출 시 같은 row를 갱신하는 실패 test를 작성한다. +- [x] **RED:** 이름/연락처/우편번호/주소 공백 입력을 거부하는 실패 test를 작성한다. +- [x] **RED 확인:** focused test 실패를 확인한다. +- [x] **GREEN:** 단일 row persistence, 관리자 service, request/response DTO, controller endpoint를 구현한다. +- [x] **GREEN 확인:** focused test 통과를 확인한다. + +#### Task 11.2 선물 상세 받을 주소 노출 구현 + +**Goal 실행 `P11-T2`:** 보낸 선물의 운송장 등록 전 상세에만 받을 주소를 노출한다. + +- **Files:** Modify `GiftQueryService.kt`; Test `GiftQueryServiceTest.kt`, `GiftControllerTest.kt`. +- [x] **RED:** `direction=SENT`이고 `status=RECEIVED`인 상세만 `mailbox`를 반환하는 실패 test를 작성한다. +- [x] **RED:** 받을 주소 미등록 또는 다른 상태/방향이면 `mailbox=null`인 실패 test를 작성한다. +- [x] **RED 확인:** focused test 실패를 확인한다. +- [x] **GREEN:** `GiftQueryService`에서 받을 주소 repository를 조회해 기존 `GiftMailboxResult`로 매핑한다. +- [x] **GREEN 확인:** focused test 통과를 확인한다. + +### Phase 11 Gate + +**Goal 실행 `P11-GATE`:** 관리자 설정과 사용자 상세 노출을 판정한다. + +```bash +./gradlew test --tests "*GiftAdminServiceTest" --tests "*AdminGiftControllerTest" --tests "*GiftQueryServiceTest" --tests "*GiftControllerTest" +./gradlew ktlintCheck +``` + +**Expected:** 받을 주소 미등록/등록/수정, 상세 `mailbox` 노출 조건, 기존 선물 상세 권한 정책이 통과한다. + ## Decision Log | 날짜 | ID | 상태 | 결정 | 근거 | 영향 Goal/문서 | diff --git a/docs/20260929_크리에이터_선물하기/prd.md b/docs/20260929_크리에이터_선물하기/prd.md index 1d148d04..500753bf 100644 --- a/docs/20260929_크리에이터_선물하기/prd.md +++ b/docs/20260929_크리에이터_선물하기/prd.md @@ -384,8 +384,8 @@ Response: { "applicationNo": "A-1002609300001", "direction": "SENT", - "status": "TRACKING_REGISTERED", - "statusName": "발송 확인", + "status": "RECEIVED", + "statusName": "접수 완료", "giftInfo": { "recipientCreatorNickname": "크리에이터닉네임", "senderNickname": null, @@ -393,7 +393,7 @@ Response: "categoryName": "인형", "applicationNo": "A-1002609300001", "paidCan": 80, - "tracking": "CJ대한통운_1234567890", + "tracking": null, "shippingRequestedAt": null }, "senderInfo": { @@ -403,11 +403,11 @@ Response: }, "recipientAddress": null, "mailbox": { - "name": "소다라이브 사서함", - "address": "구현 후 제공", - "phoneNumber": "구현 후 제공" + "name": "소다라이브 선물 담당자", + "address": "(06234) 서울시 강남구 ..., 3층 선물 접수처", + "phoneNumber": "01012345678" }, - "trackingRequired": false, + "trackingRequired": true, "recipientAddressRequired": false, "recipientAddressDeadlineAt": "2026-10-09T03:00:00Z", "delivery": { @@ -446,6 +446,8 @@ Response: } ``` +`mailbox`는 관리자가 등록한 전역 단일 받을 주소다. 보낸 사람 관점(`direction=SENT`)이고 상태가 운송장 등록 전인 `RECEIVED`일 때만 내려준다. 받을 주소가 등록되지 않았거나 다른 상태/방향이면 `mailbox`는 `null`이다. 주소는 상세 조회 시점의 최신 관리자 설정을 사용한다. + 받는 크리에이터 관점 응답 예시는 다음과 같다. ```json @@ -802,6 +804,40 @@ Response: 크리에이터가 배송지를 아직 입력하지 않은 경우에도 `recipientInfo.nickname`은 내려주고, `recipientInfo.name`, `recipientInfo.phoneNumber`, `recipientInfo.address`는 빈 문자열 `""`로 내려준다. +#### 8.13.3 관리자 선물 받을 주소 설정 API + +선물 받을 주소는 전역 단일 설정이다. 팬이 운송장을 등록하기 전에 보낸 선물 상세에서 이 주소를 확인하고 택배를 발송한다. + +`GET /api/v2/admin/gift-mailbox` + +Response: + +```json +{ + "name": "소다라이브 선물 담당자", + "address": "(06234) 서울시 강남구 ..., 3층 선물 접수처", + "phoneNumber": "01012345678" +} +``` + +설정이 없으면 공통 envelope의 `data`는 `null`이다. + +`PUT /api/v2/admin/gift-mailbox` + +Request: + +```json +{ + "name": "소다라이브 선물 담당자", + "phoneNumber": "01012345678", + "zipCode": "06234", + "address": "서울시 강남구 ...", + "addressDetail": "3층 선물 접수처" +} +``` + +Response는 저장된 받을 주소를 `name`, `address`, `phoneNumber`로 내려준다. `address`는 기존 주소 응답과 동일하게 `(우편번호) 주소, 상세주소` 형식이다. `name`, `phoneNumber`, `zipCode`, `address`는 필수이며 공백만 입력할 수 없다. `addressDetail`은 선택이다. + `availableActions`는 현재 상태별로 다음 값만 내려준다. | 현재 상태 | availableActions |