# vigneshpy/railvazhi architecture

> Architecture diagram of the GitHub repository vigneshpy/railvazhi, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-13). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/vigneshpy/railvazhi
- Repository: https://github.com/vigneshpy/railvazhi

## Overview

#### Purpose and workspace

Rail Vazhi predicts railway-level-crossing closure windows along a user’s road route, then recommends whether to leave or wait. It is a pnpm monorepo with a browser client, HTTP API, and shared TypeScript contracts:
- `apps/web`
- `apps/api`
- `packages/shared/src/index.ts`

#### Entry points and request surface

The API process is initialized in `apps/api/src/index.ts` and exposes focused route handlers:
- Prediction orchestration: `apps/api/src/routes/predict.ts`
- Train-related data endpoints: `apps/api/src/routes/trains.ts`
- Gate endpoints: `apps/api/src/routes/gates.ts`

The Next.js App Router client begins at `apps/web/src/app/layout.tsx` and `apps/web/src/app/page.tsx`. The browser calls the API URL configured through `NEXT_PUBLIC_API_URL`.

#### Prediction pipeline

`POST /api/predict` is the central control flow. It accepts origin/destination coordinates, obtains a road route, identifies crossings near that route, and produces closure predictions plus a travel recommendation.

Core stages are implemented in:
- Road routing via OSRM: `apps/api/src/services/routing.ts`
- Spatial crossing lookup: `apps/api/src/services/gates.ts`
- Live/scheduled closure calculation: `apps/api/src/services/prediction.ts`
- Aggregated response endpoint: `apps/api/src/routes/predict.ts`

The important boundary is that the API owns all external-data, spatial, and prediction logic; the web app renders returned route/gate/recommendation data rather than computing closures itself.

#### Geospatial persistence

PostgreSQL 16 with PostGIS is the authoritative local dataset for stations and level crossings. Schema, migrations, and seeded corridor data reside in:
- `apps/api/src/db/schema.sql`
- `apps/api/src/db/migrate.ts`
- `apps/api/src/db/seed.sql`

The database client is centralized in `apps/api/src/db/client.ts`. Route-to-gate matching uses PostGIS spatial proximity (`ST_DWithin`), isolating geometry querying from HTTP handlers and routing providers.

#### Train-data and fallback boundary

Train timing is sourced from NTES scraping and falls back to schedule-based information when live data is unavailable. This provider behavior is isolated in:
- `apps/api/src/services/ntes.ts`
- `apps/api/src/services/prediction.ts`

Predictions convey confidence such as Live versus Scheduled. This containment allows NTES/provider changes without altering the frontend or spatial gate query layer.

#### Web interaction and notification model

The mobile-oriented frontend gathers locations, renders the route and predicted gates, and shows the recommendation:
- Route input/location selection: `apps/web/src/components/RouteForm.tsx`, `apps/web/src/components/LocationPickerModal.tsx`
- Map rendering: `apps/web/src/components/RouteMap.tsx`
- Gate and recommendation presentation: `apps/web/src/components/GateCard.tsx`, `apps/web/src/components/RecommendationBanner.tsx`

Saved routes are browser-local rather than server accounts, through `apps/web/src/hooks/useFavourites.ts`. Route monitoring and notifications are client-side via `apps/web/src/hooks/useRouteWatcher.ts`, `apps/web/src/components/NotificationToggle.tsx`, and the service worker at `apps/web/public/sw.js`.

#### Runtime and deployment dependencies

The API runs Node.js 20, Express, and strict TypeScript; the web runtime is Next.js 14 with Leaflet/OpenStreetMap mapping. External services are OSRM’s public routing server, Nominatim for search/reverse geocoding, and NTES for train data. Expected deployment separates PostGIS (Supabase), API hosting (Railway; `apps/api/railway.toml`), and web hosting (Vercel), with API CORS restricted by `WEB_ORIGIN`.

