Skip to content

imharjot/drophouse

Repository files navigation

DropHouse

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.

The demo

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.

Stack

pnpm workspace, two packages:

  • server/ — Fastify + TypeScript, a long-lived process hosting the bid HTTP API and a WebSocket gateway. PostgreSQL via pg, with an append-only bid_events table plus projected lots / lot_state rows. 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.

Run it locally

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:web

Then 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:web

Tests

pnpm test

There 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.

Layout

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

About

A real-time timed-drop auction with a no-oversell bid core — server-authoritative anti-snipe clock and a replayable append-only bid ledger.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages