The platform map

The revenue operations platform I built and run at work, drawn as a map. Twenty-six systems for a mid-size manufacturer, built and maintained alongside a full-time marketing role. Together they run the work between an order arriving and the money being right -- pricing the sales, reconciling the payments, collapsing duplicate accounts into real customers, tracking every shipment, and flagging what drifted overnight. Open a group, then a system, to read why it exists and what it changed.

Select a group to open it

← Back to the map

One platform

One platform. Five groups, 26 systems.

The company runs on an ERP that was never built to talk to anything else. Orders, inventory, customers, shipping, tax, and marketing each lived in their own tool, and people moved data between them by hand.

This is the layer that connects them. Orders and inventory arrive from the ERP on a schedule and stay current. Customer records that arrived fragmented, where 77% of contacts shared an email address with another record, resolve to the real customer behind them. The tax reconciliation that cost accounting a week every month runs nightly and reports its own exceptions. Payments are checked against what the gateway actually settled, not what the ERP recorded. The warehouse gets the labels the ERP will not print. The storefront gets pricing, promotions, and availability that match what is actually in stock.

It has run in production since February 2026. One person built it and maintains it alongside a full-time marketing role.

Data Ingestion

The services that pull records out of the ERP and the other systems the business runs on, so current data arrives on a schedule instead of by hand.

Order, Inventory, and Product Ingestion

I built three services that pull changed records out of the ERP continuously, so every other tool on the platform works from current data.

Ingestion reporting in. Across the top, five stored credentials with the days left before each expires. Below them one tile per sync job, carrying what it changed in the last day, how many times it ran, how many of those runs errored, and when it last finished.
Run count and error count sit on the same tile, so a job that runs often and fails often is visible without opening it.

Live production view; identifying details substituted.

The constraint

Orders, inventory, and product records live in the hosted ERP, and everything I built has to read them. Reading product detail out of the ERP's own backend consumes one of the company's paid license seats, so a sync that opens that backend for every product competes with the people who need those seats to do their jobs.

How it works

The product sync runs in two phases. The first upserts everything the free REST API returns. The second opens the licensed backend reader only for the products the first phase flagged as changed. All three services write field-level diffs into one shared changelog, so a question about what changed has a single place to look.

Delta polling on its own would not be enough. The ERP sometimes corrects a record without bumping its modification stamp, and a stamp-based query never sees that edit, so a nightly pass re-scans every record regardless of stamp. Each service also holds its checkpoint until the last record of a batch is committed, so an interrupted run resumes where it actually left off. The local copy is never more than a day out of agreement with the ERP.

Read the full writeup on GitHub

Shipment and Order Tracking

A tracking pipeline I built to keep the status of every open shipment current, on carrier APIs that will not simply let you ask.

Open shipments grouped by where they have got to: 71 with a label created, 11 picked up, 63 in transit, 10 out for delivery and 4 carrying delays or issues. Each row shows the carrier service, how old the shipment is, its current status and its estimated arrival, over a line reporting the carriers were last polled four minutes ago.
Support works this board instead of pasting tracking numbers into carrier sites. Anything delayed or stuck sits in its own bucket instead of buried in the list.

Live production view; identifying details substituted.

The constraint

Customers and reps ask where an order is, and the answer lives at FedEx and USPS. FedEx allows roughly 1,000 tracking calls a day, and USPS direct polling allowed 60 an hour. Polling every open shipment on a flat cadence runs past both ceilings, and once the account is throttled nobody gets an answer.

The result

Every open shipment stays current on about 492 FedEx calls a day against a ceiling near 1,000, and support reads one status vocabulary rather than two carriers' worth.

How it works

The scheduler is the real work. It discovers open shipments from the ERP and spends a fixed call budget by urgency: a package out for delivery is worth checking constantly, one sitting in transit is not, and a delayed or exception shipment can wait longer still. Calls concentrate in the hours when deliveries actually happen, with one sweep overnight for late scans, which drops overnight usage by about 80%.

Underneath it, a normalizer collapses the carriers into one model the dashboard can render: more than 40 FedEx status codes and 11 USPS categories resolve onto 8 statuses. The pipeline picks its carrier client from the tracking number itself, because the carrier field on the order is not always right, and a later update can never overwrite a known delivery estimate with an empty one.

