Aluminum Joinery Quoter

An aluminum joinery quoter that gives credible prices, not made-up numbers.

RoleSole developer: product, pricing engine, backend, database, security and mobile appClientGrupo CPS, aluminum-and-glass joinery industryYear2026CodePrivate · owned by Grupo CPS
Next.js 16ReactTypeScriptTailwindCSS 4Three.jsPostgreSQLSupabase self-hostedExpo / React NativeJest
2.44× → ~1%

How much the error in calculating the aluminum dropped, compared to the factory system. I did not fix it with a hand-tuned fudge factor, but by understanding where the difference came from.

A web app, and now a mobile app too, where the client builds their order of aluminum-and-glass windows and gets a price. The challenge was not the screen, but getting the price right: what looked like a simple formula actually depended on how much aluminum and glass each window really uses. To get it right, I studied the 2,641 real recipes from the factory software, pulled out the numbers that drive the cost, and then validated it with test orders the factory itself priced in that software.

Grupo CPS manufactures aluminum-and-glass joinery. Quoting each order by hand is slow and depends on technical staff: every client inquiry took up someone’s time at the factory before anyone even knew whether the order was serious.

They wanted a simple web app where the client signs up, builds a cart with their windows, sends the order and tracks it. The problem was in the word “simple”: the price of a window does not come from multiplying area by a price per square meter. It depends on how much aluminum profile each window type uses (frame, sash, glazing bead, transoms), on the real glass measurement, on hardware, labor, margin and VAT.

The company already calculated all of this precisely in its factory software, WinMaker, which stores one “recipe” per window type: 2,641 files in a closed format, impossible to use directly on a website. My first simple calculation counted 2.44× less aluminum than the window actually uses.

What I had to work around.

No access to the factory software from the web

WinMaker is a desktop system with its own format. It exposes no API and cannot be queried live: whatever I needed from it had to be extracted once and live in my model.

Internal costs that can never leak

The client must see a final price, never the cost, the margin or the price per square meter. Any design where the browser does the math was out from the start.

Data maintained by technicians, not the programmer

Recipes, catalogs, colors and parameters change with the factory. They had to be editable from a panel, without touching code.

A single developer

Product, engine, backend, database and security, in parallel with other company systems. Every layer had to be simple to maintain.

Pull from the recipes only the numbers that move the price, without copying the whole factory software.

I had two bad options: a simple formula (fast but false) or rebuilding the entire factory software (precise but unfeasible). I chose the middle ground: read from the recipes only the measurements that affect the cost.

The error was not a wrong number, it was structural. The simple formula counted only the outline of the frame. But a real window holds much more aluminum: the frame, the opening sash, the bead that holds the glass and the transoms. And the glass is measured by the real opening that is left, not by the total size of the window.

So I built a program that reads those 2,641 recipes and pulls out, for each window type, the exact measurements the factory already uses. Those measurements feed the pricing calculation that already existed: what changes is how much material is counted, not how the price is built.

Simple formula calculated4.75 m
Now calculates (factory: 11.61 m)11.72 m

Concrete example, the one I measured with: a 1200×1000 mm fixed window with one transom. The simple formula calculated 4.75 m of aluminum profile. For that same window, the factory software breaks down 11.61 m: the frame, the transom and the glazing bead of each pane. With the measurements pulled from the recipes, my calculation gives 11.72 m. That is where the 2.44× comes from, and where the ~1% comes from.

Why it is built this way.

Pure pricing engine, no I/O

All the pricing is pure functions, testable with no database. That is why it could be validated against the factory without spinning up any service, and the mobile app reuses it as is to quote offline.

Geometry separated from costing

The recipes changed how much material is counted without touching how the price is built. Later the costing became real too (each profile by its weight and the per-kilo price of the chosen color, labor per recipe) without touching the geometry. Each half changed without breaking the other.

Custom parser and AST evaluator for the .PRO format

