Case Study·Client project·B2B e-commerce

Live at dukesupply.com

We built Duke Supply's B2B ordering platform in Vue 3 & Nuxt, connected to NetSuite and their delivery fleet.

Duke Supply supplies janitorial and building-maintenance products to New York buildings. We built their Nuxt storefront, staff dashboard and the API that ties them to NetSuite and Routific: customer-specific pricing, account approval, quick ordering, two-way ERP sync and proof of delivery.

  • Vue 3.5
  • Nuxt 3
  • Vuetify 3
  • Ant Design Vue
  • Pinia
  • Node.js
  • MongoDB
  • NetSuite
  • Routific
Duke Supply cleaning chemicals category page with product grid, sorting, Quick Order button and login-to-see-price labels
Customer pricing Each account sees its own NetSuite price level after login
Quick Order Order many items at once by name or SKU, plus custom requests
ERP-synced catalog Products, categories and stock mirrored from NetSuite
NetSuite
Two-way ERP sync
customers · orders · items · prices · fulfillments
7
NetSuite webhooks handled
SuiteScript events pushed to the API
3
Apps we built
storefront · staff dashboard · API
10 min
Delivery status sync
NetSuite ↔ Routific, with proof of delivery

A supplier whose business runs on NetSuite and its own trucks

Duke Supply is a long-established supplier of janitorial and building-maintenance products to buildings across New York City, delivering with its own trucks. Its customers are companies with their own price levels, and its operations run on NetSuite.

A generic e-commerce template wouldn't work. The website had to know each company's price level, accept orders on account, and stay in step with NetSuite for customers, products, stock and orders, while deliveries planned in Routific reported back with proof.

We built the storefront, the staff dashboard and the API between all of it. It's a client project, so this page shows the live website and describes our engineering without publishing the client's code.

Client
Duke Supply: janitorial and building-maintenance supplies for New York buildings
Our role
Storefront, staff dashboard, API, and the NetSuite and Routific integrations
Storefront
Nuxt 3 · Vue 3.5 · Vuetify 3 · Tailwind · Pinia
Dashboard
Nuxt 3 SPA · Ant Design Vue · Pinia · Chart.js
Backend
Node.js · Moleculer · MongoDB · AWS S3
Integrations
NetSuite (REST, SuiteQL, SuiteScript) · Routific · GA4 Data API · Resend
Status
Live at dukesupply.com

Store first, then the ERP, then the hard part: making it reliable

We got a working B2B store live quickly, connected it to the systems the business already runs on, then spent a second phase making every integration resilient and visible. It's the order we recommend for any store that has to live alongside an ERP. Dates come from the project's git history.

Duke Supply timelineAug 2024 → 2026
AUG 2024 API foundation
OCT 2024 B2B storefront
NOV 2024 Checkout & dashboard
FEB 2025 NetSuite integration
APR 2025 Routific delivery sync
2026 Customer migration & hardening
01

Start from a proven foundation

Aug 2024
On Duke Supply

The API started from an e-commerce backend foundation our team had built before, then was stripped down to what a B2B distributor needs: everything for marketplaces, consumer payments and foreign couriers was removed within weeks. Duke Supply got a working base on day one instead of paying to rebuild authentication, catalog and orders from scratch.

What you get
  • A head start from proven building blocks
  • Only the parts your business needs
  • Budget spent on what makes you different
02

Build the B2B store

Oct – Nov 2024
On Duke Supply

Duke Supply sells to buildings and facility teams, not consumers. The storefront and staff dashboard were built around that from the start.

  1. Storefront, company account requests, price tiers on customers
  2. Server-side cart, CI/CD to production
  3. Staff dashboard, checkout, pay-on-account orders, GA4 analytics
What you get
  • A storefront shaped around how your buyers actually order
  • Clean, review-ready pull requests
  • Async daily updates and a weekly progress review
03

Connect the ERP and the trucks

Feb – May 2025
On Duke Supply