Read the full writeup on GitHub

Legacy Tooling Integration

A sync I built to read the company's central pricing and mapping workbook off SharePoint and land it in the platform database.

The constraint

The numbers that drive pricing and product mapping for the main brand live in an Excel workbook on SharePoint, maintained by hand by the people who own them. Anything downstream either re-keys those numbers or runs on a stale copy. The people who own those numbers work in that workbook every day and were not going to move out of it.

How it works

The file is checked far more often than it changes, so the sync asks SharePoint whether the document has moved before it asks for the document. Most checks end at the response header without transferring the file; only a real change triggers a download and a parse. The credential it holds is read-only, so the sync can never write back to the workbook; the write direction does not exist in the code.

Read the full writeup on GitHub

Email and Marketing Infrastructure

Two services I built to pull the marketing side of the business into the platform: email campaigns, and trade show attendees.

The email board: nine campaigns across four brands and a broadcast list, each row carrying its subject line, brand, send state and its link into the campaign tracker -- sale countdowns, a product launch, two firmware release notes, a maintenance notice and two show announcements. Across the top the board reports its last sync a minute back.
Campaign content syncs straight from the email platform, so the board is always live, and a preview of any campaign can be shared from here before it sends. Each row ties the campaign to its item on the project tracker.

Live production view; identifying details substituted.

The constraint

A campaign lives in two systems at once. The sending platform holds the campaign itself, and Monday.com holds the review workflow the marketing team already works in, so neither side knows the whole state of a send. The company's trade show runs on a ticketing platform with no public API, so the attendee list cannot be pulled on a schedule by any supported means.

The result

Campaigns from both systems merge into one record the platform can report on, and the attendee list arrives on its own every day instead of landing as a hand-exported spreadsheet.

How it works

People rename campaigns on both sides, so the sync normalizes the names before it compares them; matching on the raw values would drift apart within a week. The sending platform does not always expose preheader text as a field, so the service reads it back out of the campaign HTML, which is what the platform's own preview then shows.

The ticketing platform gave me no API to work with, so the import signs in the way a person does and drives the export from a saved browser session, then parses the file into the database on a schedule.

Read the full writeup on GitHub

Promotion Change Monitoring

I built a nightly check that reports when someone changes a promotional deal in the ERP.

Every promotion under watch: 265 deals with 93 of them active, sorted into groups that each carry their own on, off or archived state, from quantity and club discounts through dealer, warranty and regional pricing. The table lists each deal with its coupon code, whether it is live, and the group it belongs to.
Each group carries its own on, off or archived state, and the nightly check reads all of it out of a system that keeps no record of what changed.

Live production view; identifying details substituted.

The problem

Any employee with admin access can edit a live deal, and the ERP keeps no audit log and sends no notification when they do. Coupon codes have been blanked, discount amounts zeroed, and amount types flipped from percent to dollar, and nothing in the system told anyone it had happened.

The result

A change to any of 29 fields on a tracked deal now surfaces within a day, and the eight that decide whether a discount applies and how much it is come through at a higher severity.

How it works

The ERP's REST API was the obvious source and turned out to be the wrong one: its deals endpoint returns the metadata but omits the coupon code, the discount amount, the amount type, and the order amount, which are exactly the fields that get corrupted. So the check signs in to the ERP's own backend, opens each deal's edit form, and reads the values a person would see there, then compares them field by field against the previous night's copy.

Read the full writeup on GitHub

Customer Foundation

One current copy of the customer base, resolved down to the real people behind it, so the whole platform answers about the same customer.

Customer and Contact Mirror

I built the mirror that keeps the ERP's customer and contact records copied into PostgreSQL, so the rest of the platform has something it can actually query.

The result

The mirror holds more than 40,000 customers and 115,000 contacts as of August 2026, rebuilt nightly, and it is what every customer-facing tool on the platform reads from.

How it works

A nightly enumeration re-walks the whole source and upserts what it finds, roughly 470 paged requests, and it continues past transient errors, because one flaky call partway through a walk that long would throw away the entire refresh. Re-walking everything rather than tracking changes is the deliberate choice: the copy corrects itself every night, and the worst staleness anything downstream can read is 24 hours by construction.

