From 46069b07a07667d86171e6a3adc359a3ef898926 Mon Sep 17 00:00:00 2001 From: justin Date: Thu, 28 May 2026 21:11:46 -0500 Subject: [PATCH] Add DOT/FMCSA compliance checker API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GET /api/v1/dot/lookup?dot=XXXXXX — live compliance check combining local census data + FMCSA QCMobile API. Checks: - Operating status (allowed to operate Y/N) - MCS-150 biennial update (overdue detection) - Insurance filing (BIPD, cargo, bond) - Safety rating (S/C/U) - Operating authority status - Out-of-service rates vs national average - Crash record GET /api/v1/dot/search?name=Acme — name search against local census Co-Authored-By: Claude Opus 4.6 (1M context) --- api/src/index.ts | 2 + api/src/routes/dot-lookup.ts | 346 +++++++++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 api/src/routes/dot-lookup.ts diff --git a/api/src/index.ts b/api/src/index.ts index f4634aa..9729d9e 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -46,6 +46,7 @@ import portalRmdReviewRouter from "./routes/portal-rmd-review.js"; import portalEsignGenericRouter from "./routes/portal-esign-generic.js"; import pucRouter from "./routes/puc.js"; import fccCarrierRegRouter from "./routes/fcc-carrier-registration.js"; +import dotLookupRouter from "./routes/dot-lookup.js"; const app = express(); @@ -116,6 +117,7 @@ app.use(fccFilingsRouter); app.use(foreignQualRouter); app.use(pucRouter); app.use(fccCarrierRegRouter); +app.use(dotLookupRouter); app.use(adminCryptoRouter); // Note: identityRouter mounted above express.json() for webhook route, // but also handles non-webhook routes (create-session, poll) which work fine with json() diff --git a/api/src/routes/dot-lookup.ts b/api/src/routes/dot-lookup.ts new file mode 100644 index 0000000..bdb349e --- /dev/null +++ b/api/src/routes/dot-lookup.ts @@ -0,0 +1,346 @@ +/** + * DOT / FMCSA motor carrier compliance lookup. + * + * GET /api/v1/dot/lookup?dot=1234567 + * GET /api/v1/dot/search?name=Acme+Trucking + * + * Combines local census data with live FMCSA QCMobile API for + * real-time compliance status checks. + */ + +import { Router } from "express"; +import pool from "../db.js"; + +const router = Router(); +const FMCSA_API_KEY = process.env.FMCSA_API_KEY || ""; +const FMCSA_BASE = "https://mobile.fmcsa.dot.gov/qc/services/carriers"; + +// ── Helpers ───────────────────────────────────────────────────────── + +async function fmcsaFetch(path: string): Promise { + if (!FMCSA_API_KEY) return null; + try { + const url = `${FMCSA_BASE}/${path}${path.includes("?") ? "&" : "?"}webKey=${FMCSA_API_KEY}`; + const resp = await fetch(url, { + signal: AbortSignal.timeout(10000), + headers: { "Accept": "application/json" }, + }); + if (!resp.ok) return null; + return await resp.json(); + } catch { + return null; + } +} + +type CheckStatus = "green" | "yellow" | "red" | "unknown"; + +interface ComplianceCheck { + id: string; + label: string; + status: CheckStatus; + detail: string; + action_url?: string | null; +} + +function twoYearsAgo(): Date { + const d = new Date(); + d.setFullYear(d.getFullYear() - 2); + return d; +} + +// ── DOT Lookup ────────────────────────────────────────────────────── + +router.get("/api/v1/dot/lookup", async (req, res) => { + const rawDot = (req.query.dot as string || "").trim().replace(/\D/g, ""); + if (!rawDot) { + res.status(400).json({ error: "Provide a DOT number." }); + return; + } + + try { + // 1. Local census data + const local = await pool.query( + "SELECT * FROM fmcsa_carriers WHERE dot_number = $1", + [rawDot], + ); + const census = local.rows[0] || null; + + // 2. Live FMCSA API + const snapshot = await fmcsaFetch(rawDot); + const carrier = snapshot?.content?.carrier || null; + + // 3. Authority check + const authorityData = await fmcsaFetch(`${rawDot}/authority`); + const authorities = (authorityData?.content || []).map((a: any) => a.carrierAuthority); + + if (!census && !carrier) { + res.status(404).json({ error: `DOT# ${rawDot} not found.` }); + return; + } + + // Build compliance checks + const checks: ComplianceCheck[] = []; + const name = carrier?.legalName || census?.legal_name || "Unknown"; + const dba = carrier?.dbaName || census?.dba_name || ""; + + // ── Check 1: Operating Status ── + if (carrier) { + const allowed = carrier.allowedToOperate === "Y"; + const status = carrier.statusCode; + checks.push({ + id: "operating_status", + label: "Operating Status", + status: allowed ? "green" : "red", + detail: allowed + ? `Authorized to operate. Status: ${status === "A" ? "Active" : status}.` + : `NOT authorized to operate. Status: ${status}. This carrier cannot legally operate.`, + }); + } + + // ── Check 2: MCS-150 Biennial Update ── + { + const outdated = carrier?.mcs150Outdated === "Y"; + const mcs150Date = census?.mcs150_parsed || null; + const isOverdue = mcs150Date ? new Date(mcs150Date) < twoYearsAgo() : null; + + if (outdated || isOverdue) { + checks.push({ + id: "mcs150", + label: "MCS-150 Biennial Update", + status: "red", + detail: `OVERDUE — last filed ${mcs150Date || "unknown date"}. The MCS-150 must be updated every 2 years. ` + + `Failure to update can result in USDOT deactivation and fines up to $1,000/day (capped at $10,000). ` + + `File at: https://safer.fmcsa.dot.gov/CompanyUpdateSearch.aspx`, + action_url: "https://safer.fmcsa.dot.gov/CompanyUpdateSearch.aspx", + }); + } else if (mcs150Date) { + checks.push({ + id: "mcs150", + label: "MCS-150 Biennial Update", + status: "green", + detail: `Current — last filed ${mcs150Date}.`, + }); + } else { + checks.push({ + id: "mcs150", + label: "MCS-150 Biennial Update", + status: "unknown", + detail: "Filing date not available. Verify at SAFER.", + }); + } + } + + // ── Check 3: Insurance ── + if (carrier) { + const bipdRequired = carrier.bipdInsuranceRequired === "Y"; + const bipdOnFile = carrier.bipdInsuranceOnFile !== null && carrier.bipdInsuranceOnFile !== "0"; + const cargoRequired = carrier.cargoInsuranceRequired === "Y"; + const cargoOnFile = carrier.cargoInsuranceOnFile !== null && carrier.cargoInsuranceOnFile !== "0"; + const bondRequired = carrier.bondInsuranceRequired === "Y"; + const bondOnFile = carrier.bondInsuranceOnFile !== null && carrier.bondInsuranceOnFile !== "0"; + + const issues: string[] = []; + if (bipdRequired && !bipdOnFile) issues.push("Liability (BIPD) insurance required but not on file"); + if (cargoRequired && !cargoOnFile) issues.push("Cargo insurance required but not on file"); + if (bondRequired && !bondOnFile) issues.push("Bond/trust fund required but not on file"); + + if (issues.length > 0) { + checks.push({ + id: "insurance", + label: "Insurance Filing", + status: "red", + detail: issues.join(". ") + ". Operating without required insurance can result in immediate out-of-service order and operating authority revocation.", + }); + } else if (bipdRequired || cargoRequired) { + checks.push({ + id: "insurance", + label: "Insurance Filing", + status: "green", + detail: "Required insurance is on file with FMCSA.", + }); + } + } + + // ── Check 4: Safety Rating ── + if (carrier && carrier.safetyRating) { + const rating = carrier.safetyRating; + const ratingDate = carrier.safetyRatingDate || ""; + const ratingMap: Record = { + S: { status: "green", label: "Satisfactory" }, + C: { status: "yellow", label: "Conditional" }, + U: { status: "red", label: "Unsatisfactory" }, + }; + const r = ratingMap[rating] || { status: "unknown", label: rating }; + checks.push({ + id: "safety_rating", + label: "Safety Rating", + status: r.status, + detail: `${r.label}${ratingDate ? ` (rated ${ratingDate})` : ""}. ` + + (rating === "U" ? "An Unsatisfactory rating may lead to an operations out-of-service order." : "") + + (rating === "C" ? "A Conditional rating indicates deficiencies that need correction." : ""), + }); + } + + // ── Check 5: Operating Authority ── + if (carrier) { + const commonActive = carrier.commonAuthorityStatus === "A"; + const contractActive = carrier.contractAuthorityStatus === "A"; + const brokerActive = carrier.brokerAuthorityStatus === "A"; + const isForHire = census?.authorized_for_hire || false; + + if (isForHire && !commonActive && !contractActive) { + checks.push({ + id: "authority", + label: "Operating Authority", + status: "red", + detail: "For-hire carrier without active operating authority. Common authority: " + + (carrier.commonAuthorityStatus || "None") + ", Contract authority: " + + (carrier.contractAuthorityStatus || "None") + + ". You cannot legally transport freight for compensation without active authority.", + }); + } else if (commonActive || contractActive || brokerActive) { + const types: string[] = []; + if (commonActive) types.push("Common"); + if (contractActive) types.push("Contract"); + if (brokerActive) types.push("Broker"); + checks.push({ + id: "authority", + label: "Operating Authority", + status: "green", + detail: `Active authority: ${types.join(", ")}.`, + }); + } + } + + // ── Check 6: Out-of-Service Rates ── + if (carrier) { + const driverOos = parseFloat(carrier.driverOosRate) || 0; + const driverNat = parseFloat(carrier.driverOosRateNationalAverage) || 5.51; + const vehicleOos = parseFloat(carrier.vehicleOosRate) || 0; + const vehicleNat = parseFloat(carrier.vehicleOosRateNationalAverage) || 20.72; + + if (driverOos > driverNat * 1.5 || vehicleOos > vehicleNat * 1.5) { + checks.push({ + id: "oos_rate", + label: "Out-of-Service Rate", + status: "red", + detail: `Driver OOS: ${driverOos.toFixed(1)}% (national avg: ${driverNat}%). ` + + `Vehicle OOS: ${vehicleOos.toFixed(1)}% (national avg: ${vehicleNat}%). ` + + `Significantly above national average — targeted for increased inspections.`, + }); + } else if (driverOos > driverNat || vehicleOos > vehicleNat) { + checks.push({ + id: "oos_rate", + label: "Out-of-Service Rate", + status: "yellow", + detail: `Driver OOS: ${driverOos.toFixed(1)}% (national avg: ${driverNat}%). ` + + `Vehicle OOS: ${vehicleOos.toFixed(1)}% (national avg: ${vehicleNat}%). ` + + `Above national average.`, + }); + } else if (carrier.vehicleInsp > 0 || carrier.driverInsp > 0) { + checks.push({ + id: "oos_rate", + label: "Out-of-Service Rate", + status: "green", + detail: `Driver OOS: ${driverOos.toFixed(1)}% (national avg: ${driverNat}%). ` + + `Vehicle OOS: ${vehicleOos.toFixed(1)}% (national avg: ${vehicleNat}%). Within normal range.`, + }); + } + } + + // ── Check 7: Crash History ── + if (carrier) { + const crashes = carrier.crashTotal || 0; + const fatal = carrier.fatalCrash || 0; + const injury = carrier.injCrash || 0; + if (fatal > 0) { + checks.push({ + id: "crashes", + label: "Crash Record", + status: "red", + detail: `${crashes} total crashes on record, including ${fatal} fatal and ${injury} injury crashes.`, + }); + } else if (crashes > 0) { + checks.push({ + id: "crashes", + label: "Crash Record", + status: "yellow", + detail: `${crashes} crash(es) on record, ${injury} with injuries. No fatalities.`, + }); + } else { + checks.push({ + id: "crashes", + label: "Crash Record", + status: "green", + detail: "No crashes on record.", + }); + } + } + + // Build response + const redCount = checks.filter(c => c.status === "red").length; + const yellowCount = checks.filter(c => c.status === "yellow").length; + + res.json({ + dot_number: rawDot, + legal_name: name, + dba_name: dba || null, + phy_city: carrier?.phyCity || census?.phy_city || null, + phy_state: carrier?.phyState || census?.phy_state || null, + telephone: census?.telephone || null, + email: census?.email_address || null, + fleet: { + power_units: carrier?.totalPowerUnits ?? census?.nbr_power_unit ?? null, + drivers: carrier?.totalDrivers ?? census?.driver_total ?? null, + }, + mcs150_date: census?.mcs150_parsed || null, + carrier_type: carrier?.censusTypeId?.censusTypeDesc || census?.carrier_operation || null, + for_hire: census?.authorized_for_hire || false, + checks, + summary: { + red: redCount, + yellow: yellowCount, + green: checks.filter(c => c.status === "green").length, + total: checks.length, + }, + checked_at: new Date().toISOString(), + }); + } catch (err) { + console.error("[dot-lookup] Error:", err); + res.status(500).json({ error: "DOT lookup failed." }); + } +}); + +// ── Name Search ───────────────────────────────────────────────────── + +router.get("/api/v1/dot/search", async (req, res) => { + const name = (req.query.name as string || "").trim(); + if (!name || name.length < 2) { + res.status(400).json({ error: "Provide a business name (at least 2 characters)." }); + return; + } + + try { + const result = await pool.query( + `SELECT dot_number, legal_name, dba_name, phy_city, phy_state, + nbr_power_unit, authorized_for_hire, mcs150_parsed + FROM fmcsa_carriers + WHERE legal_name ILIKE $1 OR dba_name ILIKE $1 + ORDER BY legal_name + LIMIT 50`, + [`%${name}%`], + ); + + res.json({ + results: result.rows, + count: result.rows.length, + query: name, + source: "FMCSA Motor Carrier Census", + }); + } catch (err) { + console.error("[dot-search] Error:", err); + res.status(500).json({ error: "Search failed." }); + } +}); + +export default router;