<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ahsan Mehmood</title>
    <description>The latest articles on DEV Community by Ahsan Mehmood (@iamahsanmehmood).</description>
    <link>https://dev.to/iamahsanmehmood</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3813758%2F4e51aeb9-4998-4138-a021-26bb36662d98.jpg</url>
      <title>DEV Community: Ahsan Mehmood</title>
      <link>https://dev.to/iamahsanmehmood</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamahsanmehmood"/>
    <language>en</language>
    <item>
      <title>Building a Multi-Terminal Restaurant POS with C# .NET — Architecture &amp; Lessons</title>
      <dc:creator>Ahsan Mehmood</dc:creator>
      <pubDate>Mon, 09 Mar 2026 03:33:29 +0000</pubDate>
      <link>https://dev.to/iamahsanmehmood/building-a-multi-terminal-restaurant-pos-with-c-net-architecture-lessons-56e2</link>
      <guid>https://dev.to/iamahsanmehmood/building-a-multi-terminal-restaurant-pos-with-c-net-architecture-lessons-56e2</guid>
      <description>&lt;p&gt;Building a Point-of-Sale system sounds straightforward until you realize it needs to handle &lt;strong&gt;multiple terminals, thermal printers, kitchen displays, real-time table tracking, and never lose a transaction&lt;/strong&gt; — even when the network drops.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;RestoCare+&lt;/strong&gt; — a multi-terminal restaurant POS system — and in this post, I'll walk through the architecture decisions, the problems I ran into, and what I'd do differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I spent 4+ years working as a supervisor at a restaurant in Islamabad. I saw firsthand how terrible most POS systems were — slow, unreliable, confusing for staff, and impossible to maintain.&lt;/p&gt;

&lt;p&gt;When I transitioned into software development, this was the first real product I wanted to build. Not because it was technically exciting, but because I &lt;strong&gt;deeply understood the problem&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language:&lt;/strong&gt; C#&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; .NET Framework (WinForms for UI)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; SQL Server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Printing:&lt;/strong&gt; ESC/POS commands via Windows Services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture:&lt;/strong&gt; Client-Server with centralized SQL database&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  High-Level Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  Terminal 1   │    │  Terminal 2   │    │  Terminal 3   │
│  (Cashier)    │    │  (Cashier)    │    │  (Manager)    │
└──────┬───────┘    └──────┬───────┘    └──────┬───────┘
       │                   │                   │
       └───────────┬───────┴───────────────────┘
                   │
           ┌───────┴───────┐
           │   SQL Server   │
           │   (Central DB) │
           └───────┬───────┘
                   │
       ┌───────────┼───────────┐
       │           │           │
┌──────┴──┐  ┌────┴────┐  ┌───┴──────┐
│ Thermal  │  │ Kitchen  │  │ Receipt  │
│ Printer 1│  │ Display  │  │ Printer  │
└─────────┘  └─────────┘  └──────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Design Decisions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Centralized Database, Not Peer-to-Peer
&lt;/h3&gt;

&lt;p&gt;Every terminal connects to a &lt;strong&gt;single SQL Server instance&lt;/strong&gt;. I considered SQLite per terminal with sync, but restaurants can't tolerate eventual consistency — if Terminal 1 marks Table 5 as occupied, Terminal 2 needs to see that immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Connection string points to central SQL Server&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;connectionString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConfigurationManager&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionStrings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"RestoCareDB"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;ConnectionString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Real-Time Table Management
&lt;/h3&gt;

&lt;p&gt;The table management system uses a polling approach to keep all terminals in sync. Every terminal refreshes the floor plan every few seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Table status refresh timer&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Timer&lt;/span&gt; &lt;span class="n"&gt;_tableRefreshTimer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;InitializeTableSync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_tableRefreshTimer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 3-second interval&lt;/span&gt;
    &lt;span class="n"&gt;_tableRefreshTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;RefreshTableStatuses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_tableRefreshTimer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;RefreshTableStatuses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ElapsedEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_tableRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAllWithStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;UpdateTableUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why polling instead of SignalR/WebSockets?&lt;/strong&gt; Simplicity. In a restaurant with 3-5 terminals on a local network, a 3-second poll is good enough and dramatically simpler to debug when something goes wrong at 9 PM on a Friday night.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Thermal Printing via Windows Service
&lt;/h3&gt;