Customers and contacts are two separate resources in the ERP, and which contact is the billing or shipping default is recorded on the customer rather than on the contact. A refresh that walked only contacts would leave those defaults pointing at contacts that had since been deactivated, so the sweep takes contacts first and customers second, then derives every default flag from the fresh copy in one set-based update. A separate nightly control re-checks that the flags still point at live contacts, instead of assuming the derivation held.

Identity Resolution

An engine I built to decide which of the ERP's customer accounts are the same human being.

The customer console. Facets across the top count 30,138 customers by brand, spend band, recency, state, support history and subscription, and a confidence row sorts them by how each identity was established, from externally verified down to probabilistic and flagged. Below that, resolved customers with their order counts, last order dates and how many raw accounts each one absorbed.
Each customer row shows why the system believes the identity, and the accounts column counts the raw records that merged into it.

Live production view; identifying details substituted.

The problem

The ERP holds more than 40,000 accounts, and many of them are one person showing up more than once: households, shared email addresses, repeat guest checkouts, dealer staff. Exact matching cannot collapse those, so anyone asking a question about a customer is really asking about one fragment of that customer.

The result

The spine resolves those accounts into about 30,000 people across 8,200 household clusters, at a measured 0.48% false-merge rate on the build certified for production.

How it works

It runs on Splink probabilistic record linkage, tuned for precision over recall, because a wrong merge puts one customer's orders and history into another customer's view. People known to be distinct carry cannot-link rules that no later stage of the pipeline is allowed to override. The nightly rebuild waits on a human review step before it runs, because the rebuild replaces the live spine.

Read the case study on GitHub

Deduplication and Address Quality

The pass I built to determine which accounts are duplicates of each other, and the pipeline that corrected the address data underneath them.

Bulk address verification over 118,946 ingested addresses, reporting 291 undeliverable and 16,705 duplicate groups. The Duplicates view lists each customer with the address on file and the carrier's residential or commercial verdict next to the flag the record currently carries.
Names and street lines are substituted, and the substitution is stable, so the two halves of a duplicate group still land on the same address here. City, state and postcode are unchanged.

Live production view; identifying details substituted.

The problem

77% of contacts in the customer base shared an email address with another contact, and one address covered 165 separate records. Reporting on that base counts the same customer several times over, and nobody could say which accounts belonged together. The same records carried wrong residential and commercial address flags, and those flags decide how an order ships and what the shipping costs.

The result

16,705 duplicate groups covering 29,124 accounts, an average of 1.74 accounts per real customer, plus about 31,650 verified address-flag corrections across roughly 50,000 records.

How it works

Grouping runs entirely in SQL over the mirrored tables and assigns every account a deterministic group id from normalized phone, email, and address keys. I kept it in pure SQL because grouping logic that lives in application code drifts depending on which path last touched a record, and the same data has to produce the same groups every time for anyone downstream to trust the result. Accounts whose keys disagree stay separate and pass to the identity engine.

On the address side I put the bulk classification on FedEx and reserved a second validator for the ambiguous cases only, which took a roughly five-hour run down to about fifteen minutes. Every flag is read back after the write to confirm the value took, so a silently rejected correction gets caught rather than counted as applied.

Read the case study on GitHub

Operations Tools

What the warehouse, accounting, and marketing teams open to get their work done.

Pricing Automation

I built the service that runs a sale end to end: it pushes the new prices, proves each one took, and puts the originals back when the sale is over.

Pricing sessions, each one recording whether it worked at product or SKU level, a note saying what it was for, and where it got to. Most read completed, one is mid-run, and the newest is still a draft.
The notes are what the operator wrote at the time, and every session can be put back the way it was.

Live production view; identifying details substituted.

The problem

Running a sale meant editing more than 800 product option prices by hand in the ERP admin, then editing every one of them back at the end. Each sale cost more than two days of that work. The ERP also drops some edits silently, so a price that looked applied was not necessarily applied, and the way that surfaces is a customer being charged the wrong amount.

The result

A sale now takes about three hours, and most of that is the operator reading the proposed changes before approving them.

