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.
@google/generative-ai)pdfjs-dist)app/api/)rates/: Proxy for the Noviship/TotalShip XML API. Fetches real-time carrier quotes.parse-ai/: Handles Google Gemini prompts for extracting product specifications from unstructured text.suppliers/, customers/, products/: CRUD endpoints for Supabase data management.proxy/: Bypasses CORS restrictions when fetching remote spec sheet URLs.app/utils/)calculations.js: Billable weight logic (DIM weight), Imperial/Metric conversions, and mock rate fallbacks.invoiceParser.js: Multi-modal engine. Combines PDF text extraction, Image OCR (Tesseract), and heuristic Regex patterns to identify Suppliers and Customers.productParser.js: Orchestrates the transition between Regex-based spec extraction and Gemini-driven "Magic Lookup" for model names.PROCESS_ARCHITECTURE.md: External documentation containing BPMN and Sequence diagrams of the end-to-end system flows.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.
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.
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.
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.
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.
XXXX.XX.XX format. A global migration script ensures all historical data complies with this 8-digit standard.products table) strictly stores dimensions in Inches and Pounds to guarantee consistent calculation logic across the app.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.
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).
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.
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.
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.
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.
@mdlcommunications.com email address via the Microsoft identity platform..env.local and never committed to version control..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="..."
The application follows a standard modern web development lifecycle to ensure stability and seamless updates.
npm run dev on port 3100..env.local file is used to store private keys. This file is ignored by git to prevent security leaks.npm test.The production environment is hosted on Vercel, which is natively optimized for Next.js applications.
main branch on GitHub, Vercel automatically detects the change, triggers a new build, and deploys the updated version to production. NEXTAUTH_URL in production is set to the custom domain (e.g., https://bsc.mdlcommunications.com).npm run build locally once to ensure no build-time errors exist before pushing to GitHub.