Case file · 04 of 07 · White-labeled
A live ERP, an API-first storefront
Problem
The catalog lived in NetSuite, but the website held an aging copy. The group wanted its marketing site and storefront in one application, connected to the ERP. They sell by quote, so checkout wasn't needed. Deployment had to use their Azure tenant. The first job was understanding roughly 59,900 ERP items and how they grouped into products.
Approach
I separated the API, sync worker and Next.js storefront. The worker mirrors NetSuite into Postgres; the storefront reads through the API and never calls the ERP during a page request. A native part-number field was filled on 99.4% of sellable items. That gave us the grouping key for roughly 28,100 products with condition variants, without adding a client field. The sync fetches before writing, compares content hashes and refuses to reconcile a suspiciously small response. The database allows one runner at a time. CI checks OpenAPI drift, privileged routes fail closed, and a nine-tool read-only MCP server uses the same service layer as REST.
Result
The backend is complete and verified against the ERP sandbox. A full sync reconciled 59,886 items in 5.4 minutes, with 100% hash stability and no unnecessary writes. Delta syncs take less than a second. CI deploys into the client's Azure through OIDC federation, without long-lived credentials. There are no checkout paths. Twenty-six architecture decision records explain the choices. The UI is still being built, and the client decides when to launch.
5.4 MIN
FULL SYNC · 59,886 ITEMS · 100% HASH-STABLE
- · 59,886 ERP items → 28,095 logical products / 59,559 condition variants (live-verified)
- · Grouping key found at 99.4% fill; no new client schema needed
- · Full sync 5.4 min, 100% hash stability, 0 writes on re-sync; delta sync <1s
- · 9-tool read-only MCP server on the storefront
- · 26 ADRs
- · 0 checkout paths; RFQ-only by design