Live bus tracking, ETAs, and routes — built with Next.js (App Router) and TailwindCSS, featuring Leaflet maps, Server-Sent Events for live updates, and a minimal driver simulator.
- Overview
- Features (MVP)
- Tech Stack
- Project Structure
- Getting Started
- Run Locally
- Environment Variables
- Available Scripts
- Key Application Flows
- Demo Guide
- API Endpoints
- API Reference
- Frontend Routes
- Data & Persistence
- Real-Time Location Streaming
- Testing & Quality
- Deployment Checklist
- Roadmap
- Contributing
- License
- Notes
CityMover is a smart public transport OS designed for smaller cities, university towns, and government-run fleets that struggle with legacy systems. The platform closes the visibility gap between transport authorities, drivers, and commuters by combining live GPS tracking, digital ticketing, and proactive communications in a single product.
The project grew out of pilots with the Government of Punjab’s Higher Education Department, where bus fleets serving students and staff needed modern tooling without expensive proprietary hardware. CityMover therefore emphasizes low-bandwidth resilience, mobile-first UX, and integrations that work with existing infrastructure.
From the commuter perspective, the app surfaces real-time route information, predictive ETAs, and QR ticketing so that daily travel becomes predictable and cashless. Drivers get simple simulators or mobile dashboards to publish live updates. Transport officers view operational analytics, track fleet health, and reconcile digital payments.
A modular architecture lets CityMover extend to additional modes (e.g., trains) or integrate with municipal systems such as student ID portals, subsidy programs, and emergency alerts. The current codebase focuses on a fully functional bus operations MVP while laying the groundwork for multi-modal expansion.
- Live bus tracking on a map
- Search buses and view route info
- Select a stop to view ETAs (distance/speed based)
- Driver simulator to send mock GPS updates
- Authority dashboard with live locations and route stats
- PWA basics: manifest, theme-color, installable
- Next.js (App Router), React, TailwindCSS v4
- Leaflet + React-Leaflet for maps
- SSE for real-time location streaming
- In-memory mock data layer (buses, routes, stops, locations)
- MongoDB + Mongoose for persistent storage
- Razorpay for digital payments and settlement workflows
- Nodemailer for transactional email (OTP, password reset)
- Cloudinary for ticket and profile media storage
src/lib/data.js— Mock data and in-memory location storesrc/lib/eta.js— ETA computation utilsrc/lib/events.js— Simple pub/sub for streamingsrc/app/api/— REST + SSE endpoints (legacy App Router prototype)src/pages/api/— Primary Pages Router API endpoints for auth, payments, bookings, locationssrc/components/MapView.jsx— SSR-safe Leaflet map with SSE integrationsrc/pages/index.js— Marketing landing pagesrc/pages/BusTracker.js— Live tracking, trip planner, and booking entrypointsrc/pages/BusBook.js— Ticket checkout view with Razorpay integrationsrc/pages/api/auth/*— Authentication endpoints (signup, login, reset flows)src/pages/otp.js,src/pages/resetpassword.js— OTP verification and password reset UXsrc/models/— Mongoose schemas for users, tickets, and supporting datasrc/lib/— Shared utilities (dbConnect, nodemailer, imageUpload, validation schemas)middleware.ts— Session-aware middleware to guard protected routespublic/manifest.json,public/icons/*— PWA assets
- Node.js ≥ 18.18 (Next.js 15 requirement)
- npm ≥ 9 (or compatible package manager)
- MongoDB instance (Atlas/local)
- Razorpay test keys for payment demos
- SMTP provider (e.g., Brevo, SES, Mailgun) for email flows
- Optional: Cloudinary account for media uploads
npm installnpm run dev
# open http://localhost:3000npm run build
npm run start- Install deps (already done in scaffold):
npm install
- Start dev server:
npm run dev
- Open http://localhost:3000
If you recently edited the SSE stream (/api/stream/locations), fully restart the dev server to clear stale module state (Ctrl+C then npm run dev).
Create .env.local with:
| Variable | Purpose |
|---|---|
MONGODB_URI |
MongoDB connection string used by src/lib/dbConnect.js |
PROJECT_URL |
Optional legacy fallback for MongoURI |
MAIL_HOST / MAIL_PORT |
SMTP host configuration for Nodemailer |
MAIL_AUTH / MAIL_PASS |
SMTP credentials for sendOTPEmail() and reset emails |
RAZORPAY_KEY_ID / RAZORPAY_KEY_SECRET |
Razorpay credentials for orders and signature verification |
CLOUDINARY_CLOUD_NAME / CLOUDINARY_API_KEY / CLOUDINARY_API_SECRET |
Cloudinary uploads for QR codes and profile images |
JWT_SECRET (optional) |
Token signing secret for future auth enhancements |
NEXT_PUBLIC_BASE_URL (optional) |
Absolute URL for emails, webhooks, and client fetches |
Tip: Provide a
.env.exampleto share expected keys with collaborators.
npm run dev: Start the development server with hot reload.npm run build: Create an optimized production build.npm run start: Serve the production build.npm run lint: Run ESLint with the Next.js config.
- User signs up via
src/pages/authpage.js. POST /api/auth/signupstores the user and dispatches OTP throughsendOTPEmail()insrc/lib/nodemailer.js.- OTP verification occurs on
src/pages/otp.js. - Login (
POST /api/auth/login) sets a secure, HTTP-onlycustomUsercookie. - Forgot password flow issues short-lived reset tokens via
POST /api/auth/resetpasstoken.
BusTrackerdirects the commuter toBusBookwith pre-filled route, fare, and distance.- Razorpay order is created using
POST /api/payments/orderwith amount in paise. - Signature verification occurs in
POST /api/payments/verify, ensuring payment authenticity. POST /api/bookings/confirmpersists ticket details and associates generated QR code with the user.- Tickets render in
src/pages/yourticket.js, enabling inspection and re-download.
- Drivers (or demo scripts) hit
src/app/driver/page.jsto emit location updates viaPOST /api/location/update. src/lib/events.jsbroadcasts through an in-memory pub/sub channel./api/stream/locationsexposes SSE for clients.src/components/MapView.jsxconsumes the stream, throttles updates, and animates markers.
/dashboard(App Router prototype) summarizes active buses, routes, and aggregated stats.- Extend with role-based controls once JWT refresh tokens are introduced.
- Landing Page (
/): explains product value and showcases features tailored to government stakeholders. - Bus Tracker (
/BusTracker): live map, trip planner, ETAs, and booking hand-off. - Driver Simulator (
/driver): choose a demo bus (e.g.,b1,b3) and emit GPS updates every 3 seconds. - Dashboard (
/dashboard): observe total buses, active fleet counts, and live data table. - Ticket Wallet (
/yourticket): verify QR codes and ticket metadata after completing a payment flow.
GET /api/buses→{ buses, routes, stops }GET /api/location/:busId→ Latest location for a specific busPOST /api/location/update→ Push new location from driver app/simulatorGET /api/eta/:stopId→ ETAs for a stopGET /api/locations→ Snapshot of all current locationsGET /api/stream/locations→ SSE stream (location + snapshot events)
Most endpoints return { success, message, data }. Always inspect the HTTP status code for errors.
POST /api/auth/signup- Body:
{ fullName, email, password } - Result: Creates user, returns pending status, and emails OTP.
- Body:
POST /api/auth/login- Body:
{ email, password } - Result: Validates credentials and issues session cookie.
- Body:
POST /api/auth/logout- Result: Clears session cookie.
POST /api/auth/resetpasstoken- Body:
{ email } - Result: Sends password reset email.
- Body:
POST /api/auth/resetpassword- Body:
{ token, password } - Result: Updates password after token validation.
- Body:
POST /api/payments/order- Body:
{ amountPaise, currency? } - Result: Returns Razorpay order payload + publishable key.
- Body:
POST /api/payments/verify- Body:
{ razorpay_payment_id, razorpay_order_id, razorpay_signature } - Result: Confirms payment authenticity.
- Body:
POST /api/bookings/confirm- Body:
{ ticketData } - Result: Persists ticket record.
- Body:
GET /api/buses- Returns master data for buses, routes, and stops.
GET /api/location/:busId- Latest coordinates for a single bus.
POST /api/location/update- Payload:
{ busId, lat, lng, speed, heading }. - Effect: Updates in-memory store and notifies subscribers.
- Payload:
GET /api/eta/:stopId- Computes ETAs using heuristics in
src/lib/eta.js.
- Computes ETAs using heuristics in
GET /api/locations- Snapshot of all active bus coordinates.
GET /api/stream/locations- Server-Sent Events channel for real-time updates.
/(src/pages/index.js): marketing and stakeholder narrative./BusTracker(src/pages/BusTracker.js): commuter interface for tracking and booking./BusBook(src/pages/BusBook.js): fare breakdown and payment flow./yourticket(src/pages/yourticket.js): ticket wallet with QR retrieval./trains(src/pages/trains.js): future module teaser for multimodal transport./authpage,/otp,/resetpassword: authentication flows./dashboard(src/app/dashboard/page.js): authority-facing dashboard (App Router)./driver(src/app/driver/page.js): driver simulator emitting location data.
- MongoDB models stored in
src/models/(users, tickets, routes, passes, etc.). src/lib/dbConnect.jsmaintains a singleton connection usingmongoose.connect().- Passwords hashed with
bcryptjs; OTPs and reset tokens include expiry fields. - Tickets store fare, distance, payment references, and QR image references.
- Consider offloading high-frequency location writes to Redis streams when scaling.
- Drivers (or IoT devices) post to
/api/location/updatewith latest telemetry. src/lib/events.jspublishes updates to subscribers./api/stream/locationsregisters SSE connections and serves both initial snapshots and incremental updates.MapView.jsxbuffers updates, usesrequestAnimationFrame, and animates icons with heading-awaredivIconmarkers.- Fallback polling via
/api/locationsensures resilience if SSE disconnects.
npm run lintkeeps the codebase aligned with Next.js ESLint presets.- Add component tests using React Testing Library for critical flows (auth, booking).
- Consider Cypress/Playwright end-to-end tests for multi-step journeys (sign-in → booking → ticket verification).
- Mock Razorpay, Nodemailer, and MongoDB in tests to avoid external dependencies.
- Continuous Integration suggestion: run lint + unit tests on every PR.
- Provision MongoDB Atlas and whitelist hosting IPs.
- Populate environment variables on hosting provider (Vercel, Netlify, Render, etc.).
- Configure Razorpay webhooks for payment settlement confirmation.
- Set SMTP credentials with a verified domain for higher deliverability.
- Point
NEXT_PUBLIC_BASE_URLto the production domain. - Monitor SSE connection counts; move to Redis pub/sub or Socket.io when scaling.
- Enable HTTPS and HSTS for secure cookie transport.
- Migrate remaining Pages Router flows into App Router (or vice versa) for consistency.
- Switch from in-memory SSE store to Redis or Kafka for multi-instance deployments.
- Integrate Firebase Cloud Messaging for push notifications.
- Implement role-based access control with JWT refresh tokens and middleware guards.
- Expand
/trainsmodule via GTFS data ingestion. - Add mobile apps (React Native/Expo) leveraging the same APIs.
- Introduce analytics for route performance and commuter retention.
- Fork the repo and create a feature branch.
- Install dependencies and set up
.env.local. - Follow existing ESLint + Prettier rules; run
npm run lintbefore committing. - Include screenshots for UI updates in PR descriptions.
- Request reviews from maintainers; address feedback promptly.
Proprietary software for CityMover pilot programs. Reach out to maintainers for licensing discussions.
- This project uses an in-memory store for simplicity (ideal for hackathon/demo). Replace with a database (e.g., Postgres + Redis) for production.
- For push notifications, integrate Firebase Cloud Messaging.