RetailFlow POS

πŸ“ Regional Pharmacy Chain (12 Locations) πŸ“… 2023

A unified, offline-first point-of-sale system that modernized inventory, checkout, and reporting β€” deployed across LAN + cloud.

The Challenge

The client relied on paper logs and a legacy desktop app that couldn’t sync across stores. This caused:

They needed a resilient, modern POS that worked today β€” without disrupting daily operations.

Our Approach

We designed a hybrid LAN/cloud architecture to ensure uptime, data integrity, and scalability:

System Architecture

Local Store (LAN) POS UI (Electron) Node.js API SQLite (Local) Sync Queue Cloud Infrastructure Central API (Node.js) PostgreSQL (RDS) Multi-Store Sync SMS Gateway Analytics

Key insight: Local SQLite ensures uptime; cloud PostgreSQL enables cross-store analytics and backups.

Key Screenshots

POS Login & Dashboard
Login & Dashboard

Secure login and real-time sales/inventory overview.

POS Checkout Interface
Checkout Flow

Intuitive barcode scanning and split-payment support.

Inventory Management
Inventory Management

Track stock levels, receive alerts, and manage suppliers.

Receipt Printing
Receipt Generation

Professional thermal receipt printing with store branding.

Measurable Impact

37%
↓ in average queue time
$18k/yr
Saved in labor costs
99.2%
Inventory accuracy

The system was deployed across all 12 locations in 8 weeks β€” with zero downtime during cutover.

Tech Deep Dive

Core Stack & Key Decisions

β–Ό
Node.js 18 Electron React 18 SQLite PostgreSQL AWS EC2/RDS

Why SQLite locally? Zero-config, file-based DB ensures offline operation. Data syncs to cloud PostgreSQL for analytics.

Electron over web? Direct hardware access (printers, barcode scanners) without browser limitations.

Sync Strategy (Critical Path)

β–Ό

We implemented a conflict-free replicated data type (CRDT-inspired) sync queue:

// Local store pushes to sync queue on mutation db.run(`INSERT INTO sync_queue (table, action, payload, timestamp) VALUES (?, ?, ?, ?)`, ['sales', 'INSERT', JSON.stringify(sale), Date.now()]);

Cloud pulls every 60s, applies changes, and broadcasts to other stores. Conflicts are resolved by timestamp + store priority.

Thermal Printer Abstraction Layer

β–Ό

Created a unified interface to support 8+ printer models (Epson, Star, Bixolon):

class ThermalPrinter { constructor(model) { this.driver = PrinterDrivers.get(model); // Factory pattern } printReceipt(sale) { const commands = this.driver.generateESCPOS(sale); this.driver.send(commands); } }

This reduced integration time for new hardware from 3 days β†’ 2 hours.

Client Voice

β€œdingi.co delivered a system that just works β€” even during internet outages. Our staff adopted it in 2 days, and we’ve eliminated stockouts completely. Worth every penny.”
β€” Operations Director, Regional Pharmacy Chain

Lessons Learned

Want a Similar System?

We offer a free 60-minute POS Audit β€” we’ll review your workflow and propose a tailored solution.

Get Your Free Audit β†’