Engineering lessons from shaping restaurant software around service pressure, resilient workflows, and auditable state.

Operational software lives inside a real-time service

eRestro pushed us to think about software as part of a live restaurant operation rather than a set of administrative screens. During service, a delay is not an abstract latency number. It can interrupt a conversation, leave preparation state unclear, or force staff to reconstruct what happened while customers wait. The interface competes with noise, movement, interruptions, shared devices, and uneven connectivity.

That environment changes priorities. The primary path needs fast recognition, large and unambiguous actions, and minimal text entry. Secondary detail should remain available without crowding the next decision. A beautiful dashboard has limited value if staff cannot tell whether an action committed, recover a suspended order, or hand work to another role. Operational confidence is a product feature.

Model state transitions explicitly

Orders, preparation, service, payments, cancellations, and refunds are related but not identical states. Treating them as one mutable status produces confusing edge cases: an item can be prepared while payment fails, a payment can be authorized while a request times out, or part of an order can be removed after work begins. Explicit transitions and invariants make those situations visible rather than exceptional strings in a notes field.

  • Give each order and payment operation an idempotency key so retries do not duplicate intent.
  • Record who initiated, approved, or corrected consequential transitions and why.
  • Keep displayed status derived from durable events or state, not optimistic interface memory alone.
  • Represent partial completion and partial failure instead of forcing everything into success or failure.
  • Reconcile external payment or delivery state rather than assuming a timeout means nothing happened.

Design for degradation before calling it offline support

Connectivity is not simply online or offline. It can be slow, intermittent, captive, or available to one device but not an integration. Define which work may continue from cached data, which actions may queue, and which require a confirmed server or payment-provider response. Make degraded mode visible so staff know whether they are viewing current state and what remains pending.

  1. Classify operations

    Separate local-safe drafts, queueable commands, server-authoritative reads, and actions that must not proceed without a live confirmation.

  2. Persist user intent

    Store pending work durably with identifiers, timestamps, actor context, and the version of data on which the decision was made.

  3. Synchronize deterministically

    Send idempotent commands, order them where required, and use explicit conflict rules rather than last write wins by accident.

  4. Explain exceptions

    Show which action is pending, rejected, or needs review and give staff a safe recovery path instead of a generic sync error.

Shape the product around roles and moments

A server, kitchen operator, cashier, manager, and owner need different views of the same operation. Role design should reduce distraction, but permission design must also protect discounts, voids, refunds, configuration, and reporting. Shared devices make identity especially important: quick reauthentication and clear actor attribution can be more practical than a long-lived generic session.

Reports deserve the same state discipline as transactions. Business-day boundaries, reopened orders, tax categories, refunds, tips, and external settlement can make apparently simple totals disagree. Define each measure, its time basis, and how it reconciles to source events. If two screens answer different questions, label them rather than forcing numbers to look identical.

Build the recovery experience alongside the primary flow

Operational products are judged by what happens after a printer disconnects, a device refreshes, a payment response arrives late, or someone makes a correction under pressure. Logs help engineers, but staff need product-level recovery: resume, retry safely, reassign, explain, reconcile, or escalate. Support teams need an audit trail that tells a coherent story without direct database edits.

The broader eRestro lesson is that resilience is not a backend property hidden behind the interface. It is the combined behavior of state models, network assumptions, interaction design, permissions, reporting, and support. Designing those pieces around the realities of service produces software people can reason about when conditions are imperfect—which is when operational software matters most.