← Back to home

MTI Corporation · Richmond, CA

B2B Quote Automation Ecosystem

A dual-interface Shopify embedded app that bridges the gap between customers requesting bulk material quotes and the sales team processing them. As Lead Architect & Full-stack Developer, I designed and built both the customer-facing storefront experience and the internal admin dashboard from scratch, transforming a 10-minute manual workflow into a 30-second automated process.

The system handles 20,000+ product catalog search, real-time tax calculation via California CDTFA API, event-driven email notifications, client-side PDF generation, and one-click conversion from quotes to Shopify draft orders.

83%
Faster processing
90%
Test coverage
20k+
Products searchable
2
Synced interfaces
ReactRemixRedux ToolkitShopify PolarisShopify App BridgeGraphQLDrizzle ORMCloudflare WorkersAWS SESjsPDFhtml2canvasSunEditorJestReact Testing Library
Full workflow: customer submits quote → admin reviews, edits pricing, and sends automated email with PDF

System Architecture

The ecosystem consists of two synchronized applications: a customer-facing storefront embedded in the Shopify store for seamless quoting, and an internal admin app (Quote List, Quote Create, Quote Detail) that gives sales reps full control over the quote lifecycle — from creation to draft order conversion.

The storefront communicates with the admin through a REST API endpoint (api.shopify.jsx) that handles quote creation, customer account provisioning, and event-driven email notifications. The admin side uses Shopify GraphQL for product data, Drizzle ORM on Cloudflare D1 for quote persistence, and the California CDTFA API for real-time tax calculation.

Customer storefrontQuote Cart, inquiry, staff CCAdmin dashboardRemix + Shopify PolarisRemix API routesapi.shopify.jsxCloudflare D1Drizzle ORMAWS SESEmail serviceCDTFA APICA tax ratesjsPDFClient-side PDFShopify GraphQLProducts, draft orderssubmitread / writeauto emailsmutations
Dual-interface architecture with shared data layer and external services

Story 1

The Storefront Experience

Customer-facing · Capture intent with minimal friction

The core challenge was allowing buyers to request bulk quotes without disrupting their regular shopping experience. I engineered a standalone Quote Cart system completely independent of Shopify's standard shopping cart using Redux Toolkit. This decoupled architecture means customers can browse for regular purchases and build B2B quotes simultaneously — no state conflicts, no confusion.

The smart inquiry form captures personal and company information with dynamic validation. Customers can also choose which staff members to CC when submitting their quote, the same email chip system used on the admin side. A Review Page lets users verify everything before final submission.

When a quote is submitted, an event-driven triple email workflow fires automatically: (1) a notification to the selected staff members with quote details and a direct link to the admin detail page, (2) an admin-wide alert, and (3) a confirmation email to the customer with a summary of their request. If the customer is new, the system auto-creates their Shopify account and sends an activation email, with optional tax exemption file upload that routes to the finance team.

Quote Cart drawer
Inquiry form with staff CC
Customer flow: Add to Quote Cart → Fill inquiry form (select staff CC) → Review → Submit

Decoupled Quote Cart

Redux Toolkit slice independent of Shopify's cart, enabling simultaneous retail browsing and B2B quoting.

Triple email notification

Event-driven AWS SES emails to staff, admin, and customer on every submission, with deep links to admin.

Auto customer provisioning

New customers get a Shopify account auto-created via GraphQL mutation, with activation email and optional tax exemption flow.

Story 2

Quote Management Hub

Admin-facing · Search, sort, and create quotes

The Quote List is the admin entry point. All customer-submitted quotes flow here in real time from the storefront. Reps can search by Quote ID or customer name (fuzzy search powered by Drizzle ORM with SQL LIKE queries), sort by date or customer name in either direction, and see Read/Unread status at a glance. Pagination handles large volumes at 20 quotes per page.

The "Create Quote" button opens a full creation form for phone or email orders that bypass the storefront. The standout feature here is the product search across 20,000+ items, staff can search by product name and filter by Category, Collection, Type, or Vendor using Shopify's ResourcePicker API. For items not in the catalog (like shipping fees or custom fabrication charges), the "Add Customized Product" modal lets reps create ad-hoc line items with manual title, price, quantity, tax toggle, weight, and description.

Quote List with search
Sort by customer or date
Quote List: search by ID or customer, sort by date or name
Product search with category/collection/type/vendor filters
Add Customized Item modal
Quote with catalog product + custom shipping fee
Left: Search 20k+ products with filters — Center: Custom item modal — Right: Mixed catalog + custom items

Story 3

The Quote Detail Command Center

Admin-facing · Everything on one page, fully editable

This is the core workspace, a 2,300-line React component where 80% of daily work happens. The design principle was simple: never leave the page. Product details, customer information, pricing, team assignments, email composition, and lifecycle actions all live in one workspace.

Every B2B customer has unique requirements, different pricing for the same product, tax-exempt status on certain items, custom shipping terms. Staff can inline-edit any product's price, quantity, and per-item tax toggle, and the subtotal, tax (fetched live from California CDTFA API based on the customer's address), and total recalculate instantly. The "Hide Price" badge lets reps suppress pricing on specific items in the generated PDF.

Quote Detail command center
Quote Detail: product info, customer details, staff assignment, email — all on one page
Inline editing: modify price, quantity, and per-item tax — total recalculates instantly

Story 4

One-Click Email & Team Coordination

Admin-facing · From 10 minutes of manual work to 30 seconds

