A production-grade, multi-tenant Point of Sale platform built for retail, restaurant, and pharmacy operations. Combines a native C++20 desktop client with cloud sync, a React management dashboard, and a Python AI analytics worker — designed to operate fully offline and sync seamlessly when connectivity is restored.
- What This System Does
- Architecture
- Feature Reference
- Security Model
- Prerequisites
- Local Development Setup
- Production Deployment
- Multi-Tenant Provisioning
- Environment Variables
- Troubleshooting
- License
Most POS software either runs entirely in the browser (unreliable offline) or runs entirely on-device (no central management). This platform does both correctly.
The C++ terminal client operates at full capability with zero internet connectivity — processing sales, managing inventory, printing receipts, and running shift reports against an encrypted local database. When connectivity is available, a background sync engine reconciles all terminal activity with the cloud in real time. A React dashboard gives tenant managers remote visibility and control over every aspect of their store configuration without touching the terminal hardware.
The multi-tenant architecture supports hundreds of independent retail businesses on a single cloud instance, with PostgreSQL Row-Level Security guaranteeing at the database layer that one tenant's data can never be accessed by another — regardless of application-layer behaviour.
Designed for: retail chains, restaurants with KOT workflows, pharmacies, and any business requiring reliable operation in low-connectivity environments.
┌──────────────────────────────────────────────────────────────────────┐
│ CLOUD INFRASTRUCTURE │
│ │
│ ┌───────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ Admin │ │ Node.js API │ │ Python AI │ │
│ │ Dashboard │◄──►│ Express │◄──►│ Analytics Worker │ │
│ │ React + Vite │ │ Port 3000 │ │ asyncpg │ │
│ └───────────────┘ └────────┬────────┘ └─────────────────────┘ │
│ │ │ │
│ ┌───────────▼─────────────────────────▼──────┐ │
│ │ PostgreSQL (Row-Level Security) │ │
│ │ Redis (sessions · rate limiting) │ │
│ └────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
▲
│ HTTPS + HMAC-signed payloads
│ Sync every 30 seconds
▼
┌──────────────────────────────────────────────────────────────────────┐
│ C++ POS CLIENT (per terminal) │
│ │
│ ┌────────────────┐ ┌──────────────────┐ ┌─────────────────────┐ │
│ │ ImGui UI │ │ SyncEngine │ │ HandshakeTimeBomb │ │
│ │ checkout │ │ background │ │ offline grace │ │
│ │ inventory │ │ thread │ │ period enforcement │ │
│ │ shift reports │ └──────────────────┘ └─────────────────────┘ │
│ └───────┬────────┘ │
│ │ │
│ ┌───────▼──────────────────────────────────────────────────────┐ │
│ │ SQLCipher Local DB │ │
│ │ AES-256 encryption · PBKDF2 key derived from HW fingerprint │ │
│ └───────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
| Component | Language | Role |
|---|---|---|
| C++ POS Client | C++20, ImGui | Native desktop terminal. Offline-first, encrypted local DB, background cloud sync |
| Node.js API | Node.js 20, Express | Central cloud API. Handles auth, sync, tenant management, webhooks |
| React Dashboard | React, Vite | Tenant and superadmin management UI. Store config, staff, inventory, reports |
| Python Worker | Python, asyncpg | AI analytics: sales forecasting, demand patterns, anomaly detection |
| PostgreSQL | v15+ | Primary data store with Row-Level Security enforced at schema level |
| Redis | v7 | Session storage, rate limiting, ephemeral sync state |
- Parent/child product variants (size, colour, weight, or any custom attribute)
- Component recipes and kits — sell assembled products that auto-decrement component stock
- Stock transfers between terminals and locations
- Reorder level alerts with configurable thresholds per product
- Custom tax groups and rates per jurisdiction
- Multiple tax brackets applied to individual products
- Tax-inclusive and tax-exclusive pricing modes
- Per-tenant tax configuration — no shared tax tables between clients
- Full quote-to-invoice conversion workflow
- Invoice payment tracking with partial payment support
- Business expense recording
- M-Pesa STK Push integration for mobile payment collection
- Custom roles with granular permission sets
- Maximum discount limits enforced per role
- Commission rate tracking per staff member
- Fast PIN-based cashier login — no password typing at the terminal
- Supplier and customer database with full contact history
- Loyalty tier system with configurable reward point accrual
- Customer purchase history accessible at checkout
- X Report: open shift with starting float declaration
- Z Report: close shift with expected vs. actual cash reconciliation
- Per-terminal shift history with audit trail
- Kitchen Order Ticket (KOT) generation and routing
- Table management with cover tracking
- Barcode generation for products and shelf labels
- Webhooks for CRM platforms (Mailchimp, SMS gateways)
- M-Pesa STK Push (native, no third-party payment processor)
- REST API for third-party integrations
Security is enforced at multiple independent layers. A failure at any single layer does not compromise the system.
Every table that holds tenant data has RLS policies attached. Queries execute within a tenant context set at connection time. A bug in the application that constructs the wrong query cannot return another tenant's rows — the database engine itself filters them out.
All synchronisation requests from the C++ client to the cloud API carry an HMAC-SHA256 signature over the full request body, computed using a secret injected at build time. The API rejects any request whose signature does not match. This prevents replay attacks and payload tampering even if the HTTPS layer were compromised.
The terminal's local SQLite database is encrypted using SQLCipher with an AES-256 key derived via PBKDF2 from the machine's hardware fingerprint (CPU ID, motherboard serial, and MAC address combined). If the physical terminal is stolen, the database cannot be decrypted on any other machine. If hardware components are replaced, the key changes and the database must be re-initialised from the cloud.
The C++ client performs a cryptographic handshake with the cloud API on startup and every 30 seconds during operation. If the cloud cannot be reached for more than 14 consecutive days, the terminal enters restricted mode and blocks checkout. This enforces subscription validity without preventing legitimate offline operation during short outages.
- Cloud API: JWT access tokens (short-lived) with Redis-backed refresh token rotation
- Terminal cashiers: PIN-based login with brute-force lockout after 5 failed attempts (15-minute lockout)
- Superadmin and tenant admin accounts: bcrypt-hashed passwords, rate-limited login endpoint
Verify all versions before proceeding. Mismatched versions are the most common source of build failures.
For cloud backend and dashboard:
node --version # Required: v20.x
docker --version # Required: 24.0+
docker compose version # Required: v2.20+For C++ client (additional):
cmake --version # Required: 3.20+# C++20 compiler:
g++ --version # GCC 12+ (Linux)# or
clang++ --version # Clang 14+ (macOS/Linux)# or Visual Studio 2022 17.4+ (Windows)For Python analytics worker:
python3 --version # Required: 3.11+Follow steps in order. Each depends on the previous completing successfully.
git clone https://github.com/Ray001-sudo/pos-platform.git
cd pos-platform# RSA keypair for JWT signing
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -out public.pem
# HMAC secrets for sync and handshake (generate separately)
openssl rand -hex 64 # copy output → SYNC_HMAC_SECRET in .env
openssl rand -hex 64 # copy output → HANDSHAKE_HMAC_SECRET in .envcp .env.example .env
# Edit .env and fill in all variables# See Section 9 — Environment Variables for the full referencedocker compose up -d postgres redis
# Wait for both to show healthy:
docker compose ps# Apply schema with RLS policies
psql $DATABASE_URL -f cloud_schema.sqlcd backend-api
npm install
npm start
# API available at http://localhost:3000cd admin-dashboard
npm install
npm run dev
# Dashboard available at http://localhost:5173cd analytics-worker
pip install -r requirements.txt
python main.pycd cpp-client
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j$(nproc)
./build/pos_clientOn first launch, enter your local API URL (http://localhost:3000), the Tenant ID created in the dashboard, and a Terminal ID. The client will perform an initial sync and be ready for use.
- CPU: 2 vCPUs (4 recommended for 10+ concurrent tenants)
- RAM: 4 GB (8 GB recommended)
- Disk: 50 GB SSD
- OS: Ubuntu 22.04 LTS
ssh root@YOUR_SERVER_IP
apt update && apt upgrade -y
apt install -y docker.io docker-compose-plugin nginx certbot python3-certbot-nginx
systemctl enable --now dockergit clone https://github.com/Ray001-sudo/pos-platform.git /var/www/pos-platform
cd /var/www/pos-platform
# Generate production secrets (same commands as local setup)# Place private.pem and public.pem in /var/www/pos-platform/secrets/# Fill in .env with production values
docker compose -f docker-compose.prod.yml up -dPoint your DNS A records to the server IP before running Certbot.
# Create Nginx config for API and dashboard# api.yourdomain.com → localhost:3000# admin.yourdomain.com → localhost:5173 (or built static files)
certbot --nginx \
-d api.yourdomain.com \
-d admin.yourdomain.com \
--non-interactive \
--agree-tos \
-m your@email.comdocker compose exec postgres psql -U $POSTGRES_USER -d $POSTGRES_DB \
-f /docker-entrypoint-initdb.d/cloud_schema.sqlcd /var/www/pos-platform/backend-api
node scripts/create-superadmin.jsufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP (redirects to HTTPS)
ufw allow 443/tcp # HTTPS
ufw deny 3000/tcp # API — internal only, proxied by Nginx
ufw deny 5432/tcp # PostgreSQL — never exposed publicly
ufw deny 6379/tcp # Redis — never exposed publicly
ufw enablesystemctl enable certbot.timer
systemctl start certbot.timerA single cloud deployment supports unlimited independent tenants. Each tenant's data is isolated at the database layer via RLS and identified by a UUID that flows through every API request.
- Log into the admin dashboard at
https://admin.yourdomain.comusing superadmin credentials. - Navigate to Tenants → New Tenant.
- Enter the business name, category (Retail / Restaurant / Pharmacy), subscription plan, and module access.
- The system generates a unique Tenant UUID and a default Tenant Admin user. Share these credentials securely with the client.
The tenant admin logs in with their Tenant UUID and configures:
- Taxes: jurisdiction-specific rates and groups
- Staff: roles with granular permissions, PIN assignment
- Inventory: products, variants, recipes, reorder levels
- Store settings: receipt branding, currency, timezone
Install the compiled pos_client binary on the client's hardware (Windows or Linux).
On first launch:
- Enter the cloud API URL, Tenant UUID, and Terminal UUID (generated from the tenant dashboard).
- The client calls
/api/v1/license/check, receives a signed handshake token, and performs a full initial sync — downloading all products, staff, taxes, and settings into the local encrypted database. - Cashiers log in via PIN. The terminal is ready for offline operation immediately.
All variables are defined in .env.example. Required variables will cause startup failure if absent.
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string with SSL mode |
REDIS_URL | Yes | Redis connection string |
JWT_PRIVATE_KEY_PATH | Yes | Path to RSA private key PEM file |
JWT_PUBLIC_KEY_PATH | Yes | Path to RSA public key PEM file |
SYNC_HMAC_SECRET | Yes | 64-byte hex secret for C++ sync payload signing |
HANDSHAKE_HMAC_SECRET | Yes | 64-byte hex secret for terminal handshake |
MPESA_CONSUMER_KEY | No | Safaricom Daraja API consumer key |
MPESA_CONSUMER_SECRET | No | Safaricom Daraja API consumer secret |
MPESA_SHORTCODE | No | M-Pesa business shortcode |
MPESA_PASSKEY | No | M-Pesa Lipa Na M-Pesa passkey |
WEBHOOK_SECRET | No | Secret for validating outbound webhook deliveries |
NODE_ENV | No | development or production. Default: development |
PORT | No | API server port. Default: 3000 |
| Symptom | Root Cause | Resolution |
|---|---|---|
C++ client: Handshake failed | Cannot reach cloud API — network outage or wrong POS_CLOUD_URL | Terminal continues operating via 14-day offline grace period. Verify API URL and network connectivity. |
C++ client: Checkout Blocked | Subscription suspended or 14-day offline grace period expired | Reconnect to internet. Superadmin must set tenant status to active in dashboard to refresh the handshake token. |
C++ client: Database corrupted or encrypted | Hardware fingerprint changed (motherboard, CPU, or NIC replaced) — PBKDF2 key no longer matches | Delete the local SQLite cache file and re-run terminal initialisation to resync from cloud. |
C++ sync: Transaction rejected: invalid signature | SYNC_HMAC_SECRET in the C++ binary does not match the server .env | Recompile the C++ client with the correct secret, or verify the server .env has not been rotated without a client rebuild. |
API: 429 Too Many Requests | PIN entered incorrectly 5+ times — brute-force lockout triggered | Account locked for 15 minutes automatically. Tenant admin can unlock immediately from the dashboard if urgent. |
API: 401 Unauthorized | Refresh token expired or revoked in Redis | User must log out and log back in to obtain a new token pair. |
Dashboard: Tenant not found | Login attempted with an invalid or mistyped Tenant UUID | Verify the exact UUID from the superadmin provisioning screen. UUIDs are case-sensitive. |
| Kafka consumer lag growing | Analytics worker falling behind sync volume | Scale the Python worker horizontally or increase its batch processing size in config.yaml. |
| PostgreSQL RLS: empty result sets on valid queries | Session tenant context not set before query execution | Ensure the API middleware runs SET app.current_tenant_id = $1 on every connection before any query. Check the auth middleware order in app.js. |
Proprietary — All rights reserved. © Hexaflow Labs.
Unauthorised copying, distribution, or modification of this software or its documentation is strictly prohibited. For licensing enquiries, contact bensonray25@gmail.com.