상위 Epic
왜
- 지금 원칙은 "토너먼트에 담기는 순간 자동 위시 편입"이고, 그 밑엔 **"토너먼트 = 항상 나 자신을 위한 결정"**이라는 전제가 깔려 있다.
- 실제로는 그 전제가 깨지는 케이스가 있다 — 선물용(타인을 위한 결정)과 소셜(타인이 담은 것). 이때 자동 편입하면 "내가 사고 싶은 것"이 아닌 아이템이 내 위시에 섞인다.
- 판단 기준을 **"누가 담았나"가 아니라 "누구를 위한 것인가"**로 재정의한다.
무엇을 — 최종 정책
아이템 출신(링크/이미지) × 토너먼트 종류(개인/소셜)로 편입 규칙을 나눈다.
|
개인(SOLO) 토너먼트 |
소셜(SOCIAL) 토너먼트 |
| 링크 아이템 |
START 시 자동편입 |
ROOT 에게 "위시에도 담기" 수동 버튼 |
| 이미지 아이템 |
제외 |
제외 |
- 개인 + 링크 = 자동편입 — 혼자 하는 결정이고, 링크는 상품 정체성이 있어 "내 위시"로 추적할 가치가 있음.
- 소셜 = 자동 OFF — 내가 담든 친구가 담든 "정말 나를 위한 건지"를 시스템이 판단 불가. 대신 주인이 "이건 진짜 갖고 싶다" 싶은 것만 수동으로 담게.
- 이미지 = 항상 제외 — 링크(상품 정체성)가 없어 위시로 옮겨도 가격 추적·새로고침이 안 되는 반쪽 위시가 된다.
설계
편입 시점 — START 정산 (담는 순간 아님)
생성 직후엔 모든 토너먼트가 SOLO 라(아무도 참여 안 함), 담는 순간엔 개인/소셜을 알 수 없다. 그래서 자동편입을 담을 때가 아니라 START 시점에 정산한다 — 그때 SOLO/SOCIAL 이 확정되므로 선물 후보가 위시에 잘못 섞이는 일이 없다. (부작용: START 안 한 개인 토너먼트의 링크는 편입 안 됨 — 커밋 안 한 것이라 수용.)
자동편입 — 서버, START · SOLO
startAsOwner 에서 토너먼트가 SOLO(참가자 = owner 1명)면, owner 의 링크 아이템(sourceUrl 있음) 전부를 owner 위시로 생성.
- SOCIAL 이거나 이미지 아이템이면 안 함.
- 외부 호출 없는 순수 영속화지만, 위시 생성은 별도 빈에 위임해 짧은 트랜잭션으로 묶는다(
WishPersistenceService 패턴).
수동 "위시에도 담기" — 신규 API, SOCIAL
- 새 엔드포인트:
POST /tournaments/{id}/items/{tournamentItemId}/wish (필요 시 다건).
- 권한: ROOT owner 만 (아니면 403). 대상은 모든 참가자의 링크 아이템 — 주인이 친구가 올린 것 중 갖고 싶은 것도 자기 위시로.
- ROOT 위시로 생성. 이미지 아이템(
sourceUrl 없음)은 거부.
엣지 케이스
- 중복(이미 위시에 있음): 멱등 — 조용히 skip, 에러 안 냄. 버튼은 "담김" 상태로.
- 이미지 아이템(
sourceUrl 없음): 자동·수동·API 모두 제외/거부.
- CLONE 토너먼트: 항상 SOCIAL → 자동편입 없음. 버튼은 ROOT 화면에서만.
- 위시 snapshot: 출전 고정본이 아니라 아이템의 현재 active snapshot으로 위시 생성 (이후 가격추적이 최신 기준으로 이어지게).
클라
- 소셜 + ROOT 뷰: 각 링크 아이템(
sourceUrl 있음)에 "위시에도 담기" 버튼, 이미 위시면 "담김" 표시.
- 개인: 버튼 없음 (START 시 자동).
테스트
- 단위: 링크/이미지 판정, SOLO/SOCIAL 판정, 멱등(중복 skip).
- 통합: START·SOLO 자동편입, START·SOCIAL 미편입, 수동 API 계약(성공 / 비-ROOT 403 / 이미지 거부 / 멱등).
코드 현황 (조사 완료)
이미지가 전제한 "토너먼트 담기 → 위시 자동 편입"은 서버·웹·앱 어디에도 실제로 없다. 현재는 위시와 토너먼트 후보 바구니가 완전히 분리된 두 컬렉션이다.
- 서버:
addItemsFromWish는 반대 방향(위시 → 토너먼트)이고 담으려면 이미 위시일 것을 요구(itemNotInWishlist). 링크/이미지 담기(TournamentItemService)는 위시를 만들지 않음.
- 클라: 링크/이미지 담기 공용 다이얼로그(
GetItemDialog)가 type prop 으로 배타 분기 — type="wish" → 위시에만, type="tournament" → 후보 바구니에만.
활용 가능한 기존 재료:
- 링크/이미지 구분: 토너먼트 아이템 응답의
sourceUrl(이미지로 등록하면 undefined).
- 개인/소셜 구분:
TournamentPlayType(SOLO/SOCIAL) 파생값 — CLONE 이거나 참가자 2명 이상이면 SOCIAL. start() 가 startAsOwner/startAsMember 로 갈려 SOLO 판정 훅 지점이 명확.
실작업 범위
- 서버 자동편입 —
startAsOwner·SOLO 에서 owner 링크 아이템을 owner 위시로 (별도 빈 위임). 이미지 제외.
- 서버 수동 API —
POST .../items/{id}/wish, ROOT-only(403), 모든 참가자 링크 아이템 대상, 멱등, 이미지 거부. *Api/*ApiExamples/응답 문서화 포함.
- 클라 버튼 — 소셜 ROOT 뷰의 링크 아이템에 "위시에도 담기"(+"담김" 상태).
- 테스트 — 위 단위·통합.
상위 Epic
왜
무엇을 — 최종 정책
아이템 출신(링크/이미지) × 토너먼트 종류(개인/소셜)로 편입 규칙을 나눈다.
설계
편입 시점 — START 정산 (담는 순간 아님)
생성 직후엔 모든 토너먼트가 SOLO 라(아무도 참여 안 함), 담는 순간엔 개인/소셜을 알 수 없다. 그래서 자동편입을 담을 때가 아니라 START 시점에 정산한다 — 그때 SOLO/SOCIAL 이 확정되므로 선물 후보가 위시에 잘못 섞이는 일이 없다. (부작용: START 안 한 개인 토너먼트의 링크는 편입 안 됨 — 커밋 안 한 것이라 수용.)
자동편입 — 서버, START · SOLO
startAsOwner에서 토너먼트가 SOLO(참가자 = owner 1명)면, owner 의 링크 아이템(sourceUrl있음) 전부를 owner 위시로 생성.WishPersistenceService패턴).수동 "위시에도 담기" — 신규 API, SOCIAL
POST /tournaments/{id}/items/{tournamentItemId}/wish(필요 시 다건).sourceUrl없음)은 거부.엣지 케이스
sourceUrl없음): 자동·수동·API 모두 제외/거부.클라
sourceUrl있음)에 "위시에도 담기" 버튼, 이미 위시면 "담김" 표시.테스트
코드 현황 (조사 완료)
이미지가 전제한 "토너먼트 담기 → 위시 자동 편입"은 서버·웹·앱 어디에도 실제로 없다. 현재는 위시와 토너먼트 후보 바구니가 완전히 분리된 두 컬렉션이다.
addItemsFromWish는 반대 방향(위시 → 토너먼트)이고 담으려면 이미 위시일 것을 요구(itemNotInWishlist). 링크/이미지 담기(TournamentItemService)는 위시를 만들지 않음.GetItemDialog)가typeprop 으로 배타 분기 —type="wish"→ 위시에만,type="tournament"→ 후보 바구니에만.활용 가능한 기존 재료:
sourceUrl(이미지로 등록하면undefined).TournamentPlayType(SOLO/SOCIAL) 파생값 — CLONE 이거나 참가자 2명 이상이면 SOCIAL.start()가startAsOwner/startAsMember로 갈려 SOLO 판정 훅 지점이 명확.실작업 범위
startAsOwner·SOLO 에서 owner 링크 아이템을 owner 위시로 (별도 빈 위임). 이미지 제외.POST .../items/{id}/wish, ROOT-only(403), 모든 참가자 링크 아이템 대상, 멱등, 이미지 거부.*Api/*ApiExamples/응답 문서화 포함.