- postgres-init/05-anchoring-schema.sql 신설(02-learning-schema 스타일) — anchoring 스키마· adjustments·인덱스 2종(부분 인덱스 포함)·뷰 2종. sessions 컬럼은 01/04 소관으로 명시 - 루트 docker-compose.yml 에 anchoring + anchoring-redis 서비스 추가(기존 스타일), 헤더 서비스 목록·DB 준비 절차 갱신, 모듈 compose 의 로그 로테이션(10MB×5) 이관 - 모듈 schema.sql·docker-compose.yml 삭제 — DDL 단일 원본은 postgres-init/05 - tests/conftest 부트스트랩 경로를 05 로 교체, 문서 4종·주석 포인터 갱신 (인수인계의 낡은 'negodata 가 redis 참조' 문구도 무Redis 현실로 교정) - 검증: 모듈 20·negodata 50 테스트 통과, docker compose config 정상 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
70 lines
4.1 KiB
SQL
70 lines
4.1 KiB
SQL
-- ============================================================
|
|
-- anchoring : 앵커링 값 자동 조정 배치 (schedules/anchoring) 자산
|
|
-- ============================================================
|
|
-- negosium_db 안의 8번째 schema. schedules/anchoring 서비스가 소유한다(backend 는 소비만).
|
|
-- 01-schema*.sql 과 동일 컨벤션: FK 미사용(앱 레이어 무결성), TIMESTAMPTZ(UTC), 코드값 SMALLINT.
|
|
-- 규범 문서: schedules/anchoring/docs/개발용.md §6.
|
|
--
|
|
-- sessions 의 앵커링 컬럼(anchoring_price·anchoring_value·last_offer_price·used_by_adjustment_id)은
|
|
-- 여기 두지 않는다 — 신규 DB 는 01-schema*.sql, 기존 DB 는 04-alter*.sql 소관.
|
|
-- 유일한 DDL 원본 — 구 schedules/anchoring/schema.sql 은 여기로 이관 후 삭제(2026-07-06).
|
|
-- 구 이름(rate_adjustments 등)의 기존 DB 는 schedules/anchoring/migrations/20260706_rename_anchoring.sql 적용.
|
|
|
|
\connect negosium_db
|
|
|
|
CREATE SCHEMA IF NOT EXISTS anchoring;
|
|
|
|
-- 앵커링 값 조정 이력. append-only — UPDATE/DELETE 금지, updated_at/deleted 의도적 생략.
|
|
CREATE TABLE IF NOT EXISTS anchoring.adjustments (
|
|
adjustment_id BIGSERIAL PRIMARY KEY,
|
|
company_id uuid NOT NULL, -- 테넌트(partner.items.company_id 유래)
|
|
supplier_type SMALLINT NOT NULL, -- 1=유통(δ20) 2=제조(δ10) 3=총판(δ15)
|
|
price_range_index INTEGER NOT NULL, -- 가격구간 0..45 자릿수 사다리 (앱 보장)
|
|
sample_count INTEGER NOT NULL, -- 유효 표본 수 n (>=10, 앱 보장)
|
|
success_count INTEGER NOT NULL, -- n 중 성공(BID_SUCCESS) 건수
|
|
anchoring_value_before SMALLINT NOT NULL, -- 직전 값(‰) (이력 없었으면 정적 테이블 시작값)
|
|
anchoring_value_after SMALLINT NOT NULL, -- 조정 후 값(‰), clamp [10,200] 앱 보장
|
|
used_session_ids JSONB NOT NULL, -- 소비한 세션 uuid 배열(창 박제 — 재현성·감사)
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- 현재 값 조회 최적화: 칸별 최신 조정
|
|
CREATE INDEX IF NOT EXISTS idx_adjustments_cell
|
|
ON anchoring.adjustments (company_id, supplier_type, price_range_index, adjustment_id DESC);
|
|
|
|
-- 배치 스캔 최적화: 미처리 "재협상" 세션만 (부분 인덱스).
|
|
-- qt_type=1 을 술어에 포함해야 함 — 빼면 배치가 마킹하지 않는 비재협상 세션이
|
|
-- 영구 잔류해 인덱스가 전체 세션 수에 비례해 성장한다(의도는 이월 풀만 담는 소형 인덱스).
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_anchoring_pending
|
|
ON negotiation.sessions (status)
|
|
WHERE used_by_adjustment_id IS NULL AND deleted = false AND qt_type = 1;
|
|
|
|
-- ── 조회용 뷰 (파생 — 상태 없음, 진실 원천은 adjustments) ──────────
|
|
|
|
-- 회사별 앵커링 값 변경 이력 리스트업: "언제, 어떤 칸이, 몇 건 중 몇 건 성공으로, 몇 ‰에서 몇 ‰로"
|
|
CREATE OR REPLACE VIEW anchoring.value_history AS
|
|
SELECT adjustment_id,
|
|
company_id,
|
|
supplier_type, -- 1유통/2제조/3총판
|
|
price_range_index, -- 0..45 자릿수 사다리
|
|
anchoring_value_before, -- 이전 값(‰)
|
|
anchoring_value_after, -- 새 값(‰)
|
|
anchoring_value_after - anchoring_value_before AS value_change,
|
|
sample_count,
|
|
success_count,
|
|
round(success_count::numeric / sample_count, 3) AS success_rate,
|
|
created_at
|
|
FROM anchoring.adjustments;
|
|
|
|
-- 칸별 현재값: 칸의 최신 조정 행. 여기 없는 칸의 현재값 = 정적 테이블 시작값(10‰)
|
|
CREATE OR REPLACE VIEW anchoring.current_values AS
|
|
SELECT DISTINCT ON (company_id, supplier_type, price_range_index)
|
|
company_id,
|
|
supplier_type,
|
|
price_range_index,
|
|
anchoring_value_after AS anchoring_value,
|
|
adjustment_id AS last_adjustment_id,
|
|
created_at AS last_adjusted_at
|
|
FROM anchoring.adjustments
|
|
ORDER BY company_id, supplier_type, price_range_index, adjustment_id DESC;
|