Skip to content
Published on

Bank Deposit System Architecture — Dissecting the Heart of Core Banking

Authors

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 TypeCharacteristicsInterest StructureKey Design Point
Demand deposit (checking/savings)Free deposits and withdrawalsLow floating rate, paid at settlement periodsHigh-frequency transactions, concurrency control
Time deposit (lump sum)A lump sum parked for a fixed termContract rate, paid at maturityMaturity management, early termination rates
Installment savingsFixed monthly installmentsPer-installment day-count interestInstallment tracking, missed/early payments
Flexible installment savingsFree-form contributionsDay-count interest per contributionPer-entry interest calculation
MMDAMarket-rate-linked demand accountTiered rates by balance bandDaily 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.

  1. 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.
  2. 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."
  3. 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.

StrategySuitable ForRisk
Pessimistic lock (FOR UPDATE)General deposits/withdrawals, debit pathsHot-account lock contention
Optimistic lock (version)Rare-conflict updates, limit changesThroughput collapse under retry storms
Conditional UPDATE debitSimple debits (with availability check)Hard to express complex validation
Per-account serialized queueUltra-high-frequency master accountsAdded 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:

  1. Send a result-inquiry (original transaction confirmation) message to ask the counterpart system for the outcome. The global transaction id is the trace key.
  2. 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.
  3. 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.

AspectOnlineBatch
UnitOne transactionAll accounts or extracted targets
Time constraintTens to hundreds of msBatch window (tens of minutes to hours)
Typical workDeposits, withdrawals, transfers, inquiriesInterest accrual, maturity processing, dormancy, balance verification
Failure handlingImmediate rejection/compensationRestart, 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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).

ItemTypical Target Level
Normal core transaction volumeHundreds to thousands per second
Peak (payday, pre-holiday)3x to 10x normal
Online response timeWithin 100ms inside the core, less for simple inquiries
Availability target99.9 percent or higher per year (excluding planned downtime), higher for critical paths
Daily batch windowCompletion 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

ScenarioSymptomResponse
Ledger DB failoverTransactions fail for seconds to tens of secondsAutomatic failover, channel retry policy, open-item reconciliation
External line outageAll interbank transfers time outRedundant line switchover, park then bulk-reconcile
Hot-account lock stormDelays propagate from one accountQueueing/throttling, isolate the product's traffic
Batch delayClosing unfinished before business openBatch restart points, prioritize open-critical predecessors
Duplicate message arrivalRisk of double-processingIdempotency 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."

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

TermKorean UsageMeaning
DepositsSu-sinTaking and managing deposits; the liability side of a bank
LendingYeo-sinLoan business; the asset side of a bank
Core banking systemGyejeong-gyeThe system of record holding the ledger
Information system / DWJeongbo-gyeData systems for analytics and reporting
External gatewayDaeoe-gyeMessage integration with outside institutions
LedgerWonjangThe official record of accounts, balances, transactions
Message (telegram)JeonmunFixed-format transaction messages between systems
Posting dateGyeri-iljaThe business date a transaction is attributed to
EOD closingIl-magamThe per-business-day settlement and cleanup batch
Daily accumulated balanceIl-jeoksuRunning total of daily balances; basis of interest
Uncleared itemsTajeom-gwonChecks and bills not yet settled
ReconciliationDaesaVerifying agreement between two records
Compensating transactionBosang-georaeAn opposite transaction offsetting the original
Dormant depositsHyumyeon-yegeumDeposits 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