Main entry points: [`apps/web/src/app/page.tsx`](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/app/page.tsx) (Next.js app), [`apps/api/src/index.ts`](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/index.ts) (Express API), [`apps/api/src/routes/predict.ts`](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/routes/predict.ts) (Prediction endpoint), [`apps/api/src/services/prediction.ts`](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/prediction.ts) (Closure prediction)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["Browser client"]
  node_web_app["Next.js app<br/>Next.js 14<br/>[page.tsx]"]
  node_route_form["Route input<br/>React component<br/>[RouteForm.tsx]"]
  node_location_picker["Location picker<br/>React component"]
  node_route_map["Route map<br/>Leaflet component<br/>[RouteMap.tsx]"]
  node_prediction_ui["Gate &amp; recommendation UI<br/>React components<br/>[GateCard.tsx]"]
  node_route_watcher["Route watcher<br/>client hook<br/>[useRouteWatcher.ts]"]
  node_service_worker["Notification worker<br/>service worker<br/>[sw.js]"]
end

subgraph group_api["API service"]
  node_api_server["Express API<br/>Node.js 20<br/>[index.ts]"]
  node_predict_route["Prediction endpoint<br/>POST /api/predict<br/>[predict.ts]"]
  node_routing_service["Road routing<br/>routing service<br/>[routing.ts]"]
  node_gate_service["Spatial gate lookup<br/>PostGIS service<br/>[gates.ts]"]
  node_prediction_service["Closure prediction<br/>prediction service<br/>[prediction.ts]"]
  node_train_routes["Train &amp; gate endpoints<br/>Express routes<br/>[trains.ts]"]
  node_ntes_provider["NTES provider<br/>scraper service<br/>[ntes.ts]"]
end

subgraph group_data["Data providers"]
  node_postgis[("Stations &amp; crossings<br/>PostgreSQL 16 + PostGIS<br/>[schema.sql]")]
  node_osrm{{"OSRM<br/>external routing API"}}
  node_nominatim{{"Nominatim<br/>geocoding API"}}
end

node_shared_contracts["Shared contracts<br/>TypeScript package<br/>[index.ts]"]

node_web_app -->|"collects route"| node_route_form
node_route_form -->|"selects locations"| node_location_picker
node_location_picker -->|"searches/geocodes"| node_nominatim
node_web_app -->|"renders route"| node_route_map
node_web_app -->|"renders predictions"| node_prediction_ui
node_web_app -->|"monitors route"| node_route_watcher
node_route_watcher -->|"notifies"| node_service_worker
node_web_app -->|"NEXT_PUBLIC_API_URL"| node_api_server
node_api_server -->|"POST /api/predict"| node_predict_route
node_api_server -->|"train/gate requests"| node_train_routes
node_predict_route -->|"road route"| node_routing_service
node_routing_service -->|"routing request"| node_osrm
node_predict_route -->|"route geometry"| node_gate_service
node_gate_service -->|"spatial proximity query"| node_postgis
node_predict_route -->|"crossing predictions"| node_prediction_service
node_prediction_service -->|"live timing"| node_ntes_provider
node_prediction_service -.->|"scheduled fallback data"| node_postgis
node_web_app -->|"uses contracts"| node_shared_contracts
node_api_server -->|"uses contracts"| node_shared_contracts

