← All technical work

Event-driven Architecture · Order Tracking

Bringing Event-Driven Architecture to a Legacy POS

A scalable enterprise architecture for producing, distributing, and consuming business events across a distributed restaurant estate and cloud applications.

Order tracking required lifecycle events the company's legacy POS was never designed to produce. The resulting architecture processed high-volume transaction updates into meaningful business events and established a reusable event model through which internal and external systems could publish, subscribe to, and act on events without coupling producers to individual consumers.

1,200+
Restaurants at scale
Millions
Transactions processed hourly
Near real time
Business event processing

Problem & Constraints

Order tracking and other guest experiences needed real-time visibility into restaurant activity, but the legacy POS lacked the capabilities to produce the business events those experiences required. The architecture needed to derive meaningful events from high-volume POS state changes without disrupting restaurant operations, while providing a scalable event capability that could support new producers, consumers, and use cases over time.

Legacy system limitations
Meaningful business events had to be inferred from successive POS state changes.
Enterprise scale
Millions of transactions per hour across more than 1,200 restaurants, with substantial peak-period bursts.
Operational isolation
Event capture and processing could not interfere with POS performance or normal restaurant operations.
Distributed processing
Horizontal scaling introduced sequencing, concurrency, and stale-state considerations.
Real-time relevance
For guest-facing experiences, delayed events could become incorrect or misleading.
Producer-consumer independence
Event producers and consumers needed to evolve independently without direct dependencies on one another.

Architecture Overview

Architecture showing POS order state flowing from the restaurant edge through scalable Azure transaction processing, where state changes are converted into business events and published to downstream consumers
Event-driven architecture transforming legacy state into business events

The architecture created an event-driven layer between the legacy restaurant POS and modern enterprise applications. The existing POS Agent captured normalized order state and sent it asynchronously to Azure, where queued, horizontally scalable transaction processors compared each incoming snapshot with previously persisted state. Meaningful transitions were converted into domain events and published through Azure Event Grid for independent downstream consumption.

Order Tracking became the primary consumer, using event-specific handlers and business configuration to determine when events should result in guest communication. A complementary enterprise messaging capability supported communication in the opposite direction when cloud applications needed to reach a specific restaurant, creating reusable communication patterns between the restaurant edge and centralized enterprise applications.

Key Architecture Decisions

Derive business events from legacy state

The POS produced state snapshots rather than domain events, so the processing layer compared current and previous state to identify meaningful transitions. Only significant state changes became business events, creating a modern event model without requiring changes to the legacy POS.

Keep event processing off the restaurant critical path

Reuse the existing POS integration boundary to capture normalized state rather than introducing another restaurant-side integration mechanism. Event capture followed an independent execution path so cloud processing or connectivity issues could not interfere with normal restaurant operations.

Decouple ingestion from processing for scale

Accept and queue incoming transactions independently from event processing, allowing each stage to scale according to its workload. Horizontally scalable processors absorbed high-volume bursts without requiring restaurant systems to wait for downstream processing.

Preserve event timing and freshness

Capture event time at the restaurant so business sequencing reflected when activity occurred rather than when asynchronous processing completed. Stale-state protection and freshness controls prevented delayed or superseded state from producing events that were technically accurate but no longer operationally relevant.

Separate business events from consumer reactions

Publish what happened without embedding knowledge of who would consume the event or how they would respond. Subscribers independently determined whether an event mattered and what action to take, allowing producers and consumers to evolve without direct dependencies.

Use the communication pattern that matches the interaction

Use publish/subscribe for business events that independent consumers could react to, and targeted messaging when a cloud application needed to communicate with a specific restaurant. Keeping those interaction models distinct avoided forcing different communication semantics through a single mechanism.

Engineering Approach

The engineering approach focused on creating a scalable event-processing layer without introducing additional complexity into restaurant operations. Lightweight state capture at the restaurant edge fed asynchronous Azure processing, where queued workloads, horizontally scalable services, state-transition detection, and publish/subscribe messaging converted high-volume POS activity into reusable business events. Configuration-driven consumers and operational telemetry allowed downstream behavior to evolve independently while providing visibility into the health of the distributed processing path.

Application & Services
.NET · Azure Service Fabric · RESTful APIs · Azure Functions
Data & Messaging
Azure SQL Database · Azure Event Grid · Azure Service Bus · Asynchronous Messaging
Patterns & Principles
Factory Pattern · Strategy Pattern · Event-Driven Architecture · Publish/Subscribe · State-Transition Detection · Separation of Concerns
Release & Reliability
Horizontal Scaling · Queued Processing · Circuit Breakers · Stale-State Protection · Application Insights · Log Analytics · Operational Dashboards · Threshold-Based Alerting
Security
Authenticated Service Access · Protected API Boundaries · Layered Network & API Security

Results & Evolution

What began as the technical foundation for Order Tracking became a reusable event and messaging architecture connecting the restaurant edge with enterprise applications. By separating legacy POS state from the business events consumed by modern applications, the architecture allowed new capabilities to respond to restaurant activity without becoming coupled to the POS or its underlying integration model.

  • Proved the architecture under production peaks: The processing path scaled across compute, messaging, and persistence during peak periods involving millions of transactions per hour, with even greater bursts during the restaurant industry's busiest holidays and events.
  • Created reusable business events from legacy state: Order lifecycle changes became independently consumable domain events rather than behavior embedded specifically for Order Tracking. Producers published what happened while downstream applications determined whether and how to react.
  • Designed beyond the initial use case: Although Order Tracking became the primary consumer, the architecture was designed to support additional domains and consumers without restructuring the underlying event-generation pipeline.
  • Enabled configuration-driven guest experiences: Order Tracking could independently determine whether lifecycle events should result in guest communication based on factors such as service method and order source, allowing business policy to evolve without changing event generation.
  • Established reusable communication with the restaurant edge: The complementary enterprise messaging capability supported targeted communication from cloud applications back to individual restaurants and was reused by capabilities including Last-Mile Delivery and curbside guest-arrival workflows.

Architectural Perspective

I tend to favor architectures built around clear boundaries, thoughtful abstractions, explicit responsibilities, and loose coupling between components that change for different reasons. Those principles shaped this design, abstracting legacy POS state into meaningful business events while allowing producers, consumers, and business policy to evolve independently. The goal was to contain complexity at the appropriate boundaries and expose cleaner, reusable capabilities rather than allowing the constraints of the underlying systems to propagate throughout the architecture.