This question evaluates full‑stack engineering competencies including API design, data persistence, input validation, transactional integrity for monetary data, frontend-backend integration, automated testing, and developer documentation.
Using an AI coding tool of your choice (e.g., Cursor), build a minimal full‑stack web application that supports simple monetary transactions and account balances. Requirements: expose a REST or GraphQL API for creating transactions (credit/debit), persist data (in‑memory or lightweight DB is acceptable), provide a simple frontend to submit and view transactions, validate inputs, prevent negative balances, and include basic tests. Provide setup instructions and a concise README.
Quick Answer: This question evaluates full‑stack engineering competencies including API design, data persistence, input validation, transactional integrity for monetary data, frontend-backend integration, automated testing, and developer documentation.
Build a minimal full-stack app for monetary transactions
This is the "AI coding" round: using an AI coding tool of your choice (e.g., Cursor), build a small but correct full-stack web application that supports basic monetary transactions and account balances. You will be evaluated on correctness and judgment, not on breadth or styling — the scenario is deliberately small so the money-correctness decisions stand out.
Build the following:
Backend API
— expose either a REST
or
a GraphQL API (pick one) that can:
Create accounts.
Post a transaction (credit or debit) against an account.
Retrieve accounts (with current balance) and a list of transactions.
Data persistence
— an in-memory store or a lightweight database is acceptable.
Frontend
— a simple page that lets a user create an account, submit a credit or debit transaction, and view the current balance plus recent transactions.
Validation and business rules
— validate inputs (non-negative amounts with up to 2 decimal places, required fields) and prevent negative balances (reject any debit that would drive an account below zero).
Developer experience
— a concise README with setup/run instructions, an API summary, and any assumptions.
Deliverables: source code for backend and frontend, runnable tests with instructions, and the README. Money must be handled precisely — avoid floating-point errors. Keep the UI minimal; functionality matters far more than styling.
Constraints & Assumptions
Single currency per account is acceptable; cross-account transfers are out of scope unless you choose to add them.
In-memory persistence is explicitly allowed (data may be lost on restart).
No authentication/authorization is required.
Amounts are non-negative decimals with at most 2 decimal places.
Optimize for
correctness and clarity over breadth
— a small, correct app beats a large, leaky one.
Clarifying Questions to Ask Guidance
REST or GraphQL — is one preferred, or is the choice mine as long as it's justified?
Is the in-memory store acceptable for the final submission, or should I demonstrate a real (e.g., SQLite/Postgres) persistence path?
Should a transaction be a single-leg posting (credit/debit on one account), or do you want true double-entry transfers between two accounts?
What should the API return on an overdraw or a malformed amount — which HTTP status codes and error shapes do you expect?
Is multi-currency or FX in scope, or one currency per account?
How much should I invest in the UI vs. the backend/tests, given the time box?
What a Strong Answer Covers Guidance
A strong submission demonstrates the following dimensions:
Money representation
— amounts stored as integer minor units (cents), with strict parsing/formatting and no floating-point arithmetic anywhere in the money path.
Atomic, race-free debits
— the overdraw check happens
inside
the write (conditional update or row lock), not as a separate read-then-write; the candidate can articulate why the naive version is wrong under concurrency.
Clear data model & invariant
— accounts vs. transactions, balance as a derived/denormalized value, and the explicit
balance == Σ(credit) − Σ(debit)
invariant.
Clean API contract
— sensible endpoints/verbs and consistent status codes for success, validation failure, overdraw, and missing account; well-formed request/response shapes.
Validation coverage
— required fields, amount format (≤ 2 decimals, non-negative), unknown transaction type, and unknown account all rejected with clear errors.
Tests that prove correctness
— happy path plus error cases (overdraw, malformed amount, unknown account) and, ideally, a unit test that pins the money-precision behavior (e.g.,
0.29
parses exactly).
Judgment about scope
— explicitly naming what was simplified (single-process, in-memory, single-leg) and how it would generalize, rather than silently shipping a happy-path toy.
Developer experience
— a README that lets the interviewer run the app and tests in minutes, with assumptions stated.
Follow-up Questions Guidance
Your in-memory implementation is "safe" today because Node is single-threaded — exactly where does that safety break, and what's the minimal change to keep debits race-free across multiple processes?
A client times out and retries
POST /transactions
. How do you prevent a double-charge? Sketch the idempotency mechanism.
One account receives a high rate of concurrent debits and becomes a hot row. What's the bottleneck, and how would you scale past it?
Brex deals in real ledgers — how would you evolve this single-leg model into double-entry, and what new invariant does that introduce? How do you handle a reversal/refund without mutating history?