PreviousNext

Inside Our Offline-First Business Management Platform — IMEI Tracking, POS & Inventory Built for Uganda

A deep case study of the offline-first Business Management Platform Desishub built for a multi-branch Kampala phone retailer — Sales, Purchases, Inventory, IMEI Tracking, Finance and Reports in a single Grit Framework desktop binary.

Inside Our Offline-First Business Management Platform — IMEI Tracking, POS & Inventory Built for Uganda

A few months ago, a multi-branch phone retailer in Kampala came to Desishub with a familiar problem: three shops, five tills, a spreadsheet for inventory, and a creeping suspicion that handsets were going missing. Their cloud POS dropped offline every time fibre wobbled, customers walked out mid-sale, and reconciliation between branches was a Monday-morning nightmare.

We built them a desktop Business Management Platform on the Grit Framework. It runs offline, syncs in the background, tracks every IMEI to its handset, and in the first week it caught 28 missing phones the spreadsheet had never seen.

This post walks through the build — the architecture, the modules, the offline sync, the IMEI module, and the production patterns we now reuse across every Desishub desktop project.

Table of Contents

  1. The client and the problem
  2. Why we chose offline-first desktop
  3. The architecture in one diagram
  4. Modules shipped
  5. Deep dive — the IMEI tracking module
  6. Offline-first sync — how it actually works
  7. The Synced indicator UX pattern
  8. Multi-branch operations
  9. Results after six weeks
  10. FAQs

The Client and the Problem

A consumer electronics retailer, three branches in Kampala, around 40 staff across sales, stock and accounts. Stock: smartphones (Samsung, Tecno, iPhone), accessories, airtime.

The presenting symptoms:

  • Sales staff abandoning transactions when their cloud POS lost internet
  • Inventory in a shared spreadsheet — edited by 12 people, accurate to nobody
  • No way to match a physical handset on the shelf to the IMEI on the box, leaving room for swap-outs
  • End-of-day reconciliation took two staff a full hour per branch
  • No reliable view of credit sales or customer ledgers
  • Finance had to ask Sales for numbers; Sales had to ask Inventory; nobody trusted anyone

Underneath all of that, the real problem: their software model didn't match the connectivity reality of running a shop in Kampala.

Why We Chose Offline-First Desktop

We considered three options and ruled out two quickly:

  1. Pure cloud SaaS — already what they had, already broken. Off the table.
  2. Hybrid web app with service workers — works, but service-worker caches are fragile, and the IMEI flow needed local barcode-scanner integration that browsers handle poorly.
  3. Offline-first desktop app with background sync — local SQLite, native scanner support, runs whether fibre is up or down. Picked.

The desktop binary is built with Grit Framework's desktop architecture — Wails + Go + React. The full app installs in a 20 MB binary, runs on every cashier's Windows PC, and reads/writes to a local SQLite database that syncs to a central Postgres on a Hetzner server whenever the network is available.

Grit Framework architecture — type-safe monorepo with offline-first engine and instant deployment

The Architecture in One Diagram

┌────────────────────────────────────────────────────────────┐
│  Cashier PC (Branch A)        Cashier PC (Branch B)        │
│  ┌──────────────────────┐     ┌──────────────────────┐    │
│  │  Grit Desktop App    │     │  Grit Desktop App    │    │
│  │  React UI            │     │  React UI            │    │
│  │  ────────────        │     │  ────────────        │    │
│  │  Go business logic   │     │  Go business logic   │    │
│  │  Local SQLite        │     │  Local SQLite        │    │
│  │  Sync worker  ⇅      │     │  Sync worker  ⇅      │    │
│  └──────────┬───────────┘     └──────────┬───────────┘    │
└─────────────┼─────────────────────────────┼────────────────┘
              │                             │
              │   HTTPS (when online)       │
              ▼                             ▼
       ┌──────────────────────────────────────────┐
       │  Central Sync API (Go, Grit web stack)   │
       │  Postgres (transactions, IMEIs, audit)   │
       │  Object storage (receipts, images)       │
       │  Pulse observability + Sentinel limiter  │
       └──────────────────────────────────────────┘

Every desktop client is the same binary. The only difference between Branch A and Branch B is the branch ID stored in a local config file at install time, and the role assigned to the logged-in user.

Modules Shipped

The platform shipped with six modules in the first release:

ModuleWhat it doesOffline?
DashboardLive KPIs — sales today, top SKUs, low stock, missing IMEIs✅ (reads local DB)
SalesWalk-in POS, credit sales, refunds, receipt printing✅ Full transactions
PurchasesGoods received notes, supplier invoices, landed cost
InventoryStock per branch, transfers, adjustments, reorder alerts
IMEI TrackingEvery handset's IMEI registered against the stock unit
SetupProducts, categories, branches, tax rates, payment methods
FinanceCustomer ledger, supplier ledger, daily P&L
AdministrationUsers, roles, audit logs✅ (writes sync on reconnect)
ReportsSales, stock, IMEI gap, finance, branch comparison

The sidebar lives in the desktop shell so navigation is instant — no page loads, no spinners. Every list view paginates against the local SQLite.

Deep Dive — The IMEI Tracking Module

This is the module that paid for the project in the first month.

IMEI Tracking dashboard in Desishub's Business Management Platform — 3 tracked products, 28 missing handsets

The problem. When a phone retailer receives a shipment of, say, 8 × Samsung Galaxy S24 256GB, the stock-count says 8. But each of those eight handsets has a unique IMEI printed on its box. Without recording the IMEI against the stock unit, a dishonest staff member can swap a real handset for an empty box, sell the real one off the books, and the spreadsheet still says 8.

