Software Development
We helped evolve a multi-tenant auction platform from a Laravel and Vue application using Redis, Pusher, and a dedicated Node.js timing service into a new architecture that separates Laravel domain APIs from a TypeScript event-sourcing engine built around Redis Streams and WebSockets.
Client: Confidential European Auction Platform
Industry: Online Auctions
The Client
A European technology company operates a multi-tenant platform for online and hybrid auctions. Multiple organizers use individually branded websites while sharing a common auction engine.
The Challenge
An auction platform is not a conventional marketplace. Once bidding begins, timing and ordering become part of the business logic. Competing bids can arrive almost simultaneously, late bids can extend a lot's closing window, and every connected participant must see the same price, bidder status, and countdown. The platform also has to isolate multiple organizers, support localized catalogs and pedigree data, and continue evolving while live auctions remain operational.
We helped develop the original production platform and are now contributing to its event-driven rebuild.
The first generation was built as a multi-tenant Laravel application with a Vue.js frontend.
Laravel managed the platform's principal workflows:
Redis supported caching, queues, and short-lived auction state. Pusher delivered bid updates to connected browsers so bidders and auction operators could see changes without repeatedly refreshing the page.
This architecture allowed different auction organizers to share a common codebase while maintaining separate branding, settings, catalogs, users, and operational rules.
The late-bid extension phase introduced a particularly difficult requirement.
When a qualifying bid is placed near the end of a lot, the auction must extend the closing window. Every connected client must receive the new deadline, and the server—not an individual browser—must remain the authority on when bidding ends.
A separate Node.js application coordinated auction scheduling and time synchronization. It managed the dynamic bidding timer outside the normal Laravel request lifecycle and supplied a consistent time reference to connected clients.
The original system therefore combined several specialized components:
This system supported live auction operations, but its growth exposed an architectural limitation: the active auction state was distributed across the database, Redis, scheduled jobs, and connected clients.
Real-time bidding is fundamentally a sequence of events:
Treating these steps only as database updates makes concurrency and recovery increasingly difficult. If a failure occurs between two steps, the system must determine what was accepted, what was persisted, and which updates reached connected clients.
The next generation needed one authoritative and reproducible history of each auction.
The platform is now being rebuilt with Laravel as the API and domain layer.
Laravel owns the durable business model: tenants, users, permissions, auctions, lots, products, pedigrees, media, administrative workflows, and other transactional operations.
Time-sensitive auction execution is handled by a TypeScript service designed around event sourcing. Rather than treating the latest database row as the complete truth, bidding actions are written as ordered events to Redis Streams. The real-time service consumes those events and computes the current auction state.
Events can represent operations such as:
This provides a chronological record of how an auction reached its current state.
The event stream allows the TypeScript service to rebuild active auction state after a restart by replaying recorded events.
The service no longer has to infer the last valid combination of cache entries, timers, and database values. It can reconstruct the state from the same ordered history that originally produced it.
This creates a stronger foundation for:
The relational database remains the durable system of record for the wider platform, while the event stream provides the history required to calculate active real-time state.
WebSockets distribute computed auction state to browsers and administrative interfaces.
Instead of requiring every frontend to reconstruct the result of individual events, the real-time service produces an authoritative auction view. Connected clients subscribe to the auctions they are authorized to follow and receive updates as state changes.
This supports:
The WebSocket boundary also applies authorization rules so application permissions cannot be bypassed through the real-time channel.
The existing platform could not stop evolving while the new architecture was developed.
The original Laravel and Vue system continued receiving production features, fixes, translations, import improvements, and auction-specific changes. In parallel, functionality was progressively redesigned across the Laravel API, TypeScript real-time engine, and modern frontend.
This required distinguishing between:
The result is more than a framework upgrade. It is a gradual transition from a real-time-enabled web application to a platform where real-time auction execution is treated as a dedicated domain.
The original platform established a dependable multi-tenant foundation for online and hybrid auctions.
The ongoing rebuild preserves accumulated business knowledge while giving real-time bidding a more explicit architecture. Laravel owns transactional APIs and durable workflows. TypeScript processes ordered auction events. Redis Streams provide replayable event history, and WebSockets distribute authoritative state to connected users.
The project demonstrates an important principle: when timing, concurrency, and recovery directly affect commercial outcomes, real-time behavior should be designed as a first-class system.