A* search over a real multi-modal transport graph β air, sea, and land β that returns the top-N Pareto-efficient shipping routes ranked by cost, transit time, regulatory feasibility, and COβ footprint, with AI-driven prohibited/restricted-item screening.
π Live App Β· π₯ Demo Video Β· π¦ Source Β· π§ Quick Start Β· π‘οΈ Security
- Executive Summary & Impact Metrics
- Architecture & Data Flow
- Technical Deep-Dive
- Tech Stack
- Directory Structure
- Development & Quick Start Guide
- Testing & Verification
- Security Controls & Roadmap
Cross-border freight planning is a multi-objective shortest-path problem over a heterogeneous transport graph: shippers must jointly optimize cost, transit time, and carbon footprint across air/sea/land legs, while respecting regulatory feasibility β country-level import/export bans and item-specific prohibited/restricted-goods rules that vary per corridor. Manually cross-referencing customs regulations against route options creates both latency and compliance risk before a shipment even departs.
GlobalRoute Navigator precomputes a global multi-modal transport graph (nodes = ports/airports/land hubs with geocoordinates and country codes; edges = mode-tagged legs with cost/time/COβ weights) and runs a weighted A* search with a haversine-distance admissible heuristic to return the top-N non-dominated routes in a single request. A Gemini-backed prohibited-items classifier screens the shipment description against country-level restriction data before the search runs, converting regulatory rules into hard avoid_countries constraints or soft penalty_countries cost penalties inside the same optimization pass.
| Metric | Value | Mechanism |
|---|---|---|
| Route candidates returned | Top 3β5 per query (top_n, configurable) |
Priority-queue A* with completed-path pruning |
| Transport modes supported | Air, Sea, Land + hybrid multi-leg | allowed_modes filter on multigraph edges |
| Heuristic admissibility | Haversine great-circle distance / fastest-mode speed | precompute_heuristics() per-goal cache |
| COβ emission factors | Sea 0.01 Β· Land 0.1 Β· Air 0.7 (kg/ton-km) | EMISSION_FACTORS lookup table |
| Optimization objectives | Cost weight + time weight (must sum to 1.0) | Validated request schema (Pydantic) |
| Regulatory screening | Prohibited (hard avoid) + restricted (soft penalty) | Gemini-classified avoid_countries / penalty_countries |
| Graph load strategy | Precomputed pickle graph, loaded once at boot | graph_final_8_precalc.pkl |
| API response shape | Ranked paths + coordinates + avoided/penalized countries | POST /find_paths/ |
graph TB
subgraph Frontend["Frontend β Next.js 15 + TypeScript"]
A["React 19 UI β Route Search Form"]
B["Leaflet.js Interactive Map<br/>+ react-leaflet, @turf/turf"]
C["Clerk Auth<br/>(NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY)"]
D["Prisma ORM Client"]
end
subgraph Data["Data & Persistence"]
E["Prisma Schema<br/>Shipment Β· Route Β· Segment"]
F["(SQLite dev / Postgres-ready<br/>via DATABASE_URL)"]
end
subgraph Backend["Backend β FastAPI (Python)"]
G["POST /find_paths/<br/>PathRequest schema"]
H["make_avoid_list()<br/>Prohibited-item screening"]
I["astar_top_n_avoid_countries()<br/>Weighted A* multigraph search"]
J["precompute_heuristics()<br/>Haversine admissible heuristic"]
end
subgraph AI["AI Layer"]
K["Google Gemini<br/>gemini-1.5-flash"]
L["rapidfuzz<br/>Fuzzy prohibited-item matching"]
end
subgraph Graph["Route Graph Engine"]
M["graph_final_8_precalc.pkl<br/>Precomputed multigraph"]
N["Nodes: ports/airports/hubs<br/>lat, lon, country_code"]
O["Edges: mode-tagged legs<br/>time_norm, price_norm, CO2"]
end
A --> C
A --> G
B --> A
D --> E
E --> F
G --> H
H --> K
H --> L
G --> I
I --> J
I --> M
M --> N
M --> O
I -->|"ranked paths + coordinates"| A
A --> B
style Backend fill:#0f172a,color:#fff,stroke:#009688
style AI fill:#1a0033,color:#fff,stroke:#7D00FF
style Graph fill:#1a1a2e,color:#fff,stroke:#00ADD8
sequenceDiagram
participant U as User
participant F as Frontend (Next.js)
participant API as FastAPI Backend
participant AI as Gemini + rapidfuzz
participant G as Multigraph (A*)
U->>F: Enter origin, destination, cargo details
F->>API: POST /find_paths/ (PathRequest)
API->>API: Validate time_weight + price_weight == 1.0
API->>AI: make_avoid_list(description, prohibited_flag, restricted_flag)
AI-->>API: { avoid_countries, penalty_countries }
API->>G: astar_top_n_avoid_countries(start, goal, avoid_countries, ...)
G->>G: precompute_heuristics(goal) β haversine cache
G->>G: Priority-queue search, prune on top_n completion
G-->>API: Ranked paths + edge details + coordinates
API-->>F: { avoided_countries, penalty_countries, paths[] }
F->>U: Render top 3β5 routes on Leaflet map
flowchart TB
A["Receive PathRequest<br/>start, goal, weights, modes"] --> B{"start/goal country<br/>in avoid_countries?"}
B -->|"Yes"| C["Reject: No valid route"]
B -->|"No"| D["precompute_heuristics(goal)<br/>haversine-based h(n)"]
D --> E["Push (f=h, g=0, start) to priority queue"]
E --> F{"Queue empty?"}
F -->|"Yes"| G["Return best top_n completed paths"]
F -->|"No"| H["Pop lowest f_cost node"]
H --> I{"node == goal?"}
I -->|"Yes"| J["Record completed path<br/>Prune if top_n reached & f_cost worse"]
I -->|"No"| K["Expand edges: filter by allowed_modes"]
K --> L{"neighbor country<br/>in avoid_countries?"}
L -->|"Yes"| F
L -->|"No"| M["g_cost += time_w*time_norm + price_w*price_norm<br/>+ border_penalty + restricted_penalty"]
M --> N["f_cost = g_cost + h(neighbor)"]
N --> O["Push to priority queue"]
O --> F
J --> F
style C fill:#3a0000,color:#fff,stroke:#ff4d4d
style G fill:#003a1a,color:#fff,stroke:#00ff88
flowchart LR
A["Cargo description<br/>(free text)"] --> B["rapidfuzz<br/>fuzzy match against logistics_data.json"]
B --> C["Gemini gemini-1.5-flash<br/>ask_gemini() classification"]
C --> D{"prohibited_flag == avoid?"}
D -->|"Yes"| E["Add country to avoid_countries<br/>(hard constraint β path excluded)"]
D -->|"No, ignore"| F["Skip prohibited screening"]
C --> G{"restricted_flag == avoid / penalty?"}
G -->|"avoid"| E
G -->|"penalty"| H["Add country to penalty_countries<br/>(soft cost penalty in A*)"]
G -->|"ignore"| I["Skip restricted screening"]
astar_top_n_avoid_countries() runs a standard priority-queue A* over a networkx multigraph, but instead of stopping at the first path found, it keeps popping until top_n distinct completed paths are collected β sorted by true g_cost β and prunes remaining queue entries once the current f_cost exceeds the worst of the top-N so far. The heuristic itself, precompute_heuristics(), is computed once per goal node using haversine great-circle distance divided by the fastest possible mode speed (air) for a time estimate, and the cheapest mode's per-km rate (sea) for a price estimate β keeping h(n) admissible (never overestimating true cost) so the search remains provably optimal for the top result while still surfacing near-optimal alternatives.
Every edge traversal accumulates g_cost = time_weight * time_norm + price_weight * price_norm + border_penalty + restricted_penalty, where time_weight + price_weight is enforced to sum to exactly 1.0 by the Pydantic request schema. border_penalty adds a fixed cost whenever consecutive nodes sit in different country_codes (modeling customs friction), while restricted_penalty layers in the AI-classified soft regulatory cost β meaning a single scalar priority-queue comparison simultaneously balances four independent business objectives without a separate multi-criteria solver.
make_avoid_list() takes the shipment's free-text cargo description and β depending on prohibited_flag (ignore/avoid) and restricted_flag (ignore/avoid/penalty) β first runs rapidfuzz fuzzy string matching against a curated logistics_data.json prohibited/restricted-item dataset, then escalates ambiguous cases to Gemini 1.5 Flash (ask_gemini()) for natural-language classification. The result converts directly into the A* engine's avoid_countries (hard exclusion) and penalty_countries (soft cost) sets β regulatory compliance becomes a graph-search constraint, not a downstream manual check.
Rather than building the transport graph per-request, the backend loads a single precomputed graph_final_8_precalc.pkl at process boot (pickle.load on graph_final_8_precalc.pkl), where every edge already carries normalized time_norm/price_norm weights and every node carries latitude/longitude/country_code. This trades a heavier deploy artifact for near-instant per-request search latency, since no geocoding or normalization work happens on the request path.
| Layer | Technology | Architectural Purpose |
|---|---|---|
| Frontend | Next.js 15, React 19, TypeScript | Server-rendered route-search UI and results dashboard |
| Mapping | Leaflet.js, react-leaflet, @maptiler/sdk, @turf/turf |
Interactive geospatial rendering of top-N routes with geometry ops |
| Auth | Clerk (@clerk/nextjs) |
Session management and user-scoped shipment history |
| Backend / Core Logic | FastAPI (Python), Pydantic | Typed request validation, async route-search endpoint |
| Algorithm | Custom A* (heapq priority queue) + haversine heuristic |
Multi-objective shortest-path search over the transport multigraph |
| Graph Engine | networkx multigraph, precomputed .pkl |
Mode-tagged edges (air/sea/land) with cost/time/COβ weights |
| AI Integration | Google Gemini (google-generativeai, gemini-1.5-flash) |
Natural-language prohibited/restricted-item classification |
| Fuzzy Matching | rapidfuzz |
Fast approximate string matching against the regulatory dataset |
| Database / ORM | Prisma (Shipment, Route, Segment models) |
Typed persistence layer for shipment history and route segments |
| Geospatial Data | geopandas, gdacs-api |
Geospatial dataset processing and hazard/incident enrichment |
| Deployment | Vercel (frontend), Render (backend) | Edge-hosted frontend + containerizable Python API service |
GlobalRoute-Navigator/
βββ backend/
β βββ main.py # FastAPI app β /find_paths/, /health, /
β βββ precalc.py # Graph precomputation pipeline
β βββ graph_final_8_precalc.pkl # Precomputed multigraph (nodes + edges)
β βββ prohibited_items/
β β βββ find_prohibited.py # Gemini + rapidfuzz classification
β β βββ logistics_data.json # Prohibited/restricted-item dataset
β βββ safety_analysis/
β β βββ analysis.py # Incident-risk scoring
β β βββ incident_counts_by_node.json
β βββ data/raw/edges/ # Raw transport-leg source data
β βββ requirements.txt
βββ frontend/
β βββ routesyncai/
β βββ src/
β β βββ app/ # Next.js App Router pages
β β βββ components/ # Route map, search form, UI primitives
β β βββ services/ # api.ts β backend HTTP client
β β βββ hooks/ # Custom React hooks
β β βββ lib/ # Client utilities
β βββ prisma/
β β βββ schema.prisma # Shipment / Route / Segment models
β βββ package.json
βββ requirements.txt # Root-level Python dependency pin
βββ vercel.json # Frontend deploy configuration
βββ .env.example # Required environment variables
βββ docker-compose.yml # Local multi-service orchestration
βββ SECURITY.md # Vulnerability disclosure policy
βββ LICENSE # MIT License
| Requirement | Version | Purpose |
|---|---|---|
| Node.js | >= 18.x |
Frontend build/runtime |
| Python | >= 3.10.x |
Backend build/runtime |
| Google Gemini API key | β | Enables prohibited/restricted-item AI screening |
git clone https://github.com/Aaditya1273/GlobalRoute-Navigator.git
cd GlobalRoute-Navigatorcp .env.example .env.env.example:
# --- Backend (FastAPI) ---
GEMINI_API_KEY=your_gemini_api_key_here
# --- Frontend (Next.js) ---
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key_here
CLERK_SECRET_KEY=your_clerk_secret_key_here
DATABASE_URL="file:./dev.db"
# NEXT_PUBLIC_API_URL=http://localhost:8000 # point the frontend at a local backendcd backend
pip install -r requirements.txt
uvicorn main:app --reloadBackend runs at http://localhost:8000 β verify with GET /health.
cd frontend/routesyncai
npm install
npm run devdocker compose up --build# Backend health check
curl http://localhost:8000/health
# Example route search request
curl -X POST http://localhost:8000/find_paths/ \
-H "Content-Type: application/json" \
-d '{
"start": "USNYC",
"goal": "INBOM",
"top_n": 3,
"time_weight": 0.5,
"price_weight": 0.5,
"allowed_modes": ["land", "sea", "air"],
"prohibited_flag": "avoid",
"restricted_flag": "penalty",
"description": "electronics shipment"
}'
# Frontend lint + type-check
cd frontend/routesyncai && npm run lint
# Frontend production build (validates types + Prisma client generation)
npm run buildCoverage types implemented:
- β
Manual/API-level verification β
/healthand/find_paths/endpoints are directly testable viacurl/Postman - β
Schema validation β Pydantic
PathRequestmodel rejects malformed weights (time_weight + price_weight != 1.0) at the API boundary - β
Type-check gate β
next buildfails the build on TypeScript errors before deploy β οΈ Automated unit/integration test suite β not yet present in this repo (notests/directory); see roadmap below
- Input validation at the API boundary β Pydantic enforces types, ranges (
top_n > 0, weights in[0.0, 1.0]), and literal enums (prohibited_flag,restricted_flag) before any request reaches the search engine - Authenticated shipment history β Clerk-gated sessions scope
Shipmentrecords touserIdin the Prisma schema, preventing cross-user data access - Secrets kept server-side β
GEMINI_API_KEYandCLERK_SECRET_KEYare never exposed to the client bundle; onlyNEXT_PUBLIC_CLERK_PUBLISHABLE_KEYships to the browser - Fail-safe AI classification β
ask_gemini()explicitly checks for a missing/placeholder API key before calling out, avoiding silent misclassification of regulatory constraints - CORS currently permissive (
allow_origins=["*"]) β flagged below as a hardening item for production multi-tenant use - See
SECURITY.mdfor the full vulnerability-disclosure policy and reporting process
β οΈ Operational note: the backend's CORS middleware currently allows all origins (allow_origins=["*"]) perbackend/main.py. This is fine for a public read-mostly routing API but should be scoped to the deployed frontend origin before handling authenticated or write-heavy traffic at scale.
π Live App Β· π₯ Demo Video Β· π¦ GitHub Β· π‘οΈ Report a Vulnerability
Aaditya Rawat Β· Arpit Singh Β· Jay
Built with FastAPI, A* Search, Next.js, and Google Gemini β optimizing global logistics, one route at a time.