The real value came from connecting the store to the systems that run the business. Orders, customers, items, price levels and fulfillments now flow between the website and NetSuite, and deliveries flow through Routific back into both.

  1. NetSuite integration and Routific service
  2. Item fulfillments synced from NetSuite
  3. Routific scheduler and proof-of-delivery sync
  4. SuiteScript webhooks and RESTlet in NetSuite
What you get
  • Integrations designed around your ERP, not around the website
  • One source of truth for orders and stock
  • Staff working in the tools they already use
04

Bring existing customers online

Mar – Apr 2026
On Duke Supply

Duke Supply's customers already lived in NetSuite. We imported them with their addresses intact and added an email-first login: existing customers enter their email and get a secure link to set a password, instead of being asked to register again.

What you get
  • A migration path for customers you already have
  • No duplicate accounts or re-registration
  • Addresses and history carried over
05

Make the integrations resilient and visible

Apr – May 2026
On Duke Supply

Integrations fail in the real world, so we made failure safe and visible: a log of every push, webhook and error, retries that respect NetSuite's limits, protection against NetSuite echoing our own changes back, and a panel for staff to fix stuck fulfillments themselves.

What you get
  • Integration logs your team can read
  • Automatic retries with backoff
  • Recovery tools so support doesn't need a developer

Eight problems behind a store that runs on an ERP

The storefront is the visible part. Underneath are two systems of record, a delivery fleet and companies that each pay their own price. These are the problems we solved on Duke Supply, described without exposing the client's code.

01

One order, two systems of record

NetSuiteEventsConsistency
Problem
A web order has to become a NetSuite sales order, and changes made in NetSuite have to flow back, without making the buyer wait on the ERP, losing orders when NetSuite is slow, or creating loops when each system reports the other's change.
How we solved it
Orders are saved locally and confirmed to the buyer instantly, then pushed to NetSuite in the background. Each order tracks its sync status, staff can retry or force a push, and NetSuite's echo of our own update is ignored for a short window. A creation webhook that arrives before NetSuite's ID is written back is matched to the right local order.

Where this applies to you Any store or portal that has to stay in step with an ERP, CRM or inventory system.

Buyer
Instant confirmation, ERP push in background
Status
Pending, synced or failed per order
Echoes
Our own updates ignored for 30 seconds
Recovery
Retry and force-push for staff
02

Working within NetSuite's API limits

NetSuiteResilience
Problem
NetSuite throttles concurrent requests and returns rate-limit and server errors under load. A naive integration drops orders exactly when the business is busiest.
How we solved it
Every NetSuite call retries on rate limits, server errors and NetSuite's own concurrency errors, honours Retry-After when given, and otherwise backs off exponentially. The OAuth signature is regenerated on every attempt so retries stay valid.

Where this applies to you Integrations with any rate-limited API: ERPs, marketplaces, payment and shipping providers.

Retries on
429, 5xx, concurrency and request limits
Backoff
5s → 10s → 20s → 40s → 60s cap
Headers
Retry-After respected
Auth
Token-based auth, re-signed per attempt
03

Every customer sees their own price

B2B pricingMongoDB
Problem
Duke Supply's customers have negotiated price levels in NetSuite. The website has to show each buyer their price, filter by price correctly, and never let a stale price into an order.
How we solved it
Each account belongs to a tier mapped to a NetSuite price level. Prices resolve to the customer's level, then the default level. The same rule runs inside database queries so price filters match what the buyer sees, prices are recalculated at checkout, and visitors who aren't logged in are asked to log in instead of seeing a list price.

Where this applies to you B2B stores, wholesale portals and any product with contract or tiered pricing.

Source
NetSuite price levels per customer tier
Fallback
Default price level
Filters
Same rule applied inside queries
Checkout
Prices recalculated before ordering
04

From warehouse to doorstep, with proof

RoutificNetSuiteLogistics
Problem
Duke Supply delivers with its own trucks. Office staff, drivers and customers need to know where every order is, and finance needs proof it arrived, across NetSuite, the routing system and the website.
How we solved it
Packed fulfillments from NetSuite are sent to Routific. A scheduler reconciles NetSuite and Routific every 10 minutes and never runs two cycles at once. Delivery photos and signatures are copied to S3 and into NetSuite's file cabinet through a custom RESTlet, and the order's status updates itself from its fulfillments.

