This file provides structured context for AI coding assistants (GitHub Copilot, Cursor, Claude, GPT). It describes the repository's purpose, architecture, conventions, and constraints.
MapMyTrain is a real-time Indian Railways spatial tracking platform. It renders live train positions on a hardware-accelerated WebGL map canvas using binary WebSocket streaming, LERP interpolation, and PostGIS spatial queries.
Stack: Next.js 16 + MapLibre GL JS (frontend) | FastAPI + asyncpg (backend) | PostgreSQL 16 + PostGIS 3.4 | Redis 7.2
Frontend (Next.js 16) → WebSocket (binary) → Backend (FastAPI) → NTES Scraper
↓ ↓ ↓
MapLibre WebGL Redis Cache PostgreSQL + PostGIS
(60 FPS canvas) (token bucket) (spatial indexes)
| Path | Purpose |
|---|---|
frontend/app/ |
Next.js App Router pages and layouts |
frontend/components/map/ |
MapCanvas, TrackLayer, TrainMarker, TerrainLayer |
frontend/components/ui/ |
SearchBar, TrainDrawer, TrainAnalytics, StatusBar |
frontend/hooks/ |
useWebSocket (binary parser), useMapInteractions |
frontend/providers/ |
WebSocketProvider (context for train positions) |
frontend/lib/ |
types.ts (Train, Station, TrainPosition), constants.ts |
backend/app/main.py |
FastAPI app with lifespan (db, redis, cache, ingestion, cleanup) |
backend/app/config.py |
Pydantic v2 settings (DATABASE_URL, REDIS_URL, MOCK_MODE) |
backend/app/database.py |
asyncpg connection pool manager |
backend/app/routers/ |
REST endpoints (trains, stations) + WebSocket /stream |
backend/app/services/ |
CacheService, Broadcaster, interpolation, rate_limiter |
backend/app/ingestion/ |
NTES scraper (62 UAs), parser (regex + BeautifulSoup fallback), worker |
backend/migrations/ |
SQL schema files (001-006) |
backend/tests/ |
pytest test suite (17 tests) |
- No
anytypes — all spatial payloads map to explicit interfaces - Use
useReffor map viewport state, notuseState(prevents WebGL re-init) - Train positions use
Traininterface (notTrainInfo)
- asyncpg for database — no ORM, raw SQL with parameterized queries
- Pydantic v2 for settings and schemas
- Binary protocol: 16-byte frames
[TrainID:4][Lng:4][Lat:4][Bearing:2][Delay:2]
- 5-service stack: db (PostGIS), redis, tileserver, backend, frontend
- Log rotation: json-file driver, 10m max-size, 3 files
- Health checks on db and redis services
- Ingestion:
worker.pyscrapes NTES API every 120s with 62 User-Agent rotation - Caching: Raw telemetry in Redis (120s active TTL, 30min inactive)
- Broadcasting: Redis Pub/Sub → WebSocket binary frames
- Rendering: MapLibre GL JS decodes binary → directional SVG train markers
- Create route in
backend/app/routers/ - Add Pydantic model in
backend/app/schemas/ - Register in
backend/app/main.pyviaapp.include_router()
- Create in
frontend/components/map/orfrontend/components/ui/ - Use
useMap()fromMapContextfor map access - Import types from
frontend/lib/types.ts
# Backend
cd backend && python -m pytest tests/ -v
# Frontend lint
cd frontend && npm run lint| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
REDIS_URL |
Redis connection string |
DEVELOPMENT_MOCK_MODE |
Enable mock data (default: true) |
INGESTION_INTERVAL_SECONDS |
Scraper cycle interval (default: 120) |
NEXT_PUBLIC_USE_MOCK_TELEMETRY |
Use mock train data on frontend |
NEXT_PUBLIC_BACKEND_WS_URL |
WebSocket endpoint URL |
NEXT_PUBLIC_TILE_SERVER_URL |
Vector tile server URL |
- Monorepo only — do not split into separate repos
- ODbL compliance required — live telemetry separate from OSM track data
- 60 FPS target — avoid unnecessary re-renders, use refs for map state
- Binary WebSocket — no JSON for train positions (16-byte frames only)