Project Info
Inspiration
Have you ever been stranded when an NYC subway line suddenly goes down? It’s pure chaos. Hundreds of frustrated people pour out onto the street looking for a ride, while nearby roads instantly gridlock. We wanted to solve this dual problem: how can we proactively guide taxis toward stranded passengers without turning the surrounding streets into a parking lot? That question sparked the idea for CabVector. How We Built It We built CabVector from the ground up as a full-stack web application: The Brain (Backend): We used FastAPI to handle the state management, scoring logic, safety workflows, and live API endpoints. The Interface (Frontend): Next.js powers our multi-page interactive dashboard. The Map: Leaflet and CARTO tiles bring the data to life, visualizing the disruptions, map legends, and staging zones. The Integrations: We built hooks for MTA, NYC DOT, OpenAI, and Groq APIs. Knowing that live demos can be risky, we engineered dependable fixture data so the app runs flawlessly even without API keys. The entire system is governed by a strict, deterministic workflow: $$ \text{Fleet proposal} \rightarrow \text{Traffic validation} \rightarrow \text{Approved dispatch} $$ A taxi's state doesn't change until it passes through every single checkpoint. A dispatch is only approved if it makes sense for both the driver's wallet and the city's traffic grid: $$ (L\text{-Score} > 70) \land (\text{Congestion Index} \leq 0.7) $$ Challenges We Ran Into If you've ever worked with live public city data, you know the struggle. Transit and traffic feeds are notoriously flaky—authentication methods change, responses lag, and connections drop out of nowhere. Instead of letting the app break, we engineered resilient fallback mechanisms and live health indicators. If a provider goes down, the dashboard stays functional and is completely transparent about what data is missing. Another massive headache was keeping everything perfectly in sync. Ensuring the map, fleet state, alerts, and backend decisions were all telling the same story required us to nail down clear shared contracts and rely heavily on server-sent events. What We Learned This project was a masterclass in building operational AI. We learned that these systems absolutely need reliable fallbacks, transparent rules, and a hard wall between an AI's "suggestion" and a system's "action." On the technical side, we leveled up our skills in real-time state synchronization, map visualizations, and collaborative full-stack architecture. We also had a great time using Codex (powered by GPT-5.6) as an engineering copilot. It was incredibly helpful for untangling integration bugs and organizing our implementation phases, proving its worth as a collaborator rather than a runtime dispatch engine.
CabVector
CabVector is a simulated New York City/MTA pre-emptive taxi-staging system. It detects sustained transit disruption, estimates displaced passenger demand, produces a driver-facing Lucrativeness Score (L-Score), recommends nearby staging zones, validates traffic safety, and models approved movement of a 20-taxi fleet.
This repository is an MVP simulator, not a passenger-booking app, live taxi-dispatch system, fare engine, or traffic-signal controller.
How it works
- A transit delay above 600 seconds must persist for three minutes before it becomes a disruption.
- Passenger spill and historical station footfall determine the integer L-Score (1–100).
- An L-Score above 70 permits Fleet to propose available taxis for a staging zone.
- Traffic approves only congestion at or below 0.7.
- Only an approval can call the state-update function that dispatches taxis.
Project layout
| Area | Responsibility |
|---|---|
backend/main.py | FastAPI application, fixture-backed in-memory state, and API routes |
backend/core/ | Shared models and deterministic score calculation |
backend/agents/ | Approval-gated Fleet → Traffic → Action workflow |
backend/data/ | Recorded hourly footfall fixture for the demo |
backend/tests/ | API, scoring, and agent workflow tests |
frontend/ | Next.js dashboard with live API integration and an interactive Leaflet/CARTO Dark Matter map |
Delivery status
The table below is the current repository-wide plan. A phase is only fully complete when every listed workstream is complete.
| Phase | Developer / workstream | Status | Delivered or pending work |
|---|---|---|---|
| Phase 0 — alignment and contracts | All developers | Complete | NYC/MTA simulation boundary, safety rules, shared Pydantic models, shared TypeScript contracts (frontend/types/contracts.ts), static fixtures (frontend/lib/fixtures.ts), and frozen API examples. |
| Phase 1 — platform and API | Developer A | Complete | FastAPI application, configuration boundary, seeded state, GET /api/state, POST /api/trigger_agent, and SSE endpoint. |
| Phase 1 — data and scoring | Developer B | Complete | Footfall fixture, recorded scoring scenarios, deterministic passenger-spill calculation, and 1–100 L-Score engine. |
| Phase 1 — agent workflow | Developer C | Complete | Strict workflow schemas, deterministic Fleet → Traffic → Action graph, congestion veto, L-Score gate, and approval-only state update boundary. |
| Phase 1 — dashboard shell | Developer D | Complete | Next.js dashboard layout, map/control split, status indicators, KPI cards, alert feed, and terminal shell using static contract fixtures. |
| Phase 2 — API integration | Developer A | Complete | Two-second state polling and structured SSE delivery for the dashboard. |
| Phase 2 — transit and spatial data | Developer B | Complete | GTFS-RT fixture flattening, three-minute structural-delay validation, and 3–5 staging zones within 300 metres. |
| Phase 2 — dispatch behavior | Developer C | Complete | Nearest-taxi selection plus rejected-zone retry to a farther staging area; taxis remain unchanged until approval. |
| Phase 2 — visual simulation | Developer D | Complete | Interactive NYC map, disruption and staging-zone overlays, clickable taxi markers, alerts, KPI updates, and structured event terminal wired to the live API. |
| Phase 3 — live-data adapters and hardening | Developers A–D | Implementation complete; partially live-validated | MTA subway GTFS-RT and Bus Time SIRI reached online in a local run. NYC DOT traffic may be degraded when its public host is unreachable; the documented fixture fallback remains the correct behavior. |
| Phase 4 — quality, demo, UI redesign, and release | All developers | Complete | Complete UI redesign matching deep obsidian theme (#090D16), official logo badge integration, in-map search bar (⌘ K), 3-column status bottom deck (BottomDeck.tsx), 37/37 backend unit tests passing, Next.js 14 production build verified across all 10 routes. |
Phase 4 is complete and verified. The repository is fully tested, built, and ready for production shipping.
API
| Endpoint | Purpose |
|---|---|
GET /api/state | Returns disruptions, staging zones, taxis, and recent decision events. |
POST /api/trigger_agent | Triggers the fixture-backed dispatch decision. |
GET /api/events | Streams structured decision events over Server-Sent Events. |
GET /api/health | Returns safe provider status, mode, timestamps, and record counts; never returns credentials or raw upstream payloads. |
The frozen request and response examples are in HANDOFF.md.
Live provider inventory
The complete Phase 3 provider/data list, polling intervals, credentials, fallbacks, and safety rules is in docs/API_DATA_INVENTORY.md. Keep LIVE_FEEDS_ENABLED=false until the configured provider endpoints and keys have been tested against the fixture-backed fallback.
Agent safety workflow
The deterministic traffic adapter returns 0.5 by default. It can be configured above 0.7 to verify the veto path. Fleet and Traffic never modify taxi records directly. The workflow uses one approval-only integration point:
def apply_approved_dispatch(update: DispatchConfirmation) -> None:
"""Persist dispatched taxis after Traffic approval."""
The DispatchConfirmation payload contains station_id, assigned_zone_id, dispatched_taxis, and final_congestion_index, matching the public DISPATCH_CONFIRMED event.
Fixture data
backend/data/turnstile_data.csv is a small committed demo fixture, not a live MTA export. The score engine uses an exact station-and-hour lookup and aggregates duplicate observations before scoring.
| Column | Meaning |
|---|---|
station_id | Stable station or stop identifier |
station_name | Human-readable station name |
hour | Local hour from 0 through 23 |
footfall | Historical passenger count for that station and hour |
Missing footfall is deliberately surfaced as unscored; CabVector does not substitute nearby stations or network averages.
Run and test the backend
Install the dependencies listed in backend/requirements.txt, then start the API from the repository root:
uvicorn backend.main:app --reload
Run the completed API, deterministic workflow, and scoring tests across all workstreams:
python -m unittest discover backend/tests -v
Live traffic, map, and AI configuration
Copy .env.example to .env. To use the public NYC DOT traffic feed, set LIVE_FEEDS_ENABLED=true; its default URL needs no API key. The feed supplies observed sensor speeds, and CabVector derives its congestion index against NYC_DOT_REFERENCE_SPEED_MPH (default 30). The default live-provider timeout and Bus Time/traffic polling intervals are 60 seconds to tolerate slow public feeds.
MTA Realtime Feeds (Keyless): MTA subway feeds no longer require an API key. To query live subway delay updates keylessly, leave MTA_GTFS_API_KEY blank in your .env file. The server will automatically fetch data without authorization headers.
For an optional structured operator-summary report, configure Groq or OpenAI in your .env:
LLM_PROVIDER=groq
GROQ_API_KEY=your_key
GROQ_MODEL=llama-3.1-8b-instant
Use LLM_PROVIDER=openai with OPENAI_API_KEY and OPENAI_MODEL for OpenAI instead. When configured, the backend spawns a non-blocking background task to request a structured JSON summary from the LLM and prints it cleanly to the console terminal (avoiding encoding issues on Windows). LLM_PROVIDER=deterministic is the default and remains the only mode that drives the dispatch workflow; LLM output cannot approve or move taxis.
Custom Disruptions, Surge-Lock Fare, and Animated Taxis
- Custom Disruption Injection: The Control Panel features a drop-down menu of major NYC stations and an L-Score input. Injecting a custom disruption replaces the active disruption, clears old staging zones, generates new micro-staging zones, and reroutes the fleet dynamically.
- Surge-Lock Fare: Displays dynamic fare calculations (
$15 + $0.50 * L-score) inside the Disruption Hub card based on the current active L-Score. - Animated Taxis: Taxi markers smoothly glide along the map instead of teleporting. The frontend implements GSAP coordinate interpolations, while the backend updates mock coordinates to the assigned staging zone (with random jitter to prevent marker overlap) upon approved dispatch.
The dashboard uses Leaflet with CARTO Dark Matter tiles and OpenStreetMap/CARTO attribution for the interactive map. No Mapbox token is required. The map reflects CabVector's backend coordinates for disruptions, staging zones, and taxis; it does not make traffic or dispatch decisions. Its lower-right legend identifies the disruption marker, safe/vetoed staging zones, and proposed/dispatched/available taxi markers.
Phase 4 release checklist
- Run the full backend suite and the frontend production build.
- Demonstrate the safe fixture scenario: L-Score gate, traffic approval, taxi movement, alerts, and SSE terminal events.
- Demonstrate the congestion-veto/retry scenario without any taxi movement before approval.
- Capture
/api/healthevidence: MTA providers may beonline; NYC DOT may bedegradedonly when the UI and dispatch flow visibly retain fixture fallback. - Verify the interactive map displays the live state coordinates, taxi click popups, staging radius, visible map legend, and OpenStreetMap/CARTO attribution.
- Confirm
.envis ignored, no provider secret appears in API responses or the browser, and documentation makes no unsupported live-traffic claim.
Documentation and scope
- CABVECTOR_IMPLEMENTATION.md — MVP boundary, phase plan, and non-negotiable rules.
- HANDOFF.md — shared API contracts, completed work, and integration handoffs.
Provider credentials are not included. NYC DOT traffic is public and needs no key; MTA and the selected optional model provider remain server-side .env configuration. The deterministic approval workflow remains active unless a future display-only summary feature explicitly calls the optional model boundary.
Analysis
View
Metric
- 19
- 8
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- FastAPIIn code
- JavaScriptIn code
- Next.jsIn code
- PythonIn code
- ReactIn code
- Tailwind CSSIn code
- TypeScriptIn code
8 of 8 appear in the indexed code.
AI coding agents
No AI coding agent signals were found in this repository.
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
325 KB
Source files
77
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
rayhanf14/CabVector
91 files · 904 KB · @ 534b772
Structure
Interface
43 files · 47%Screens, components and styles rendered to the user.
Application logic
19 files · 21%Domain rules, services and shared utilities.
+1 more
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Python32%
- TypeScript26%
- Markdown22%
- CSS14%
- JavaScript6%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
frontend/package.json
npm · 14- @types/leaflet
- gsap
- leaflet
- next
- react
- react-dom
- react-leaflet
- +7 more
backend/requirements.txt
pypi · 9- fastapi
- gtfs-realtime-bindings
- httpx
- pandas
- pydantic
- pydantic-settings
- python-dotenv
- sse-starlette
- uvicorn
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.