Architecture + deploy · Spotter take-home

Complete architecture, and where Django lives

Yes — Django is deployable on Vercel now (official Python runtime + zero-config Django docs, changelog April 2026). It runs as a serverless Vercel Function, not a forever-on gunicorn box. For this app, that works if you raise maxDuration; the safer grader demo is still Next on Vercel + Django on Render.

Architecture

What we built (one picture)

The product is a trip planner that draws paper logs. The browser never runs HOS math. Django owns planning; Next owns drawing.

Layer What Path in hos/
UI Next.js 15 App Router — form, Leaflet map, SVG daily logs frontend/
API Django 5 + Django Ninja — POST /api/trips/plan, GET /api/health, OpenAPI at /api/docs backend/
Routing Nominatim geocode → OSRM drive polyline (Photon + baked sample cities as fallback) backend/trips/routing.py
HOS engine Greedy minute walk: 8h / 11h / 14h / 70h clocks; fuel every 1,000 mi; 10h sleeper; 34h restart backend/trips/hos.py
Persistence None — stateless POST (SQLite unused for plans) —
Auth None — graders hit the form —

Repo shape

hos/                          ← GitHub submission root
  README.md
  docs/assumptions.md
  backend/                    ← Django project `config`, app `trips`
    manage.py
    config/settings.py urls.py wsgi.py
    trips/api.py routing.py hos.py test_hos.py
    requirements.txt Procfile
  frontend/                   ← Next.js
    src/app/page.tsx
    src/components/…          ← TripForm, RouteMap, StopList, DailyLogSheet
    next.config.ts            ← rewrites /api → Django in local dev

Request flow

One POST, two views of the same timeline

  1. User submits current / pickup / dropoff / cycle hours.
  2. Next fetch → POST /api/trips/plan (local: rewrite to :8000; prod: NEXT_PUBLIC_API_URL).
  3. Django Ninja validates body → geocode 3 strings → OSRM route → plan_trip().
  4. Response: route (geojson) + stops + timeline + daily_logs + summary.
  5. UI: Leaflet draws the line; SVG draws each calendar day on the paper grid.

Hard rule

HOS never lives in Next Route Handlers

Even if both apps sit on Vercel, the planning Function must be the Django project. Putting clocks in app/api/… would fail the “use Django” requirement.

Research

Is Django deployable on Vercel?

Yes. As of 2026, Vercel documents Django officially:

What that means in practice:

Topic Reality on Vercel Impact on Spotter
Process model Serverless Function (Fluid compute), not a long-lived gunicorn process OK — our API is one POST, no websockets/Celery
Entry application in wsgi.py; root or backend/ with Root Directory set Set Vercel root to backend
Duration Configurable maxDuration (often 10s hobby default; up to 60s+ on paid / Fluid) Important — 3× Nominatim sleeps (~1.1s each) + OSRM can approach limits. Set 60s.
Cold start First hit after idle can be slow UI already has “waking API” copy
DB / workers Awkward for classic Django ORM + Celery Irrelevant — we are stateless
Next + Django monorepo Two Vercel projects (two Root Directories), not one magic full-stack Frontend project + API project

Our earlier plan said “Django does not run on Vercel.” That was the old story. Update: it can; treat it as a Function with a timeout budget.

Deploy

Two workable layouts

Option A · recommended for graders

Next → Vercel · Django → Render

Matches classic “SPA + API”. Predictable long requests. Assignment’s “can use Vercel.app” covers the UI.

  1. Push hos/ to GitHub.
  2. Vercel: Import repo, Root Directory frontend, Framework Next.js. Env NEXT_PUBLIC_API_URL=https://your-api.onrender.com.
  3. Render: Web service, Root backend, build pip install -r requirements.txt, start gunicorn config.wsgi:application.
  4. Env on Render: SECRET_KEY, DEBUG=0, ALLOWED_HOSTS, CORS_ALLOWED_ORIGINS=https://your-app.vercel.app, NOMINATIM_USER_AGENT.

Option B · all on Vercel

Two Vercel projects

Valid now that Django is first-class. One repo, two deployments.

  1. Project “hos-api”: Root backend. Python / Django. Add backend/vercel.json with functions maxDuration: 60 on config/wsgi.py.
  2. Project “hos-web”: Root frontend. Env NEXT_PUBLIC_API_URL → the API project URL.
  3. CORS on Django must allow the web origin. ALLOWED_HOSTS include .vercel.app.
  4. Watch Hobby duration limits on first plan with cold Nominatim.

Local vs production API URL

Environment How the browser calls Django
Local Next rewrite: /api/* → http://127.0.0.1:8000/api/* (no CORS pain)
Production NEXT_PUBLIC_API_URL = absolute API origin; CORS allowlist the Vercel web URL

Smoke checklist after deploy

  1. GET /api/health → {"status":"ok"}
  2. Sample chip “Atlanta → Macon” → map + one log, totals ≈ 24
  3. Chicago → Dallas → multi-day sheets + fuel/sleeper stops
  4. Denver → KC with cycle 68 → 34h restart appears
  5. First request after 15 min idle — “waking” message, then success

Pick

What we should do for Spotter

Recommendation

Prefer Option A for the graded demo

Render (or Railway) for Django + Vercel for Next. Lowest surprise on geocode/OSRM latency. If you want everything on Vercel for the Loom story (“all on Vercel.app”), use Option B and set maxDuration to 60 on the WSGI function.