feat(maison): Clude Maison auction house — lot 0047 + bidding API - #109
Open
sebbsssss wants to merge 1 commit into
Open
feat(maison): Clude Maison auction house — lot 0047 + bidding API#109sebbsssss wants to merge 1 commit into
sebbsssss wants to merge 1 commit into
Conversation
Ships the Sotheby's-style auction extension of clude.io as a self-
contained vertical, mounted at /maison and backed by /api/maison/*.
Frontend (apps/web/public/maison/)
- index.html — fetches the lot from /api/maison/lot/0047 before
mounting React, falls back to bundled snapshot if API is down.
- palazzo.jsx — single 1280px design surface (Bodoni + parchment +
gilt). PalazzoBidPanel POSTs bids to the API, polls for
competing bids every 8s, surfaces 409 "bid too low" errors,
disables the modal during submission.
- lot-data.js — currency formatters + LOT_FALLBACK snapshot +
window.maisonApi.{fetchLot, placeBid, refreshBids}.
- styles.css, assets/, fonts/ — copied verbatim from the design
bundle.
Backend (apps/server/src/routes/maison.routes.ts)
- GET /api/maison/lot/:lotNumber — full lot
- GET /api/maison/lot/:lotNumber/bids — live state for poll
- POST /api/maison/lot/:lotNumber/bid — { amount, paddle }
Validation: zod-checked payload, paddle limited to safe charset,
amount must be ≥ currentBid + bidIncrement, returns 409 with
canonical state on collision so the client can resync. Mounted
behind the existing apiLimiter (200/min).
State: in-memory ring buffer keyed by lotNumber. Single Railway
process — restart wipes bids. Promotion to Supabase
auction_lots/auction_bids tables + wallet-sig-verified bids is
the natural follow-up; flagged in the route file header.
Routing
- /maison and /maison/ rewrite to /maison/index.html via the
existing static-routes pattern.
- Subpaths (palazzo.jsx, styles.css, fonts/, assets/) served by
the existing express.static mount on apps/web/public/.
Tests
- 7/7 passing in apps/server/src/routes/__tests__/maison-routes.
test.ts: lot fetch (200 + 404), live state, place valid bid,
reject below increment, reject malformed payload, reject paddle
with HTML injection chars.
Honest limits flagged for follow-up
- In-memory state (single instance, restart-wipes)
- No wallet sig on POST /bid (anyone can claim a paddle)
- No settlement worker on endsAt
- Babel-in-browser transpiles palazzo.jsx per request — fine for
prototype, esbuild pre-build is a hardening item.
Not landed here
- Landing page link to /maison (held until product is announced).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships the Sotheby's-style auction extension of clude.io as a self-contained vertical, mounted at
/maisonand backed by/api/maison/*. Single live lot (0047 —truth_terminal), USDC bids with optimistic UI + server-side persistence, transparent provenance + comparables.Built from a Claude Design handoff bundle. The 1280px composition is preserved exactly; production hardening items are flagged.
What ships
Frontend —
apps/web/public/maison/index.htmlfetches the lot from/api/maison/lot/0047before mounting React; falls back to a bundled snapshot if the API is unreachable.palazzo.jsx— Bodoni + parchment + gilt. `PalazzoBidPanel` POSTs bids to the API, polls for competing bids every 8s, surfaces 409 "bid too low" errors, disables the modal during submission.lot-data.js— currency formatters, `LOT_FALLBACK` snapshot, `window.maisonApi.{fetchLot, placeBid, refreshBids}`.styles.css,assets/*.svg,fonts/Inconsolata-Variable.ttf— copied verbatim from the design bundle.Backend —
apps/server/src/routes/maison.routes.tsGET /api/maison/lot/:lotNumber— full lot dataGET /api/maison/lot/:lotNumber/bids— live state only (for polling)POST /api/maison/lot/:lotNumber/bid— `{ amount, paddle }` (zod-validated)Bid validation:
Routing — `/maison` and `/maison/` rewrite to `/maison/index.html` via the existing static-routes pattern. Subpaths served by the existing `express.static` mount on `apps/web/public/`.
Test plan
Honest limits flagged for follow-up
Not landed here (deliberately)
🤖 Generated with Claude Code