Where this applies to you Distributors, field-service and logistics businesses connecting operations software to the web.

Flow
NetSuite fulfillment → Routific → delivered
Sync
Every 10 minutes, no overlapping runs
Proof
Photos and signature to S3 and NetSuite
Status
Order status derived from fulfillments
05

A catalog that stays in step with the ERP

SuiteQLWebhooksCatalog
Problem
Products, categories, units of measure, prices and per-warehouse stock all live in NetSuite. The website has to mirror them closely without nightly batch jobs or staff re-keying data.
How we solved it
A full SuiteQL pull loads items with their price levels and stock by location, and NetSuite webhooks then update or remove individual products as they change. NetSuite classes become the store's category tree, and edits made in the dashboard go back to NetSuite only when an ERP field actually changed.

Where this applies to you Any storefront whose catalog is mastered in an ERP or PIM.

Initial
SuiteQL pull with prices and stock
Ongoing
Item, price and category webhooks
Stock
Per warehouse location
Units
Sale units and case packs shown
06

Bringing ERP customers onto the website

MigrationAuth
Problem
Duke Supply's business customers already existed in NetSuite with their addresses and history. Asking them to register again would create duplicates and lose trust.
How we solved it
Customers were imported from NetSuite with their address IDs preserved. Login starts with the email: known customers without a password receive a one-hour link to create one. New sign-ups wait in a placeholder state until NetSuite has created their record.

Where this applies to you Moving offline or phone-order customers onto a self-service portal.

Import
From NetSuite, addresses preserved
Login
Email-first, one-hour password link
New accounts
Placeholder until NetSuite confirms
Support
Staff can view the site as a customer
07

B2B accounts with approval built in

B2BWorkflow
Problem
Not everyone who signs up should be able to order on account, and every approved company needs the right price level in both systems.
How we solved it
Sign-up is a company account request. The customer is created in NetSuite in the background, and staff approve it in the dashboard, which waits for NetSuite's record, assigns a price tier and updates NetSuite in one step. New delivery addresses also need approval before they can be used at checkout.

Where this applies to you Wholesale, trade and professional stores where accounts need vetting.

Sign-up
Company account request
Approval
Staff assign tier, NetSuite updated
Duplicates
Same company name rejected
Addresses
Approved before use at checkout
08

Integrations your team can see into

ObservabilityAdmin tools
Problem
When an order or delivery goes missing between three systems, support shouldn't need a developer reading server logs to find out why.
How we solved it
Every NetSuite and Routific push, webhook and failure is written to a service log. The dashboard has a fulfillment panel where staff can retry, check, force-ship or fetch delivery proof for a stuck order themselves.

Where this applies to you Any operations-heavy product where integrations are business-critical.

Logged
Pushes, webhooks and failures by source
Sources
NetSuite, Routific, system
Panel
Retry, check, force-ship, fetch proof
Who
Support staff, no developer needed

Two Nuxt apps, one API, connected to the ERP and the road

The storefront and staff dashboard share one Node.js API. The API is the only thing that talks to NetSuite and Routific, so the business logic for pricing, approval and sync lives in one place.

Duke Supply architecture: the Nuxt storefront and Nuxt staff dashboard connect to a Node.js API on MongoDB, which syncs with NetSuite in both directions, exchanges deliveries with Routific, and uses AWS S3, Resend and the GA4 Data API.APPS WE BUILTStorefrontNuxt 3 SSR · Vuetify 3customer pricing · Quick Orderpay on account · saved listsStaff dashboardNuxt 3 SPA · Ant Design Vueapprovals · orders · catalogfulfillment panel · GA4Drivers & customersdeliveries · photos · signaturesAPI WE BUILTNode.js APIMoleculer · MongoDBpricing · approval · ordersNetSuite sync · webhooksRoutific scheduler · service logDocker · GitHub Actions · AWSSYSTEMS & SERVICESNetSuiteREST · SuiteQL · token authSuiteScript webhooks · RESTletRoutificroutes · delivery status · proofAWS S3images · delivery photosResendMJML transactional emailGA4 Data APIdashboard analytics
Built by our teamBusiness systems (two-way)ServicesPeople

