o2o-negosium-original/postgres-init/04-alter_20260702.sql
민헌 a2c299aa14 refactor(anchoring): 도메인 이름 전면 개편 — adjustments·anchoring_value/price·price_range·sample 용어 통일
용어 체계: 값=anchoring_value(정수‰)·가격=anchoring_price·조정=adjustment·구간=price_range·표본=sample

- DB: rate_adjustments→anchoring.adjustments (id→adjustment_id, price_bracket_index→price_range_index,
  nego_count→sample_count, anchor_rate_before/after→anchoring_value_before/after,
  consumed_session_ids→used_session_ids)
- sessions: target_anchoring_price→anchoring_price, anchor_rate_permille→anchoring_value,
  last_offered_price→last_offer_price, anchoring_adjustment_id→used_by_adjustment_id
- 뷰: rate_history/current_rates→value_history/current_values, delta_permille→value_change
- 코드: calc_price_range_index·calc_anchoring_price·evaluate_samples·get_current_value·
  get_latest_adjusted_value·get_current_anchoring_value·fetch_current_values·get_base_anchoring_value·
  Adjustment(ORM)·update_last_offer_price, 상수 ANCHORING_VALUE_MIN/MAX·ADJUSTMENT_STEP·
  PRICE_RANGE_COUNT/INDEX_MAX, 배치 로그 키 bracket=→price_range=
- API: negodata protocol 필드 target_anchoring_price→anchoring_price (front 생성 모델·컴포넌트 동반)
- 기존 DB 마이그레이션 신설: schedules/anchoring/migrations/20260706_rename_anchoring.sql
  (멱등 DO 블록 — 테이블·컬럼·뷰·인덱스·PK 제약. 코드 배포와 동시 적용 필요)
- postgres-init 01·04, 문서 6종 동기화
- 실배포 전 수정 포함: main.py argparse 화(--dry-run 단독·오타 플래그 기동 전 차단),
  박제 정합식 calc_anchoring_price 재사용, clamped 지표가 실제 포화만 집계(경계값 유지 제외)

주의: sessions.anchoring_value(정수‰)와 quotation_settings.anchoring_value(구 float 비율)는
같은 이름·다른 단위 — 구 컬럼은 미변경.

검증: 모듈 20·negodata 50·backend 57 테스트 통과, front tsc·vite build 통과,
로컬 DB 마이그레이션 적용 후 배치 dry-run·상주 기동·양 서버 부팅 확인.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:17:01 +09:00

73 lines
5.6 KiB
SQL

-- 기존 DB ALTER 누적 파일. 새 컬럼/변경은 이 파일에 계속 append 한다.
-- 전부 IF NOT EXISTS 라 몇 번을 재실행해도 안전(돌리면 최신 상태로 맞춰짐).
-- 신규/리셋 DB 는 01-schema*.sql 에 이미 반영돼 있어 이 파일이 필요 없다.
-- ───────────────────────────────────────────────────────────
-- [2026-06-26] 견적 개편: 가격(매입/판매)·수수료율·앵커링가 + 견적/카드/협력사 분류 컬럼
-- ───────────────────────────────────────────────────────────
-- 상품: 인터넷최저가 실값 + 매입가 + 판매가
ALTER TABLE partner.items
ADD COLUMN IF NOT EXISTS internet_lowest_price BIGINT,
ADD COLUMN IF NOT EXISTS purchase_price BIGINT,
ADD COLUMN IF NOT EXISTS selling_price BIGINT;
-- 세션: 앵커링가
ALTER TABLE negotiation.sessions
ADD COLUMN IF NOT EXISTS anchoring_price BIGINT;
-- 견적: MD 제시가 + 협력사(공급채널) 유형
ALTER TABLE quotation.quotations
ADD COLUMN IF NOT EXISTS md_price BIGINT,
ADD COLUMN IF NOT EXISTS supplier_type SMALLINT;
-- 카드: 사용 범위 구분(CardUsageType): 1=공통 2=신규견적전용 3=재견적전용
ALTER TABLE card.nego_cards
ADD COLUMN IF NOT EXISTS usage_type SMALLINT NOT NULL DEFAULT 1;
ALTER TABLE card.wild_cards
ADD COLUMN IF NOT EXISTS usage_type SMALLINT NOT NULL DEFAULT 1;
-- ───────────────────────────────────────────────────────────
-- [2026-06-29] 협상 초청 메일: 세션별 발송 시각(수동 발송 버튼이 채움)
-- ───────────────────────────────────────────────────────────
ALTER TABLE negotiation.sessions
ADD COLUMN IF NOT EXISTS email_sent_at TIMESTAMPTZ;
-- ───────────────────────────────────────────────────────────
-- [2026-06-30] 알림(인박스): 협상 이벤트를 견적 작성자에게 통지
-- ───────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS company.notifications (
notification_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid NOT NULL, -- 수신자(company.users.user_id) = 견적 작성자
type SMALLINT NOT NULL, -- 알림 유형(NotificationType): 1=success(낙찰), 2=regenerated(재생성), 3=failure(결렬)
ref_qt_id uuid NULL, -- 관련 견적(quotation.quotations.qt_id)
ref_session_id uuid NULL, -- 관련 세션(negotiation.sessions.session_id)
data JSONB NULL, -- 렌더 스냅샷(유형별)
read_at TIMESTAMPTZ NULL, -- 읽은 시각(NULL=안읽음)
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON company.notifications (user_id);
CREATE INDEX IF NOT EXISTS idx_notifications_user_unread ON company.notifications (user_id, created_at) WHERE deleted = FALSE AND read_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_notifications_ref_qt_id ON company.notifications (ref_qt_id);
-- ─────────────────────────────────────────────────────────────
-- [2026-07-02] 앵커링 v1.2 — sessions 판정·마킹 컬럼 3종
-- (신규 DB 는 01-schema*.sql 에 반영됨. anchoring 스키마 자체(adjustments·뷰)는
-- 모듈 소유 DDL schedules/anchoring/schema.sql 로 적용 — 여기엔 두지 않는다.)
ALTER TABLE negotiation.sessions
ADD COLUMN IF NOT EXISTS anchoring_value SMALLINT NULL, -- 제안 당시 앵커링 값(천분율‰) 박제
ADD COLUMN IF NOT EXISTS last_offer_price BIGINT NULL, -- 협력사 마지막 제시가(가격 흔적)
ADD COLUMN IF NOT EXISTS used_by_adjustment_id BIGINT NULL; -- 앵커링 배치 소비 마킹
-- ─────────────────────────────────────────────────────────────
-- [2026-07-02] 마감 close_reason 개편 — 견적 마감사유 + 가격정책 3구간
-- (신규 DB 는 01-schema*.sql 에 반영됨.)
ALTER TABLE quotation.quotations
ADD COLUMN IF NOT EXISTS close_reason SMALLINT NULL; -- 마감 사유(CloseReason 1~8), 미마감이면 NULL
ALTER TABLE quotation.quotation_settings
ADD COLUMN IF NOT EXISTS mid_action SMALLINT NOT NULL DEFAULT 1, -- 가격정책(PriceGateAction): 앵커링가<투찰가≤목표가 처리
ADD COLUMN IF NOT EXISTS over_action SMALLINT NOT NULL DEFAULT 1, -- 가격정책(PriceGateAction): 목표가<투찰가 처리
ADD COLUMN IF NOT EXISTS regen_limit SMALLINT NOT NULL DEFAULT 1; -- 재생성 최대 횟수(체인 전체 총합, 사유 무관)