fix(negodata): 검색 실패를 '변동 없음'으로 표시하던 문구 정정

LPS 가 outcome='error'(모든 소스 차단)로 내려주는 경우가 화면에서 '변동 없음'으로 보였다.
사용자는 '검색은 잘 됐는데 더 싼 게 없구나'로 읽지만, 실제로는 **가격을 확인조차 못 한** 것이다.
뜻이 정반대라 오해가 크다.

원인: success_yn=false 를 전부 notfound 로 묶었고, notfound 와 done 이 같은 문구('변동 없음')를
쓴다. fail_reason 은 이미 API·프론트 타입까지 내려오는데 쓰이지 않고 있었다.

→ fail_reason='error' 면 failed 로 분류한다. 화면은 '탐색 실패'가 되고, 실패 사유가 함께 뜨며,
   재검색 대상(failedIds)에 포함돼 사용자가 다시 시도할 수 있다 — 확인 못 한 건 재시도가 맞다.
   'not_found'(진짜 못 찾음)는 기존대로 '변동 없음'을 유지한다.

LPS 변경 없음(이미 내려오는 값을 쓴 것). ItemState 주석도 실제 의미에 맞게 정정.
tsc: 이 파일 오류 없음(기존 xlsx 미설치 오류는 무관).

> 폴더 관례상 negodata 는 인수인계 대상이나, 이번 건은 사용자 요청으로 예외 적용.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
민헌 2026-08-07 09:38:11 +09:00
parent 152aed9908
commit 14bcf1481b

View File

@ -53,8 +53,8 @@ const toMallPrices = (byMall: LowestPriceEntryByMall): MallPrices => {
type ItemState = type ItemState =
| { kind: 'pending' } // 접수됨 — 결과 대기 | { kind: 'pending' } // 접수됨 — 결과 대기
| { kind: 'done'; price: number; malls: MallPrices } | { kind: 'done'; price: number; malls: MallPrices }
| { kind: 'notfound'; malls: MallPrices } // 동일 상품 판정 실패(기존 값 유지) | { kind: 'notfound'; malls: MallPrices } // 검색은 됐으나 같은 상품이 없었음(기존 값 유지)
| { kind: 'failed'; reason?: string } // 요청 자체가 접수되지 않음 — 재시도 대상 | { kind: 'failed'; reason?: string } // 접수 실패 또는 검색 실패(사이트 차단) — 재시도 대상
| { kind: 'timeout' } // 폴링 상한 초과 — 서버는 계속 검색 중 | { kind: 'timeout' } // 폴링 상한 초과 — 서버는 계속 검색 중
| { kind: 'stopped' }; // 사용자가 지켜보기를 중단 — 서버는 계속 검색 중 | { kind: 'stopped' }; // 사용자가 지켜보기를 중단 — 서버는 계속 검색 중
@ -256,6 +256,13 @@ export function PriceUpdateModal({ open, products, selectedIds, onDone, onClose
// by_mall 이 비어 오는 옛 이력 대비 — 최소한 대표 최저가는 보이도록 폴백을 채운다. // by_mall 이 비어 오는 옛 이력 대비 — 최소한 대표 최저가는 보이도록 폴백을 채운다.
if (Object.keys(malls).length === 0) malls.etc = fresh.lp_price; if (Object.keys(malls).length === 0) malls.etc = fresh.lp_price;
setItem(id, { kind: 'done', price: fresh.lp_price, malls }); setItem(id, { kind: 'done', price: fresh.lp_price, malls });
} else if (fresh.fail_reason === 'error') {
// 검색 자체가 실패한 경우(모든 소스 차단). '못 찾음'과 뜻이 완전히 다르다 —
// 상품이 없다는 게 아니라 **확인을 못 했다**는 뜻이라, 재시도 대상으로 분류한다.
// (LPS 가 outcome='error' 로 내려준다. '변동 없음'으로 뭉뚱그리면 사용자는
// '검색은 됐는데 더 싼 게 없구나'로 오해한다)
// 문구는 '탐색 실패 사유: {reason}' 형태로 붙는다 — 사유만 간결하게 담는다.
setItem(id, { kind: 'failed', reason: '사이트 차단으로 가격을 확인하지 못했습니다 (잠시 후 다시 시도해 주세요)' });
} else { } else {
setItem(id, { kind: 'notfound', malls }); setItem(id, { kind: 'notfound', malls });
} }