&lt;p&gt;Thermal receipt printers speak &lt;strong&gt;ESC/POS&lt;/strong&gt; — a binary command language. I built a dedicated Windows Service (&lt;code&gt;IMS Print Service&lt;/code&gt;) that handles all print jobs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ESC/POS command to print bold text&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;boldOn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;0x1B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x01&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;boldOff&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;0x1B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x00&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;centerAlign&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;0x1B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0x01&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PrintReceipt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;printer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RawPrinter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_printerName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;centerAlign&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boldOn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RESTAURANT NAME\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boldOff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,-&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; x&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Qty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\n"&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"\nTOTAL: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\n"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CutPaper&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why a Windows Service?&lt;/strong&gt; Two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The print service runs independently — even if the POS UI crashes, queued prints still go through.&lt;/li&gt;
&lt;li&gt;Multiple terminals can send print jobs to the same service, which queues them to avoid conflicts.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Kitchen Display Integration
&lt;/h3&gt;

&lt;p&gt;When a waiter submits an order, it needs to appear on the kitchen display instantly. The kitchen display is a separate WinForms app running on a screen in the kitchen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Kitchen display polls for new orders&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KitchenOrder&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPendingOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RestoCareContext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pending&lt;/span&gt; 
                     &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InProgress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreatedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kitchen staff tap items as they're prepared, and the waiter's terminal updates in real-time showing which items are ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Handling the Offline Scenario
&lt;/h3&gt;

&lt;p&gt;What happens when the network drops? This is critical in restaurants — you can't stop taking orders because WiFi went down.&lt;/p&gt;

&lt;p&gt;My approach: &lt;strong&gt;local queue with retry.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If SQL Server is unreachable, queue locally&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SubmitOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_orderRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_kitchenService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotifyNewOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SqlException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_localQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB unreachable — order queued locally"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Background task retries every 10 seconds&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mistakes I Made
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Not planning for menu changes
&lt;/h3&gt;

&lt;p&gt;My initial schema had menu items tightly coupled to orders. When the restaurant changed prices or renamed dishes, it broke historical reports. &lt;strong&gt;Fix:&lt;/strong&gt; I added a snapshot of the item at order time — &lt;code&gt;OrderItem&lt;/code&gt; stores its own &lt;code&gt;PriceAtTime&lt;/code&gt; and &lt;code&gt;NameAtTime&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Underestimating receipt formatting
&lt;/h3&gt;

&lt;p&gt;Thermal printers have &lt;strong&gt;42-character line width&lt;/strong&gt; (for 80mm paper). I spent more time formatting receipts than I expected. Arabic/Urdu text support was a whole adventure.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Not building user management from day one
&lt;/h3&gt;

&lt;p&gt;I added multi-user roles (cashier, manager, admin) later, and retrofitting permissions into an existing system is painful. &lt;strong&gt;Always plan roles early.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use .NET 8&lt;/strong&gt; instead of .NET Framework — better performance, cross-platform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add offline-first architecture&lt;/strong&gt; from the start, not as an afterthought&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a web dashboard&lt;/strong&gt; alongside the desktop app for owners to check reports remotely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use message queues&lt;/strong&gt; (RabbitMQ or even a simple one) instead of polling for kitchen display&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;RestoCare+ is running in production at real restaurants. It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ 3-5 terminals simultaneously&lt;/li&gt;
&lt;li&gt;✅ Thermal receipt printing with proper formatting&lt;/li&gt;
&lt;li&gt;✅ Kitchen display with real-time order updates&lt;/li&gt;
&lt;li&gt;✅ Table management with status tracking&lt;/li&gt;
&lt;li&gt;✅ Daily sales reports and analytics&lt;/li&gt;
&lt;li&gt;✅ Menu management with category organization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Domain knowledge is your unfair advantage.&lt;/strong&gt; My 4 years in a restaurant made me a better POS developer than someone with 10 years of pure coding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polling is fine for local networks.&lt;/strong&gt; Don't over-engineer with WebSockets when 3-second polling works perfectly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thermal printing is harder than it looks.&lt;/strong&gt; Budget extra time for this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the boring stuff well.&lt;/strong&gt; Boring features like user roles, audit logs, and error handling are what separate a demo from a product.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;I'm Ahsan Mehmood — a Full-Stack Developer and Co-Founder of &lt;a href="https://xechtech.com" rel="noopener noreferrer"&gt;XechTech&lt;/a&gt;. I share what I learn from building real-world software. Follow for more .NET, Flutter, and AI content.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Connect: &lt;a href="https://linkedin.com/in/iamahsanmehmood" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://github.com/iamahsanmehmood" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://xechtech.com" rel="noopener noreferrer"&gt;XechTech&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>architecture</category>
      <category>database</category>
    </item>
    <item>
      <title>From Restaurant Supervisor to Technical Founder: Shipping 38+ Projects in 5 Years</title>
      <dc:creator>Ahsan Mehmood</dc:creator>
      <pubDate>Mon, 09 Mar 2026 03:25:50 +0000</pubDate>
      <link>https://dev.to/iamahsanmehmood/from-restaurant-supervisor-to-technical-founder-shipping-38-projects-in-5-years-1l4m</link>
      <guid>https://dev.to/iamahsanmehmood/from-restaurant-supervisor-to-technical-founder-shipping-38-projects-in-5-years-1l4m</guid>
      <description>&lt;p&gt;Hey Dev.to 👋 I'm Ahsan Mehmood — a Full-Stack Developer and Co-Founder of XechTech, based in Islamabad, Pakistan.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Journey