How it works

Every price change carries three states: queued, applied, and verified. Verified exists as its own state because the service reads each price back after writing it and compares to the penny, and anything that fails that read-back is held for a person rather than counted as done. Every push, verify, and revert is recorded, so a sale can be put back exactly as it was found. Each product carries its own lock, so two people can run different sales at the same time without stepping on each other.

Read the case study on GitHub

Tax Reconciliation

The service I built to compare what tax was calculated, what was charged, and what was paid, across the tax engine, the ERP, and Stripe.

A month of tax reconciliation. 659 orders in view matching at 94.5 percent, with ten over the review tolerance, fifty-three that left the warehouse with no payment on record, and six charged no tax with no exemption certificate on file. Each exception opens its own section explaining what the nightly check does about it.
The month-end reconciliation runs nightly here. Every order either matches or lands in an exception pile, and each pile is a different kind of problem for accounting to clear.

Live production view; identifying details substituted.

The problem

Every month the accounting team reconciled sales tax by hand. They exported a CSV out of each of the three systems, cleaned up the column names, and then chased every row where the three disagreed. The team lead put it at one full week of every month.

The result

Month end costs about a day of human work across roughly 38,000 transactions. The same data drives a registration-threshold dashboard covering all 50 states plus DC, which caught two states approaching their thresholds in time for finance to act on it.

How it works

Both halves of a transaction have to arrive together, so the feed pulls each new tax record and enriches it from the ERP in the same pass. Reconciliation then reads one row instead of joining two systems at query time.

The fragile part of the manual process was the column names. Vendors rename fields without warning, and one renamed header breaks the match before a single number is compared. Every expected field resolves through four tiers: an exact match on the normalized header, a curated alias table, a fuzzy match, and a last tier that reads the cell values themselves to break a tie. Anything that clears no tier is left unmapped and sent to review; the service does not guess. The tax engine has renamed fields twice since launch and the resolver absorbed both. It also never writes a correction back, because a write-back decides which system was right, and that is a person's call to make.

Read the case study on GitHub

Payment Reconciliation

I built the reconciliation engine that compares what the ERP says it collected against what the payment gateways actually settled, order by order.

The shipped-without-payment review. Fifty-six orders left the warehouse with no payment on record, split into forty whose payment was voided as unverifiable and sixteen that reached this state on their own. Each row carries a billing check run against the ERP's own billing page, and every one of these came back confirmed unpaid.
The order numbers, the split and the billing verdicts are what the nightly check actually produces. Each row's billing check ran against the ERP's own billing page.

Live production view; identifying details substituted.

The problem

The ERP records a payment when its own checkout tells it to, and nothing after that ever confirms the money arrived. The payments live in the ERP, the settlements live at the card gateway, and the two were never compared, so whether an order had genuinely been paid for was not a question anyone could answer from either system alone.

The result

Both payment rails are mirrored read-only and joined into a per-order verdict, so any order can be asked whether it is verified, partly verified, still pending, or shipped with nothing behind it. The first run surfaced 92 orders that had shipped against payments the gateway never received: the ERP's checkout had been marking orders paid through a third-party card SDK that the payment provider was winding down, and 91 of the 92 had no transaction at the gateway.

How it works

Card payments join on the exact transaction reference the gateway issues. PayPal does not, because the ERP stores a third identifier that appears on neither side, so those reconcile on amount, brand, and a three-day window. An order the rails cannot settle either way gets its own verdict and is never assumed paid.

Nothing reverses on its own. A flagged order is put in front of a person with both sides shown, and if the payment is voided the order is deliberately left unlocked, because a locked order cannot accept a payment and the money still needs collecting.

Read the full writeup on GitHub

The Order Desk

Sales reps work an order on a desk I built for them, from finding the customer through pricing the freight and placing it.

Why it exists

Taking an order over the phone on the legacy path was slow. Its quote builder did not work, so a rep could not send a customer a price and pick it back up later, and there was no way to edit the cart of a customer already on the site. The rep worked across three separate pages, moved between them mid-call, and looked the same customer up again in each one.

How it works

