STP: Vehicle Cost Platform
A platform that tells a carmaker what a car costs and whether it's still profitable, the moment a price, an exchange rate or a design choice changes.
Team of six at EPITA, Sep-Oct 2026
Python, FastAPI, PostgreSQL, Kafka, SvelteKit, OData v4
- to serve a 20,000-part car's cost
- 5.8 ms
- to recompute it after a price change
- 45 ms
- reads per second, 1 → 3 copies
- ×1.8
- floating-point numbers near money
- 0
Measured on generated parts lists of 20,000 parts (a real car has around 30,000), medians of 5 runs on a 12-core development machine. Before these optimizations the same two answers took about 220 ms and 750 ms.
STP answers the questions a carmaker has while a car is still being designed: what this version costs at a given volume, whether it's still profitable against the market, and what happens if a part, a supplier, an exchange rate or the volume changes. I was the Product Owner and Scrum Master of a team of six.
A car has around 30,000 parts, and supplier prices, volume discounts and exchange rates move every day. ERPs, the systems that buy the parts and run production, cost a car accurately but late: from a frozen bill of materials (BOM), in scheduled runs, often monthly. Meanwhile engineers estimate in spreadsheets nobody else can check, even though most of a product's cost is committed by design choices (what carmakers already have).
How it's built
STP sits between the design tools, where a car's structure comes from, and the ERP, which keeps buying and building. It replaces the spreadsheet, not either system.
PostgreSQL holds every BOM, price and exchange rate. The backend computes costs, keeps the BOMs in use in memory, and runs as several identical instances. A controller fetches supplier prices from the ERP and sends published BOMs back to it.
Fast, and exact
- Only what changed is recomputed. A price change recomputes the assemblies that contain that part, not the whole car: 45 ms instead of 750 on 20,000 parts (how).
- More users means more instances, and none can answer from memory another one has made out of date (any instance, the same answer).
- No floating-point money. Every amount is an exact decimal, and each price is converted from its supplier's currency before anything is added up (never add two currencies).
- Every line explains itself, and a quote freezes the prices and rates it used (a number you can replay).
Through every optimization, across nine versions of the code, the 20,000-part test BOM always cost exactly 41,541,375.82 EUR.
Where it stands
Versioned BOMs, multi-currency costing at any volume, margins, scenarios, frozen quotes and the two-way ERP integration work end to end, against a simulated ERP. Every structural decision was written down before the code that depended on it (how we worked). The known limits are a simulated exchange-rate feed, one editor at a time per BOM, and a slower first access while a large BOM loads into memory. Next would come a BOM per plant and the cost of each manufacturing operation.
Writing on STP
10 posts, in the order they're meant to be read.
The product
- 1What carmakers already have, and where STP fitsBefore designing anything, we looked at how ERPs cost a car and what engineers use instead. Six pain points came out of it, and so did the rule that STP must plug into the systems already there, at a carmaker's scale.3 min read
- 2"What if" is answered by the backendThe dollar gains 10%: is the SUV still profitable? Margins, scenarios, price tiers and sensitivity curves, all computed server-side, so the browser never subtracts two amounts.3 min read
- 3A BOM that looks like a carSample data is part of the product. Six data sets, each answering one question, and a realistic SUV whose depth comes from subassemblies carrying their own parts, the way a real BOM's does.2 min read
Correct by construction
- 4Never add two currenciesA cost total should be rebuildable by hand from its lines, to the cent, in any currency. That rules out floats, early rounding, and adding prices before converting them.3 min read
- 5A number you can replayDrafts change, published versions don't, and a quote freezes every price and rate it used. So any number can be traced back to what produced it, and a number sent to someone never changes.3 min read
- 6The ERP never pushesSTP pulls supplier prices with a cursor, commits them before announcing them, and makes every consumer safe to run twice on the same message, so no failure leaves a price it can't account for.3 min read
Fast by design
- 7Recomputing only what a price touchedWhen one part changes price, only the assemblies above it are wrong. Recomputing just those takes 45 ms instead of 750 on a 20,000-part BOM, and gives the same result to the cent.3 min read
- 8Any instance, the same answerThree backend instances behind nginx, each with its own caches. One rule and three mechanisms keep any of them from answering out of stale memory.2 min read
- 9Where the time actually wentThree rounds of optimization made the backend faster at what they targeted, yet a cached read still took 220 ms. A profile showed 94% of it was re-rendering JSON that hadn't changed.3 min read