Skip to content
In production · paying customers

A cloud ERP we built, sold, and have run every day since.

Optician Dynamics runs optical retail businesses — the till, the prescription, the lens order, the stock in four branches and the ledger underneath all of it. Multi-tenant, cloud-hosted, billed in three currencies, and carrying its own pager.

It is the reason we can talk about operating software rather than only shipping it — and the standard every client project is now held to.

The Optician Dynamics product site, showing the multi-branch optical ERP.

What is actually in it

Optical is a shop, a lab and a clinic in one building, so the software has to be all three. This is the shape of a system that took years to get right — worth reading if you are weighing up what a serious build involves.

Point of sale

Built for dispensing rather than general retail: a sale can carry a frame, a lens specification and a professional fee, split across payment modes, with the cash drawer and the day-end reconciliation attached to it.

Prescriptions & Rx history

Sphere, cylinder, axis, addition and pupillary distance per eye, captured against the patient and kept as history — so last year is one click away and the change over time is a chart, not a memory.

Appointments & recalls

A per-branch diary with arrived, completed, no-show and cancelled as real states. Recalls close against the appointment that answers them, so the follow-up list is the one thing nobody has to maintain by hand.

Lab & workshop routing

A job card that moves through received, material ready, in production, dispatched, finalising and ready for delivery — with the technician, the expected date and a log at every stage, so "where is my order" has an answer.

Stock across branches

Stock held per branch, per warehouse, per product, per receiving batch — each batch with its own cost and retail price. That last detail is why the till can tell two identical frames apart when they were bought at different prices.

Transfers between branches

Request, approve, dispatch, receive — with disputes, cancellation and a void that reverses the accounting behind it. Inter-branch balances settle rather than drift.

Purchasing & suppliers

Purchase orders, receiving against them with cost and barcode assignment, returns, and supplier accounts with a running trade balance.

Double-entry accounting

A real general ledger: chart of accounts, daily balances per account and business date, trial balance, balance sheet, profit and loss, fiscal periods and a year-end close. Multi-currency, multi-branch, multi-tenant.

Payments

Customer accounts and settlements, cash-drawer modes, and gateway integrations — JazzCash and Safepay, wired end to end rather than listed as a logo.

HR & payroll

Employees, departments, attendance with regularisation, leave, salary structures, advances and loans, and disbursement that posts to the ledger. Sold as an add-on rather than bundled, because not every shop needs it.

Storefront & e-commerce

An online store sharing one stock position with the shop floor, so the website cannot sell a frame that a walk-in customer just bought.

Reporting

Server-rendered PDFs off the live data — sales, stock, ageing, ledger and end-of-day packs — with parameters filled from the session rather than typed by hand.

The parts that are actually hard

Anyone can demo a point of sale. These are the things that decide whether it survives contact with a real business.

Every tenant gets their own schema

One shop’s data is not a WHERE clause away from another’s. Tenants are resolved at the connection, which removes an entire category of leak — and creates the problem in the next row.

Schema changes have to reach every tenant

Shipping a migration to one database is trivial. Shipping it to a whole fleet, in order, and knowing precisely which tenants lagged behind, is the actual work. We built a fan-out pipeline with drift detection because doing it by hand does not survive the tenth customer.

The money paths need their own alarms

Uptime monitoring tells you the site is up. It does not tell you that end-of-day reconciliation silently stopped running, or that a payment mode has no accounting behind it and every sale using it is being refused. Those need tracing and alerting on the specific paths that carry money.

The till has to work when the internet does not

A shop that cannot ring up a sale is losing money in real time. That is a different architecture, not a retry — a desktop point of sale with a local database that reconciles when the line comes back.

Correctness beats features in finance

A trial balance either balances or it does not, and a customer with an accounting background will find out in one minute. That constraint shaped the whole ledger: daily balances per account and date, an audit trail, and a fiscal close that cannot be fudged.

Under the hood

The same engineering we bring to client work, because it is literally the same pipeline. Nothing here is a diagram in a proposal — it is what runs tonight.

How we run it
Services
Spring Boot microservices behind an API gateway — identity, warehouse, tenancy, documents, reporting, notifications, e-commerce.
Front end
Angular, plus an Electron desktop build for the offline point of sale.
Isolation
Per-tenant database schemas, resolved at request time.
Migrations
Liquibase changesets fanned out across the tenant fleet by a worker, with drift detection.
Delivery
Self-hosted GitLab and runners, shared pipeline templates, gated deploys to staging then production.
Observability
SigNoz for traces, logs and metrics, with alerting routed to a phone rather than an inbox.

What running it taught us

Every one of these cost us something to learn. They are now the defaults on client work, which is the practical reason to hire a company that operates its own product.

Uptime is a product feature

A shop that cannot sell is losing money while you investigate. Monitoring, alerting and a rollback path are not hardening you add later; they are the first thing we build, on client work too.

Migrations are the hard part

The interesting failures are never the code. They are a changeset that reached fourteen tenants out of fifteen, and the fifteenth being the one that pays the most. Now we verify the fan-out rather than trusting a green pipeline.

Support tells you the truth

We run our own support queue, so every rough edge arrives unfiltered by an account manager. It is uncomfortable and it is the fastest feedback loop in the company.

A green build proves less than you think

We have shipped a broken production release off a fully green pipeline. Now the pipeline verifies the deployed artefact resolves — the check is on reality, not on the build’s opinion of itself.

Questions we get asked

Can we buy Optician Dynamics?
Yes, if you are an optical business — that is what it is for, and opticiandynamics.com is the right place to start. If you are in another sector, this page is evidence rather than a product pitch: talk to us about a build instead.
Is it really multi-tenant, or one install per customer?
Genuinely multi-tenant. One platform, one deployment, isolated schemas per tenant, with schema changes fanned out across the fleet. One install per customer is a much easier thing to build and a much harder thing to operate.
Who runs it?
We do. The same team that wrote it carries the monitoring, the migrations, the upgrades and the support queue. There is no third party between the people who built it and the people it breaks for.
Would you build our product and then hand it over?
If that is what you want, yes — and we will set it up so you can actually run it, with the pipeline and the monitoring, not just a repository. Most clients ask us to keep operating it, which is the arrangement we prefer and price for.

Your business is not an optical shop. That is rather the point.

What transfers is not the software — it is knowing what breaks at year three, and having already built the machinery that stops it. Tell us what you are running on now.

Talk to us

Book a call