Build a catalogue-to-order vertical slice
The capstone is a small e-commerce learning application. Its first milestone uses a fictional catalogue and creates unpaid demo orders. Real payments, shipping and customer data require additional review and provider integration; do not simulate a successful payment by changing a browser flag.
Acceptance criteria
- Public users can browse active products and see clear loading/error states.
- A signed-in user can submit product IDs and integer quantities.
- The server obtains current prices and stock from the database.
- Order and inventory writes either commit together or roll back together.
- A user can view only their own orders; an admin update needs explicit authorization.
Data model
product(id, title, price_minor, stock, active)
app_user(id, email, password_hash)
customer_order(id, user_id, status, total_minor, created_at)
order_item(order_id, product_id, title_snapshot, unit_price_minor, quantity)
order_request(user_id, idempotency_key, request_hash, order_id)Use primary/foreign keys, nonnegative price/stock constraints and positive quantity constraints. An order item stores historical title and price so later catalogue edits do not rewrite a past order. Define currency and rounding explicitly.
API contract
GET /api/products
GET /api/products/:id
POST /api/orders authenticated, validated, idempotent
GET /api/me/orders authenticated, ownership-scoped
GET /api/orders/:id authenticated, ownership-scopedA create request sends identifiers, quantities and an idempotency key, not an authoritative price or user ID. Bound item counts and quantities. A repeated key with the same normalized request returns the original result; the same key with different content should be rejected as a conflict.
Server transaction outline
authenticate and validate request
begin transaction
claim/check idempotency key under a unique constraint
load product rows in a consistent order with appropriate locks
reject missing, inactive or insufficient-stock products
compute total from server prices with overflow checks
insert order and historical line items
decrement stock with a concurrency-safe condition
associate the completed order with the idempotency record
commit
return created order
on failure: rollback and return a documented errorThis is design pseudocode, not a ready-made transaction library. Choose locking, isolation and retry behavior for the actual database. A “check stock” query outside the write transaction is vulnerable to concurrent purchases.
Frontend state
Keep cart quantities local for convenience, but show server-confirmed totals when creating the order. Disable duplicate submission while a request is pending without treating that as the only duplicate protection. If the network response is lost, retry with the same idempotency key rather than making a new order blindly.
Milestones and tests
- Catalogue: seed three products and render the same titles in the browser.
- Cart: add/remove quantities and test empty/invalid states.
- Orders: create an unpaid demo order and verify stored line totals.
- Concurrency: attempt two orders for the last unit; at most one should succeed.
- Retry: send the same request/key twice; one order should exist.
- Access: user B must not read user A's order by changing its ID.
- Failure: force a write failure after order insertion and verify transaction rollback.
What to submit
Provide the source repository, environment-variable template without secrets, migrations, seed data, documented API responses, automated tests and a deployment/rollback guide. Demonstrate the vertical slice before adding coupons, reviews or payment providers. This capstone integrates earlier lessons; its transaction outline must be implemented and tested in the chosen stack rather than presented as a completed production store.