Projects
Back Projects

Banking Demo: Mini Banking Platform

Banking Demo: Mini Banking Platform
  • Client Personal project
  • Category FinTech Demo
  • Date February 3, 2026

Banking systems look simple on the surface: “move money from A to B.” This project shows the less visible part—keeping balances correct under errors and parallel requests, while still providing a friendly UI people can actually use.

Links

What this project does

Banking Demo is a mini banking platform with a few core flows:

  • View wallet balances (USD and EUR)
  • Transfer funds between users (same currency)
  • Exchange currency inside a single user’s wallets (USD ↔ EUR using a fixed rate)
  • Browse transaction history

It’s intentionally small, but it tries to be strict about money rules.

How the system is structured

The app uses a classic three-piece setup:

  • A web UI built with Next.js (React)
  • A Go API built with Gin
  • PostgreSQL as the source of truth for balances, transactions, and ledger entries

It’s not a microservices playground. The backend is one service with clear internal layers (routes → services → repositories), which keeps the code easier to read and reason about.

The “money move” part: correctness and audit trail

The main goal of this demo is correctness:

  • Atomic updates: a transfer should never debit without also crediting
  • Consistent state: balances and ledger entries should not drift apart
  • Concurrency safety: two requests should not be able to spend the same money
  • Auditability: every balance change should have a clear trail

To do that, the backend uses:

  • A double-entry ledger (each operation writes the matching negative/positive entries)
  • A single database transaction for each transfer/exchange
  • Row-level locks (SELECT ... FOR UPDATE) so concurrent requests serialize where they must
  • A “check funds after locking” approach to avoid timing bugs

Balances are also stored in an accounts.balance column for fast reads in the UI, while the ledger stays the clean record of movement.

Authentication and session behavior

The API uses JWT with HTTP-only cookies:

  • token for access
  • refresh_token for refresh

From the UI side, requests use cookies (credentials: "include"). If the API returns 401, the client attempts a refresh once and retries the original call. That keeps tokens out of browser storage and makes the app feel session-based.

Tech choices (and why they fit)

A few choices are very intentional:

  • PostgreSQL + transactions: strong consistency is the simplest way to keep invariants clear
  • Decimal money math: the backend uses decimal arithmetic (no floats) to avoid rounding surprises
  • Swagger/OpenAPI docs: the API surface is easy to explore and test
  • Integration tests with a real Postgres (Testcontainers): correctness is hard to prove with mocks alone

On the frontend, React Query helps keep server state predictable (loading, caching, refetching), and Zod-based validation provides quick feedback on forms.

What’s intentionally missing

This is a demo, so a few production needs are left out on purpose:

  • No user registration (users are pre-seeded in migrations)
  • No realtime updates (balances refresh via polling)
  • No idempotency keys (a retry could create duplicate operations)
  • Limited currencies and a fixed exchange rate
  • No periodic reconciliation job that recomputes balances from the ledger and reports drift

Those gaps are not “mistakes.” They are scope limits, and they make room to focus on the core: safe money operations.

Where this could go next

If you wanted to push this toward a more complete system, the next steps are clear:

  • Add idempotency keys for transfer/exchange requests
  • Add a reconciliation job (ledger sums vs balances)
  • Expand statement and filtering features (date ranges, exports)
  • Add rate limiting, structured logging, and basic tracing
  • Improve security hardening (CSRF strategy for cookie auth)

Summary

Banking Demo is a compact reference project for transactional money flows. It combines a clean web UI with a backend that treats correctness as the product—atomic updates, concurrency control, and a ledger trail that makes every change explainable.