Skip to content

Building products — glass balcony and guillotine system manufacturing

Turning a pricing spreadsheet into a quoting engine

A multi-tenant B2B application for the dealer network of a glass balcony, guillotine and sliding system manufacturer. The dealer measures on site and picks the system and glass; the server computes cost and sale price, produces the quote, and the job is tracked through production and installation.

Stack: NestJS · TypeScript · Prisma · PostgreSQL · Next.js · Flutter · Docker

Measured results

53
API endpoints
Project status record, 12 August 2026
88 + 195
Unit and end-to-end tests — all passing
Project status record, 12 August 2026
10 decimal places
Agreement between the engine and the manufacturer’s spreadsheet
Project status record, 12 August 2026
5 roles / 23 permissions
Permission matrix
Architecture decision record, 15 August 2026
4
Errors found and reported in the manufacturer’s own spreadsheet
Calculation engine analysis report §9

The problem

The manufacturer sells glass balcony and guillotine systems through its own dealer network. A dealer takes measurements in the customer's home, chooses the system, the colour and the glass, and quotes a price. For years that price came out of a spreadsheet.

The trouble with the spreadsheet was not that it was slow. The trouble was that every dealer had a copy of it. When the price list changed, nobody knew who was still working from which version. A mistake in a formula propagated quietly. And three months after a quote went out, nobody could say which exchange rate it had been calculated at.

The heart of this product is not a screen — it is the calculation engine. A wrong screen gets fixed. A wrong price has already reached the customer.

The approach

The engine lives on the server, in exactly one place. The mobile app and the web panel call the same endpoint. Written twice, it would eventually produce two different totals for the same configuration — the kind of discrepancy that surfaces only when a customer puts two quotes side by side. Panel geometry is computed server-side for the same reason: the front end draws the coordinates it is given rather than deriving its own.

Monetary values travel across the API as text. Floating point error is not an acceptable tolerance on a quote total. The front end does no arithmetic; it formats.

A field you may not see is absent from the response. For a dealer without cost visibility, the cost and margin fields are not empty — they are not there. Hiding a value in the interface is a design decision; security is not sending it.

Every project carries its own exchange rate snapshot. Without it, the same quote reopened three months later would show a different total, and that is an argument neither side can win.

Tenant isolation is enforced at the data layer, so one dealer's query cannot reach another's records because a developer forgot a filter. Authorisation runs on a matrix of five roles and twenty-three permissions.

The evidence

The engine was built against the manufacturer's own spreadsheet and the output was compared digit by digit: the results agree to ten decimal places. The comparison had an unplanned by-product — four errors were found in the manufacturer's spreadsheet and reported back.

The API exposes 53 endpoints today, and all 88 unit and 195 end-to-end tests pass. Every pull request is checked by CI; nothing goes straight to the main branches, and a pull request needs one approval.

The mobile demo was delivered on 30 July 2026.

Where it stands

The API runs in staging and the web panel is wired to the real API. Production has not been stood up yet, and the mobile app is still an offline demo.

Meanwhile the same product has been rebuilt for a second manufacturer, with its own brand and its own set of systems. That was the real exam: whether a business application written once can stand up for a second client without being written again.