Skip to content
SwiftCore
All projects

Navigo CRM

Case study · 2026

Auto-transport brokers ran each shipment across six tools. We built one system where a lead becomes a quote, an order and a dispatched load without anyone retyping it.

Client
Navigo CRM, United States
Industry
Logistics
Services
Product design, web application, backend, integrations, infrastructure, support
Platforms
Web app, public lead API, marketing site
Timeline
2026 — ongoing
Navigo CRM dashboard with the Price Check screen in front: comparable Central Dispatch loads for a Tampa to Dallas route
Navigo CRM dashboard
Fig. 1 — Dashboard and Price Check. Product screens from navigocrm.com, with sample data.

Overview

Navigo CRM is a SaaS product for US auto-transport brokers — the companies that arrange car shipping between customers and carriers. Agents take leads from many sources, quote against real market prices, send contracts that customers sign in the browser, take card payments, post loads to Central Dispatch and Super Dispatch, dispatch a carrier and see profit before the month closes. We designed and built the product end to end: the Django backend, the Vue web app, the public lead API and its documentation, the marketing site and the infrastructure it runs on.

The challenge

A broker’s day was split across spreadsheets, the Central Dispatch website, a phone system, a separate e-signature tool and month-end profit sheets. Every handoff meant retyping the same shipment, and nobody could see margin until the month was over. The product had to replace all of it without asking brokers to change how they sell.

  1. C1

    Competitors on one platform

    Every brokerage is a separate company, often competing with the others. A leak of one company’s leads or carriers to another is unacceptable.

  2. C2

    Many outside systems

    Central Dispatch, Super Dispatch, RingCentral, Zoom Phone, Gmail and QuickBooks each have their own API, limits and failure modes, and their statuses must stay in sync with the order.

  3. C3

    Payments and compliance

    Card payments had to pass Intuit’s app review, so card data could never touch our servers.

Our approach — decision logDecision log

One record from first enquiry to archived order — every screen, integration and report reads from it. Below: the decisions that shaped the system, and what each one cost.The decisions that shaped the system, and what each one cost.

No.DecisionWhyTrade-off accepted
D1A separate database schema for every company, and a separate signing key for its tokens.Isolation is enforced by the database, not by remembering a filter in every query. A token issued for one brokerage is useless in another.Creating a company runs schema migrations, and every migration runs once per tenant.
D2Leads, quotes and orders are one table with a stage, not three.Converting a quote into an order changes its state instead of copying it, so the history, notes and files follow the shipment.Each stage keeps its own status field, which makes filtering and validation more involved.
D3Cards are tokenised in the customer’s browser; market prices are cached for 30 days.Card numbers never reach our servers, which kept the Intuit review simple. Paid, rate-limited pricing lookups stay instant for repeat routes.Prices for a route can be up to a month old; agents see the cache date next to every lookup.
  1. D1

    A separate database schema for every company, and a separate signing key for its tokens.

    Why
    Isolation is enforced by the database, not by remembering a filter in every query. A token issued for one brokerage is useless in another.
    Trade-off
    Creating a company runs schema migrations, and every migration runs once per tenant.
  2. D2

    Leads, quotes and orders are one table with a stage, not three.

    Why
    Converting a quote into an order changes its state instead of copying it, so the history, notes and files follow the shipment.
    Trade-off
    Each stage keeps its own status field, which makes filtering and validation more involved.
  3. D3

    Cards are tokenised in the customer’s browser; market prices are cached for 30 days.

    Why
    Card numbers never reach our servers, which kept the Intuit review simple. Paid, rate-limited pricing lookups stay instant for repeat routes.
    Trade-off
    Prices for a route can be up to a month old; agents see the cache date next to every lookup.

Solution and architectureArchitecture

Simplified · no confidential detail

A Django core, one schema per brokerage, and integrations behind background workers.

The Vue web app talks to a Django REST API; real-time updates — the inbox, notifications and long-running jobs — travel over WebSockets. Celery workers handle everything slow or external: marketplace sync, SMS and email sync, pricing lookups and per-company scheduled tasks. PostgreSQL holds one schema per company; Redis serves as the cache, the queue and the WebSocket layer.

  • Built by SwiftCore
  • Existing or third-party system
  • Single entry point for all clients
Client
Web app (Vue)
Client
Lead providers (API)
Client
Customer signing page
Entry point
Django REST API + WebSockets
Service
Orders & dispatch
Service
Lead distribution
Service
Messaging
Service
Reports
Data
PostgreSQL, schema per company
Data
Redis
Data
Celery workers
External
Central Dispatch
Super Dispatch
RingCentral
Gmail
QuickBooks Payments
Fig. 2 — Simplified: clients, the API, core modules, data and the outside services they sync with.

Technology

The tools in production on this project, and the reason each was chosen over the alternatives.

Frontend

  • Vue 3
  • TypeScript
  • Vite
  • Pinia
  • TanStack Query
  • Element Plus
  • Tailwind CSS

Vue 3 · TypeScript · Vite · Pinia · TanStack Query · Element Plus · Tailwind CSS

A dense, table-heavy back-office app with feature-sliced modules that stay independent as the product grows.

Backend

  • Python
  • Django
  • Django REST Framework
  • Celery
  • Django Channels
  • django-tenants

Python · Django · Django REST Framework · Celery · Django Channels · django-tenants

Mature tooling for a data-heavy business system, with background jobs and WebSockets in the same codebase.

Data

  • PostgreSQL
  • Redis

PostgreSQL · Redis

Schema-per-tenant isolation in PostgreSQL; Redis for cache, queues and real-time messages.

Infrastructure

  • Docker
  • Traefik
  • Nginx
  • GitHub Actions
  • Vercel

Docker · Traefik · Nginx · GitHub Actions · Vercel

Containerised services behind a reverse proxy; the web app and the site ship from Vercel.

Quality and tooling

  • pytest
  • Vitest
  • CI on every change

pytest · Vitest · CI on every change

Tests run on every change, against the same PostgreSQL and Redis versions as production.

Results

Outcomes are still being measured.

We publish numbers only after they’ve been measured over a full period and approved by the client. Until then, here is what changed:

  • A shipment moves from lead to dispatched load in one record, without being retyped between tools.
  • Customers sign contracts and pay by card in the browser, from a link sent by email or SMS.
  • Loads are posted to Central Dispatch and carriers dispatched without leaving the order.
  • Gross profit and lead-source ROI are visible mid-month instead of after it closes.

Facing a similar problem?