click node_web_app "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/app/page.tsx"
click node_route_form "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/RouteForm.tsx"
click node_location_picker "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/LocationPickerModal.tsx"
click node_route_map "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/RouteMap.tsx"
click node_prediction_ui "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/GateCard.tsx"
click node_route_watcher "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/hooks/useRouteWatcher.ts"
click node_service_worker "https://github.com/vigneshpy/railvazhi/blob/main/apps/web/public/sw.js"
click node_api_server "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/index.ts"
click node_predict_route "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/routes/predict.ts"
click node_routing_service "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/routing.ts"
click node_gate_service "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/gates.ts"
click node_prediction_service "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/prediction.ts"
click node_train_routes "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/routes/trains.ts"
click node_ntes_provider "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/ntes.ts"
click node_postgis "https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/db/schema.sql"
click node_shared_contracts "https://github.com/vigneshpy/railvazhi/blob/main/packages/shared/src/index.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_web_app,node_route_form,node_location_picker,node_route_map,node_prediction_ui,node_route_watcher,node_service_worker toneBlue
class node_api_server,node_predict_route,node_routing_service,node_gate_service,node_prediction_service,node_train_routes,node_ntes_provider toneAmber
class node_postgis,node_osrm,node_nominatim toneMint
class node_shared_contracts toneNeutral
```

## Components

### Browser client

- [Next.js app](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/app/page.tsx): Next.js 14 · Collects routes and renders API results. · `apps/web/src/app/page.tsx`
- [Route input](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/RouteForm.tsx): React component · `apps/web/src/components/RouteForm.tsx`
- [Location picker](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/LocationPickerModal.tsx): React component · `apps/web/src/components/LocationPickerModal.tsx`
- [Route map](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/RouteMap.tsx): Leaflet component · `apps/web/src/components/RouteMap.tsx`
- [Gate & recommendation UI](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/components/GateCard.tsx): React components · `apps/web/src/components/GateCard.tsx`
- [Route watcher](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/src/hooks/useRouteWatcher.ts): client hook · Monitors saved routes and triggers notifications. · `apps/web/src/hooks/useRouteWatcher.ts`
- [Notification worker](https://github.com/vigneshpy/railvazhi/blob/main/apps/web/public/sw.js): service worker · `apps/web/public/sw.js`

### API service

- [Express API](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/index.ts): Node.js 20 · CORS-restricted HTTP boundary for the web client. · `apps/api/src/index.ts`
- [Prediction endpoint](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/routes/predict.ts): POST /api/predict · Orchestrates routing, gate matching, closure prediction, and recommendation. · `apps/api/src/routes/predict.ts`
- [Road routing](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/routing.ts): routing service · `apps/api/src/services/routing.ts`
- [Spatial gate lookup](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/gates.ts): PostGIS service · Finds crossings near the road route with ST_DWithin. · `apps/api/src/services/gates.ts`
- [Closure prediction](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/prediction.ts): prediction service · Calculates live or scheduled closure windows and confidence. · `apps/api/src/services/prediction.ts`
- [Train & gate endpoints](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/routes/trains.ts): Express routes · `apps/api/src/routes/trains.ts`
- [NTES provider](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/services/ntes.ts): scraper service · Supplies live train timing; schedules are the fallback. · `apps/api/src/services/ntes.ts`

### Data providers

- [Stations & crossings](https://github.com/vigneshpy/railvazhi/blob/main/apps/api/src/db/schema.sql): PostgreSQL 16 + PostGIS · Authoritative local geospatial dataset. · `apps/api/src/db/schema.sql`
- **OSRM**: external routing API
- **Nominatim**: geocoding API

### Other components

- [Shared contracts](https://github.com/vigneshpy/railvazhi/blob/main/packages/shared/src/index.ts): TypeScript package · Shared API data contracts. · `packages/shared/src/index.ts`

## Connections

- Next.js app → Route input: collects route
- Route input → Location picker: selects locations
- Location picker → Nominatim: searches/geocodes
- Next.js app → Route map: renders route
- Next.js app → Gate & recommendation UI: renders predictions
- Next.js app → Route watcher: monitors route
- Route watcher → Notification worker: notifies
- Next.js app → Express API: NEXT_PUBLIC_API_URL
- Express API → Prediction endpoint: POST /api/predict
- Express API → Train & gate endpoints: train/gate requests
- Prediction endpoint → Road routing: road route
- Road routing → OSRM: routing request
- Prediction endpoint → Spatial gate lookup: route geometry
- Spatial gate lookup → Stations & crossings: spatial proximity query
- Prediction endpoint → Closure prediction: crossing predictions
- Closure prediction → NTES provider: live timing
- Closure prediction → Stations & crossings: scheduled fallback data
- Next.js app → Shared contracts: uses contracts
- Express API → Shared contracts: uses contracts