The bottom section of the Quote Detail page is a complete email composition tool. From, To, and CC fields auto-populate from the quote data. The subject line auto-generates with the Quote ID. The email body loads a pre-written template customizable through SunEditor, a rich text editor with formatting, links, and file uploads. The auto-generated PDF attaches with one click.

Above the email section, the staff email chip system handles team coordination. If the customer selected specific staff during storefront submission, those selections carry over. Managers can reassign by clicking different chips. Selected assignees appear in the "Selected Emails" area and are automatically CC'd on outgoing communication, eliminating overlapping work where multiple reps unknowingly respond to the same customer.

Email composer with SunEditor
Staff email assignment chips
Left: One-click populated email with SunEditor — Right: Staff assignment with Selected Emails
!

10 min → 30 sec transformation

Before (manual)

  1. Open Shopify to find product details
  2. Copy pricing into a spreadsheet
  3. Manually calculate tax and totals
  4. Format a PDF in Word/Google Docs
  5. Open email client, write message
  6. Attach PDF, CC relevant staff
  7. Send — ~10 minutes per quote

After (automated)

  1. Open Quote Detail — all data pre-loaded
  2. Adjust pricing inline if needed
  3. Click staff email chips for CC
  4. Review auto-populated email
  5. Attach auto-generated PDF
  6. Send — ~30 seconds per quote

Story 5

Quote Lifecycle & Draft Order Conversion

Admin-facing · From quote to paid order in one click

The "More Actions" dropdown exposes four lifecycle operations that complete the quote-to-order pipeline:

More Actions dropdown: Download & Print, Convert to Draft Order, Duplicate, Delete
Lifecycle actions accessible from the Quote Detail toolbar

Convert to Draft Order

The most business-critical feature. Once a customer approves a quote, one click fires a draftOrderCreate GraphQL mutation that creates a Shopify Draft Order with all line items, customer info, shipping/billing addresses, and custom shipping. The draft order is an unpaid order, when the customer pays, it automatically converts to a finalized order. This eliminates manual data re-entry and closes the quote → payment loop entirely within Shopify.

Download & Print as PDF

Client-side PDF generation using jsPDF + html2canvas. Captures the exact layout of the quote — product details, pricing with tax breakdown, customer information, as a downloadable PDF. The "Hide Price" toggle on individual items is respected in the PDF output for cases where pricing is confidential.

Duplicate Quote

Deep copy with a new auto-generated Quote ID, useful for repeat orders or creating variations of an existing quote for the same customer.

Delete with safeguards

Deletion requires double confirmation through a warning modal ("Once deleted, it cannot be undone!") and is restricted to authorized accounts only.

Technical Deep Dive

1

Decoupled state management

Redux Toolkit slices for Quote Cart vs Shopping Cart operate independently with separate actions and selectors. The Quote Cart manages items, quantities, tax toggles, and custom products without touching the standard Shopify cart state.

// Independent slices prevent state conflicts
const quoteCartSlice = createSlice({
  name: 'quoteCart',
  initialState: { items: [], inquiry: {} },
  reducers: {
    addToQuote, removeFromQuote, updateQuantity,
    toggleItemTax, addCustomProduct
  },
});
// Regular shopping cart remains untouched
2

Server-side parallelized API requests

The Quote Detail loader fetches quote data, then dynamically builds a batch GraphQL query to resolve all product variants in a single request, instead of N sequential calls for N products. Combined with Remix's loader pattern, data is server-rendered before the page reaches the client.

// Batch GraphQL: resolve N products in 1 request
const productQueries = products.map((p, i) => `
  variant${i}: node(id: "gid://shopify/ProductVariant/${p.variant_id}") {
    ... on ProductVariant { id, title, price, inventoryQuantity,
      product { id, title }
    }
  }
`);
const { data } = await admin.graphql(`{ ${productQueries.join("\n")} }`);
3

Real-time tax via California CDTFA API

Tax rates are fetched dynamically based on the customer's shipping address using California's official tax rate API. The rate updates live as the address changes, and per-item tax toggles let reps mark individual products as tax-exempt, the total recalculates with each toggle.

4

Advanced search with fuzzy matching

The Quick Search in Quote Detail supports exact match by Quote ID, exact match by Shopify Customer ID (with GID format normalization), and fuzzy search across name, email, and phone, with phone number normalization that strips dashes, spaces, parentheses, and plus signs.

// Phone normalization for fuzzy search
const phoneExpr = sql`
  replace(replace(replace(replace(replace(
    json_extract(customer, '$.phone'),
    '-',''),' ',''),'(',''),')',''),'+','')
`;
// Matches "858-717-5278" when searching "8587175278"
5

90% test coverage on critical paths

Jest + React Testing Library covering the full quote lifecycle: cart operations, form validation, pricing calculations, PDF generation, and email dispatch. Tests catch regressions across the complex interaction between Shopify GraphQL, Drizzle ORM, and the CDTFA tax API.

What I Learned

This project taught me that the hardest engineering problems often aren't technical, they're about understanding how people actually work. The sales team's domain knowledge was essential for designing workflows that fit their reality. Features I assumed were important turned out to be unnecessary, while the Quick-Jump Navigation I almost deprioritized became the most-used feature.

The 83% processing time reduction didn't come from frontend performance tricks, it came from eliminating manual steps: auto-populating email fields, pre-calculating tax, batch-querying product data, and making the quote → draft order conversion a single click instead of a multi-step manual process. Performance optimization in a B2B context is about human workflow, not just Lighthouse scores.