Back to work

StockPilot

In production

An offline-first point of sale and inventory system for shops with unreliable internet.

Period
2024 — present
Role
Sole developer — architecture, interface, backend, infrastructure
~30k
lines of TypeScript
289
automated tests
3
surfaces, one core
Solo
built and shipped

Get the app — StockPilot

The register runs in the browser and installs like an app, and the desktop and Android builds download straight from the project's own server - no store in between.

  • Windows

    Windows 10 and later - 106 MB

    The desktop register, built by CI on every change. It keeps taking payments with the connection down and updates itself from the same server.

    Download .exe
  • Android

    Android 9 and later - 99 MB

    The signed APK, installed outside any store. You can also open the site in Chrome and choose "Install app" if you would rather not handle a file.

    Download .apk
  • iPhone and iPad

    Safari on iOS 16.4+

    No installer: open the site in Safari, then Share and "Add to Home Screen". It runs full-screen and works offline, with no App Store account needed on either side.

    Install
  • macOS

    macOS 12 and later

    Buildable locally, but unsigned, so it will not start on Apple Silicon without a developer certificate.

    Not available

A shop with patchy coverage cannot run a cloud point of sale. The connection drops at the worst possible moment — a customer at the counter, a queue behind them — and the register stops. StockPilot takes the payment locally and reconciles with the server once the network returns.

One core, three surfaces

The web app, the mobile app and the desktop register share the same business logic, the same local catalogue and the same sync client, written once in TypeScript inside a pnpm monorepo. Each surface keeps its own data on the device and reconciles through commutative operations rather than absolute values — the difference between “this sale removed 2 units” and “stock is now 17”, and the reason concurrent offline registers converge instead of clobbering one another.

What it does

Register — offline checkout, barcode scanning, free-form entries, change calculation, printable receipts, PDF invoices.

Inventory — goods receipt, price corrections, low-stock alerts, a full movement trail.

Sales — history, partial returns, cancellations, refunds.

Multi-shop — strict tenant isolation, owner / manager / employee roles, super-admin.

Catalogue — barcode import from Open Food Facts, compressed product photos.

Accounting — VAT handling on tax-inclusive and tax-exclusive prices, numbered invoices, an audit log.

Installing it

There is no app store in the loop. The register is a progressive web app: open it in a browser, choose “install”, and it lands on the home screen as a full-screen application with its own icon. A service worker keeps the interface and the local catalogue on the device, so it opens and takes payments with the connection down.

That matters more than it sounds. Shipping through the stores would mean an Apple developer account, a review queue, and a release cycle measured in days for a shop that needs a fix this afternoon. Installing from the browser puts a correction in a cashier’s hands the moment CI is green.

Running it

Docker and Traefik on a VPS, deployed over SSH from GitHub Actions. The web and mobile surfaces are in production and in daily use in a real shop, and signing up for a new shop is open to anyone.

The Electron desktop register takes payments offline, keeps inventory and history, and updates itself. What it lacks comes down to one thing: a signature. Without a certificate, Windows shows a SmartScreen warning on first launch — the installer is published, but opening it takes a detour through “More info”.