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.
Trade discounts are not "10% off with code". They are forty trigger types — quantity of a family, amount across a department, every nth order, first order, cartons, gifts, vouchers, customer‑exclusive deals — stacked, metered, re‑evaluated on every basket change, and written to every invoice line as an allowance you can audit. How aiku's discount engine works, why buy‑X‑get‑cheapest‑free counts the way it does, and the penny that float arithmetic tried to steal.
A warehouse note that is "blocked" with nothing blocking it is the worst kind of bug — invisible until a picker is standing there with no button. We replaced four cached flags and six readers with two generated columns, one predicate and an alarm.
3,300 tests against a real PostgreSQL with 800 tables, restored from a dump before every file, run in parallel on ten processes in CI and by a dozen people and their AI agents at once locally — without stepping on each other. No mocks of the schema, no synthetic repositories. How the TEST_TOKEN trick makes that possible, and the four ways such a suite goes flaky.
Four years, 1,659 migrations, 793 tables, twenty thousand columns, five thousand indexes. How the aiku schema got this big without getting lost — the group/organisation/shop spine on every row, a stats table beside every entity, slugs as public identity, jsonb where the business is still deciding, and the bridge columns that let us migrate off a twenty‑year‑old system one table at a time.
We did not rewrite the twenty‑year‑old system and flip a switch. We built the new one beside it, pulled the data across entity by entity with 106 fetchers, ran both for years, and moved one company at a time — 588,000 customers, 1.08 million invoices, eventually 88 million rows of history. The "source id" on every row, the fetchers that could not be allowed to overwrite what people had edited in the new system, the guard that froze the catalogue, the import of two decades of audit trail, and the rule that a closed shop must rest in peace.
Eight years of sent email — 245 million rows, 217 GB, never pruned — was slowing down a daily rollup and bloating every developer's copy of the database. How we moved it to an archive server in verified batches, why the retention window is 90 days and not 60, and the one trick that keeps historical stats correct after the rows are gone.
Stock in aiku is never a number you set; it is the sum of movements you record — purchase, pick, return, transfer, production, found, write‑off, audit. How 88,000 stock items across 45,000 locations stay honest: a location‑stock row per bay, a picking location per item, audits as movements with a delta and a reason, a lock that stops a low count being audited mid‑pick, and the "error" naming rule that keeps a retired SKU from ever being picked again.
Weighted average cost and FIFO computed in one pass over the movement history, a group-level switch that decides which one is "official", and why LIFO is deliberately missing.
No Kubernetes, no managed database, no serverless. aiku runs a multi‑country commerce operation on a handful of rented bare‑metal machines behind Cloudflare — a primary, a replica and a staging box — and we would choose it again. Why metal beats "cloud" for a workload like ours, what the boxes actually do, and the two incidents that are the honest cost of owning the iron.
We had an attribution feature for years and it had credited 0.08% of customers. Here is what was wrong, what we rebuilt — twenty channels, three email channels, ROAS and CAC with real costs, a per-customer journey — and the one invariant we now check after every change.
For years every line we sold carried the same VAT rate, so one rate per order was simply true. Then the range grew to include tea — zero‑rated in one market, reduced in another — and "which rate" became a question per line. The answer was not "read the product's tax code": it was presets instead of codes for staff, tax versioned like price on the historic line, frozen once sold, and a migration that re‑rated the open baskets to the penny.
When the application moved to long‑lived workers, the commercial APM agent we had run for years stopped telling the truth — and on the test runner it stopped the tests. We replaced it with NightOwl, an open‑source telemetry stack for Laravel: an agent on each box, a local buffer that survives outages, and every request, job, query, exception and log line landing as rows in a PostgreSQL database we own, on a server we already pay for, with retention measured in years. The best part arrived by accident — an AI assistant connected straight to that database with read‑only SQL.
Every count, total and trend in aiku is precomputed — by ~650 small "hydrator" jobs that run at the point of change and a nightly sweep that catches what they missed, into ~150 stats tables and 35 partitioned time series at five frequencies. Why we chose that over computing on read, the bug where a single‑day redo flattened a whole month, and the index traps in partitioned tables.
The same candle is one thing to the buyer, a box of twelve to the warehouse, and a litre of base to the factory. aiku models that with three corners — the trade unit (the physical thing), the stock (that thing, in this warehouse), the product (that thing, as sold in this shop) — and a number on every edge. Why a fraction is sometimes right and sometimes a bug, and why changing a number on an edge while an order is in flight is the most dangerous edit in the system.