-- Card-acquiring vertical-slice schema (카드 매입/승인/정산/원장) -- Loaded into PostgreSQL on first boot (docker-entrypoint-initdb.d). -- --------------------------------------------------------------------------- -- 가맹점 (merchant) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS merchant ( merchant_id TEXT PRIMARY KEY, name TEXT NOT NULL, mdr_bps INTEGER NOT NULL DEFAULT 25, -- Merchant Discount Rate, basis points (0.25%) status TEXT NOT NULL DEFAULT 'ACTIVE', created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 매입 (purchase) - the acquiring transaction -- purchase_id driven by an explicit sequence so ECPG can SELECT nextval first. -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS purchase_seq; CREATE TABLE IF NOT EXISTS purchase ( purchase_id BIGINT PRIMARY KEY, merchant_id TEXT NOT NULL, amount BIGINT NOT NULL, -- minor units (원, 정수) fee BIGINT NOT NULL, -- MDR fee net BIGINT NOT NULL, -- amount - fee status TEXT NOT NULL, -- A=접수, M=대사완료(matched), S=정산완료(settled) biz_date DATE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 승인 (approval) -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS approval_seq; CREATE TABLE IF NOT EXISTS approval ( approval_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, approved BOOLEAN NOT NULL DEFAULT true, approved_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 원장 (ledger) - double-entry style recon check written during 대사 -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS ledger_seq; CREATE TABLE IF NOT EXISTS ledger ( ledger_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, entry_type TEXT NOT NULL, -- RECON / SETTLE amount BIGINT NOT NULL, biz_date DATE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 정산 (settlement) - netting written during 정산 -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS settlement_seq; CREATE TABLE IF NOT EXISTS settlement ( settlement_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, merchant_id TEXT NOT NULL, net BIGINT NOT NULL, biz_date DATE NOT NULL, status TEXT NOT NULL DEFAULT 'SETTLED', settled_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- Seed a couple of merchants so ACQUIRE has a valid counterparty. INSERT INTO merchant (merchant_id, name, mdr_bps) VALUES ('M0001', '클라로 커피', 25), ('M0002', '포지 마트', 25) ON CONFLICT (merchant_id) DO NOTHING;