The desk is one page with the customer pinned to the left and three tabs across it: shoppers on the site right now, the order being built, and quotes saved earlier. A rep searches for a person. The ERP records the same customer as several separate accounts, and the identity work underneath is what collapses those into one result, so a rep can move between that person's accounts without losing the order in progress.

Everything the desk writes goes into the ERP through the same interface the ERP's own order screen uses, so a desk order and a hand-keyed order are the same kind of record and nothing downstream has to know which was which. Lines carry their own stock rollup, the ship-to and live carrier rates resolve in the same screen, freight can be overridden when the rate table does not cover what is shipping, and a part-built order can be saved, shared with another rep, or duplicated.

Read the full writeup on GitHub

Production Testing and QC

The warehouse tests every wireless unit before it ships on a system I built, which also tracks what happens to the ones that fail.

Aggregate results from the wireless module tester: 7,947 modules tested over 8,083 sessions at a 98.2 percent pass rate, run by six testers. A thirty-day trend charts the daily volume in pass and fail, and the registry underneath lists each module by serial and radio address with how many times it has been tested and how it last came out.
Every module is in here by serial number with every test it has been through. When a unit fails in the field, the lookup starts here instead of on paper.

Live production view; identifying details substituted.

The problem

The warehouse tracked testing on paper. The standalone Android app a previous developer wrote was never updated after that developer left and eventually stopped working. Paper cost about three minutes of data entry per unit, the company tests more than 10,000 wireless units a year, and the manager still had no throughput trends and no way to trace a bad unit back to anything.

The result

That removed more than 500 hours a year of data entry, and a unit that fails at a customer site can now be traced back to the test session that passed it and the person who ran it.

How it works

A tester connects to the unit over BLE, runs the sequence, and taps pass or fail. Each unit is registered by serial number and tested against a definition specific to its SKU, and every result lands in the module registry as it happens. A pass is built to feed a tested-inventory ledger the warehouse reads per SKU without running a report, and a fail to open a triage entry owned by a named person with a disposition of retest, repair, or scrap; the warehouse's daily path today is the tester itself, and that fuller lifecycle is seeded and waiting on adoption.

Read the case study on GitHub

Fulfillment and Label Generation

I built the station warehouse staff use to produce the shipping labels for an order, for the shipments the ERP will not print in full.

Labels produced at the fulfillment station. Each row carries the carrier the order resolved to, the exact service level behind it, the recipient, the package weight and the date it printed, with the service varying by order down to a ground hazmat label.
Each row records the service the order resolved to. The carrier and the handling follow from the method already on the order, so nobody at the station picks them.

Live production view; identifying details substituted.

Why it exists

The ERP generates every label for a multi-box shipment and prints one of them. The rest lived in a second system that covers about half of the company's labels, and the multi-box orders where a missing label hurts most are the hazmat ones, which that system never has. The shipping method itself sits on the order in more than 40 different ERP values, 16 of them hazmat methods with their own handling requirements, and getting that mapping wrong is a refused package or an overpaid rate.

How it works

The mapping from ERP shipping method to carrier service is the part that matters, so I made it explicit, including which methods are hazmat, and nothing about a label depends on a guess at the moment of printing. Labels are minted through the provider the platform already uses for address validation and tracking, which leaves one integration to maintain instead of one per carrier.

The station is built to hand fulfillment state back to the ERP through the sync that already exists. That return path is not connected yet, so a label printed here is not written onto the order in the ERP today.

Read the full writeup on GitHub

Product Catalog and Knowledge Graph

I built the layer that decides what a product is, and the knowledge graph that answers which parts actually work together.

The constraint

The ERP stores option names as raw internal strings and versions a product by duplicating its record, so nothing in it is shaped like a product page. Compatibility was not just unshaped, it was unwritten: which accessory fits which unit lived in support articles and in the heads of the people who have been there longest.

The result

The website renders from a model covering more than 56 product types, and 139 interface declarations derive 860 compatibility links across the catalog, with 93% of sellable products carrying at least one.

How it works

Five services read the product model out of PostgreSQL and emit what the storefront expects, with raw option names mapped into categories a customer can actually read. A product page composes from nine independent fragments in roughly 300ms, and each fragment is isolated, so one slow section degrades itself and not the page.