What this project shows about our Vue work

Server-rendered storefront

Product, category and blog pages fetch their data on the server with useAsyncData, so pages arrive complete.

Nuxt 3 SSR
Two design systems

Vuetify 3 with Tailwind on the storefront, Ant Design Vue in the staff dashboard, each matched to its users.

Vuetify 3 · Ant Design Vue
Quick Order

A multi-row order dialog: search by name or SKU, set quantities, and add free-text custom items for anything not in the catalog.

QuickOrderDialog
Search UX

Typeahead plus a results page with attribute filters, price buckets and sorting, backed by ranked text search.

Pinia search store
State with Pinia

Stores per domain: cart, products, search, profile and settings, with the cart kept on the server.

stores/*
Auth flows

Email-first login, create-password links and staff impersonation on top of @sidebase/nuxt-auth.

@sidebase/nuxt-auth
Validated forms

Vuelidate on registration (with password rules), login, password reset, settings and addresses.

Vuelidate
B2B checkout

Pay on account, delivery instructions, saved lists, and addresses that must be approved before use.

Checkout · AddressSideBar
Orders on behalf

Staff can create an order for a customer in the dashboard at that customer's own prices.

Dashboard OrderForm
Permission-aware admin

Staff roles with permission keys; pages show a restricted state for users without access.

usePermissions
Analytics

GA4 reports pulled through the Data API and charted inside the dashboard.

vue-chartjs · GA4 Data API
Operations tools

A fulfillment recovery panel and NetSuite sync buttons for tiers, subsidiaries and locations.

FulfillmentPanel

Projects where this experience pays off

B2B or wholesale e-commerce

Company accounts, approval, contract pricing, quick ordering and pay-on-account checkout.

Price levels per tier · account approval · Quick Order

An ERP integration

Keeping a Vue storefront or portal in step with NetSuite or another system of record, in both directions.

REST · SuiteQL · SuiteScript webhooks · RESTlet

Logistics and delivery

Routing, fulfillment status and proof of delivery flowing between operations software and your customers.

Routific sync · photos and signatures · auto status

Moving offline customers online

Bringing phone, email and rep-managed accounts onto self-service without duplicates or re-registration.

NetSuite import · email-first login

Internal dashboards

Staff tools for orders, customers, pricing and content, with roles and permissions.

Ant Design Vue · roles · orders on behalf

Fragile integrations

Integrations that drop data under load or fail silently, made resilient and visible.

Retries with backoff · service logs · recovery panel

Questions teams ask us

Is Duke Supply a client project?

Yes. Duke Supply is a New York janitorial and building-maintenance supplier. We built their storefront, staff dashboard and API, and the integrations with NetSuite and Routific. This page shows the live website and describes our engineering without publishing the client's code.

Can you integrate a Vue or Nuxt app with NetSuite?

Yes. Duke Supply's platform uses NetSuite's REST API with token-based authentication, SuiteQL queries, SuiteScript webhooks for customers, orders, items, price levels, categories and fulfillments, and a custom RESTlet for delivery proof.

Can you build B2B e-commerce?

Yes. Company account requests with approval, customer-specific price levels, quick ordering by SKU, saved lists, pay-on-account checkout and orders placed by staff on a customer's behalf are all part of this project.

Do you only do frontend?

Vue and Nuxt are our core, but this project included the Node.js API, MongoDB data model and every integration. When your frontend work depends on the backend, we can handle both.

Can you take over an existing integration that keeps breaking?

Yes. Much of the second phase of this project was exactly that: adding retries that respect API limits, logging every sync, and giving staff tools to recover stuck orders themselves.

How do we start?

Send us a short note on the contact page about what you're building and where you're stuck. We'll set up a call to go through your product and codebase.

Get started

Connecting your Vue storefront to an ERP?

Talk to the engineers who built Duke Supply's B2B store, staff dashboard and NetSuite integration. Tell us what you're building and where it's stuck.

Matched in 24 hours·48 hours free on every plan·No long-term contract