analytics
Portafolio de Iván
Projects chevron_right Multichannel operations hub

Production system · 2026

hub Multichannel integration inventory Inventory database PostgreSQL verified 143 tests

Zero overselling: a multichannel operations hub

A haberdashery business in Mexico sold on Mercado Libre with three isolated inventories that never talked to each other. Today a central append-only ledger decides what stock each channel sees, and no write is trusted until it is read back.

Key numbers

796

listings audited in the initial clean-up

1,742

movements in the append-only ledger

3.5 ms

90-day query, with no new indexes

143

automated tests (up from 115)

Tech stack

Node 22TypeScriptExpressPostgreSQLzodpinosharpPDFKitMercado Libre API
schema

How a sale travels

The central inventory is the single source of truth. Channels read from it, and the ledger records — never edits — every movement.

  1. storefront Channel

    Sale on Mercado Libre

    The order arrives through the channel API, with its listing and variation.

  2. receipt_long Ledger

    Append-only movement

    A new movement is recorded. Nothing is edited or deleted: corrections are added.

  3. inventory_2 Hub

    Stock recalculated

    The central inventory recomputes real availability for that SKU.

  4. sync_alt Write-back

    Write to the channel

    If needed, the channel is adjusted — and the write is read back to verify it.

  5. shopping_cart Storefront

    The shop serves from the hub

    The web shop no longer keeps its own stock; it publishes the hub's availability.

store

Context

The business is a haberdashery shop in Mexico whose main sales channel is Mercado Libre, moving in the order of 500 units a month on that channel alone. Day-to-day operations are run by a small team that moves physical boxes, packs shipments and answers customers; nobody is sitting around waiting for a system to ask for attention.

When I came in, stock lived in three places at once: a mirror of the Mercado Libre catalogue, the physical warehouse count, and the point of sale. None of them talked to the others. Channel sales were not recorded in any system of their own, and the web shop did not even decrement stock when someone paid.

The brief was not «build a dashboard». It was to build the place where stock finally means one single thing — without switching off the business while it was being built.

report

The problem

Three isolated inventories, and none of the three was the right one.

With three sources out of sync, overselling is not an accident: it is a matter of time. Selling a piece that already left through another channel means cancelling, apologising and paying for it in account reputation, which is the most expensive asset a marketplace seller owns.

What made it worse is that history could not be reconstructed. With no record of movements, the question «why does this box say eight when there are five?» had no possible answer: all you could do was count again and trust the new number until the next discrepancy.

And then there was the risk of the cure itself. A system that starts writing stock levels into a channel with 796 live listings can do enormous damage in a single miscalculated run. Any solution had to be useful even while switched off.

rule

Key decisions

These five are why the system could be switched on without anyone losing a night of sleep.

01 A 2xx proves nothing

Every write to Mercado Libre is read back from the channel and compared against what we meant to write. If they do not match, the movement is marked as failed, not as done.

psychology A third-party API can accept a request, answer «fine» and apply something else — or nothing. If the system believes the response instead of the state, inventory drifts away from reality exactly where nobody is looking.

02 An activation ladder, listing by listing

Nothing is switched on at once. The mode goes from off to simulation for three days, then to reduce-only, and only at the end to full writes. The first listing to climb the ladder was hand-picked, and it was a cheap one.

psychology If the system gets it wrong, I want it to get it wrong on the cheapest item in the catalogue with the team watching, not on 796 listings at once. Simulation shows exactly what it would have done before letting it do it.

03 Not writing is always safe

The process refuses to write when its data is stale: a catalogue older than 24 hours, or a warehouse cursor more than 15 minutes behind. It also aborts a run that would touch more than 20 listings or more than 150 units at a time.

psychology When in doubt, the worst outcome of doing nothing is that the channel stays as it was. The worst outcome of writing with stale data is overselling or emptying healthy listings. The asymmetry is too big to argue about.

04 A red button with no redeploy

There is a global kill switch that stops every write instantly without touching code or shipping a release, plus intermediate modes that allow reducing stock but not increasing it.

psychology When something goes wrong in production, the person who notices needs to be able to stop it in seconds. If switching off requires a deployment, in practice nothing gets switched off: people wait it out, and the damage grows.

05 Coverage with no sales is null, never zero

If a product has no sales velocity, days of coverage is reported as missing data. The CSV files the team consumes are written with a UTF-8 BOM so Excel does not mangle accents.

psychology A zero reads as «critical, it runs out today» and sends someone to restock what nobody buys. Missing data reads as what it is: there is not enough information here to have an opinion.

construction

The solution

The system was built in six phases, each useful on its own. First, cleaning up product keys: with no trustworthy SKU there is nothing to reconcile. Then a read-only central inventory that spent weeks just watching and comparing, with no authority to change anything.

The third phase brought the ledger: an append-only record of sales movements. A wrong movement is not edited, it is corrected by adding another, and stock is always the sum of history. Backfilling 90 days of history takes about two minutes, and querying that same window runs in 3.5 ms with no new indexes.

With trustworthy history in place the relationship could be inverted: the fourth phase writes back to the channel through a reconciler that verifies each write, and the fifth makes the web shop drop its own stock and serve the hub's availability instead. The last two open the way to a second channel and to the analytics layer.

It all runs on Node 22 with TypeScript over PostgreSQL, with schema validation at the boundaries, structured event logging, and CSV and PDF reports for people who work from a desk, not from a terminal.

emoji_events

Results

Sales figures are published in units only. The business's monetary amounts are not published, by the project's own rule.

lightbulb

What I learned

That the hard part of channel integration is not the API: it is deciding who is right when two systems disagree. That agreement has to be made before the first line of code, because afterwards the code makes it on its own, and almost always badly.

That a system that can be switched off quickly gets switched on sooner. The activation ladder looked like bureaucracy and turned out to be what made starting possible: nobody had to bet the account on the software being right first time.

And that a figure's honesty is worth more than its availability. Reporting absence instead of a comfortable zero is awkward the first time someone sees it on screen, and it is what stops decisions being made on invented numbers.

Selling on more than one channel and your stock never adds up? This is exactly the problem I solve.

mail Let's talk