The graph does not store which products go together. Each product declares the interfaces it exposes and the ones it accepts, on three axes: the connector it plugs into, the termination its firing cues need, and the chassis it physically fits. Compatibility is derived from those declarations every night. Eighteen antennas are eighteen small declarations rather than the 306 pairs they imply, and adding a nineteenth connects it to all of them without anyone editing a pair.

An option a customer picks resolves into the component SKUs that choice actually adds, so the graph describes a configured product and not just a catalog entry. Specification values are harvested from support articles and every value keeps a pointer back to the article it came from, so a reviewer can check a number against its source.

Read the full writeup on GitHub

Hazmat Shipping Declarations

The IATA dangerous goods declaration for an order, produced from a barcode scan by a service I built.

The problem

Every air shipment of dangerous goods needs an IATA Shipper's Declaration signed by an authorized signatory, and the company's hardware carries one fixed UN classification, so every one of those shipments needs the form. An error on it gets the shipment refused at the carrier counter. The operator was filling out a Word template by hand, printing it, signing it, and scanning it, once per shipment.

How it works

An operator scans the order and the declaration comes back filled. The shipper block, the UN number, the class, the packing group and the packing instruction are fixed in the system rather than entered per shipment, and the signatory comes from a list of the people authorized to sign.

The regulator dictates the layout, so the official IATA form is the base document and the order's data is drawn onto it. Redrawing that form myself would have put the company's compliance on my rendering of a legal document.

Read the full writeup on GitHub

Intelligence and Reporting

What the business can see once its data is collected in one place.

Demand Forecasting

A per-SKU forecasting engine I built to reproduce and pressure-test how the company decides what to reorder.

The problem

Replenishment buying ran out of one Excel workbook the purchasing lead maintained by hand, with about 186,000 formulas in it. The buying logic was that person's judgment, written down nowhere else, and no statistical baseline existed to check it against or to carry it if they left.

How it works

Each SKU is classified on how often it sells and how erratic that demand is, then routed to a model that suits it: seasonal series to AutoETS, intermittent ones to Croston's SBA, and the rest to a recent-mean estimator. A single model fitted across all SKUs over-smooths the intermittent ones and under-fits the seasonal ones, which is the failure I set out to avoid. Periods when a SKU was out of stock come out of a 37-month transaction ledger and enter the model as censored demand, because a stockout looks like zero sales and is really unmet demand.

Read the case study on GitHub

Storefront Analytics and Attribution

I built the storefront's analytics: the telemetry that records what visitors do, and the console that reads it back. The site measured nothing about itself before this.

The storefront funnel. Sixty-six orders against four thousand visits, a 0.9 percent order conversion, and every stage between the two counted in turn: arrived, viewed a page, opened the product builder, added to cart. Each stage carries its own count and its share of visits, so the drop between any two of them is readable.
Phone and office orders appear in the order count but have no visit behind them, so the funnel counts only what the site itself saw. That is also why the conversion tile reads lower than dividing orders by visits.

Live production view; identifying details substituted.

The problem

The storefront ran for years without reporting a single thing about its own traffic. Nobody could say how many visits became orders, which products people looked at, or where the buyers came from, and decisions about the site and the product line were being made without that information.

The result

Five views covering live visitors, the view-to-order funnel, acquisition, product behavior, and on-site search, and every aggregate number drills down to the individual sessions that produced it.

How it works

Attribution was the hard part. The pipeline is anonymous by design, with no cross-site identity and no personal data in the event stream, so a session cannot simply be joined to an order. The bridge I built matches sessions to orders on timing at checkout, and the matches land inside 15-second windows; sessions recorded before the bridge existed were matched retroactively. A session that does not match stays unattributed, and the console reports how many did not match. Money figures come off the authoritative order record and join through the bridge, so the console never invents its own revenue number.

Read the case study on GitHub

Live Cart Telemetry

I built the storefront's live presence tracking, and then a second half on top of it that lets a support rep change a shopper's cart with that shopper's consent.

