Auction State and Data Flow
Relevant source files
The following files were used as context for generating this wiki page:
The auction system manages the lifecycle of advertisement placements on the simulated vehicle. It coordinates bid validation, payment processing through Stripe, and real-time state synchronization across clients using Cloudflare Durable Objects and WebSockets.
The core of the system is the Auction Durable Object, which persists state in an internal SQLite database and manages media storage in R2. This ensures that every bid, placement, and artwork upload is processed atomically and broadcasted to all connected observers immediately upon payment confirmation.
System Architecture
The architecture consists of a frontend React application, a Cloudflare Worker acting as the API gateway, and a Durable Object for state management. The Durable Object serves as the single source of truth for the auction's SQL database and R2 artwork storage.
The diagram shows the communication flow between the user interface, the serverless worker, the stateful Durable Object, and external storage/payment services.
Sources: apps/website/worker/auction.ts:63-95, apps/website/README.md:1-20
Data Models
The system uses SQLite to track bids, active placements, and outbid notification queues.
Database Schema
| Table | Purpose | Key Fields |
|---|---|---|
bids | Records every bid attempt and its status. | id, amount, status, published_at, payment_id |
placements | Maps slot_id to the current winning bid_id. | slot_id, bid_id |
uploads | Tracks temporary artwork tokens before publication. | token, bid_id, created_at |
outbid_emails | Queue for outbid notifications to previous owners. | previous_bid_id, status, attempts |
Sources: apps/website/worker/auction.ts:46-75
Bid States
Bids transition through several states depending on payment success and auction competition:
- pending: The bid is created but payment is not yet verified.
- won: The payment is successful, and the bid is currently active on the car.
- outbid: The bid was previously active but has been replaced by a higher bid.
- refund_pending / refunded: The payment was successful, but a higher bid was published first, triggering an automatic refund.
- expired: The checkout session was not completed within the allowed timeframe.
Sources: apps/website/worker/auction.ts:463-485, apps/website/src/components/auction-site.tsx:135-155
Bid Submission and Payment Flow
The bid process requires validated artwork uploads and a successful Stripe Checkout session.
This sequence illustrates the path from initial artwork upload to the final publication broadcast.
Sources: apps/website/worker/auction.ts:340-450, apps/website/src/components/bid-dialog.tsx:100-150
Transactional Integrity
When a payment is fulfilled, the Durable Object executes a synchronous SQL transaction to:
- Update the current bid status to
won. - Update the previous bid for that slot to
outbid. - Update the
placementstable to point to the new bid. - Increment the global
revisioncounter. - Enqueue an outbid notification in
outbid_emails.
Sources: apps/website/worker/auction.ts:467-505
Real-time Synchronization
Clients maintain a live connection to the Auction Durable Object to receive updates without refreshing.
WebSocket Data Flow
The useAuction hook manages the client-side connection logic.
- Initial Load: The client fetches the current
AuctionSnapshotviaGET /api/auction. - Heartbeat: The client sends "ping" every 25 seconds; the server responds with "pong".
- Updates: Whenever a transaction completes, the server calls
broadcast(), sending the fullAuctionSnapshotto all connected WebSockets. - Version Control: Clients compare the
revisionnumber in the snapshot to ensure they only process newer state.
Sources: apps/website/src/components/use-auction.ts:7-60, apps/website/worker/auction.ts:145-155
The Auction Snapshot
The snapshot sent to clients contains all data needed to render the car livery and leaderboard.
type AuctionSnapshot = {
activeSlotIds: string[];
revision: number;
placements: Record<string, Placement>;
history: Placement[];
highestBids: Placement[];
totalRaised: number;
online: number;
paymentsEnabled: boolean;
};
Sources: apps/website/worker/auction.ts:108-144, apps/website/src/lib/auction.ts
Automated Recovery and Alarms
The Durable Object uses an alarm system to reconcile inconsistent states caused by network failures or missed webhooks.
- Checkout Reconciliation: The alarm checks
pendingbids with Stripe sessions older than 1 minute to see if they were paid but the webhook was missed. - Refund Processing: Retries any bids stuck in
refund_pendingstate. - Email Retries: Processes the
outbid_emailsqueue with exponential backoff for failed deliveries. - Cleanup: Deletes
uploadsthat are older than 24 hours and not associated with a published bid.
Sources: apps/website/worker/auction.ts:592-645
Summary
The Auction State and Data Flow ensures a competitive, fair, and real-time environment for advertisers. By leveraging Durable Objects, the system achieves strict transactional consistency for payments while providing low-latency updates to all visitors through WebSockets. The combination of SQL persistence and automated alarm-based recovery maintains system reliability even during external service interruptions.