Skip to main content

Prerequisites

Before you begin, ensure you have the following installed:

Node.js 18+

Download from nodejs.org

Flutter 3.0+

Install from flutter.dev

Git

Version control for cloning the repo

Android Studio / Xcode

For mobile app development (optional)
New to Flutter? You can skip the mobile app setup and just run the backend to explore the API.

Backend Setup

1

Clone the Repository

git clone https://github.com/your-org/mnd.git
cd mnd/MND-backend
2

Install Dependencies

npm install
This installs:
  • express - Web framework
  • cors - Cross-origin support for mobile apps
  • typescript - Type-safe development
  • axios - HTTP client for Google APIs
3

Configure Environment Variables

Create a .env file in the MND-backend directory:
.env
PORT=3000

# Optional: Google Distance Matrix API key
# Only needed for routes not in the graph (rare)
GOOGLE_DM_API_KEY=your_api_key_here

# Optional: Email service for magic link auth
EMAIL_SERVICE=gmail
EMAIL_USER=your-email@gmail.com
EMAIL_PASSWORD=your-app-password
The backend works without the Google API key—it only uses it as a fallback for uncached routes (thanks to aggressive 7-day caching!).
4

Start the Development Server

npm run dev
You should see:
Output
🚌 University Bus Routing API

Loading graph data...
 Loaded 19 nodes
 Loaded 7 routes
 Built adjacency list with 289 edges

 Server running on http://localhost:3000
 Network access: http://192.168.1.105:3000

📱 Access from mobile/other devices (same WiFi):
   Health check: http://192.168.1.105:3000/api/health
5

Verify the API is Running

Test the health endpoint:
curl http://localhost:3000/api/health
Expected Response:
{
  "status": "healthy",
  "timestamp": "2026-03-05T08:30:00.000Z",
  "graph": {
    "nodes": 19,
    "routes": 7
  },
  "distanceMatrix": {
    "available": true,
    "usage": {
      "monthly": "12/700",
      "daily": "2/25"
    },
    "cache": {
      "hits": 145,
      "misses": 8,
      "hitRate": "95%"
    }
  }
}

Make Your First API Request

Now that the backend is running, let’s plan a route from Tilagor to Campus at 8:00 AM:
curl "http://localhost:3000/api/routes?from=TILAGOR&to=CAMPUS&time=08:00"

Response Breakdown

The API returns 3 route options (real data from source code):
{
  "from": "TILAGOR",
  "to": "CAMPUS",
  "requestTime": "08:00",
  "options": [
    {
      "label": "Bus 1 Direct",
      "category": "fastest",
      "type": "direct",
      "transfers": 0,
      "totalTimeMin": 45,
      "totalCost": 0,
      "localTimeMin": 0,
      "localDistanceMeters": 0,
      "legs": [
        {
          "mode": "bus",
          "route_id": "bus1",
          "trip_id": "bus1_0825",
          "from": "TILAGOR",
          "to": "CAMPUS",
          "departure": "08:25",
          "arrival": "09:10",
          "durationMin": 45,
          "cost": 0
        }
      ]
    },
    {
      "label": "Bus 1 + Local",
      "category": "alternative",
      "type": "hybrid",
      "transfers": 1,
      "totalTimeMin": 35,
      "totalCost": 30,
      "localTimeMin": 10,
      "localDistanceMeters": 1500,
      "legs": [
        {
          "mode": "bus",
          "from": "TILAGOR",
          "to": "SUBIDBAZAR",
          "departure": "08:25",
          "arrival": "08:50",
          "durationMin": 25,
          "cost": 0
        },
        {
          "mode": "local",
          "from": "SUBIDBAZAR",
          "to": "CAMPUS",
          "durationMin": 10,
          "cost": 30
        }
      ]
    },
    {
      "label": "Local Only",
      "category": "fallback",
      "type": "local",
      "totalTimeMin": 40,
      "totalCost": 120,
      "legs": [
        {
          "mode": "local",
          "from": "TILAGOR",
          "to": "CAMPUS",
          "durationMin": 40,
          "cost": 120
        }
      ]
    }
  ]
}
Route Categories Explained:
  • fastest: Minimum total time
  • cheapest: Prioritizes free bus travel
  • alternative: Balanced time/cost tradeoffs
  • fallback: Local-only when no bus available

Flutter Mobile App Setup

1

Navigate to Flutter Project

cd ../mnd_flutter
2

Install Flutter Dependencies

flutter pub get
This installs packages from pubspec.yaml:
pubspec.yaml
dependencies:
  provider: ^6.1.1              # State management
  http: ^1.1.0                  # API requests
  google_maps_flutter: ^2.5.0   # Map visualization
  shared_preferences: ^2.2.2    # Local storage
  google_fonts: ^6.1.0          # Custom fonts
  intl: ^0.18.1                 # Date/time formatting
  flutter_dotenv: ^5.1.0        # Environment variables
3

Configure API Endpoint

Create a .env file in mnd_flutter/:
.env
# Your backend IP address (find it in backend startup logs)
API_BASE_URL=http://192.168.1.105:3000/api

