# W4 — 위젯 분쟁 스레드 (구매자 대칭)

작성 2026-08-19 · repo `cryptoments` (open-api, widget-ui)
선행 완료: U4(회원·파트너·관리자 분쟁 조회), W1-B(위젯 분쟁 제기·재제출·CS 안내)

---

## 배경 — 같은 분쟁의 양 당사자인데 한쪽만 볼 수 있다

```
출금 회원(p2p-ui)   스레드 O · 증빙 제출 O · 판정 결과 O          U4 로 갖춤
관리자(admin)        스레드 O · 판정 · 증빙 재요청                 U4 · W3
파트너               스레드 O(축약) · 헤더 요약                     U4 · W3-B
구매자(위젯)         제기 O · 증빙 제출 O · 상태 배지 O
                     스레드 ✘ · 증빙 재요청 인지 ✘                 ← 이번 작업
```

특히 **관리자가 구매자에게 증빙을 재요청해도 구매자가 알 방법이 없다.**
6시간 기한(`dispute_due_at`)을 걸어놓고 통지 수단이 없다.
화면 문구는 여전히 "관리자가 확인 중이며, 결과가 나오면 자동으로 안내됩니다" 라
구매자는 계속 기다리기만 한다.

---

# A. 백엔드 (open-api)

## A1. 위젯 분쟁 스레드 조회

```
GET /widgets/api/p2p/match/{matchCode}/disputes
```

- **세션은 `WidgetSessionData`** — `/widgets/api/*` 규칙. 위반하면 401
- 소유 검증은 기존 위젯 헬퍼(`findMatchByCode(matchCode, session.getPartnerId())`)를 **재사용**하라.
  새 검증을 만들지 마라
- 회원 페이지 대칭물이 있다 — `P2pWithdrawPageController` 의 disputes 조회와
  `P2pPageDisputeEventResponse`. **그 구조를 따르되 기준을 DEPOSITOR 로 바꾼다**
- 이벤트 0건이어도 200 + 빈 배열

## A2. 구매자 노출 기준 ⚠️

회원 페이지가 4필드로 축약한 것과 **같은 원칙, 반대 당사자**다.

```
노출     eventType · reason · createdAt
         evidenceUrl — source 가 DEPOSITOR 일 때만 (본인 제출분)
숨김     id · actor · source · amountKrw · payloadJson
         deliveredTo/At/Ok · disputeId · partnerId · torqEscrowId
         상대측(WITHDRAWER·ADMIN·SYSTEM·TORQ) evidenceUrl
```

**`payloadJson` 을 절대 내리지 마라** — 관리자 판정 메모가 거기 실린다.
회원 페이지도 같은 이유로 뺐다.

**`reason` 주의**: 시스템이 남긴 내부 문구가 섞인다
(예: "판매자 입금 확인 SLA 초과(10분) — 운영 판단 분쟁 전환").
회원 페이지(p2p-ui)는 **아는 코드만 표기하고 모르는 값은 생략**하도록 처리했다.
위젯도 같은 원칙을 적용하라 — 백엔드에서 거르든 프론트에서 거르든,
**어느 쪽인지 정하고 근거를 보고**하라.

## A3. 증빙 재요청 인지 필드

`P2pWidgetMatchDetailResponse` 에 **없다** — 관리자가 재요청해도 위젯이 알 수 없다.

```
추가   disputeRound · disputeWaitingOn · disputeDueAt
```

⚠️ **`disputeWaitingOn` 은 "누구 차례"를 뜻한다.** 값이 `DEPOSITOR` 일 때만
위젯이 "당신 차례"로 해석해야 한다. 상대 차례인 걸 그대로 노출해도 정보 유출은 아니지만,
**구매자에게 상대방 진행 상황을 실시간으로 알릴 필요는 없다** — 화면에서 걸러라.

---

# B. 프론트 (widget-ui)

## B1. 스레드 표시

- 분쟁 진행 중(`DISPUTED`)인 매칭 카드 또는 `p2p-dispute-reviewing` 화면에 붙인다.
  기존 화면 구조를 보고 자연스러운 곳을 골라라