Live shoppers on the storefront. Two are on the site in the last ninety seconds, one of them holding items in a cart, against 987 page views and 16 checkout views so far today. Under the counters each shopper appears with the page they are on, how long they have been there, whether they are signed in, and where they are.
Shoppers are identified by a rotating hash. The counters here exclude 11 employee and 631 bot visits.

Live production view; identifying details substituted.

The problem

The storefront runs on a legacy hosted platform that reported nothing about live shopper behavior, so nobody could see who was on the site or what was in a cart. A rep on the phone with a customer had no way to fix that customer's cart except to talk them through it click by click.

The result

A live dashboard showing the visitors, the page each one is on, and their cart contents, holding roughly 1,000 concurrent visitors at 5 to 8 percent CPU on the small server the storefront already sits on.

How it works

A behavioral taxonomy feeds an ingestion API, a heartbeat writes visitor presence, and a watchdog closes a session when the heartbeat stops. A signed-in visitor resolves to a customer record, and that customer's order history resolves through the product graph, so the view carries what equipment the shopper already owns and not only what is in the cart in front of them. It is built to be automated against, so a triggered email or an offer can key off a live cart; that automation is not built yet.

The editing half is built around consent, because a rep silently changing someone's cart is not something I was willing to ship. The rep stages the whole change as one action, the shopper's own browser renders a preview of it, and it executes through the storefront's native cart only after the shopper approves.

Read the case study on GitHub

System Health and Audit Reporting

A reporting layer I built to turn everything the platform did overnight into something a person can read in a minute.

Service controls for the platform's background work. Each named service reports whether it is running and can be stopped from its own row: the tax sync, the deal drift monitor, the inventory and order heartbeats, the restock and email campaign syncs, the document store shipment sync, and the nightly full sync.
Each row names the outside system it depends on, and all of them report into the same morning digest.

Live production view; identifying details substituted.

Why it exists

The platform grew one system at a time, and each system brought its own background services with it: syncs, watchers, nightly rebuilds. Eighteen of them report in now, too many to check by hand each morning.

The result

A digest lands every morning with last night's outcome for every service, including the ones that failed and recovered on their own. A page goes out only when a person has to act. A second machine watches the platform from outside and emails if it goes quiet, and the platform pages if that watcher dies.

How it works

Two kinds of record back it: what a service did and how many records it touched, and the field-level before and after of every change it made. The grading rules live in the reporting layer and not in the jobs themselves, so changing what counts as notable is one edit and never a re-run of anything.

Bug reports work the same way. Every page keeps a short rolling buffer of what happened in the browser, and none of it leaves the machine until someone clicks the feedback button and describes the problem, so a report arrives with the evidence already attached.

Read the full writeup on GitHub

Platform and Agents

What keeps everything else running, plus the layer an AI assistant works through.

AI Agent Tool Layer

I built an MCP server that exposes the platform to a language model as a catalog of typed, purpose-built tools.

Why it exists

I develop this platform agentically: AI agents carry out engineering and data work under my direction, and that work constantly touches live business records. The agents have to reach those systems to be useful, and I was not willing to hand them database credentials.

The result

I can ask for a customer's order history, a reconciliation status, a pricing check, a shipment's position, or a batch correction in the conversation itself, and no tool can change production data without a person confirming the exact change first.

How it works

The default environment is a daily snapshot replica, so an unexpected write lands on a copy of the data. Live SQL is held read-only at two independent layers: the tool refuses mutating statements and bounds the query before it ever leaves the process, and the database session itself is opened read-only, so getting past the first layer still yields nothing.

A write takes two calls. The first returns a preview of exactly what would change, plus a token; the second carries that token and executes. Reads carry no such risk and run unguarded. I maintain this platform alone, so every release also goes through a review gate I built to stand in for the second engineer I do not have.

Read the case study on GitHub

Production Write Safety

The write path I built sits between every tool on this platform and any record it changes in a live business system.

The constraint

The ERP keeps no audit log of what changed it and offers no undo, and its staging environment points at the same live data as production, so there is no copy of the business safe to practise on. Every write any tool makes lands on the real records on the first attempt.

How it works

A write that changes anything is a two-call tool. The first call previews the change and returns a token; nothing moves until a second call comes back carrying that token, so the confirmation is a separate deliberate act.

