Short write‑ups of problems we hit running a real commerce operation and what we changed in the code because of them. No product announcements; just the reasoning.
A live chat on every storefront, answered from the staff app by agents who see the customer's account, orders and history beside the conversation; messages translated both ways; a session that can become a ticket, a Slack thread or a summary; presence and typing over WebSockets; a dashboard of who is on the site right now and from where. And the tone rules we wrote down when an assistant started drafting replies.
226,000 images — product photos, family banners, logos, pallet photos, chat attachments — stored once and never resized by us. Every image on every page is a signed URL to an image proxy that resizes, crops and converts on the fly: AVIF and WebP with a fallback, a retina variant of each, the right width for the slot, cached at the edge. Why a proxy beat pre‑generated thumbnails, how the signature stops the proxy being a free resizer for the internet, and the "picture" element every card uses.
A trade buyer reordering forty lines, a dropshipper running a shop on someone else's platform, and a brand whose pallets we store — all log into the same customer portal, built on the same code as the staff app, living on the storefront's own domain. What each sees, what they share, why the dropshipper's order is the most complicated object in the system, and the two things the portal refuses to let a customer do.
Why a trading company wrote its own CMS instead of bolting a shop onto a page builder, and how two front‑end engineers turned "we need a product page" into seventy‑odd web blocks, a workshop that edits the live site, snapshots you can publish and roll back, and a storefront that knows its own catalogue.
Running a third‑party fulfilment business inside the same system as your own warehouse: pallets, boxes and oversize items that belong to someone else, stored items inside them, rental agreements with clauses, and a recurring bill that consolidates itself on the customer's cycle. Why a pallet's lifecycle needs twenty states and a separate "booked in" from "received", and how the 3PL customer sees all of it in their own portal.
The search box in the staff app finds a customer, an order, a pallet, a mailshot, an employee, a chat message — forty‑two model types — scoped to what you may see, typo‑tolerant, in one keystroke. How it runs on Typesense next to the application, why three places must change in lockstep when a new thing becomes searchable, the reindex command that rebuilds a section while people keep working, and the afternoon the search engine's raft log got stuck.
Our storefronts are server-rendered and personalised, which is the worst case for an HTTP cache. Here is how we put Varnish in front of them anyway — two hash buckets, a logged-in bit, tagged objects, surgical bans, and a warmer that only warms what people actually visit.
In February 2025 we stopped booting the framework on every request. What we gained, what bit us (state leaks, a deploy that kept deleting the running code, big headers), and the "anchor" directory that makes zero-downtime deploys boring.