> ## Documentation Index
> Fetch the complete documentation index at: https://dhanurgo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Toll Sync Architecture

> How toll transactions are scraped, imported, and matched to trips

# Toll Sync Architecture

HostMetrics supports automatic toll transaction syncing from three US toll providers.

## Supported Providers

| Provider    | Region                    | Columns                                                                                     |
| ----------- | ------------------------- | ------------------------------------------------------------------------------------------- |
| **NTTA**    | Texas (Dallas/Fort Worth) | Transaction Date, Transaction Time, Plaza/Gantry Name, Roadway, Amount, Tag Number, Vehicle |
| **EZPass**  | Northeast US              | Date, Time, Plaza, Agency, Amount, Tag ID, Plate                                            |
| **SunPass** | Florida                   | Date, Time, Plaza, Road, Amount, Transponder, Plate Number                                  |

## System Architecture

```mermaid theme={null}
graph TB
    subgraph Manual["Manual Import"]
        CSV["Toll CSV File"]
        Upload["Upload UI"]
    end

    subgraph Auto["Automatic Sync"]
        Cron["EventBridge Cron<br/>(every 6 hours)"]
        Dispatcher["Lambda: Dispatcher"]
        Worker["Lambda: Worker"]
    end

    subgraph Portals["Toll Agency Portals"]
        NTTA["NTTA.org"]
        EZPass["EZPass Portal"]
        SunPass["SunPass Portal"]
    end

    subgraph App["HostMetrics"]
        API["POST /api/tolls/sync"]
        Parser["toll-transactions.ts"]
        DB["toll_transactions table"]
        Matcher["Toll-Trip Matcher"]
        Trips["trips table"]
    end

    CSV --> Upload --> Parser
    Cron --> Dispatcher --> Worker
    Worker --> NTTA & EZPass & SunPass
    Worker --> DB
    API --> Worker
    Parser --> DB
    DB --> Matcher
    Trips --> Matcher
```

## Manual CSV Import Flow

```mermaid theme={null}
sequenceDiagram
    participant User
    participant UI as ImportTollsDialog
    participant Parser as toll-transactions.ts
    participant DB as Supabase

    User->>UI: Upload CSV + select provider
    UI->>Parser: importFromCSV(file, provider)
    Parser->>Parser: Detect provider field mapping
    Parser->>Parser: Parse rows (local date components!)

    Note over Parser: CRITICAL: Use local date parsing<br/>NOT toISOString() (avoids UTC date shift)

    Parser->>DB: Check for duplicates (provider + date + amount + plaza)
    Parser->>DB: Insert new toll_transactions
    Parser->>DB: Create toll_imports audit record
    DB-->>UI: Import stats (total, new, duplicates)
```

## Date Handling (Critical)

Toll dates are stored as plain `date` + `text time` fields — NOT as UTC timestamps.

**Why?** Toll agencies report transactions in their operating timezone (e.g., NTTA uses CST). Since the host is typically in the same timezone as the agency, the dates are already correct for trip matching.

**The Rule:** Never use `toISOString()` when parsing toll dates. It converts to UTC and can shift the date by ±1 day.

```typescript theme={null}
// CORRECT - preserves local date
const parsed = new Date(dateStr);
const y = parsed.getFullYear();
const m = String(parsed.getMonth() + 1).padStart(2, "0");
const d = String(parsed.getDate()).padStart(2, "0");
txDate = `${y}-${m}-${d}`;

// WRONG - shifts to UTC, may change the date
txDate = new Date(dateStr).toISOString().split("T")[0]; // DON'T DO THIS
```

## Trip-to-Toll Matching

Tolls are matched to trips by comparing dates:

1. Trip `trip_end` date (converted from UTC to user's business timezone using `formatDateTime()`)
2. Toll `transaction_date` (stored as-is in agency local time)
3. Both are compared as `YYYY-MM-DD` strings

This works because both dates are effectively in the same local timezone (the host's market).

## Lambda Worker Architecture

```
lambda/
├── toll-sync-dispatcher/
│   └── handler.ts         # Triggered by cron, dispatches per-account jobs
├── toll-sync-worker/
│   ├── handler.ts          # Main worker entry point
│   ├── matcher.ts          # Trip-to-toll matching logic
│   └── scrapers/
│       ├── base.ts         # Scraper interface
│       ├── ntta.ts         # NTTA website scraper
│       └── index.ts        # Scraper registry
└── serverless.yml          # Serverless framework deployment config
```

The dispatcher queries `toll_accounts` for active accounts and invokes a worker Lambda for each one. Workers scrape the toll portal, parse transactions, and insert them directly into Supabase.
