MDL Blind Shipping Calculator - System Manual

1. Overview

The MDL Blind Shipping Calculator is a full-stack Next.js application designed for MDL Communications. It streamlines the process of generating shipping quotes for "blind shipping" (where the supplier's identity is hidden from the client). The system integrates AI for document parsing, Supabase for data persistence, Noviship (TotalShip) for live rate fetching, and Azure AD for secure enterprise authentication.


2. Technology Stack


3. Core Architecture

3.1. API Layer (app/api/)

3.2. Utility Layer (app/utils/)

3.3. Customer & Supplier Normalization

The system implements a normalization layer to prevent directory fragmentation: * Customer Mapping: Name variations like "Société Radio Canada" or "Canadian Broadcasting Corporation" are automatically mapped to a single canonical entry: "CBC / Radio-Canada". * Location Merging: When a new location is added under a variation name, it is automatically consolidated into the canonical parent record.

3.4. Validation & Deduplication

To maintain data integrity: * Duplicate Address Check: The system prevents saving multiple locations with the same physical address for the same company. * Normalizing Addresses: Addresses are compared with a "fuzzy" logic (ignoring punctuation, case, and extra whitespace) to identify duplicates accurately.

3.3. Database Schema (Supabase)

The app uses three main tables: 1. suppliers: Stores vendor names and an array of warehouse locations (address, postal code, country). 2. customers: Stores client names and delivery locations. 3. products: A library of frequently shipped items. * Fields: name, sku, length, width, height, weight, hs_code. * Unit Note: Stored in Imperial (Inches/Lbs) as the default project standard. 4. hubs (Local JSON): Stores intermediate shipping hub locations. * Source: app/data/hubs.json * Fields: name (Key), address, city, postalCode, country, province.


4. Key Integrations

4.1. Noviship (TotalShip) Integration

The app communicates with Noviship via an XML-over-HTTP endpoint (https://api.noviship.ca/v1). * Input: Origin/Destination address, dimensions (Inches), and weight (Lbs). * Output: Parsed XML response containing carrier name (FedEx, UPS, etc.), service level, cost, and transit days. * Province Detection: The system automatically detects the destination province (e.g., 'ON', 'BC') based on the first letter of the postal code to ensure API compatibility.

4.2. Google Gemini "Magic Lookup"

When a user pastes just a model name (e.g., "OmniHub 16") into the product parser: 1. The request goes to app/api/parse-ai/route.js. 2. Gemini identifies the device type and retrieves standard specifications from its training data. 3. Human-Readable Summary: The AI also returns a plain-English summary explaining its findings (e.g., "Estimated weight based on standard 1RU chassis"), which is displayed to the user. 4. The system converts any metric results (cm/kg) into Imperial (in/lb) before returning them to the UI.

4.3. Intelligent Data Standardization

4.4. Currency & Exchange Rates

Uses https://open.er-api.com/v6/latest/CAD to fetch real-time exchange rates (USD/EUR to CAD). This ensures that manual supplier shipping quotes entered in foreign currencies are accurately reflected in the final CAD quote.

4.5. Easyship Integration (Global Carriers)

The app runs a Parallel Fetch architecture: Noviship and Easyship APIs are called simultaneously (Promise.all) to reduce latency. * Role: Provides access to international couriers not always available via Noviship. * Supported Carriers: The system normalizes responses from UPS, FedEx, DHL, USPS, Canada Post, and Purolator. * Carrier Normalization: The API response logic (app/api/rates/route.js) maps disparate slugs (e.g., fedex_ground, ups_standard) into clean, readable names like "FedEx Ground" or "UPS Standard". * Handling: Handles complex tax and duty calculations (DDP).

4.6. Easyship Sandbox Specifics

When working in the Easyship Sandbox environment (using a sandbox API key): * Zero Taxes/Duties: It is common for the API to return $0.00 for taxes and duties in Sandbox, especially if the shipment value is low or the HS code is not triggered for that specific route. * No Shipping Solutions Error: This error (422) is often caused by an address/postal code mismatch. The system implements a "Region-Aware Fallback" logic (in app/utils/easyship.js) to ensure valid sandbox addresses are used based on the country. * HS Code Formatting: The system sanitizes HS codes (removing dots) as the API requires raw numeric formats. * Category Validation: To test non-zero taxes, ensure a realistic declaredValue is set and the HS code reflects a taxable commodity for the destination region.


4.7. CBSA CARM Integration (Official)

The application is integrated with the CBSA CARM (Assessment and Revenue Management) API suite. * Official Calculator: Accessible via the "Verify with CBSA" button next to the HS Code input. * Functionality: Sends the HS Code, Declared Value, and Origin to the official CBSA engine (dutyTaxCalculator) to get legally binding estimates for Canadian imports. * Infrastructure: app/utils/cbsa.js and app/api/cbsa/route.js. * CARM Badge: When successfully verified, the Final Quote displays an "Official CBSA Duties & Taxes" label and a "CARM Assessment Verified" note.


4.8. Hub Management

The system includes a dedicated interface for managing intermediate shipping hubs. * Hub Repository: Users can define multiple hub locations (e.g., "TotalShip Kirkland", "MDL Pickering") via the Manage Hubs tab. * Dynamic Selection: For international shipments, the "Intermediate Hub" dropdown allows the user to select which hub to use. * API: app/api/hubs/route.js handles CRUD operations. * Storage: Hub data is persisted in Supabase (within the hubs table). This migration from local JSON ensures that hub configurations are consistent across different deployment environments and accessible by all team members. * Backward Compatibility: The API route includes a reduction logic to convert the Supabase row structure back into the key-value object format expected by the legacy frontend components.

4.9. Accessorial Options Integration

The system integrates granular shipping services into the Noviship XML request: * Signatures: Maps UI selection to SIGNATURE_REQUIRED or ADULT_SIGNATURE_REQUIRED. * Dangerous Goods: Adds DANGEROUS_GOODS tags to the shipment request. * Batteries: Adds BATTERIES tag. (Future expansion: specific UN number mapping). * Delivery Services: Supports APPOINTMENT_DELIVERY, INSIDE_DELIVERY, LIMITED_ACCESS_DELIVERY, etc. * Instructions: Passes user delivery notes to the <specialinstructions> XML node.


5. Security & Authentication


6. Environment Setup (.env.local)

Required keys for a functional system:

# Authentication
AZURE_AD_CLIENT_ID="..."
AZURE_AD_CLIENT_SECRET="..."
AZURE_AD_TENANT_ID="..."
NEXTAUTH_SECRET="..."
NEXTAUTH_URL="http://localhost:3100"

# Integrations
NOVISHIP_API_KEY="..."
GEMINI_API_KEY="..."
EASYSHIP_API_KEY="..."

# Database
NEXT_PUBLIC_SUPABASE_URL="..."
NEXT_PUBLIC_SUPABASE_ANON_KEY="..."

7. Development & CI/CD Workflow

The application follows a standard modern web development lifecycle to ensure stability and seamless updates.

7.1. Local Development

7.2. Source Control (GitHub)


8. Production Deployment (Vercel)

The production environment is hosted on Vercel, which is natively optimized for Next.js applications.

8.1. GitHub Integration

8.2. Dependencies & Runtime

8.3. Production Environment Variables

8.4. Deployment Checklist

  1. Verify all environment variables are saved in the Vercel Dashboard.
  2. Ensure Supabase migrations/table schemas are up to date.
  3. Check that the Azure AD Redirect URIs include the production domain.
  4. Run npm run build locally once to ensure no build-time errors exist before pushing to GitHub.