Whether a write worked is decided by reading the record back out of the system of record and comparing it against what was intended. The HTTP response is a hint. A write gets exactly one attempt and no automatic retry, because a lost response and a rejected write look identical from the caller's side, so re-sending on that ambiguity can execute the same money change twice.

The read-back asserts the invariant the change was meant to produce. Asserting the exact value written would be wrong here: an order status is a field the ERP advances on its own within minutes, so checking that it still equals the number just written would report a good write as drift. The assertion is that the order is out of the shipping states.

Unknown is a real outcome here, separate from worked and from failed. When the read-back cannot settle the question the tool says so and stops, and a person checks by hand.

Read the full writeup on GitHub

Authentication and Permissions

The sign-in and permission model I built for a dashboard that holds customer data and tools that write to production.

User management for the dashboard. Twenty-six people, each with a role, the groups they belong to, a count of the pages they can open, and an active state. Every row carries a Pages button that opens that person's individual page grants.
Nobody gets access by default. Departments, teams and individuals are granted access as needed for each tool, and groups cover the common sets in one grant.

Live production view; identifying details substituted.

The result

Sign-in runs through the company portal and requires an employee role, so customer accounts cannot reach it, and a new employee lands with access to nothing until it is granted to them.

How it works

The dashboard verifies the portal's signed token against the portal's public key, and a first sign-in creates the account with nothing attached to it. I kept a locally authenticated admin path as the fallback for a portal outage, with those credentials stored hashed. Sessions live in the database, so losing the cache does not sign the entire team out. Permissions are granted by pattern, so one grant can cover a whole family of pages, and the check runs on both the page and the route behind it.

Read the full writeup on GitHub

Service Reliability and Deployment

The operational patterns I built into every background service on the platform, so it runs without anyone watching it.

The deployment record. Ninety releases, each tagged with the version that went out, the commit it was built from, whether it was a full or partial deploy, and the size of the snapshot taken before it shipped. The current release is named at the top against its commit, and five snapshots are held on disk so any of them can be rolled back to.
A snapshot is taken before every release, so a bad deploy can be rolled straight back.

Live production view; identifying details substituted.

Why it exists

The hosted ERP has bad stretches where every request comes back as a server error. A service polling on a five-minute timer keeps calling right through a stretch like that: the calls accomplish nothing, and they add load to a system that is already struggling.

How it works

Each service counts its own consecutive failures, backs off early, and disables itself outright if the upstream stays broken, writing that state where every worker can see it and where it survives a restart. Clearing it is deliberately manual, because only a person can tell whether the other end is actually fixed.

On boot, a recovery pass re-triggers whatever stopped mid-run, in dependency order, and skips anything that had disabled itself. Schema lives with the service that owns it: each one applies its own definitions at startup, written so they can run repeatedly without effect, and guarded so that only one worker does the work while the rest keep serving traffic. That is more than 300 tables that come up on their own, with no migration step for anyone to forget.

Read the full writeup on GitHub

Desktop Hardware Connector

I built the Windows desktop application customers install to manage their wireless hardware modules over a USB radio.

The constraint

The radio vendor's library was written for Python 2.7 and has never been ported, so talking to the hardware at all means running a language runtime that went end of life in 2020. Everything else the application needed, the web interface, Bluetooth, the tray, exists only in modern Python. Building the whole product on the dead runtime would have meant shipping customers software that can never take a security update.

The result

Customers install one signed application that talks to their modules, and the obsolete runtime is quarantined inside a component they never see or interact with.

How it works

The application runs as two processes. The modern half owns the interface and everything the customer touches. The legacy half does nothing but drive the radio, and the two talk over a channel that never leaves the machine. The modern side supervises the legacy one and restarts it when it dies, and the radio process keeps its own store of module state, so the dashboard can still show the last known state while it is down.

Distribution was its own problem. An unsigned installer draws the maximum-severity warning on Windows, and on machines with Smart App Control it is blocked outright with no way for the customer to override it, which turns every install into a support call. Signing is part of the build now, so every release a customer downloads is trusted on arrival.

Read the full writeup on GitHub

Why each piece works the way it does, what broke on the way there, and where the numbers come from: 48 decision records and 9 case studies on GitHub.