Instead of executing the recipes, a static parser extracts per window type only the geometric constants (74, 126, 82/148 mm depending on the type), and each one is cited to its source file.

Immutable snapshot per order

Each order freezes the prices and names of that moment, with its number assigned atomically in the database (FOR UPDATE). Two simultaneous orders never share a number and a sent price never changes behind the scenes.

All the calculation on the server side

Endpoints return DTOs with no sensitive data. The service role lives only on the server and RLS is enabled with no public policies.

No complete recipe, no price

A line and window-type combination without a complete recipe is not offered, and a window that needs technical review is saved without a price. I would rather not quote than quote with an estimate dressed up as a price.

The order goes back to the factory software

Each order generates a .pto file the factory opens in WinMaker, which draws it and breaks it down with its own recipe. The format I first had to decode ended up being where the order lands.

What I ruled out along the way.

Area × price per m² formula

Fast, but it counted 2.44× less aluminum than real. A hand-tuned correction factor would have hidden the error instead of fixing it.

Porting all of WinMaker to the web

Precise, but unfeasible: 2,641 recipes in a closed format and a full manufacturing engine, for what had to be an entry-level quoter.

Summary links with sequential IDs

They allowed enumerating other people’s orders by changing a number. Replaced with UUID tokens impossible to guess.

Calculating with costs in the browser

It would have exposed costs and margins to anyone opening the dev tools. The calculation with costs runs on the server; the mobile app quotes offline, but only with sale prices.

A full-stack app with a pricing engine at its core.

  1. 01

    Step-by-step builder, with the window in 3D

    The client picks type, dimensions, line, glass, color and accessories across four screens, with a live price. They see the window in 3D, which they can rotate, and the technical drawing, and can compare lines and glass before deciding.

  2. 02

    Quote without an account

    They leave their contact details first and then build the window. Clients with an account keep drafts and orders.

  3. 03

    Several windows per order

    They add, duplicate and adjust windows in one order until it is the way they want.

  4. 04

    Quote as a PDF

    A clean PDF with all the windows, their specs and the total. Resellers get a version with their own brand to hand to their client.

  5. 05

    Frozen order and tracking

    On submit, the prices and names of that moment are saved and nothing is recalculated behind the scenes. In “My orders” they see the status of each one and can share a summary via a private link.

  6. 06

    Offline mobile app (in development)

    An app that uses the same pricing engine as the web and quotes with no signal, using downloaded sale prices. Orders wait in a queue and send themselves when the connection comes back.

The quoter does not replace WinMaker, the system the factory has always worked with: it is the client’s front door, and the order ends up there, as a file WinMaker opens. The client never sees internal costs or margin: only the final price reaches the browser and the app.

An internal panel where technicians load the factory’s reality.

Parameterizable technical recipes

Technicians load what each window type takes: profiles with their cuts, accessories, glass and manufacturable limits. Each recipe picks components from real catalogs: profiles with their price per color, accessories, IGU spacers and labor.

Load status per recipe

A board shows what each recipe is missing to quote with real cost: profiles not loaded, profiles with no price in the color, limits or accessories. Whatever is incomplete is not offered to the client.

From order to workshop

Each order shows its cost breakdown and moves through statuses aligned with the company’s sales board. From there, the team generates the .pto file the factory opens in WinMaker.

Parameters that govern the engine

Margin, VAT, waste factors, colors with their WinMaker code, the dollar exchange rate taken from the Central Bank (with history and a manual fallback), and users with roles and discounts: everything that affects the price is managed from the panel, behind APIs with role-based access control.

This is what lets the system live without the programmer: the owners of the data are the factory technicians, not the code. The client-facing page is the visible half; this is the half that keeps it honest.

How it all fits together, in a diagram you can move around.

Five views with draggable boxes and a step-by-step walkthrough: the full circuit, what the client does, how the price is calculated, what the technician loads and how the order reaches the factory. It is the same piece I use to explain the system in ten minutes.

