← All articles

Software Architecture/4 min read

Designing a point-of-sale system for 50 hot dog stands

How our team designed the software architecture for a POS system for 50 hot dog stands: offline-first sales, real-time stock sync, external integrations and security choices captured as ADRs.

Mohamad.B Alhakim

Not every project starts with code. In this software architecture course, our team of three (Hassan, Izabella and I) designed the system for Hot Diggety Dog, a local hot dog seller with 50 stands. The deliverable was a Software Architecture Document (SAD): what to build, how the parts fit together, and why.

The case

Hot Diggety Dog wanted a lightweight point-of-sale (POS) system that lets stand operators:

  • register sales quickly, with discounts,
  • keep stock up to date in real time for the mobile stock teams,
  • analyse sales by time and location,
  • post on social media automatically when a stand is in a busy area,
  • export data to their accounting software.

And a few constraints that shaped everything:

  • it runs on tablets and phones (Android and iOS), not laptops,
  • it has to work without a network,
  • an MVP within 8 weeks, and the system has to last at least 3 years.

Requirements first

We started by listing 18 requirements and labelling each one as functional, non-functional or a constraint. A few examples:

  • Register a sale with product, quantity, price, discount, time and stand location. (functional)
  • Keep selling without a network, and sync when the connection comes back. (non-functional)
  • Stock updates arrive in under 2 seconds under normal network conditions. (non-functional)
  • A modular design that can be maintained for 3+ years. (non-functional)

From there we derived a context diagram, a use-case model, a data model and a list of nine business functions: take an order, process a payment, print a receipt, apply discounts, manage stock, register deliveries, post on social media, export to accounting, and work offline.

The components

The design splits the system into components with clear interfaces:

ComponentTalks viaJob
POS client appREST / HTTPSTaking orders, starting payments, printing receipts
Inventory serviceinternal API / event busProcessing orders and keeping stock
Report and export serviceREST / HTTPSReports, and CSV/UBL exports for accounting
Social media serviceREST / HTTPSPosting deals and "we're here" updates
Authentication serviceREST / HTTPSLogin, roles and access control
Payment gatewayHTTPSCard and digital payments through an external provider
Receipt printerUSB / BluetoothPrinting receipts

Internally, services talk asynchronously over an event bus. A sale at one stand becomes an event; the inventory service updates stock and every stock team's device hears about it. That's what makes the 2-second target realistic without every device constantly polling a server.

Designing for things going wrong

In version two of the SAD we added a risk matrix: for each risk, how likely is it, how bad would it be, and what does the design do about it?

RiskLikelihoodImpactMitigation
Network drops during an eventmediumhighOffline mode with local storage, sync later
Data leak through the APIlowhighOAuth 2.0 and TLS 1.3 for all external traffic
API overloaded at peak timesmediummediumAPI gateway with throttling and caching
Wrong stock after a bad syncmediumhighEvent bus with confirmation on every sync
Social media integration breakshighlowSeparate integration service with retries
Lost or stolen devicemediumhighAES-256 encryption on the device, mandatory login

Two choices follow directly from this. Offline-first: a hot dog stand at a festival can't stop selling because the Wi-Fi is down, so sales are stored locally and synced on reconnect. And isolating the social media integration in its own service: those APIs change often, and when they break, it shouldn't take the till down with them.

Decisions as ADRs

We captured the important decisions as Architecture Decision Records: the choice, the alternative we rejected, why, and which requirements it serves.

  • OAuth 2.0 instead of API keys: stronger control and token renewal. (roles and authentication, offline sync)
  • HTTPS with TLS 1.3 instead of HTTP for all external traffic: protects against eavesdropping and man-in-the-middle attacks. (sales, social media, data integrity)
  • AES-256 for local data instead of plaintext: a stolen tablet shouldn't leak customer or payment data. (sales, offline mode)
  • An API gateway instead of direct connections to external services: one place for logging, throttling and security. (stock sync, social media, availability)

Linking every decision to a requirement was the most useful habit from this project. It turns "we chose OAuth" into "we chose OAuth because requirement 8 asks for roles and authentication", which is much easier to defend, and to revisit later.

The research question

Because the POS exchanges sensitive data with several outside parties, our research question was: how do you design the communication between the POS and external providers securely? We planned a technical experiment on top of a literature study: a prototype POS connected to mock APIs for payments, social media and accounting, comparing OAuth 2.0, API tokens and certificates on security, response time and error rate.

What I took away

  • Write down the "why". ADRs make decisions reviewable long after the meeting where they were made.
  • Design for failure. The risk matrix drove more of the architecture than the feature list did.
  • Keep fragile integrations at arm's length. The parts you don't control should be the easiest to replace.
  • Iterate on the document too. The second version of the SAD, with the risk matrix and the requirement links, was much stronger than the first.
Designing a point-of-sale system for 50 hot dog stands - Mohamad Bashar Alhakim