o2o-negosium-original/postgres-init/alters/2026-08-07-iilp-source-state.sql
민헌 95086cb3f6 feat(negodata): 4단계 — 사용자 화면에서 '없음'과 '확인 못함'을 구분
마지막 단계. 차단당해 못 본 몰이 화면에서 '–'(없음)로 보여 사용자가 "쿠팡엔 더 싼 게 없구나"로
오해하던 문제를 끝낸다. 안 본 걸 없다고 말하지 않는다.

사용자 화면은 **셋으로 접는다**(lps/docs/result-states.md 3-2절). 할 수 있는 행동이
'쓴다/다시 시도/넘어간다' 뿐이라, 원인이 달라도 다음 행동이 같으면 같은 표기다:
  matched                            → 가격
  no_match · empty                   → '–'        (확인했고 없었다)
  blocked · env_blocked · unavailable → '확인 못함' (못 봤다)
운영자 화면(lps-admin)은 같은 데이터로 7상태를 그대로 본다 — 목적이 진단이라 접지 않는다.

체인 전체를 이었다:
- postgres-init/alters/2026-08-07-iilp-source-state.sql — item_internet_lowest_prices 에
  sources/partial 추가(멱등, **운영 적용 필요**)
- models.py / lps_sync_crud 읽기 계약 / lps_sync_service 미러링 / LowestPriceEntry 프로토콜
- orval 재생성(ORVAL_INPUT 으로 저장 스펙에서 — 서버 없이). 생성 diff 는 새 필드만.
- PriceUpdateModal: 가격이 없는 몰이 '못 본 몰'이면 '–' 대신 '확인 못함'.

partial 은 LPS 가 판단해 내려준 사실을 그대로 쓴다 — 화면이 '어떤 상태가 확인된 것인가'를
다시 판정하면 상태 정의가 LPS 와 negodata 두 곳으로 흩어진다.

E2E 검증(실 DB 2시나리오): by_mall 은 둘 다 naver 뿐인데 쿠팡 칸이 '확인 못함'(차단) / '–'(0건)
으로 갈린다. tsc 오류 없음(기존 xlsx 미설치 오류는 무관). negodata 97 · lps 292 passed.

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:21:56 +09:00

35 lines
2.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 2026-08-07 · 최저가 수집 이력에 '몰별 확인 상태' 미러링 (기존 DB 보정)
-- 배경: '그 몰에 더 싼 게 없었다'와 '그 몰이 막혀서 못 봤다'가 화면에서 똑같이 '–' 로 보인다.
-- 사용자는 앞쪽으로 읽지만 실제로는 뒤쪽일 수 있다 — 안 본 걸 없다고 말하는 셈이다.
-- by_mall 은 **가격이 있는 몰만** 담으므로 그 구분이 담길 자리가 없었다.
-- LPS 가 lps_db.price_history.sources/partial 로 내려주기 시작했고(2026-08-07),
-- lps_sync_service 가 이 컬럼으로 미러링한다. 상태 정의는 lps/docs/result-states.md.
-- 멱등: ADD COLUMN IF NOT EXISTS — 여러 번 실행해도 안전.
-- 적용: psql -h <host> -p <port> -U <user> -d <db> -f postgres-init/alters/2026-08-07-iilp-source-state.sql
\connect negosium_db
-- 몰별 확인 상태 — {"naver": {"state": "matched", "count": 40},
-- "coupang": {"state": "blocked", "error": "..."}}
-- state: matched / no_match / empty / blocked / env_blocked / unavailable / skipped
ALTER TABLE partner.item_internet_lowest_prices
ADD COLUMN IF NOT EXISTS sources JSONB NULL;
-- 결과가 완전한가. true = 못 본 몰이 있어 이 값이 최종이 아니다.
-- sources 에서 유도할 수 있지만 컬럼으로 둔다 — 화면이 '어떤 상태가 확인된 것인가'라는 판단
-- 규칙까지 알아야 하면 상태 정의가 LPS 와 negodata 두 곳으로 흩어진다. 판단은 LPS 가 끝낸다.
ALTER TABLE partner.item_internet_lowest_prices
ADD COLUMN IF NOT EXISTS partial BOOLEAN NOT NULL DEFAULT FALSE;
COMMENT ON COLUMN partner.item_internet_lowest_prices.sources IS
'몰별 확인 상태 {몰: {state, count|error}} — lps_db.price_history.sources 미러링. state=SourceState';
COMMENT ON COLUMN partner.item_internet_lowest_prices.partial IS
'못 본 몰이 있어 결과가 최종이 아님 — 화면은 이 값으로 "일부 확인 못함"을 표시';
-- 검증
SELECT column_name, data_type, column_default
FROM information_schema.columns
WHERE table_schema = 'partner' AND table_name = 'item_internet_lowest_prices'
AND column_name IN ('by_mall', 'sources', 'partial')
ORDER BY column_name;