# Google Maps API key (for route visualization)
GOOGLE_DM_API_KEY=your_google_maps_key
Android Emulator? Use http://10.0.2.2:3000/api instead of localhost.iOS Simulator? Use http://localhost:3000/api.
The API config is loaded in lib/config/api_config.dart:
lib/config/api_config.dart
import 'package:flutter_dotenv/flutter_dotenv.dart';

class ApiConfig {
  static const String baseUrl = 'http://192.168.0.114:3000/api';
  static const Duration timeout = Duration(seconds: 30);
  
  // Google Maps API Key - loaded from .env
  static String get googleMapsApiKey => dotenv.env['GOOGLE_DM_API_KEY'] ?? '';
}
4

Run the App

flutter run
Select your Android device/emulator when prompted.
First Launch:The app will:
  1. Load environment variables from .env
  2. Fetch 19 locations from /api/nodes
  3. Display the route planning screen
5

Test Route Planning in the App

  1. Select Origin: Choose “Tilagor” from the dropdown
  2. Select Destination: Choose “Campus”
  3. Set Time: Tap the time field, select 08:00
  4. Tap “Find Routes”
You should see 3 route cards appear (from the API response above)!
Tap the map icon on any route card to visualize it with Google Maps polylines.

Understanding the Code

Here’s how the Flutter app calls the backend API (from real source code):

Service Layer: Making API Requests

lib/services/route_service.dart
import '../models/node.dart';
import '../models/route_option.dart';
import 'api_service.dart';

class RouteService {
  final ApiService _api = ApiService();

  Future<List<Node>> getNodes() async {
    final data = await _api.get('/nodes');
    return (data['nodes'] as List)
        .map((node) => Node.fromJson(node))
        .toList();
  }

  Future<List<RouteOption>> planRoute({
    required String from,
    required String to,
    required String time,
  }) async {
    final data = await _api.get('/routes', params: {
      'from': from,
      'to': to,
      'time': time,
    });
    
    return (data['options'] as List)
        .map((option) => RouteOption.fromJson(option))
        .toList();
  }
}

UI Layer: Displaying Routes

lib/screens/home/home_screen.dart (excerpt)
Future<void> _searchRoutes() async {
  setState(() {
    _loading = true;
    _routes = [];
  });

  try {
    final routes = await _routeService.planRoute(
      from: _fromNode!,  // e.g., "TILAGOR"
      to: _toNode!,      // e.g., "CAMPUS"
      time: _time,       // e.g., "08:00"
    );
    setState(() {
      _routes = routes;
      _loading = false;
    });
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Failed to find routes: $e')),
    );
  }
}

Data Models

The API response maps to Flutter models:
class Node {
  final String id;
  final String name;
  final String type;

  Node({required this.id, required this.name, required this.type});

  factory Node.fromJson(Map<String, dynamic> json) {
    return Node(
      id: json['id'],
      name: json['name'],
      type: json['type'],
    );
  }
}

Troubleshooting

Error:
Error: listen EADDRINUSE: address already in use :::3000
Solution:
  1. Change the port in .env:
    PORT=3001
    
  2. Kill the process using port 3000:
    # macOS/Linux
    lsof -ti:3000 | xargs kill -9
    
    # Windows
    netstat -ano | findstr :3000
    taskkill /PID <PID> /F
    
Error:
Failed to load locations: SocketException: Connection refused
Solution:
  1. Check backend is running: Visit http://localhost:3000/api/health in browser
  2. Check IP address: Use the network IP shown in backend startup logs
  3. Android Emulator: Use http://10.0.2.2:3000/api
  4. Firewall: Allow port 3000 in Windows Firewall / macOS Security
  5. Same WiFi: Ensure phone and computer are on same network
Symptom:
{
  "from": "TILAGOR",
  "to": "CAMPUS",
  "options": []
}
Possible Causes:
  1. Invalid node IDs: Use /api/nodes to get valid IDs (e.g., TILAGOR, not Tilagor)
  2. Time format: Use 24-hour format HH:MM (e.g., 08:30, not 8:30 AM)
  3. Graph data not loaded: Check backend logs for “Loaded X nodes”
Error:
PlatformException: API key not valid
Solution:
  1. Get API key: Google Cloud Console
  2. Enable APIs:
    • Maps SDK for Android
    • Maps SDK for iOS
    • Directions API
  3. Add to .env:
    GOOGLE_DM_API_KEY=AIzaSy...
    
  4. Android: Also add to android/app/src/main/AndroidManifest.xml
Error:
Because mnd_flutter depends on provider ^6.1.1...
Solution:
  1. Update Flutter: flutter upgrade
  2. Clear cache: flutter pub cache clean
  3. Retry: flutter pub get

Next Steps

Explore API Endpoints

Learn about all available endpoints beyond /routes

Understand the Algorithm

Deep dive into the multi-strategy route planner

Customize the Graph

Add new locations, routes, or transport modes

Deploy to Production

Host the backend on Render, Heroku, or AWS

Stuck? Check the GitHub issues or join our Discord community.