By Hamza Makraz · · 7 min read
Building Farblieferant: a Sto paint dealer's shop on Symfony
How we took a certified Sto paint dealer from phone-and-email orders to a full online shop — a guided product finder, exact paint pricing, Stripe checkout, and a live link into Sto's ERP.
- case-study
- e-commerce
- symfony
- stripe
Putting a paint catalogue online is not the same problem as putting t-shirts online. Farblieferant is a certified Sto partner in Germany, and Sto products are technical: a façade render behaves nothing like an interior silicate paint, colours carry per-litre surcharges, and the price a customer pays has to match — to the cent — what the manufacturer’s ERP will invoice. The team had been selling the traditional way: phone, e-mail, trade contacts. They wanted a real shop. Not a template.
Here is what that actually took.
The challenge: a technical catalogue, non-expert buyers
Two things made this more than a generic storefront.
First, the buyers are mixed. Some are professional painters who know exactly which Sto product they want. Just as many are ambitious DIY customers who know the job — “I’m repainting a damp bathroom” — but not the product. A search bar serves the first group and abandons the second.
Second, this is Germany. The legal surface area — AGB, Widerrufsbelehrung, Impressum, Datenschutz, GDPR-conform cookie consent — is not a “phase two” item. It ships with release one or it doesn’t ship.
A product finder instead of a search bar
So the centrepiece of the storefront isn’t search — it’s a guided Produktberater. The buyer answers a short series of questions (where are you painting, which surface, which finish) and the shop narrows the catalogue to what actually fits.
Under the hood it’s a small recommendation engine. Each answer is linked to a set of product tags; each product carries tags of its own. When the buyer finishes the journey, we score every product by how many of the selected tags it matches and rank by that overlap — so the most relevant products surface first rather than an unordered filter result. The final step can even carry its own heading and copy, so a “damp bathroom” path lands on a page that reads like advice, not a query.
It’s built as a Symfony UX Live Component, so each answer updates the results in place — no full page reload, no single-page-app framework to maintain.
Pricing that has to be exact
Paint pricing is deceptively hard. A variant has a base price, a colour can add a per-litre or per-kilogram surcharge depending on its colour class, and a margin sits on top — then 19% VAT. Do that with floating-point arithmetic and you will, eventually, be one cent off on an invoice. In German retail, one cent off is a real problem.
So there is no float arithmetic in the money path. Every amount is stored as integer cents and computed with a precise decimal money library. The price the finder shows, the price in the cart, and the price the customer is charged are the same number, derived the same way.
Wired into Sto’s ERP
The prices and availability aren’t guesses, either. The shop talks to Sto’s ERP (SAP, via its Cloud Platform Integration layer) in two phases:
- Simulate — before an order is placed, ask the ERP to confirm current price and availability.
- Create — once payment succeeds, book the real order back into SAP.
That two-step flow is the difference between a shop that looks connected and one that won’t sell something it can’t fulfil.
Checkout, invoices, and the German essentials
Checkout runs on Stripe Checkout Sessions — cards, PayPal, and Klarna in one flow, with the order reference and any coupon carried through as metadata. On a paid order, an asynchronous job generates a PDF invoice and e-mails it to the customer; the heavy work happens off the request, so checkout stays fast.
Around that sit the things a German shop simply must have: the legal pages managed as editable CMS content, a free-shipping threshold and coupon engine, and Google Consent Mode v2 wired to the analytics layer so GTM only fires once the customer has actually consented.
The stack, and why
- Symfony 8 / PHP 8.5 for the backend — a boring, durable choice the team can run for years.
- Live Components + Stimulus for interactivity (cart, finder, search) — rich UX without shipping and maintaining a separate front-end app.
- Asset Mapper + Tailwind CSS v4 — no Webpack, no bundler config to babysit.
- A two-firewall security model — customers and back-office staff are fully separated, with a third, unauthenticated path reserved for the Stripe webhook.
- EasyAdmin for the back office, so the team runs the catalogue, orders, and coupons without a developer in the loop.
Nothing exotic. The interesting parts are the paint-specific pieces — the finder, the cent-exact pricing, the ERP link — not the framework.
What it adds up to
| Before | After |
|---|---|
| Orders by phone, e-mail, trade contacts | A full self-serve shop: browse, configure, pay, ship |
| Buyers had to already know the product | A guided finder that maps a job to the right product |
| Prices quoted manually | Cent-exact pricing, validated live against Sto’s ERP |
| No web presence | German-compliant from the first release |
If this sounds like your problem
We designed and built Farblieferant end to end — brand, storefront, pricing engine, ERP integration, and the back office the team runs day to day. We didn’t read about cent-precise pricing or two-phase ERP order flows; we shipped them.
If you’re a dealer or a brand sitting on a technical catalogue and a phone number where a shop should be, that’s exactly the kind of work we like. Tell us what you’re trying to build — we reply within one business day.