Skip to content
Live-commerce marketplace, Collectibles and resale e-commerce

Live Auction Marketplace

A livestream shopping marketplace where collectors bid live and every auction is provably fair.

Admin auction detail showing a closed lot with its immutable, append-only bid log
A closed auction with its append-only bid log, per-bid server timestamps, bidder IDs, and the anti-snipe-extended close time.

The platform is a livestream shopping marketplace for collectibles and resale, built for launch in the UAE (AED) and Australia (AUD). Sellers broadcast live from their phones and auction items in real time or sell at fixed prices; buyers bid, chat, and check out without leaving the stream; platform staff run approvals, moderation, payments, and disputes from a web admin panel.

We built the entire product across three repositories: a NestJS backend monorepo with dedicated API, realtime, and worker deployables; a Next.js web dashboard serving both the staff admin panel and the seller console; and a Flutter mobile app for iOS and Android. Around the code sits a 30-plus-document normative architecture set, two full codebase audits with file-and-line evidence, and a cloud deployment runbook.

The build ran against a 12-milestone statement of work that began with a two-phone auction proof of concept, correct winner under racing bids, before any product code, and carried that standard of proof through to a scripted acceptance run of the finished bidding engine.

Problem

Three real-time systems, with money in every one of them

Live auction commerce is one of the harder e-commerce categories to build correctly. The product has to keep video, chat, and bidding honest at once while guaranteeing that money-critical events are never ambiguous: two people tapping Buy Now in the same instant must produce exactly one order, a bid arriving in the last second must extend the auction fairly, a video glitch must never corrupt auction state, and every bid must remain provable after the fact.

The two-region launch added a second layer of difficulty. The UAE and Australia differ in currency, tax (VAT versus GST), consumer law, and even in what Stripe offers, Express accounts are unavailable in the UAE, forcing a Custom-account integration with platform-hosted compliance. Region had to be a first-class concept in payments, tax, sale terms, and seller onboarding, not a translation detail.

Public landing page announcing live shopping for collectors in the UAE and Australia
The public brand site, buying and selling happen in the mobile app; this site is the seller and staff console.
Approach

Four decisions, enforced in code rather than convention

Postgres is the system of record and Redis is a derived cache: the bid write path never reads Redis, and a full Redis flush loses no business data. Video and bidding ride separate transports, LiveKit WebRTC carries video while Socket.IO and Postgres carry bids and chat, so a video hiccup cannot corrupt an auction.

The server is authoritative for everything with money in it. Auction timers are absolute server end-times; prices, currency, commission, and tax are computed server-side; no money value is ever accepted from a client. The mobile checkout sends product IDs and an idempotency key, nothing else.

Platform economics are configuration, not constants. Commission rates, tax rates, bid increments, anti-snipe windows, and dispute-hold periods live as settings rows with per-seller, per-category, and default precedence, editable from the admin panel.

Admin dashboard with work-queue tiles for applications, approvals, disputes, and payouts
The operational home: alert tray and work queues for seller applications, product approvals, open disputes, and payouts in escrow.
Solution

An auction engine proven by executed checks, wrapped in a complete marketplace

A dedicated auction module implements bid validation, increment bands, reserve prices, and anti-snipe extension, with exactly one code path allowed to write a bid and exactly one component, the background worker's close ticker, allowed to close a lot. Every accepted bid lands in an append-only log with a millisecond server timestamp and a monotonic sequence number; database triggers refuse edits and deletes, so no API, UI, or administrator can rewrite auction history. A scripted acceptance run against real Postgres and Redis passed all 18 checks, from increment enforcement and idempotent retries to a single close with the winner taken from the log.

Payments span two regulatory regimes. Every seller, order, and payout belongs to exactly one Stripe entity, Australia on Connect Express, UAE on Connect Custom, and the entity is a required argument on every payment operation, so a charge cannot silently route through the wrong platform. The commission engine resolves rates by precedence with VAT or GST on fees as its own line in every money breakdown; refunds reverse commission in the same transaction; paid orders sit in escrow states until delivery confirmation and a configurable dispute-hold window before payout release.

