복식부기를 도입해서 정합성 있는 결제 시스템을 만들어보자
그렇다. 임시 저장 기능이 없어서 시리즈를 임시 저장처럼 쓰고 있는 모습이다. 하지만 오히려 좋아. 글 미리보기 기능이 생긴(?) 셈이자나?
재취업 준비를 하면서, 이력서에 "복식부기를 도입해서 정합성 확보" 적은 한줄땜에 리뷰로 쓴 글이 아니다.
흑흑 스프링 백앤드 일자리를 가고싶은데 책임이 필요없는 신입에서 1년차 자리가 없어
이런 법적인 부분도 좋아한다면 예자선씨의 핀테크 규제와 실무 책을 보자. 권하는 책 중 하나이다.
이런 상황에서는 복식부기가 도입돼야 추후 분쟁이 생겨도 "어디서 빵꾸가 났는지" 알아낼 수 있음
-- billing.billing_account definition
-- Drop table
-- DROP TABLE billing.billing_account;
CREATE TABLE billing.billing_account (
billing_account bigserial NOT NULL,
currency bpchar(3) NOT NULL,
balance numeric DEFAULT 0 NOT NULL,
account_type varchar(8) NOT NULL,
account_ref int8 NOT NULL, -- 시스템 = 0
system_comment varchar(255) NULL,
"comment" varchar(255) NULL,
created timestamp DEFAULT now() NOT NULL,
updated timestamp DEFAULT now() NOT NULL,
CONSTRAINT billing_account_pk PRIMARY KEY (billing_account)
);
CREATE INDEX billing_account_type_idx ON billing.billing_account USING btree (account_type, account_ref);
-- Column comments
COMMENT ON COLUMN billing.billing_account.account_ref IS '시스템 = 0';
-- billing.transaction_prepare definition
-- Drop table
-- DROP TABLE billing.transaction_prepare;
CREATE TABLE billing.transaction_prepare (
tx_prepare_id bigserial NOT NULL,
tx_type varchar(32) NOT NULL,
tx_name varchar(255) NOT NULL,
tx_comment text NULL, -- IP 또는 파라메터 등
status bpchar(3) NOT NULL,
created_at timestamp DEFAULT now() NOT NULL,
updated_at timestamp DEFAULT now() NOT NULL,
issued_by int8 NOT NULL,
CONSTRAINT transaction_prepare_pk PRIMARY KEY (tx_prepare_id),
CONSTRAINT transaction_prepare_billing_account_fk FOREIGN KEY (issued_by) REFERENCES billing.billing_account(billing_account) ON DELETE CASCADE ON UPDATE CASCADE
);
-- Column comments
COMMENT ON COLUMN billing.transaction_prepare.tx_comment IS 'IP 또는 파라메터 등';
-- billing."transaction" definition
-- Drop table
-- DROP TABLE billing."transaction";
CREATE TABLE billing."transaction" (
tx_id int8 NOT NULL,
currency bpchar(3) NOT NULL, -- CURRENCY 미리보기임. 너무 믿진 말 것
amount_total numeric NOT NULL, -- balance 미리보기임. 너무 믿진 말것 (실 계산전에 나옴)
issued_by int8 NOT NULL,
related_tx_id int8 NOT NULL,
created_at timestamptz DEFAULT now() NOT NULL,
system_comment varchar(255) NULL,
CONSTRAINT transaction_pk PRIMARY KEY (tx_id),
CONSTRAINT transaction_transaction_prepare_fk FOREIGN KEY (tx_id) REFERENCES billing.transaction_prepare(tx_prepare_id) ON DELETE RESTRICT ON UPDATE CASCADE
);
-- Column comments
COMMENT ON COLUMN billing."transaction".currency IS 'CURRENCY 미리보기임. 너무 믿진 말 것';
COMMENT ON COLUMN billing."transaction".amount_total IS 'balance 미리보기임. 너무 믿진 말것 (실 계산전에 나옴)';
-- billing.ledger_entry definition
-- Drop table
-- DROP TABLE billing.ledger_entry;
CREATE TABLE billing.ledger_entry (
ledger_id bigserial NOT NULL,
tx_id int8 NOT NULL,
account_id int8 NOT NULL,
side bpchar(1) NOT NULL,
amount numeric NOT NULL,
account_balance_before numeric NOT NULL,
account_balance_after numeric NOT NULL,
created_at timestamp DEFAULT now() NOT NULL,
"comment" varchar(255) NULL,
log varchar(255) NULL,
CONSTRAINT ledger_entry_pk PRIMARY KEY (ledger_id),
CONSTRAINT ledger_entry_billing_account_fk FOREIGN KEY (account_id) REFERENCES billing.billing_account(billing_account) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT ledger_entry_transaction_fk FOREIGN KEY (tx_id) REFERENCES billing."transaction"(tx_id) ON DELETE RESTRICT ON UPDATE CASCADE
);
-- billing.ledger_entry_link definition
-- Drop table
-- DROP TABLE billing.ledger_entry_link;
CREATE TABLE billing.ledger_entry_link (
pk bigserial NOT NULL,
parent_ledger_id int8 NOT NULL,
child_ledger_id int8 NOT NULL,
"comment" varchar(255) NULL,
tx_id int8 NOT NULL, -- index로 한번에 긁어올 수 있도록
CONSTRAINT ledger_entry_link_pk PRIMARY KEY (pk),
CONSTRAINT ledger_entry_link_ledger_entry_fk FOREIGN KEY (parent_ledger_id) REFERENCES billing.ledger_entry(ledger_id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT ledger_entry_link_ledger_entry_fk_1 FOREIGN KEY (child_ledger_id) REFERENCES billing.ledger_entry(ledger_id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT ledger_entry_link_transaction_fk FOREIGN KEY (tx_id) REFERENCES billing."transaction"(tx_id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX ledger_entry_link_child_ledger_id_idx ON billing.ledger_entry_link USING btree (child_ledger_id);
CREATE INDEX ledger_entry_link_parent_ledger_id_idx ON billing.ledger_entry_link USING btree (parent_ledger_id);
-- Column comments
COMMENT ON COLUMN billing.ledger_entry_link.tx_id IS 'index로 한번에 긁어올 수 있도록';
billing.billing_account {
billing_account_id (pk, bigserial)
currency (bpchar(3), not null)
balance (numeric, default 0)
account_type (varchar(8), not null)
account_ref (int8, not null) -- 시스템 = 0
system_comment (varchar(255))
comment (varchar(255))
created (timestamp, default now())
updated (timestamp, default now())
}
Indexes:
- billing_account_type_idx (account_type, account_ref)
Comments:
- account_ref: "시스템 = 0"
billing.transaction_prepare {
tx_prepare_id (pk, bigserial)
tx_type (varchar(32), not null)
tx_name (varchar(255), not null)
tx_comment (text) -- IP 또는 파라메터 등
status (bpchar(3), not null)
created_at (timestamp, default now())
updated_at (timestamp, default now())
issued_by (int8, not null, fk → billing_account.billing_account_id)
}
Foreign Keys:
- issued_by → billing.billing_account(billing_account_id)
(on delete cascade, on update cascade)
Comments:
- tx_comment: "IP 또는 파라메터 등"
billing.transaction {
tx_id (pk, int8)
currency (bpchar(3), not null) -- CURRENCY 미리보기 (참고용)
amount_total (numeric, not null) -- balance 미리보기 (실 계산 전)
issued_by (int8, not null, fk → billing_account)
related_tx_id (int8, not null)
created_at (timestamptz, default now())
comment_system (varchar(255))
}
Foreign Keys:
- issued_by → billing.billing_account(billing_account_id)
(on delete restrict, on update cascade)
- tx_id → billing.transaction_prepare(tx_prepare_id)
(on delete restrict, on update cascade)
Comments:
- currency: "CURRENCY 미리보기임. 너무 믿진 말 것"
- amount_total: "balance 미리보기임. 너무 믿진 말것 (실 계산전에 나옴)"
billing.ledger_entry {
ledger_id (pk, bigserial)
tx_id (int8, not null, fk → transaction.tx_id)
account_id (int8, not null, fk → billing_account.billing_account_id)
side (bpchar(1), not null)
amount (numeric, not null)
account_balance_before (numeric, not null)
account_balance_after (numeric, not null)
created_at (timestamp, default now())
comment (varchar(255))
log (varchar(255))
}
Foreign Keys:
- account_id → billing.billing_account(billing_account_id)
- tx_id → billing.transaction(tx_id)
(모두 on delete restrict, on update cascade)
billing.ledger_entry_link {
pk (pk, bigserial)
ledger_id_parent (int8, not null, fk → ledger_entry.ledger_id)
ledger_id_child (int8, not null, fk → ledger_entry.ledger_id)
comment (varchar(255))
tx_id (int8, not null, fk → transaction.tx_id)
link_type (varchar(32), not null) -- 트리의 루트 네이밍
}
Foreign Keys:
- ledger_id_parent → billing.ledger_entry(ledger_id)
- ledger_id_child → billing.ledger_entry(ledger_id)
- tx_id → billing.transaction(tx_id)
(모두 on delete cascade, on update cascade)
Indexes:
- ledger_entry_link_child_ledger_id_idx (ledger_id_child)
- ledger_entry_link_parent_ledger_id_idx (ledger_id_parent)
Comments:
- tx_id: "index로 한번에 긁어올 수 있도록"
- link_type: "뷰 단에서 트리를 표시할 때 root name"
사실 이것은 Okchun 서비스에서도 적용했고, 과거 백오피스에서도 적용했던 기법이다. 결제의 흐름이 복잡할 수록 유용하다.