Make writes safe: transactions, locks and idempotency
Continues from the last build: Every request is authenticated and every row is scoped to its merchant.
A merchant ran a flash sale on a limited drop, 5 units of a sneaker.
What you'll build
A checkout endpoint that survives 20 concurrent requests against 5 units of stock (exactly 5 succeed, 15 get a clean 409), replays the exact same response for a retried Idempotency-Key, rejects a reused key with a different payload as 422, and enforces the order state machine in the database as well as in code so an invalid transition is a 409 no matter which code path tried it.
See how we teach, before you sign up
You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:
// Fires N concurrent checkout requests and reports how many succeeded.
const API_URL = process.env.API_URL ?? 'http://localhost:3000';
const PRODUCT_ID = process.env.PRODUCT_ID ?? '<seed-a-product-and-paste-its-id>';
const CONCURRENCY = 20;
async function checkout(i: number) {
const res = await fetch(`${API_URL}/v1/orders`, {
method: 'POST',
headers: {
'content-type': 'application/json',
authorization: `Bearer ${process.env.API_KEY}`,
},
body: JSON.stringify({
customerId: 'race-test-customer',
items: [{ productId: PRODUCT_ID, qty: 1 }],
}),
});
return { i, status: res.status };
}
async function main() {
const attempts = Array.from({ length: CONCURRENCY }, (_, i) => checkout(i));
const results = await Promise.allSettled(attempts);
const succeeded = results.filter(
(r) => r.status === 'fulfilled' && r.value.status === 201,
).length;
console.log(`succeeded: ${succeeded} / ${CONCURRENCY}`);
}
main();
Reading this file
const CONCURRENCY = 20;matches the brief's 20 concurrent requests against 5 units of stockPromise.allSettled(attempts)allSettled, not all, so a rejected request does not stop you from counting the othersr.value.status === 201counts only true successes, a 409 or 422 is correctly excluded from the success tally
Run this unchanged before and after each fix milestone, it is your one source of truth for whether the bug is gone.
That's 1 of 7 explained code blocks in this single project.
The build, milestone by milestone
- 1
Reproduce the oversell with a concurrency script
5 guided stepsYou cannot prove a fix works if you never measured the bug. A race condition that you cannot reproduce on demand is a race condition you cannot verify you fixed. This milestone gives you the baseline number every later milestone is judged against.
- 2
Fix the stock decrement with a lock or an atomic update
6 guided stepsTwo statements can never be made atomic by adding more application code around them, only the database can guarantee that a read and a write happen without another transaction sneaking in between. This is the difference between an API that is correct under load and one that is correct in demos.
- 3
Make the whole order write atomic
6 guided stepsAn order with line items but no payment intent, or a payment intent with no order, is a support nightmare and sometimes a compliance one. The database's transaction boundary is the only thing that can promise all-or-nothing across four tables in one request.
- 4
Add idempotency keys so retries are safe
7 guided stepsStorefronts and mobile clients retry on timeout, that is correct behavior on their end, but without an idempotency layer every retry is a brand new order to your database. The fix belongs in the same transaction as the order write, not as an in-memory cache that forgets everything on deploy or disagrees across two API instances.
- 5
Enforce the order state machine in code and in the database
6 guided stepsApplication-level validation is only as strong as every code path that writes to the table. A backfill script, a future teammate's one-off query, or a bug in a different route can all write a bad status directly. A database-level backstop makes the invalid state physically unrepresentable, which is a much stronger guarantee than 'we remembered to check'.
What's inside when you start
You'll walk away with
This is portfolio-grade. Build it free.
Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.
Start building