Interview concept

Payment Ledger Data Modeling and Money Movement Invariants

Asked of: Software Engineer

Last updated

What's being tested

This topic tests whether you can model money as an auditable, immutable history rather than as a mutable balance field. The interviewer is probing your understanding of double-entry accounting, idempotency, transaction boundaries, retries, and invariants that must remain true during concurrent or partially failed operations. Google cares because payment-like systems combine correctness, durability, and distributed-systems failure modes: a small modeling error can create duplicated funds, lost funds, or an audit trail that cannot explain what happened.

Core knowledge

  • Double-entry bookkeeping represents every movement with balanced postings: total debits equal total credits. For every journal entry, ∑debit=∑credit\sum \text{debit} = \sum \text{credit}; never create money by updating only a sender or recipient balance.

  • Model an immutable journal entry with an entry_id, operation or transfer ID, creation time, currency, and one or more ledger postings. Each posting identifies an account, direction, amount, and currency; corrections append reversing entries rather than mutating history.

  • Store amounts as integer minor units—for example, cents—not floating-point values. Enforce amount > 0, a supported currency, and currency-specific scale; USD 10.25 becomes 1025, while zero-decimal currencies require different validation.

  • Separate the ledger of record from a materialized balance. The ledger is authoritative and append-only; balances are cached projections that can be rebuilt by summing postings. This makes corruption detectable and supports audit, replay, and backfills.

  • Use a client-supplied idempotency key scoped to the operation and authenticated caller. Persist the key with the normalized request and final result; a retry returns the original result, while reuse with different parameters fails rather than creating another transfer.

  • Define explicit money-movement states, such as PENDING, POSTED, FAILED, and REVERSED. A payment authorization, capture, settlement, refund, and chargeback are distinct business events; do not overload one status to represent all of them.

  • Make the posting transaction atomic in a storage system such as Spanner, Postgres, or another strongly consistent database: validate accounts and currency, insert the journal entry and postings, and update any balance projection in one commit.

  • State invariants precisely: postings for one committed transfer balance to zero; account balances equal opening balance plus posted signed postings; a transfer cannot be posted twice; and no account may become negative unless overdraft is explicitly supported.

  • Handle concurrency with serializable transactions, conditional writes, or per-account version checks. A check-then-update sequence under weaker isolation can allow two withdrawals to observe the same balance and both succeed.

  • Treat external effects separately from ledger commits. Use an outbox pattern to publish a durable “transfer posted” event after the database transaction; consumers must also be idempotent because delivery can be duplicated.

  • Design reconciliation as an independent correctness boundary. Compare internal postings with processor settlement files or bank statements using stable external IDs, then represent discrepancies as explicit cases or correcting entries—not silent balance edits.

  • Decide what “atomic” means across system boundaries. Internal accounts can commit atomically, but a bank or card network cannot join your transaction; use a saga, compensating reversal, and durable state transitions for failures after external submission.

Worked example — Payment Ledger Data Modeling and Money Movement Invariants

I would first clarify whether the prompt asks for an internal wallet transfer, card payment, or settlement flow, and whether pending funds, fees, multiple currencies, and overdrafts are required. I would declare that amounts are integer minor units, the ledger is append-only, and a successful transfer must produce balanced postings in one strongly consistent transaction. I would organize the answer around four pillars: the account and posting schema, the transfer state machine, idempotent request handling, and invariant enforcement plus reconciliation. For a wallet transfer, I might create a journal entry with debit and credit postings, reserve or validate available funds, commit the entry, and derive balances from the ledger or a verified projection. I would explicitly choose serializable isolation or optimistic version checks to prevent concurrent withdrawals from violating the nonnegative-balance rule. I would also flag that publishing notifications is not part of the database transaction, so an outbox and idempotent consumers are needed. I would close by saying that, with more time, I would specify retention, audit access, disaster recovery, multi-region consistency, and reconciliation workflows.

A second angle

The same model applies differently to a card payment, where authorization may place a hold before capture creates final ledger postings. The key distinction is that a processor timeout does not prove failure, so retries require an idempotency key and lookup by the processor’s external reference. A strong design separates authorization, capture, refund, and chargeback events instead of treating them as balance updates. It also models fees and currency conversion explicitly so the merchant, customer, processor, and fee accounts remain balanced.

Common pitfalls

Pitfall: Treating balance as the source of truth and updating sender and recipient rows independently can lose money when one write succeeds and the other fails. Use an immutable balanced journal and derive or verify projections.

Pitfall: Saying “use a unique idempotency key” without defining its scope, stored response, parameter mismatch behavior, and lifecycle leaves retries underspecified. Explain what happens when the first request is still processing or the client retries after a timeout.

Pitfall: Claiming a distributed transaction makes a bank transfer atomic overstates the guarantee. Distinguish atomic internal posting from asynchronous external movement, then describe durable states, reconciliation, and compensating reversals.

Connections

An interviewer may pivot to distributed transactions, serializability, and the outbox pattern, or ask how to design replayable event consumers. Be ready to connect this model to event sourcing, reconciliation, fraud holds, multi-currency exchange, and disaster recovery without weakening the core invariants.

Further reading

Related concepts