The fix. The IMEI Tracking page shows, for every tracked product, the expected stock count and the number of IMEIs registered against it. The gap is rendered in red.

ProductCategorySKUStockIMEIs in StockSoldMissing
Samsung Galaxy S24 256GBPhonesSAM-S24-2568008
Tecno Camon 30PhonesTEC-C30-128150015
iPhone 16 Pro 256GBPhonesAPL-IP16P-2565005

A KPI strip at the top makes the same point loud: Tracked products 3 • IMEIs in Stock 0 • IMEIs Sold 0 • Missing 28.

Workflow. When a shipment arrives, the stock controller hits Upload IMEIs on each product card. They paste in the IMEIs (one per line) or scan them with a USB barcode reader. The desktop app validates the format (Luhn-checksum for 15-digit IMEIs), stores them locally, and syncs to the central server. At the till, scanning a handset's IMEI checks out one unit and updates Sold automatically.

Compliance bonus. UCC (Uganda Communications Commission) and customs queries about specific handsets now take seconds instead of hours — the IMEI ledger is queryable per branch and per timeframe.

Offline-First Sync — How It Actually Works

The hardest part of offline-first is conflict resolution. Two cashiers might sell the same SKU in different branches while the network is down. When fibre returns, we can't blindly add both transactions — we need to keep the data honest.

The pattern Grit Desktop apps use:

  1. All mutations write to a local outbox table first. Each row has an idempotency key, a vector clock and a timestamp.
  2. A sync worker drains the outbox to the central API as soon as connectivity is available, in chronological order.
  3. The API applies CRDT semantics for counter-like fields (stock_on_hand is a counter, not a "set to N" operation).
  4. For non-counter conflicts, the server keeps both versions and surfaces a Conflict row in the Administration module for a human to resolve.
  5. A background pull worker fetches changes from other branches and applies them locally.

This is the only way to run multi-branch retail in Uganda honestly. Anything else is "last write wins" and quietly loses you stock.

The Synced Indicator UX Pattern

In the top-right of every screen, the workspace shows a small green dot with the word Synced. When the sync worker is mid-cycle it switches to a spinner; when the connection drops it switches to an amber Working offline — 3 pending. Staff trust that indicator more than they trust the network bars in the system tray, because it tells them whether the business data is safe.

The pattern is in every Desishub desktop app now, including the Business Management Platform and HMK Estates. Borrow it — your users will thank you.

Multi-Branch Operations

The branch picker (in the screenshot it's set to Head Office) scopes every list view, every report and every sale to the chosen branch. Users with the Administrator role can switch branches; cashiers are locked to theirs.

Stock transfers between branches are a first-class workflow:

  1. Branch A creates a Transfer Out with a list of SKUs and quantities
  2. Stock leaves Branch A's inventory immediately (in-transit)
  3. Branch B sees it in their Incoming Transfers queue
  4. Branch B confirms receipt; stock lands in Branch B's inventory
  5. If quantities mismatch, a Variance row is opened automatically

Auditable, offline-friendly, and reconcilable per day.

Results After Six Weeks

  • 28 missing handsets identified and recovered in week 1 via the IMEI gap report
  • Reconciliation time dropped from ~3 hours per day across 3 branches to ~15 minutes total
  • Zero abandoned sales due to internet outages — staff stopped noticing fibre drops
  • Daily P&L visibility for the owner from any device, including weekends from home
  • Audit-ready ledgers for both UCC IMEI queries and URA (revenue authority) audits

What This Reusable for Your Business

The same desktop architecture works for:

  • Supermarkets and minimarts
  • Pharmacies and clinics
  • Hardware and electronics retailers
  • Tyre, motor-spare and parts shops
  • Hotels and restaurants
  • Real estate offices managing multiple properties (see HMK Estates)
  • Logistics and field-service teams

The Grit Framework scaffold means we can typically have a domain-tailored version of this platform in a client's hands inside 8–12 weeks, including hardware integration and staff training.

FAQs

1. Will the platform work in a power cut? Yes — every cashier PC should have a UPS, but the moment power returns the app picks up exactly where it left off. No data loss.

2. Can my accountant access the data without installing the desktop app? Yes. The central server exposes a web admin (also built on Grit) where Finance can run reports, view ledgers and export to Excel/PDF without touching the desktop app.

3. How is the data backed up? Three layers: (1) local SQLite file is auto-snapshotted hourly on each PC, (2) the central Postgres has nightly backups to encrypted object storage, (3) we keep 30 days of point-in-time recovery on the central database.

4. Can I plug in a thermal receipt printer? Yes — 80mm thermal printers (Epson TM-T20, Xprinter XP-58) print receipts natively via the Go backend. Cash drawers triggered from the printer are supported too.

5. Does it support mobile money? Yes — MTN MoMo and Airtel Money are both wired in as payment methods at the till. Manual confirmation, or auto-confirmation via the operator's collections API depending on your account.

6. Can I limit cashiers to seeing only their own sales? Yes — RBAC is enforced per resource. Cashiers see their own till; supervisors see the branch; administrators see the company.

7. How much does a build like this cost in UGX? For a 3-branch, 6-module deployment with IMEI tracking, expect UGX 35M – UGX 60M depending on hardware integration scope. Read the pricing breakdown in Best Desktop App Development Company in Uganda 2026.

Suggested Articles

Want one for your business?

If you run a shop, clinic, school or estate that needs to be honest about its inventory and reliable when fibre is down, book a discovery call with Desishub. We'll quote you in UGX and have a working demo of the platform — wired to your real product catalogue — in your hands within three weeks.