A strict boundary between public and private.

UI

Web and mobile app

Configurator · orders · Expo app that quotes offline.

API

app/api/*

HTTP boundary: auth, authorization and DTOs with no sensitive data.

SRV

src/server/*

Private logic: orders, PDF, the .pto file and the exchange rate.

CALC

src/lib/cotizador/*

Pure pricing engine, no I/O; the app reuses it to quote offline.

DOM

src/technical/* · src/shared/*

Window types, validations and contracts shared by web and mobile.

DB

PostgreSQL

Canonical schema on self-hosted Supabase, with Row-Level Security.

The part that calculates measurements is separated from the part that builds the price, and neither touches the database. That is why bringing in the factory numbers did not break the prices, real costing did not break the geometry, and the mobile app could use the same engine without rewriting it.

Client data and internal costs are at stake: security was a requirement, not an add-on.

No data served straight from the database

Everything goes through the server with login. The database master key lives only there, it never reaches the client’s browser.

Share links impossible to guess

A summary link is not a running number (1, 2, 3…) but a random code, so nobody can change it to peek at other people’s orders.

Inputs always bounded

Dimensions within each recipe’s limits, integer quantities with a cap, limited text. An unknown color stops the quote instead of quoting wrong.

Internal costs never exposed

The client sees the final price, never the cost or the margin. The calculation with costs happens on the server, and the mobile app only receives sale prices.

Frozen, auditable orders

Each order stores an immutable snapshot of prices and names, with its number assigned atomically in the database: two simultaneous orders never share a number, and nothing changes behind the scenes afterward.

Access control checked on every build

A test fails the build if any API route is left without access control. A self-run audit also closed a cost leak in a public route and hardened the headers.

What can be measured.

2.44× → ~1%

error in the aluminum calculation against the factory system, fixed in the geometry rather than with a correction factor.

2,641

real factory recipes analyzed by reverse engineering.

Validated

with test orders the factory itself priced in WinMaker: the web’s cost never falls below the workshop’s.

In production

at cotizador.grupocps.com.uy, the front door for Grupo CPS clients.

How I know the numbers are right.

Factory recipes analyzed
2,641
Proprietary .PRO format cracked
Custom parser + safe AST evaluator
Material error vs. the factory system
2.44× → ~1%
Validation
Test orders priced by the factory in WinMaker
Calibration
The company’s historical quote archive
Access control
Checked by a test on every API route
Code quality
Strict TypeScript, no type errors

The “shadow mode”: a tool that compares, window by window, what my system calculates against the real parts breakdown from the factory software. It measures how far off I am before calling a price good. Then came the real test: orders the factory priced in its own software and sent back, with one fixed rule: every gap gets closed with a cause, not a coefficient.

The quoter in action.

System walkthrough: from building the window in 3D to the submitted order.
3D visualization: the quoted window rotates to be seen from any angle.
Generated PDF with the assembled quote
PDF generated automatically with the assembled quote, ready to save or share.
Internal technical-data panel of the quoter
The internal panel: technical recipes, catalogs and the parameters that feed the engine.
Recipe load status with real-cost traffic light
The “load status” view: what each recipe is missing to quote with real cost.
  • The hard problem is rarely the visible one: the screen was the easy part, the value was in calculating well and validating the numbers.
  • I did not brute-force copy the 2,641 recipes: I pulled out only what moves the cost and left the rest as separate research.
  • Measure before you claim: “shadow mode” turned a hunch (“the price doesn’t add up”) into a number (2.44×) and then into a validation (~1%).
  • A complete system includes whoever maintains it: the internal panel and its load status make the technicians, not the programmer, the owners of the data.
  • A pure core pays off: since the engine never touched the database, the offline mobile app came out by reusing it, without rewriting the calculation.

Want to talk about this project?

The code is private, but I can walk you through how it is built. Write to me if this interests you or you want to talk about a role.