- 시간순, 이벤트 유형 한글 라벨, 간결하게 (위젯은 좁다)
- 이벤트 0건이면 스레드 영역을 아예 그리지 마라
- 문구는 `locales/ko.js` 경유. **하드코딩 금지.** 다국어 키가 여럿이면 대응 언어도 채워라

## B2. 증빙 재요청 알림 ★

`disputeWaitingOn === 'DEPOSITOR'` 이면 **구매자 차례**다.

- 눈에 띄게 표시 — "추가 증빙이 필요합니다" + 기한(`disputeDueAt`)
- **증빙 제출 CTA 를 함께 띄워라.** W1-B 에서 재제출이 가능하게 만들어 뒀다
- 기한이 지났으면 그 사실도 알려라. **다만 프론트에서 시각 비교로 판정하지 말고**,
  서버가 초과 여부를 주는지 먼저 확인하라. 없으면 `dueAt` 만 표시하고 판정은 하지 마라
- 기존 "관리자가 확인 중이며, 결과가 나오면 자동으로 안내됩니다" 문구는
  **재요청이 온 상태에서는 거짓말이다.** 그 경우 문구를 바꿔라

## B3. 폴링과의 정합

위젯은 3초 폴링으로 매칭 상태를 갱신한다. 스레드도 같은 주기로 갱신되게 하되,
**별도 타이머를 만들지 마라** — 기존 폴링에 얹어라.

---

## 코딩 규칙

- open-api 세션: `/widgets/api/*` 는 **`WidgetSessionData`**
- Java 17 · Lombok(`@Data` 금지) · DTO 멤버 JavaDoc 필수
- **DDL 금지. DB 접속 금지**
- **분쟁 가드를 완화하지 마라** — 이 작업은 조회·표시뿐이다
- 위젯 Vue 버전·스타일은 기존 파일을 먼저 확인하고 따른다. 새 라이브러리 금지
- `Rest.js` 의 전역 4xx 처리를 바꾸지 마라 — 호출부에서 응답을 검사한다 (W1-B 원칙)

## 완료 기준

```
1  ./gradlew :open-api:compileJava 통과
2  widget-ui 빌드 통과 (스크립트는 package.json 확인 — build:prod 일 수 있다)
3  스레드 응답에 payloadJson·actor·상대측 evidenceUrl 이 없다
4  이벤트 0건이어도 200 + 빈 배열
5  disputeWaitingOn=DEPOSITOR 일 때 구매자에게 "당신 차례"가 보이고 제출 CTA 가 뜬다
6  상대 차례일 때는 그 사실을 노출하지 않는다
7  문구가 locales 경유다
8  별도 폴링 타이머를 만들지 않았다
```

## 보고 형식

- 작업별 수정 파일:라인 + 한 줄
- **A2 의 `reason` 필터링을 서버·프론트 어디서 했는지와 근거**
- B2 에서 기한 초과 판정을 어떻게 처리했는지 (서버 필드 유무)
- 스레드를 어느 화면에 붙였는지와 근거
- 지침이 실제 코드와 어긋난 지점 — **고치지 말고 먼저 보고**
- 빌드 결과

## 착수 전 필수 확인

```
open-api/.../controller/widget/P2pWidgetController.java        (세션·소유검증 헬퍼·기존 분쟁 EP)
open-api/.../dto/p2p/P2pWidgetMatchDetailResponse.java         (A3 추가 대상)
open-api/.../controller/p2p/P2pWithdrawPageController.java     (회원 스레드 — 대칭 참고)
open-api/.../dto/p2p/P2pPageDisputeEventResponse.java          (축약 기준 — 대칭 참고)
widget-ui/src/views/p2p.vue                                     (분쟁 화면·폴링·CTA 게이트)
widget-ui/src/locales/ko.js                                     (문구 키)
widget-ui/src/api/widgetApis.js
p2p-ui/src/views/DisputeView.vue                                (회원 스레드 UI — reason 필터 선례)
```

지침과 다르면 **멈추고 보고하라.**
