A real-time timed-drop auction. One scarce lot, many buyers racing for it, a hard deadline. The whole point is staying correct while everyone hammers the same lot at once: bids are totally ordered, accepted at most once, written to an append-only ledger you can replay, and the clock is the server's, not the browser's.
Open a drop room in two browser tabs and try to break it. Each tab is a separate bidder. Race yourself — fire two bids at the same instant for the same amount. One tab wins and leads; the other gets a clean "outbid" with no double-award and no oversell. Bid in the last few seconds and watch the countdown extend itself. Then open the audit page and replay the whole thing tick by tick, re-derived straight from the event log.
pnpm workspace, two packages:
server/— Fastify + TypeScript, a long-lived process hosting the bid HTTP API and a WebSocket gateway. PostgreSQL viapg, with an append-onlybid_eventstable plus projectedlots/lot_staterows. Inputs validated with Zod.web/— Next.js (App Router) + React + Tailwind. A drop-room page with a live countdown, a live bid feed over WebSocket, and a place-bid form with optimistic feedback reconciled against server truth.
See DESIGN.md for how correctness-under-contention actually works.
Requires Node 20+, pnpm, and Docker (for Postgres).
pnpm install
# 1. start postgres
docker compose up -d
# 2. create the schema
pnpm db:migrate
# 3. seed a few live lots
pnpm db:seed
# 4. run the api (long-lived process, defaults to :4000)
pnpm dev:server
# 5. in another shell, run the web client (:3000)
pnpm dev:webThen open http://localhost:3000, pick a lot, and open it in two tabs.
Config lives in environment variables (see .env.example). The defaults assume the
docker Postgres and the API on :4000. If port 4000 is taken, set PORT on the
server and point the web client at it:
PORT=4100 pnpm dev:server
NEXT_PUBLIC_API_URL=http://localhost:4100 NEXT_PUBLIC_WS_URL=ws://localhost:4100 pnpm dev:webpnpm testThere are two kinds:
- Pure unit tests (no database) for the bid-decision and replay logic. These run anywhere.
- A concurrent-bidder integration test that fires 50 simultaneous bids at one lot and asserts exactly one winner, one accepted event, gapless ordering, and an idempotent replay. It needs the docker Postgres; if none is reachable it skips cleanly with a message instead of failing.
server/
src/
domain/ pure logic: bid decision, anti-snipe, replay (unit-tested)
services/ bid write path (per-lot critical section + atomic write)
db/ pool, schema, migration runner, seed, repositories
routes/ http endpoints (lots, bids, audit)
ws/ websocket gateway + in-memory room hub
test/ concurrent-bidder integration test + helpers
web/
src/
app/ next routes: home, drop room, audit
components/ countdown, bid form, drop room
lib/ api client, ws hook, types, formatting