Phase 2a: 모듈서버 패턴 + 재사용 빌드시스템 (ac 모듈 38서비스 실동작)

- ac_svr(30 매입서비스 advertise) + rc_svr/st_svr, dbio 정적라이브러리, common 라이브러리
- app/build.sh: 모듈 자동발견(app/src/<mod>/<mod>_svr.pgc) → ecpg+buildserver+ndrxconfig 생성
- ac 배치 2종, 스키마 9테이블, 검증: 41서비스 AVAIL, 체인·배치 psql 커밋, prepared_xacts=0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
forge-bot 2026-07-19 09:37:17 +00:00
parent e6e29e6b5d
commit 05a0ff3e56
28 changed files with 1964 additions and 410 deletions

View file

@ -1,4 +1,4 @@
-- Card-acquiring vertical-slice schema (카드 매입/승인/정산/원장)
-- Card-acquiring schema (카드 매입/승인/정산/원장 + ac 모듈 상세 테이블)
-- Loaded into PostgreSQL on first boot (docker-entrypoint-initdb.d).
-- ---------------------------------------------------------------------------
@ -8,13 +8,13 @@ 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%)
daily_limit BIGINT NOT NULL DEFAULT 100000000,
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 (
@ -23,8 +23,11 @@ CREATE TABLE IF NOT EXISTS purchase (
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)
status TEXT NOT NULL, -- A=접수, M=대사완료, S=정산완료, C=취소, H=보류, V=void
biz_date DATE NOT NULL,
channel TEXT NOT NULL DEFAULT 'POS', -- POS/EDC/EDI/FOREIGN
issuer TEXT NOT NULL DEFAULT 'UNKNOWN',
category TEXT NOT NULL DEFAULT 'GEN',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
@ -41,13 +44,13 @@ CREATE TABLE IF NOT EXISTS approval (
);
-- ---------------------------------------------------------------------------
-- 원장 (ledger) - double-entry style recon check written during 대사
-- 원장 (ledger) - recon/settle entries
-- ---------------------------------------------------------------------------
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
entry_type TEXT NOT NULL, -- RECON / SETTLE / XFER / SETTLELINK
amount BIGINT NOT NULL,
biz_date DATE NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
@ -67,8 +70,101 @@ CREATE TABLE IF NOT EXISTS settlement (
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)
-- ---------------------------------------------------------------------------
-- ac 모듈 상세 테이블 (취소/할부/수수료조정/원천/세금계산서/해외/EDI/미매입/집계)
-- ---------------------------------------------------------------------------
CREATE SEQUENCE IF NOT EXISTS ac_cancel_seq;
CREATE TABLE IF NOT EXISTS ac_cancel (
cancel_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
cancel_type TEXT NOT NULL, -- FULL / PARTIAL / REFUND / VOID
amount BIGINT NOT NULL,
reason TEXT NOT NULL DEFAULT '',
biz_date DATE NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE SEQUENCE IF NOT EXISTS ac_install_seq;
CREATE TABLE IF NOT EXISTS ac_install (
install_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
seq_no INTEGER NOT NULL,
months INTEGER NOT NULL,
month_amount BIGINT NOT NULL,
biz_date DATE NOT NULL
);
CREATE SEQUENCE IF NOT EXISTS ac_feeadj_seq;
CREATE TABLE IF NOT EXISTS ac_fee_adj (
adj_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
delta BIGINT NOT NULL,
reason TEXT NOT NULL DEFAULT '',
biz_date DATE NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE SEQUENCE IF NOT EXISTS ac_wht_seq;
CREATE TABLE IF NOT EXISTS ac_wht (
wht_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
tax_amount BIGINT NOT NULL,
biz_date DATE NOT NULL
);
CREATE SEQUENCE IF NOT EXISTS ac_taxinv_seq;
CREATE TABLE IF NOT EXISTS ac_tax_invoice (
inv_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
merchant_id TEXT NOT NULL,
supply BIGINT NOT NULL,
vat BIGINT NOT NULL,
biz_date DATE NOT NULL
);
CREATE SEQUENCE IF NOT EXISTS ac_fx_seq;
CREATE TABLE IF NOT EXISTS ac_fx (
fx_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
ccy TEXT NOT NULL,
fx_amount BIGINT NOT NULL,
krw_amount BIGINT NOT NULL,
rate_bps BIGINT NOT NULL,
biz_date DATE NOT NULL
);
CREATE SEQUENCE IF NOT EXISTS ac_edi_seq;
CREATE TABLE IF NOT EXISTS ac_edi (
edi_id BIGINT PRIMARY KEY,
merchant_id TEXT NOT NULL,
doc_no TEXT NOT NULL,
amount BIGINT NOT NULL,
biz_date DATE NOT NULL
);
CREATE SEQUENCE IF NOT EXISTS ac_unmatch_seq;
CREATE TABLE IF NOT EXISTS ac_unmatch (
unmatch_id BIGINT PRIMARY KEY,
purchase_id BIGINT NOT NULL,
reason TEXT NOT NULL,
biz_date DATE NOT NULL
);
-- 가맹점 일별 집계 (배치가 채움)
CREATE TABLE IF NOT EXISTS merchant_summary (
merchant_id TEXT NOT NULL,
biz_date DATE NOT NULL,
txn_count BIGINT NOT NULL DEFAULT 0,
gross_amount BIGINT NOT NULL DEFAULT 0,
fee_amount BIGINT NOT NULL DEFAULT 0,
net_amount BIGINT NOT NULL DEFAULT 0,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (merchant_id, biz_date)
);
-- Seed merchants so ACQUIRE has a valid counterparty.
INSERT INTO merchant (merchant_id, name, mdr_bps, daily_limit) VALUES
('M0001', '클라로 커피', 25, 100000000),
('M0002', '포지 마트', 25, 100000000),
('M0003', '클라로 면세점', 30, 500000000)
ON CONFLICT (merchant_id) DO NOTHING;