&lt;/h2&gt;

&lt;p&gt;In 2017, I was working as a restaurant supervisor. By 2021, I had pivoted into software development full-time. Today, I've shipped &lt;strong&gt;38+ production projects&lt;/strong&gt; across 8+ organizations, serving clients in Pakistan, the US, and Australia.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Build
&lt;/h2&gt;

&lt;p&gt;My core stack is &lt;strong&gt;.NET/C#&lt;/strong&gt;, but I work across the full spectrum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🖥️ &lt;strong&gt;Desktop&lt;/strong&gt;: Multi-terminal POS systems, payroll, accounting tools (C#, .NET, SQL Server)&lt;/li&gt;
&lt;li&gt;📱 &lt;strong&gt;Mobile&lt;/strong&gt;: Cross-platform apps with Flutter (Booktionary, EstiMate Pro, DLP App)&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Web&lt;/strong&gt;: React, Laravel, Node.js, TypeScript (pal.gov.pk, xechtech.com)&lt;/li&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI&lt;/strong&gt;: AutoCAD AI Agent, Gemini PC-Commander, LLM-powered workflows&lt;/li&gt;
&lt;li&gt;🏗️ &lt;strong&gt;Engineering&lt;/strong&gt;: 7+ structural tools for RPEQ-certified projects in Australia&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Company: XechTech
&lt;/h2&gt;

&lt;p&gt;I co-founded &lt;a href="https://xechtech.com" rel="noopener noreferrer"&gt;XechTech&lt;/a&gt; in 2021 with my partner Aaqib Saleem. We build high-end software solutions — from RestoCare+ (a restaurant POS system with thermal printing and kitchen displays) to AI-powered PDF automation tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Projects
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RestoCare+ POS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-terminal restaurant POS&lt;/td&gt;
&lt;td&gt;C#, .NET, SQL Server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EstiMate Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI-powered PDF automation&lt;/td&gt;
&lt;td&gt;Flutter, Dart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Engineering Suite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7+ structural analysis tools&lt;/td&gt;
&lt;td&gt;C#, .NET, AutoCAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PAL Website&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Government website&lt;/td&gt;
&lt;td&gt;PHP, Laravel, Flutter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Booktionary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dictionary &amp;amp; book app&lt;/td&gt;
&lt;td&gt;Flutter, SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AutoCAD AI Agent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI-generated floor plans&lt;/td&gt;
&lt;td&gt;Python, Gemini API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I've Learned
&lt;/h2&gt;

&lt;p&gt;The biggest lesson from shipping 38+ projects: &lt;strong&gt;Solve real problems for real people.&lt;/strong&gt; The fanciest tech stack means nothing if it doesn't solve a pain point.&lt;/p&gt;

&lt;p&gt;I built RestoCare+ because I spent 4 years in a restaurant and knew exactly what was broken. I built engineering tools because construction firms in Australia needed calculations done faster. Every successful project started with understanding the problem deeply.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm currently focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI integration into traditional business software&lt;/li&gt;
&lt;li&gt;Growing XechTech's client base internationally&lt;/li&gt;
&lt;li&gt;Sharing what I've learned through writing here on Dev.to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're a developer in Pakistan building your career, or if you're transitioning into tech from another field — I'd love to connect. Drop a comment or find me on &lt;a href="https://linkedin.com/in/iamahsanmehmood" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; 🤝&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Follow me for posts about .NET, Flutter, AI integration, and building software businesses from Pakistan.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>startup</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
