Skip to content

How it works

Vladislav Aleshaev edited this page Oct 14, 2026 · 7 revisions

The shape of the system, in short. The full description is one document, complete on its own: How AzureBank works.

The parts

flowchart TB
    Browser["Browser<br/>React 19 SPA"]
    BFF["BFF<br/>ASP.NET Core + YARP"]
    API["API<br/>ASP.NET Core"]
    DB[("SQL Server")]
    Browser -->|"HttpOnly session cookie"| BFF
    BFF -->|"service key + bearer, added server-side"| API
    API -->|"EF Core"| DB
Loading
  • The browser runs the React app. It holds a cookie, never the JWT.
  • The BFF serves the built app, holds the session and is the API's only client.
  • The API owns the money rules.
  • SQL Server is the database, reached through EF Core.
  • The README's diagram has a fifth box, the notice relay, which is outside the path of a request.

The one decision everything follows from

The app in the browser never receives, stores or sends a JWT. Its requests are authenticated by an HttpOnly cookie. The BFF keeps the tokens on the server and adds the bearer header itself.

  • There is no CORS anywhere, because everything is same-origin.
  • The API refuses a request that does not carry the BFF's service credential, with two exemptions: its health probes and, in Development only, the pages of the API's documentation.

The guarantees, and where each is written

Guarantee In short
A payment is applied at most once per key
Read: Moving money once · the proof
Every money move carries an idempotency key, and the server claims the key before it acts. It held under 24 concurrent duplicates on a real SQL Server.
The JWT never reaches the browser
Read: The one decision · where each guarantee stops
The BFF keeps it in a server-side session.
One PIN entry authorises one payment
Read: A second factor
The authorisation is bound to the account, the amount and, for a transfer, the payee, is valid two minutes and is spent once. Three wrong PINs in a row lock the PIN for 15 minutes.
An audit trail that can be checked
Read: A tamper-evident record
Security events go to an append-only, hash-chained table. A tool in the repository walks the chain: it is run by hand, on no schedule, and it does not detect rows cut from the end of the table.
The frontend is held to the API's contract
Read: Three claims about the contract
The committed contract is what the API generates, and one contract suite runs against the mock and the real stack.
One trace per request
Read: Keeping the two halves honest
A request through the BFF is one trace down to SQL, and every error carries its trace id. Traces leave the process only when a collector's address is set in its environment, and the template of the deployed demo sets none. What its containers print goes to a log workspace kept 30 days.

Rules about money

  • One money move is at most €100,000.
  • Transfers to other people are at most €5,000 in a UTC day, by default.
  • There are no optimistic updates on money: a balance comes from a refetch.

Read next

Clone this wiki locally