Sellers get a full lifecycle, application queue, Stripe-hosted KYC, product listing with presigned media uploads, scheduled shows, go-live broadcasting with second-camera pairing, shipping labels through EasyPost and Aramex, and earnings with CSV export, mirrored across the mobile app and the web seller console. Staff operate an 18-section admin panel with five server-enforced roles, an append-only audit log, and the ability to join any live stream silently for moderation.

Key features
  • Server-authoritative live auctions

    Bid validation, increment bands, reserve prices, and anti-snipe extension run entirely server-side, with an immutable append-only bid log enforced by database triggers.

  • Live video selling with chat and moderation

    Sellers broadcast through LiveKit with pinned products, reactions, giveaways, and viewer lists; moderation exists at seller level (mute, kick, remove messages) and staff level (silent room join, logged stream termination).

  • Dual-region payments

    Stripe Connect Express for Australia and Connect Custom for the UAE, with a configurable commission engine, VAT/GST on fees, escrow-style payout gating, and commission-reversing refunds.

  • Complete seller lifecycle

    Application, staff approval, Stripe KYC, listing with media upload, scheduled shows, fulfilment via carrier integrations, and earnings tracking, on both mobile and the web seller console.

  • 18-section admin operation

    Auctions with a read-only bid log, orders, disputes with evidence threads, payouts, product approval, moderation, analytics, and staff management under five database-resolved roles.

  • Platform economics as live configuration

    Commission, tax rates, anti-snipe windows, and dispute holds are versioned settings editable from the admin panel, resolved with per-seller, per-category, and default precedence.

Admin order detail showing a server-computed money breakdown for an auction-won order
An auction-won order in AED with the server-computed breakdown: sale price, commission, tax on the fee, and seller net.
Platform settings for commission, anti-snipe, dispute hold, and per-region tax rates
The money and auction rules every other screen reads, commission, anti-snipe, dispute hold, and per-region VAT/GST, under a settings version number.
Product approval queue filtered to pending listings
The moderation view of the catalogue, filtered to listings pending approval.
Roles and permissions screen listing the five system staff roles
Five system staff roles, Owner, Admin, Finance, Moderator, Support, each locked against editing or deletion.
Under the hood
  1. 01

    One bid path, one closer

    All bids pass through a single service that is the only writer to the bid log, and only the worker's close ticker may close a lot, correctness under concurrency comes from eliminating alternative paths, not reconciling them.

  2. 02

    Append-only enforcement in the database

    The bid log, audit log, and order status history refuse UPDATE and DELETE via triggers. Business invariants live as CHECK constraints across 85 reversible migrations, with money stored as bigint minor units.

  3. 03

    Permissions resolved from the database on every request

    JWT claims are never trusted for authorization, so bans, suspensions, and role demotions take effect immediately rather than at token expiry.

  4. 04

    Transactional outbox and idempotency throughout

    Domain events publish inside the caller's database transaction and are consumed idempotently; client-retryable endpoints replay by Idempotency-Key, so a retried bid never writes a second log row.

  5. 05

    Testing against real infrastructure

    713 backend unit tests plus 283 integration tests against real Postgres and Redis in Testcontainers, 212 dashboard unit tests with a multi-role Playwright suite, and 1,190 Flutter widget tests with golden-image regression.

Outcome
  • The scripted bidding-engine acceptance run passed 18 of 18 checks against real infrastructure, covering increment enforcement, idempotent retries, server-side anti-snipe, concurrent-bid sequencing, and single-close-with-correct-winner.
  • Documented suite status at the last report: 713 backend unit, 283 backend integration, and 212 dashboard unit tests passing; 87 of 92 Playwright specs passing; 1,385 mobile tests passing with zero analyzer warnings.
  • The delivered API surface spans 157 paths and 185 operations with 90 registered error codes and 85 database migrations.
  • The platform has not yet launched, so no production or user metrics exist, remaining pre-launch work is tracked openly in the repository's own audit documents.

Next project

Live Shopping PlatformE-commerce and live shopping