- Published on
Bank Deposit System Architecture — Dissecting the Heart of Core Banking
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- Introduction
- An Overview of the Deposit Domain
- Core, Information, and External Systems — The Three Layers of Bank IT
- Deposit Ledger Design — The Core in Tables
- Transaction Processing — The Life of a Single Withdrawal
- Transfers and Interbank Transactions — The KFTC Shared Network
- The Dual Structure of Online and Batch
- Performance Requirements — The Core in Numbers
- Failure Scenarios and Responses
- Testing Strategy
- Glossary
- Closing Thoughts
- References
Introduction
In bank IT, the words "core banking" carry a different weight. When a channel goes down, customers are inconvenienced; when the core goes down, the bank stops. At the center of that core sits the deposit system. From the moment a customer presses the withdrawal button at an ATM to the moment the ledger balance is updated and the transaction record is finalized, those few hundred milliseconds condense design principles refined over decades.
I wrote this article for developers encountering the core banking deposit domain for the first time, and for engineers who must interface with the core during next-generation projects or channel integration work. We will dissect the structure of the deposit business domain, ledger table design, transaction processing sequences, concurrency control, and the coexistence of end-of-day closing with nonstop operation — all from a practitioner viewpoint. Please note up front that this is a general technical explanation, not a description of any specific institution's internals, and not investment or legal advice.
An Overview of the Deposit Domain
What Is the Deposit Business
Banking work divides broadly into deposits (taking money in) and lending (giving money out). The deposit business covers everything involved in accepting and managing customer deposits; from the bank's perspective these are liabilities (money owed back to customers). Representative deposit products include the following.
| Product Type | Characteristics | Interest Structure | Key Design Point |
|---|---|---|---|
| Demand deposit (checking/savings) | Free deposits and withdrawals | Low floating rate, paid at settlement periods | High-frequency transactions, concurrency control |
| Time deposit (lump sum) | A lump sum parked for a fixed term | Contract rate, paid at maturity | Maturity management, early termination rates |
| Installment savings | Fixed monthly installments | Per-installment day-count interest | Installment tracking, missed/early payments |
| Flexible installment savings | Free-form contributions | Day-count interest per contribution | Per-entry interest calculation |
| MMDA | Market-rate-linked demand account | Tiered rates by balance band | Daily balance tracking |
Even though all of these are "deposits," their transaction patterns differ completely. Demand deposits form a high-frequency transaction domain with thousands of deposits and withdrawals per second, while time deposits trade rarely but live or die by the correctness of interest calculation and maturity processing. System design must reflect this difference.
The Account Lifecycle
A deposit account follows a clear state machine.
+----------+
open (new) | | block event occurs
-------------> | ACTIVE | ----------------------+
| | |
+----------+ v
| ^ +-----------+
close request| | unblock | BLOCKED |
| +------------------- | |
v +-----------+
+----------+ |
| CLOSED | <-------------------------+
| | forced closure (legal grounds etc.)
+----------+
|
v after a defined period
+----------+ +-----------+
| DORMANT | -----> | ESCHEAT |
| | | |
+----------+ +-----------+
What matters in practice are the side effects of state transitions. At closure, accrued unpaid interest must be settled and paid out; at dormancy conversion, a separate process hands the account over to the dormant deposit management scheme (contribution to the public dormant funds body, and so on). The biggest difference between an ordinary CRUD application and core banking is that every state transition drags an accounting entry along with it.
Core, Information, and External Systems — The Three Layers of Bank IT
Korean bank IT has traditionally divided systems by business nature.
+-----------------------------------------------------------------+
| Channel Layer |
| Internet banking Mobile app ATM Teller Phone Open banking |
+------------------------------+----------------------------------+
| messages / APIs
+------------------------------v----------------------------------+
| Core Banking Layer |
| +-----------+ +-----------+ +-----------+ +--------------+ |
| | Deposits | | Lending | | FX | | Common (cust, | |
| | (ledger) | | (ledger) | | (ledger) | | product, GL) | |
| +-----------+ +-----------+ +-----------+ +--------------+ |
+-------+----------------------------------------------+----------+
| txn log / ledger replication (CDC, batch) | external msgs
+-------v------------------+ +------------------------v----------+
| Information Layer (DW) | | External Gateway Layer |
| MIS Risk Marketing | | KFTC Central bank Card network |
| Analytics Reg. reports | | Shared networks SWIFT Open API |
+---------------------------+ +-----------------------------------+
- The core banking layer holds the ledger and is the System of Record. The truth about balances lives in the core, and only in the core.
- The information layer is an analytical system built by replicating and transforming core data. Management reports, risk measurement, and marketing campaigns run here, and it absorbs read-heavy load to protect the core's online performance.
- The external gateway layer handles message exchange with outside institutions: the KFTC shared networks, the central bank network, SWIFT, and so on. Interbank transfers are possible because this layer exists.
This separation matters because the layers have different consistency grades. The core requires strong consistency (transactional ACID), while the information layer tolerates lag from minutes to a day. This is also why a channel should never hit the core directly to display "average balance as of yesterday."
Deposit Ledger Design — The Core in Tables
The skeleton of a deposit ledger consists of three kinds of tables: the account master, the transaction history, and the balance (or balance history). Below is a simplified schema example for explanation purposes (real next-generation systems have hundreds of columns).
Account Master
CREATE TABLE deposit_account_master (
account_no CHAR(14) NOT NULL, -- account number
customer_id VARCHAR(20) NOT NULL, -- customer id
product_code VARCHAR(10) NOT NULL, -- product code
currency_code CHAR(3) NOT NULL DEFAULT 'KRW',
account_status CHAR(2) NOT NULL, -- 01:active 02:blocked 03:closed 04:dormant
open_date DATE NOT NULL, -- opening date
maturity_date DATE, -- maturity (time/installment)
contract_rate NUMERIC(7,4), -- contract rate (annual, %)
contract_amount NUMERIC(17,0), -- contract amount (monthly installment etc.)
last_txn_date DATE, -- last transaction date (dormancy check)
branch_code VARCHAR(6) NOT NULL, -- managing branch
passbook_seq INTEGER DEFAULT 0, -- passbook rollover count
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
CONSTRAINT pk_dam PRIMARY KEY (account_no)
);
CREATE INDEX ix_dam_customer ON deposit_account_master (customer_id);
CREATE INDEX ix_dam_maturity ON deposit_account_master (maturity_date, account_status);
The maturity-date index is the lifeline of the daily batch that extracts accounts reaching maturity. Tracking the last transaction date for dormancy determination is also the master's job.
Transaction History (Journal)
CREATE TABLE deposit_transaction_history (
account_no CHAR(14) NOT NULL,
txn_date DATE NOT NULL, -- business (posting) date
txn_seq INTEGER NOT NULL, -- per-account sequence
txn_datetime TIMESTAMP NOT NULL, -- system timestamp
txn_type CHAR(2) NOT NULL, -- 01:credit 02:debit 03:interest 04:correction
txn_amount NUMERIC(17,0) NOT NULL, -- transaction amount
balance_after NUMERIC(17,0) NOT NULL, -- balance after txn (passbook printing)
counterparty VARCHAR(60), -- narrative / counterparty display
channel_code CHAR(2) NOT NULL, -- channel (teller/ATM/mobile)
teller_id VARCHAR(10), -- operator (branch transactions)
global_txn_id VARCHAR(32) NOT NULL, -- global transaction id (end-to-end trace)
reversal_yn CHAR(1) NOT NULL DEFAULT 'N', -- reversal flag
original_txn_ref VARCHAR(32), -- original txn reference (on reversal)
CONSTRAINT pk_dth PRIMARY KEY (account_no, txn_date, txn_seq)
);
CREATE UNIQUE INDEX ux_dth_global ON deposit_transaction_history (global_txn_id);
There are three design points here.
- Transaction history is immutable (append-only). A wrong transaction is never fixed with an UPDATE; instead a reversal (correction) entry in the opposite direction is appended. The ledger's audit trail comes from this.
- The post-transaction balance is recorded in the journal itself. This serves passbook printing and dispute handling, but it also lets the balance verification batch check the chain "previous balance-after plus transaction amount equals current balance-after."
- The global transaction id is the trace key that runs from the channel all the way to the external gateway. It anchors result inquiries after timeouts (original transaction lookup) and duplicate prevention (idempotency).
Balance Management
CREATE TABLE deposit_balance (
account_no CHAR(14) NOT NULL,
current_balance NUMERIC(17,0) NOT NULL, -- current balance
available_balance NUMERIC(17,0) NOT NULL, -- withdrawable balance
hold_amount NUMERIC(17,0) NOT NULL DEFAULT 0, -- holds/garnishments
uncleared_amount NUMERIC(17,0) NOT NULL DEFAULT 0, -- uncleared items (checks/bills)
last_txn_seq INTEGER NOT NULL, -- last transaction sequence
version_no BIGINT NOT NULL DEFAULT 0, -- optimistic lock version
updated_at TIMESTAMP NOT NULL,
CONSTRAINT pk_db PRIMARY KEY (account_no)
);
The subtlety of the deposit domain is that current balance and available balance differ. Amounts under garnishment or pledge, and incoming check deposits that have not yet cleared, sit in the balance but cannot be withdrawn. The withdrawal eligibility rule looks roughly like this.
available balance = current balance - hold amount - uncleared items + overdraft limit (if contracted)
withdrawal approval condition: requested amount <= available balance
Transaction Processing — The Life of a Single Withdrawal
Deposit/Withdrawal Sequence
Simplified, a withdrawal (transfer debit) initiated from a mobile app flows like this.
Customer Channel Srv Core (Deposits) DB
| | | |
|--withdraw->| | |
| |--msg(debit)-->| |
| | |--1. validate status->| (active? blocked?)
| | |--2. lock balance row->| SELECT ... FOR UPDATE
| | |--3. check available-->|
| | |--4. debit balance---->| UPDATE balance
| | |--5. INSERT journal--->|
| | |--6. record GL entry-->|
| | |<------ COMMIT -------|
| |<--approved----| |
|<--done-----| | |
The crux is that steps 2 through 5 form a single DB transaction. If another transaction slips in between the balance check and the debit, a double withdrawal occurs, so validation and update must happen inside the same lock window.
Pessimistic Locking — The Bread and Butter of Core Banking
Traditional core banking uses pessimistic locks: lock the balance row first, then validate and update.
-- begin transaction
BEGIN;
-- 1) read the balance row under an exclusive lock
SELECT current_balance, available_balance, last_txn_seq
FROM deposit_balance
WHERE account_no = '11012345678901'
FOR UPDATE;
-- 2) after the application validates the available amount, debit it
UPDATE deposit_balance
SET current_balance = current_balance - 500000,
available_balance = available_balance - 500000,
last_txn_seq = last_txn_seq + 1,
updated_at = CURRENT_TIMESTAMP
WHERE account_no = '11012345678901';
-- 3) record the journal entry
INSERT INTO deposit_transaction_history
(account_no, txn_date, txn_seq, txn_datetime, txn_type,
txn_amount, balance_after, channel_code, global_txn_id, reversal_yn)
VALUES ('11012345678901', CURRENT_DATE, 124, CURRENT_TIMESTAMP, '02',
500000, 1500000, '03', 'G20260613000000123456', 'N');
COMMIT;
Pessimistic locking guarantees consistency, but lock waits grow long on hot accounts (corporate master accounts, virtual-account settlement accounts where traffic concentrates). On payroll day, when tens of thousands of credits pour into one corporate account, that account's balance row becomes a serialization point.
Optimistic Locking and Trade-offs
In areas where reads dominate and conflicts are rare, version-column-based optimistic locking is also used.
UPDATE deposit_balance
SET current_balance = current_balance - 500000,
version_no = version_no + 1
WHERE account_no = '11012345678901'
AND version_no = 42; -- succeeds only if version matches what was read
-- zero rows updated means conflict, so retry
The practical trade-offs can be summarized as follows.
| Strategy | Suitable For | Risk |
|---|---|---|
| Pessimistic lock (FOR UPDATE) | General deposits/withdrawals, debit paths | Hot-account lock contention |
| Optimistic lock (version) | Rare-conflict updates, limit changes | Throughput collapse under retry storms |
| Conditional UPDATE debit | Simple debits (with availability check) | Hard to express complex validation |
| Per-account serialized queue | Ultra-high-frequency master accounts | Added infrastructure complexity |
The conditional UPDATE pushes the validation into the SQL itself.
UPDATE deposit_balance
SET available_balance = available_balance - 500000,
current_balance = current_balance - 500000
WHERE account_no = '11012345678901'
AND available_balance >= 500000; -- zero rows updated means insufficient funds
Transfers and Interbank Transactions — The KFTC Shared Network
Intrabank vs. Interbank Transfers
A transfer within the same bank (intrabank) can wrap the debit account and the credit account in one transaction (even then, the textbook approach is to lock accounts in sorted account-number order to avoid deadlocks). The problem is interbank transfers. We cannot touch the other bank's ledger, so messages travel through the electronic banking shared network operated by the Korea Financial Telecommunications and Clearings Institute (KFTC).
Bank A (debit side) KFTC (switch) Bank B (credit side)
| | |
|--1. debit (own ledger) | |
|--2. interbank credit ->| |
| request msg |--3. credit request --->|
| | |--4. credit (B ledger)
| |<--5. credit response --|
|<--6. final response ---| |
|--7. finalize txn | |
| | |
| (actual funds between banks settle separately |
| via deferred net settlement over BOK-Wire+) |
One conceptual separation matters here: customer ledger posting (immediate) and interbank fund settlement (deferred net settlement) happen at different times. The customer sees an instant credit, but clearing between banks settles later through the central bank payment system. Banks therefore manage counterparty settlement risk, which leads to regulatory mechanisms such as collateral and net debit caps.
Timeouts and Compensating Transactions
The nightmare of interbank transactions is the "unknown" state. If response 5 never arrives, we cannot tell whether the credit happened. The standard response pattern is:
- Send a result-inquiry (original transaction confirmation) message to ask the counterpart system for the outcome. The global transaction id is the trace key.
- If still unknown, park the transaction and hand it to automatic/manual reconciliation. A completed debit with an unknown credit means customer money is in limbo, so this gets top priority.
- Once confirmed as failed, automatically generate a compensating transaction (debit reversal). The principle is to append an opposite transaction, never to erase the original.
Distributed transactions (2PC) cannot span banks, so interbank processing in core banking is essentially the ancestor of the compensating-transaction (Saga) pattern.
The Dual Structure of Online and Batch
A deposit system has two faces: online transaction processing during the day (and night), and daily batch processing.
| Aspect | Online | Batch |
|---|---|---|
| Unit | One transaction | All accounts or extracted targets |
| Time constraint | Tens to hundreds of ms | Batch window (tens of minutes to hours) |
| Typical work | Deposits, withdrawals, transfers, inquiries | Interest accrual, maturity processing, dormancy, balance verification |
| Failure handling | Immediate rejection/compensation | Restart, range reprocessing |
A representative end-of-day (EOD) flow looks like this.
[Business day D closing starts]
1. Online cutover preparation (new transactions get posting date D+1)
2. Open item cleanup (external reconciliation, finalize parked txns)
3. Interest accrual batch (accumulate daily balances, fix payable interest)
4. Maturity processing (notices, auto-renewal, auto-closure)
5. Dormancy / long-inactive determination
6. Ledger vs. general ledger (GL) reconciliation
7. Data feed to the information layer (CDC correction, daily snapshot)
8. Daily trial balance and cash position finalization
[Business day D+1 opens]
24x7 Operation Coexisting with EOD
In the past, online service was taken down during closing; today transfers must work at 3 a.m. Representative techniques for making nonstop service coexist with EOD:
- Posting-date switch: the system never stops; transactions after midnight or the cutover moment simply receive posting date D+1. "Today" is decoupled from wall-clock time and tied to the posting date.
- Forward-dated buffer area: transactions arriving while closing batches run are written to a separate buffer (or a D+1 partition) and merged into the main ledger flow after closing completes.
- Online-friendly closing batches: instead of locking all accounts, processing is split by partition, and online transactions on accounts outside the current partition keep flowing.
- Nonstop ledger rollover: the balance snapshot is logically frozen as of D, and subsequent transactions affect only the D+1 balance. Closing outputs such as the daily trial balance are produced from the snapshot.
A classic field trap here is "double-counting transactions during closing." If the moment the interest batch reads a balance overlaps with the moment an online transaction changes it, the daily accumulated balance wobbles. Daily accumulation must therefore be reconstructible from the transaction journal rather than read from the live balance, and every closing artifact must come from a snapshot whose as-of time is explicit.
Performance Requirements — The Core in Numbers
For a large commercial bank, commonly cited levels are as follows (institutions and eras vary widely; treat these as order-of-magnitude intuition).
| Item | Typical Target Level |
|---|---|
| Normal core transaction volume | Hundreds to thousands per second |
| Peak (payday, pre-holiday) | 3x to 10x normal |
| Online response time | Within 100ms inside the core, less for simple inquiries |
| Availability target | 99.9 percent or higher per year (excluding planned downtime), higher for critical paths |
| Daily batch window | Completion within a few hours; delays risk the next business open |
Performance design points peculiar to core banking:
- Read offloading: balance inquiries and history lookups go to read replicas or the information layer, leaving the ledger DB to update transactions only. However, the balance check immediately before a withdrawal must always hit the primary.
- Hot-account countermeasures: for accounts with concentrated updates, such as virtual-account master accounts, consider sharding the balance (sub-balance splitting) or letting credit-side postings flow through asynchronous aggregation.
- Journal partitioning: partition by transaction date to control index depth, and migrate old history to an archive tier.
Failure Scenarios and Responses
Redundancy Architecture
[Channels] [Channels]
\ /
+---v-------------------------v---+
| L4 / message routing |
+---+-------------------------+---+
| (Active) | (Active or Standby)
+------v------+ +------v------+
| App Srv #1 | | App Srv #2 | <- stateless, scale-out
+------+------+ +------+------+
| |
+---v-------------------------v---+
| Ledger DB (Primary) |
+---------------+------------------+
| synchronous replication
+---------------v------------------+
| Ledger DB (Standby) | <- same or nearby site
+---------------+------------------+
| asynchronous replication
+---------------v------------------+
| Disaster Recovery (DR) site | <- remote, regular drills
+-----------------------------------+
The synchronous replication leg of the ledger DB targets zero data loss (RPO 0), and the DR site guards against regional disasters. Korean electronic finance supervision regulations impose requirements on disaster recovery posture and recovery time objectives, so defining RTO/RPO targets for critical work and running regular failover drills is standard practice.
Representative Failure Scenarios
| Scenario | Symptom | Response |
|---|---|---|
| Ledger DB failover | Transactions fail for seconds to tens of seconds | Automatic failover, channel retry policy, open-item reconciliation |
| External line outage | All interbank transfers time out | Redundant line switchover, park then bulk-reconcile |
| Hot-account lock storm | Delays propagate from one account | Queueing/throttling, isolate the product's traffic |
| Batch delay | Closing unfinished before business open | Batch restart points, prioritize open-critical predecessors |
| Duplicate message arrival | Risk of double-processing | Idempotency keyed on global transaction id |
Idempotent processing in one sentence: a transaction with the same global transaction id is applied once even if it arrives twice, and the second arrival receives the first result. The unique index on the journal's global transaction id is the last line of defense.
Testing Strategy
Core banking tests must verify not "does the code run" but "is the money right."
- Automated consistency assertions: after every scenario, automatically check that (a) journal totals match balance deltas, (b) the balance-after chain is intact, and (c) ledger and GL entries reconcile. Make these shared assertions.
- Concurrency tests: bombard the same account with simultaneous credits and debits from hundreds of threads and verify the final balance is arithmetically exact. The count of insufficient-funds rejections must also add up.
- Date-boundary tests: pin down scenarios verifying that transactions just before, during, and just after closing receive the correct posting date and that daily accumulation does not wobble. Injectable system dates are a prerequisite.
- Fault injection: automate cases like killing the app server right before commit, delaying external responses, and re-sending duplicate messages, to validate compensation and reconciliation logic.
- Migration reconciliation: for next-generation or migration projects, parallel testing — feeding identical transactions to old and new systems and comparing ledgers exhaustively — is practically mandatory.
Glossary
| Term | Korean Usage | Meaning |
|---|---|---|
| Deposits | Su-sin | Taking and managing deposits; the liability side of a bank |
| Lending | Yeo-sin | Loan business; the asset side of a bank |
| Core banking system | Gyejeong-gye | The system of record holding the ledger |
| Information system / DW | Jeongbo-gye | Data systems for analytics and reporting |
| External gateway | Daeoe-gye | Message integration with outside institutions |
| Ledger | Wonjang | The official record of accounts, balances, transactions |
| Message (telegram) | Jeonmun | Fixed-format transaction messages between systems |
| Posting date | Gyeri-ilja | The business date a transaction is attributed to |
| EOD closing | Il-magam | The per-business-day settlement and cleanup batch |
| Daily accumulated balance | Il-jeoksu | Running total of daily balances; basis of interest |
| Uncleared items | Tajeom-gwon | Checks and bills not yet settled |
| Reconciliation | Daesa | Verifying agreement between two records |
| Compensating transaction | Bosang-georae | An opposite transaction offsetting the original |
| Dormant deposits | Hyumyeon-yegeum | Deposits converted to dormant status after long inactivity |
Closing Thoughts
A deposit system is not a showcase of flashy technology. Quite the opposite: it is a structure where layers of devices — concurrency control, immutable journals, idempotency, compensating transactions, closing snapshots — are stacked to uphold one simple proposition: the balance must never be off by even one won. When bringing new architecture (MSA, event sourcing, cloud) into core banking, this essence does not change. The technology changes, but the question stays the same: "Where in this design could the money go wrong?"
In the next article we will dig into the crown jewel of the deposit domain: the interest calculation engine, from day-count computation through preferential rates and tax withholding.
References
- Korea Financial Telecommunications and Clearings Institute (KFTC): https://www.kftc.or.kr
- Bank of Korea payment systems (BOK-Wire+): https://www.bok.or.kr/eng/main/contents.do?menuNo=400362
- Financial Supervisory Service (Korea): https://www.fss.or.kr
- Electronic Financial Transactions Act (Korean Law Information Center): https://www.law.go.kr
- BIS - Principles for Financial Market Infrastructures: https://www.bis.org/cpmi/publ/d101.htm
- ISO 20022 financial messaging standard: https://www.iso20022.org
- SWIFT standards: https://www.swift.com/standards
- PostgreSQL documentation - concurrency control (MVCC, row locks): https://www.postgresql.org/docs/current/mvcc.html
- Oracle Database documentation - transactions and locking: https://docs.oracle.com/en/database/
- Depositor Protection Act (Korean Law Information Center): https://www.law.go.kr