Bidding against a price that already changed
Active participants need the latest accepted bid and closing time without repeatedly refreshing. A bid placed against a stale price is not a bid anyone can honour.

BidRush is a cross-platform auction marketplace for live bidding — discovery, real-time bid updates, soft-close extensions and an integrated payment flow, with the backend holding sole authority over auction state on iOS and Android.
Server-authoritative bidding.
Safe on a bad connection.

Two phones can submit valid-looking bids against the same displayed price. The server has to decide which transition is real, and prevent a race in the auction record.
Follow a bid ↗Consumer marketplace / auctions
Real-time mobile auction platform
Product architecture to real-time backend
A marketplace built mainly on CRUD APIs and periodic polling produces visible inconsistencies: outdated prices, conflicting bids, unfair last-second outcomes, duplicate bid requests and delayed post-auction settlement.
Live auctions happen on real mobile networks. A bidder can lose connectivity after the server accepts a bid but before the app receives the response — so retries, reconnection and authoritative recovery have to be part of the design rather than an afterthought.
BidRush was built around a different principle: the backend remains the authoritative auction engine, while mobile clients receive fast real-time updates and recover safely whenever connectivity changes.
Active participants need the latest accepted bid and closing time without repeatedly refreshing. A bid placed against a stale price is not a bid anyone can honour.
Two devices submit valid-looking bids against the same displayed price. The server must decide which state transition is valid and prevent a race condition in the auction record.
If payment readiness is only checked after an auction closes, sellers end up with a winner who cannot complete. Payment authorization had to become part of the bidding lifecycle.
Four views of the delivered application.
Each shows another step from browsing a listing to capturing the winner's payment.

Buyers browse listings and open the auctions they want to follow, with seller media delivered through S3 and CloudFront rather than repeatedly pulled from a single origin.
Browse→Join room→Bid→Validate→Soft close→Win→Capture
Every bid is validated by the backend against the current auction state, official server time, the minimum next amount, bidder eligibility, payment readiness, an idempotency key and the auction version. The phone's opinion of the price is never the deciding factor.
That is also what makes reconnection safe: the client does not assume it received every event. It loads an authoritative snapshot, subscribes to what follows, and refreshes the snapshot again after any reconnection.
Look under the hood ↘Bid submission stays an authenticated request with transactional semantics. Socket.io carries continuous event delivery, but it is not the transport a bid depends on.
The auction record moves to the new price and version, and the change is published to every connected participant and pushed to those who are not.
A bid below the minimum, against a stale version, or from an ineligible bidder is refused outright — the auction record never enters an ambiguous state.
Each bid carries a stable idempotency key, so a retry returns the original outcome rather than placing a second bid — which matters most in exactly the moments the network is worst.
A valid bid in the final 60 seconds extends the auction by 60 seconds, subject to a configured cap, so outcomes reflect intent rather than network timing.
The split runs through the whole stack: PostgreSQL holds what must be correct, Redis and Socket.io distribute what must be fast, and Stripe decides what must be paid — none of them standing in for another.
A shared iOS and Android product experience, with typed application contracts and platform-appropriate secure storage.
iOS and Android can drift into separate feature implementations. A shared foundation keeps auction behaviour identical on both, which matters when the rules decide who wins.
Explicit domain modules for identity, auctions, the bidding engine, listings, payments and notifications.
The backend can hold clear domain boundaries without taking on service-management overhead that the product does not yet need.
The authoritative record for auctions, bids, users and transaction state.
Deciding which of two simultaneous bids is valid is a transactional question. It needs a store that can refuse the second one.
Fast distribution of accepted auction changes out to connected clients.
PostgreSQL is truth; Redis is speed. Conflating the two would either slow the auction record down or make the fast path authoritative.
Persistent connections delivering live price, status and closing-time changes to active auction rooms.
Continuous delivery and transactional commands are different guarantees. The socket keeps everyone current; the bid itself stays a request that can be retried safely.
Tokenization and authorization during bidding, capture after the auction closes, with webhooks reconciling asynchronous payment state.
Its role is not checkout. Establishing payment readiness during the auction is what reduces winners who cannot complete the purchase.
The confirmed implementation is React Native with Expo, Node.js/Express, PostgreSQL, Redis Pub/Sub, Socket.io, Stripe authorization and capture, Amazon S3, CloudFront, APNs and Firebase Cloud Messaging. The source also documents a deeper production-grade AWS reference architecture; those components are architectural extensions rather than confirmed deployed infrastructure, and are not claimed here.
Technology names identify the documented implementation, not partnerships or endorsements.
Bring one flow where timing decides an outcome — bidding, booking, inventory, allocation. In 30 minutes, we will map where your state actually lives, and what a client is currently allowed to assume that it should not.
30 minutes · Your marketplace, timing and settlement