Skip to content

DevSars24/tracking-device

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›°οΈ NEXUS TRACKER

Real-Time Multi-User Location Tracking System


Node.js Express.js Socket.IO EJS Leaflet.js License: ISC Live Demo


A production-grade, real-time device tracking system built on WebSockets, Event-Driven Architecture, and full-stack Node.js engineering. Track multiple users simultaneously on a live interactive map with millisecond-precision location updates.

Built by Saurabh Singh Rajput β€” Self-Taught Full-Stack Developer & Coder Β· IIIT Bhagalpur


πŸ“‘ Table of Contents

  1. 🌐 Live Demo
  2. 🎯 What This Project Does
  3. πŸ—οΈ System Architecture
  4. ⚑ Core Backend Concepts
  5. πŸ—‚οΈ Project Structure
  6. πŸ’» Tech Stack Deep Dive
  7. πŸ”Œ API & Socket Event Reference
  8. πŸ“ Complete Data Flow
  9. 🧠 Frontend Intelligence
  10. βš™οΈ Quick Start
  11. πŸš€ Deployment
  12. πŸ—ΊοΈ Roadmap
  13. 🀝 Contributing

🌐 Live Demo

⚠️ Cold Start Notice: Hosted on Render's free tier β€” the first request may take 5–15 seconds to wake the server. This is normal for free-tier cold starts.

πŸ“ Grant location permission when prompted to see your GPS pin on the live map.

Testing Multi-User Tracking:

  1. Open the link in two different browser tabs or devices
  2. Watch both pins appear simultaneously on the map
  3. Move around β€” pins update in real-time via WebSocket

🎯 What This Project Does

Nexus Tracker solves the classic real-time communication problem: how do you push live data from multiple clients to all other clients simultaneously β€” without any client needing to poll or ask?

Feature Description
🌍 Live GPS Tracking Captures latitude / longitude via browser Geolocation API
πŸ‘₯ Multi-User Sync Every connected user sees every other user's live position
πŸ“‘ Persistent WebSocket Single bi-directional connection per client β€” zero polling overhead
🧭 Smart Fallbacks GPS β†’ Retry β†’ IP Geolocation 3-tier fallback chain
πŸ“Œ Auto Cleanup Disconnected user markers removed from all active maps instantly
πŸ—ΊοΈ Interactive Map Leaflet.js + OpenStreetMap with dark-mode filter & smooth animations
πŸ“± Responsive Mobile-first design that works on any screen size

πŸ—οΈ System Architecture

graph TB
    subgraph ClientA["πŸ–₯️ Client A β€” Browser"]
        GPS_A["πŸ“ Geolocation API"]
        SOCKET_A["πŸ“‘ Socket.IO Client"]
        MAP_A["πŸ—ΊοΈ Leaflet.js Map"]
    end

    subgraph Server["βš™οΈ Node.js Server β€” Port 3000"]
        EXPRESS["πŸš€ Express.js\nHTTP Router"]
        EJS["πŸ“„ EJS Template\nEngine"]
        SOCKETIO["πŸ”Œ Socket.IO\nWebSocket Server"]
        BROADCAST["πŸ“’ io.emit()\nBroadcast Engine"]
    end

    subgraph ClientB["πŸ–₯️ Client B β€” Browser"]
        GPS_B["πŸ“ Geolocation API"]
        SOCKET_B["πŸ“‘ Socket.IO Client"]
        MAP_B["πŸ—ΊοΈ Leaflet.js Map"]
    end

    GPS_A -->|"send-location\n{lat, lng}"| SOCKET_A
    SOCKET_A -->|"WebSocket\nws://"| SOCKETIO
    GPS_B -->|"send-location\n{lat, lng}"| SOCKET_B
    SOCKET_B -->|"WebSocket\nws://"| SOCKETIO

    SOCKETIO --> BROADCAST
    BROADCAST -->|"receive-location\n{id, lat, lng}"| SOCKET_A
    BROADCAST -->|"receive-location\n{id, lat, lng}"| SOCKET_B

    SOCKET_A --> MAP_A
    SOCKET_B --> MAP_B

    EXPRESS -->|"GET /"| EJS
    EJS -->|"Rendered HTML"| ClientA
    EJS -->|"Rendered HTML"| ClientB

    style Server fill:#1e293b,color:#38bdf8,stroke:#38bdf8
    style ClientA fill:#0f172a,color:#94a3b8,stroke:#334155
    style ClientB fill:#0f172a,color:#94a3b8,stroke:#334155
    style BROADCAST fill:#7c3aed,color:#fff,stroke:#7c3aed
Loading

Architecture Pattern: Event-Driven Real-Time Pub/Sub The server acts as a message broker β€” receiving location events from any client and instantly broadcasting them to all connected clients. This is the same foundational pattern behind Google Maps Live Share, Uber driver tracking, and multiplayer games.


⚑ Core Backend Concepts

πŸ” WebSockets vs HTTP Polling

This project uses WebSockets β€” a critical architectural distinction from traditional HTTP:

Dimension HTTP (Traditional) WebSocket (This Project)
Connection Open β†’ Request β†’ Response β†’ Close Open once, stays open permanently
Direction Client β†’ Server only Bi-directional (full-duplex)
Overhead Full HTTP headers on every request Minimal framing after handshake
Latency High β€” new TCP handshake each time Very low β€” persistent TCP connection
Real-time Faked via setInterval polling Native push β€” instant delivery
Best For REST APIs, static pages Live tracking, chat, gaming

WebSocket Handshake Flow:

sequenceDiagram
    participant C as πŸ–₯️ Client Browser
    participant S as βš™οΈ Node.js Server

    C->>S: HTTP GET / (Accept: text/html)
    S-->>C: 200 OK β€” EJS rendered HTML

    Note over C,S: Script loads, socket.io client initializes

    C->>S: HTTP GET /socket.io/?... (Upgrade: websocket)
    S-->>C: 101 Switching Protocols

    Note over C,S: βœ… Persistent WebSocket tunnel established

    loop Every GPS update (~5–10s)
        C->>S: send-location {latitude, longitude}
        S-->>C: receive-location {id, lat, lng}
    end

    C->>S: disconnect (tab closed / network drop)
    S-->>C: user-disconnected (broadcast to all)
Loading

Socket.IO adds on top of raw WebSockets:

  • πŸ”„ Auto-reconnection on network drops
  • πŸ” Fallback to HTTP long-polling if WebSockets are firewall-blocked
  • 🏠 Room/namespace management for grouped broadcasts
  • πŸ”€ Multiplexing multiple logical channels over one connection

🎯 Event-Driven Architecture

The backend is built entirely on Node.js's event loop β€” single-threaded, non-blocking, handling thousands of concurrent sockets without spawning threads.

// βœ… EVENT-DRIVEN PATTERN β€” Non-blocking, scalable
io.on('connection', (socket) => {           // πŸ”Œ Event: new client joined
    socket.on('send-location', (data) => {  // πŸ“ Event: GPS update received
        io.emit('receive-location', {
            id: socket.id,
            ...data                         // Spread: merges id + {lat, lng}
        });
    });

    socket.on('disconnect', () => {         // ❌ Event: client left
        io.emit('user-disconnected', socket.id);
    });
});

Emit Method Comparison:

Method Reaches Use Case
io.emit(event, data) ALL connected sockets Broadcast GPS to everyone
socket.emit(event, data) Only that one client Send private acknowledgement
socket.broadcast.emit(...) Everyone except sender Notify others of your presence
io.to(room).emit(...) All in a room Group/fleet tracking (future)

πŸ“‘ Real-Time Data Broadcasting

flowchart LR
    A["πŸ–₯️ Client A\nGPS Update\nlat: 28.6, lng: 77.2"]
    S["βš™οΈ Server\nio.emit()"]
    R1["πŸ–₯️ Client A\nβœ… Own marker updated"]
    R2["πŸ–₯️ Client B\nπŸ†• A's marker appears"]
    R3["πŸ–₯️ Client C\nπŸ†• A's marker appears"]

    A -->|"send-location\n{lat, lng}"| S
    S -->|"receive-location\n{id:'aB3x', lat, lng}"| R1
    S -->|"receive-location\n{id:'aB3x', lat, lng}"| R2
    S -->|"receive-location\n{id:'aB3x', lat, lng}"| R3

    style S fill:#7c3aed,color:#fff
    style A fill:#0f172a,color:#38bdf8,stroke:#38bdf8
    style R1 fill:#064e3b,color:#6ee7b7,stroke:#059669
    style R2 fill:#1e293b,color:#94a3b8,stroke:#334155
    style R3 fill:#1e293b,color:#94a3b8,stroke:#334155
Loading

Why io.emit() and not socket.broadcast.emit()? Using io.emit() means Client A also receives its own location echo. This ensures A's own marker renders consistently across all sessions β€” a self-including broadcast.

The Spread Operator Pattern:

io.emit('receive-location', { id: socket.id, ...data });
//                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
//                 Merges: { id: "aBcDeFg1x", latitude: 28.6, longitude: 77.2 }
//                 The client uses `id` as the map marker dictionary key

πŸ”Œ Socket Lifecycle Management

stateDiagram-v2
    [*] --> Connecting : Browser opens page

    Connecting --> Connected : WebSocket handshake βœ…\nsocket.id assigned

    Connected --> Tracking : socket.on('send-location')\nGPS data received

    Tracking --> Tracking : io.emit('receive-location')\nBroadcast to ALL clients

    Connected --> Disconnected : Tab closed / network drop\nsocket.on('disconnect')

    Tracking --> Disconnected : Tab closed / network drop

    Disconnected --> Cleanup : io.emit('user-disconnected', socket.id)\nAll clients remove marker

    Cleanup --> [*] : markers[id] deleted\nmap.removeLayer() called
Loading

Key Design Decisions:

Decision Why
Use socket.id as device ID Auto-generated, unique per session, no DB required
Ephemeral IDs Reconnection creates new ID β€” keeps architecture stateless
markers[socket.id] as key O(1) lookup and deletion when disconnection event fires
Server emits disconnect event Clients have no way to know a peer left β€” server is the source of truth

πŸ—‚οΈ Project Structure

tracking-device/
β”‚
β”œβ”€β”€ πŸ“„ app.js                    ← Entry point: Express + Socket.IO server
β”‚
β”œβ”€β”€ πŸ“ views/
β”‚   └── πŸ“„ index.ejs             ← SSR HTML template (EJS view engine)
β”‚
β”œβ”€β”€ πŸ“ public/                   ← Static assets auto-served by Express
β”‚   β”œβ”€β”€ πŸ“ css/
β”‚   β”‚   └── 🎨 style.css         ← Glassmorphism dark UI, responsive layout
β”‚   └── πŸ“ js/
β”‚       └── ⚑ script.js         ← Client: GPS, Socket.IO, Leaflet logic
β”‚
β”œβ”€β”€ πŸ“„ package.json              ← Project manifest & npm dependencies
β”œβ”€β”€ πŸ“„ package-lock.json         ← Exact dependency version lockfile
└── πŸ“„ .gitignore                ← Excludes node_modules, .env

Layer Responsibilities:

graph LR
    A["πŸ“„ app.js\nSERVER LAYER"] -->|"renders"| B["πŸ“„ index.ejs\nVIEW LAYER"]
    A -->|"serves"| C["🎨 style.css\nSTYLE LAYER"]
    A -->|"serves"| D["⚑ script.js\nCLIENT LOGIC LAYER"]
    D -->|"emits events"| A

    style A fill:#7c3aed,color:#fff,stroke:#7c3aed
    style B fill:#1e40af,color:#bfdbfe,stroke:#3b82f6
    style C fill:#065f46,color:#a7f3d0,stroke:#059669
    style D fill:#92400e,color:#fde68a,stroke:#d97706
Loading

πŸ’» Tech Stack Deep Dive

graph TD
    subgraph Backend["βš™οΈ Backend β€” Node.js Runtime"]
        NJS["Node.js v18+\nV8 Engine Β· Event Loop"]
        EXP["Express.js v5\nHTTP Routing Β· Middleware"]
        SIO["Socket.IO v4.8\nWebSocket Server"]
        EJS2["EJS v3.1\nServer-Side Templating"]
    end

    subgraph Frontend["🌐 Frontend β€” Browser"]
        SIO_C["Socket.IO Client\nWebSocket Client"]
        LEAF["Leaflet.js v1.9.4\nMap Rendering"]
        GEO["Geolocation API\nGPS / Network"]
        CSS["Custom CSS\nGlassmorphism Β· Dark UI"]
    end

    subgraph Infra["πŸš€ Infrastructure"]
        RENDER["Render.com\nFree Tier PaaS"]
        OSM["OpenStreetMap\nTile CDN (free)"]
        IPAPI["ipapi.co\nIP Geolocation Fallback"]
    end

    NJS --> EXP
    NJS --> SIO
    EXP --> EJS2
    SIO <-->|"WebSocket"| SIO_C
    SIO_C --> LEAF
    GEO --> SIO_C
    LEAF --> OSM
    EXP --> RENDER
    GEO -.->|"fallback"| IPAPI

    style Backend fill:#1e293b,color:#38bdf8,stroke:#38bdf8
    style Frontend fill:#0f172a,color:#94a3b8,stroke:#334155
    style Infra fill:#1a1a2e,color:#a78bfa,stroke:#7c3aed
Loading

βš™οΈ Node.js β€” The Runtime

Node.js executes JavaScript outside the browser via V8 (Chrome's JS engine). Its non-blocking I/O and event loop allow a single process to handle thousands of concurrent WebSocket connections without spawning threads β€” each client is just an event listener in memory.

πŸš€ Express.js v5 β€” The HTTP Framework

const app = express();

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// Middleware: serve /public as static root
app.use(express.static(path.join(__dirname, 'public')));

// Route: render EJS view on GET /
app.get('/', (req, res) => res.render('index'));
Responsibility How
Routing app.get('/') maps the root route to EJS render
Static Serving express.static('public') auto-serves CSS, JS files
Middleware Pipeline Runs express.static before route handlers
View Engine app.set('view engine', 'ejs') registers EJS

πŸ”Œ Socket.IO v4.8 β€” The WebSocket Engine

const http  = require('http');
const { Server } = require('socket.io');

// ⚠️ KEY: Socket.IO needs the raw http.Server, NOT the Express app
const server = http.createServer(app);  // Wraps Express in Node's http module
const io     = new Server(server);      // Attaches Socket.IO to same port

Why http.createServer(app) and not just app.listen()? Socket.IO must intercept the raw HTTP Upgrade header at the TCP level β€” before Express processes the request. Sharing one http.Server instance lets both Express (HTTP) and Socket.IO (WebSocket) listen on port 3000 simultaneously.

πŸ“„ EJS β€” Server-Side Templating

On GET /, Express compiles views/index.ejs into plain HTML and sends it:

EJS Syntax Purpose
<%= variable %> Output escaped HTML value
<% code %> Execute JS logic inline (loops, conditions)
<%- include('partial') %> Compose sub-templates

πŸ—ΊοΈ Leaflet.js v1.9.4 β€” Interactive Mapping

const map = L.map('map').setView([0, 0], 2);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19   // Street-level precision
}).addTo(map);

Uses OpenStreetMap tiles β€” completely free, no API key required.

πŸ“ Geolocation API β€” GPS Data Source

// watchPosition fires continuously on device movement
navigator.geolocation.watchPosition(
    ({ coords }) => {
        socket.emit('send-location', {
            latitude:  coords.latitude,
            longitude: coords.longitude
        });
    },
    errorHandler,
    { enableHighAccuracy: true, timeout: 20000, maximumAge: 10000 }
);

watchPosition vs getCurrentPosition: getCurrentPosition fires once. watchPosition fires every time the device moves β€” essential for continuous live tracking.


πŸ”Œ API & Socket Event Reference

HTTP Endpoints

Method Route Content-Type Description
GET / text/html EJS-rendered tracking UI
GET /css/style.css text/css Dark theme stylesheet
GET /js/script.js application/javascript GPS + map client script

Socket.IO Events

Client β†’ Server

Event Payload Type Payload Fields When Emitted
send-location Object { latitude: Number, longitude: Number } Every GPS position update

Server β†’ All Clients

Event Payload Type Payload Fields When Emitted
receive-location Object { id: String, latitude: Number, longitude: Number } Any client sends location
user-disconnected String socketId A client disconnects

Full Interaction Sequence:

sequenceDiagram
    participant A as πŸ–₯️ Client A
    participant S as βš™οΈ Server
    participant B as πŸ–₯️ Client B

    Note over A,B: Both clients connected via WebSocket

    A->>S: send-location {lat: 28.6, lng: 77.2}
    S-->>A: receive-location {id:"aB3x", lat:28.6, lng:77.2}
    S-->>B: receive-location {id:"aB3x", lat:28.6, lng:77.2}

    Note over A: Moves own 🟒 marker
    Note over B: Creates/moves πŸ”΅ marker for A

    B->>S: send-location {lat: 19.0, lng: 72.8}
    S-->>A: receive-location {id:"xY9z", lat:19.0, lng:72.8}
    S-->>B: receive-location {id:"xY9z", lat:19.0, lng:72.8}

    Note over A: Creates/moves πŸ”΅ marker for B
    Note over B: Moves own 🟒 marker

    Note over A: User closes browser tab
    A->>S: disconnect (automatic)
    S-->>B: user-disconnected "aB3x"
    Note over B: Removes A's πŸ”΅ marker from map
Loading

πŸ“ Complete Data Flow

flowchart TD
    START(["🌐 User opens browser"]) --> HTTP["HTTP GET /\nExpress router"]
    HTTP --> EJS_RENDER["EJS compiles index.ejs\n→ HTML response"]
    EJS_RENDER --> LOAD["Page loads in browser\nscript.js executes"]

    LOAD --> WS_CONNECT["socket.io client\nWebSocket handshake\n→ socket.id assigned"]
    LOAD --> MAP_INIT["Leaflet.js\nmap initialized\nsetView 0,0 zoom:2"]
    LOAD --> GEO_WATCH["navigator.geolocation\n.watchPosition() starts"]

    GEO_WATCH --> GPS_SUCCESS{"GPS signal\nobtained?"}
    GPS_SUCCESS -->|"βœ… Yes"| EMIT["socket.emit\n'send-location'\n{lat, lng}"]
    GPS_SUCCESS -->|"❌ Timeout"| RETRY["Retry with\nlow accuracy"]
    RETRY --> GPS_SUCCESS
    RETRY -->|"3 retries failed"| IP_FALLBACK["fetch ipapi.co/json\nIP Geolocation"]
    IP_FALLBACK --> EMIT

    EMIT --> SERVER_RECV["Server receives\nsocket.on('send-location')"]
    SERVER_RECV --> BROADCAST["io.emit('receive-location')\n{id, lat, lng}\n→ ALL clients"]

    BROADCAST --> SELF["Client A\nUpdate own marker 🟒"]
    BROADCAST --> OTHERS["Client B, C...\nCreate/move marker πŸ”΅"]

    WS_CONNECT --> DISCONNECT{"Client\ndisconnects?"}
    DISCONNECT -->|"Yes"| SERVER_DISC["Server: socket.on('disconnect')"]
    SERVER_DISC --> DISC_BROADCAST["io.emit('user-disconnected'\nsocket.id)"]
    DISC_BROADCAST --> CLEANUP["All clients:\nmap.removeLayer(marker)\ndelete markers[id]"]
    CLEANUP --> DONE(["βœ… Map cleaned up"])

    style START fill:#7c3aed,color:#fff,stroke:#7c3aed
    style BROADCAST fill:#7c3aed,color:#fff,stroke:#7c3aed
    style EMIT fill:#1e40af,color:#bfdbfe,stroke:#3b82f6
    style GPS_SUCCESS fill:#1e293b,color:#94a3b8,stroke:#334155
    style IP_FALLBACK fill:#92400e,color:#fde68a,stroke:#d97706
    style CLEANUP fill:#064e3b,color:#a7f3d0,stroke:#059669
    style DONE fill:#064e3b,color:#a7f3d0,stroke:#059669
Loading

🧠 Frontend Intelligence

πŸ“ GPS Fallback Chain

flowchart TD
    START(["πŸš€ Page loads"]) --> T1["Tier 1: High-Accuracy GPS\nenableHighAccuracy: true\ntimeout: 30s"]

    T1 --> T1_OK{"Success?"}
    T1_OK -->|"βœ… GPS Lock"| USE["Use coordinates\nShow 🟒 green badge\nZoom map to level 16"]
    T1_OK -->|"❌ Timeout"| T2["Tier 2: Low-Accuracy GPS\nenableHighAccuracy: false\nFaster lock, less precise"]

    T2 --> T2_OK{"Success?"}
    T2_OK -->|"βœ… GPS Lock"| USE
    T2_OK -->|"❌ Retry 1/3"| T2
    T2_OK -->|"❌ All 3 retries failed"| T3["Tier 3: IP Geolocation\nfetch ipapi.co/json\nCity-level accuracy ~1–10km"]

    T3 --> T3_OK{"Success?"}
    T3_OK -->|"βœ… IP data received"| IP_USE["Use IP coordinates\nShow 🟑 yellow badge\nZoom map to level 12"]
    T3_OK -->|"❌ API error"| ERR["Show ❌ error alert\nPrompt to enable GPS"]

    style START fill:#7c3aed,color:#fff
    style USE fill:#064e3b,color:#a7f3d0,stroke:#059669
    style IP_USE fill:#78350f,color:#fde68a,stroke:#d97706
    style ERR fill:#7f1d1d,color:#fca5a5,stroke:#ef4444
    style T1 fill:#1e293b,color:#38bdf8,stroke:#0284c7
    style T2 fill:#1e293b,color:#94a3b8,stroke:#334155
    style T3 fill:#1e293b,color:#a78bfa,stroke:#7c3aed
Loading

πŸ—ΊοΈ Smart Map Centering Logic

// Only recenter if device moved MORE than 100 meters
// Prevents map jitter from GPS accuracy oscillation (typically 5–50m)
const distance = map.distance(
    [currentCenter.lat, currentCenter.lng],
    [latitude, longitude]
);

if (distance > 100) {
    map.setView([latitude, longitude], 16, {
        animate: true,
        duration: 0.5,
        easeLinearity: 0.25
    });
}

🎨 Visual Marker Differentiation

// ownId is stored on socket 'connect' event
socket.on('connect', () => { ownId = socket.id; });

// Marker color is determined purely client-side β€” zero server changes needed
icon: L.icon({
    iconUrl: id === ownId
        ? 'marker-icon-2x-green.png'  // 🟒 Your own device
        : 'marker-icon-2x-blue.png'   // πŸ”΅ Other users
})

πŸ”„ Live GPS Status Badge States

Badge Text Badge Color Triggered By
Initializing GPS... πŸ”΅ Sky Blue Page just loaded
GPS Active (Xm) 🟒 Green GPS lock β€” accuracy in meters shown
GPS Timeout (Retry N/3) 🟑 Amber Retrying GPS acquisition
IP Location (Less Precise) 🟑 Amber IP geolocation fallback active
Location Access Denied πŸ”΄ Red User denied browser permission
GPS Unavailable πŸ”΄ Red Hardware or signal issue

βš™οΈ Quick Start

Prerequisites

  • Node.js v18+ β†’ Download
  • Modern browser: Chrome, Edge, Firefox, Safari
  • Location permissions enabled in browser settings

Installation

# Clone the repository
git clone https://github.com/DevSars24/tracking-device.git

# Navigate into project
cd tracking-device

# Install all dependencies
npm install

Run Locally

node app.js
# β†’ Server running on http://localhost:3000

Visit http://localhost:3000 Β· Grant location access Β· Open in a second tab to test multi-user tracking.

Installed Dependencies

{
  "express":   "^5.1.0",    ← HTTP framework, routing, static serving
  "socket.io": "^4.8.1",   ← WebSocket server with long-poll fallback
  "ejs":       "^3.1.10"    ← Server-side HTML template engine
}

πŸš€ Deployment

Currently deployed on Render free tier.

Deploy to Render in 5 Steps

  1. Push code to GitHub
  2. Go to render.com β†’ New Web Service
  3. Connect your repository
  4. Set build config:
    Runtime:       Node
    Build Command: npm install
    Start Command: node app.js
    
  5. Click Deploy β€” Render assigns a public *.onrender.com URL

⚑ Production Port Fix

// ❌ Current (local only)
server.listen(3000, () => console.log('Server running on http://localhost:3000'));

// βœ… Production-ready (dynamic port for Render/Heroku/Railway)
server.listen(process.env.PORT || 3000, () => {
    console.log(`Server running on port ${process.env.PORT || 3000}`);
});
Environment Port Notes
Local Dev 3000 Hardcoded, works immediately
Render / Heroku process.env.PORT Assigned by platform at runtime

πŸ—ΊοΈ Roadmap

gantt
    title Nexus Tracker β€” Feature Roadmap
    dateFormat YYYY-MM
    section Shipped
        Real-time GPS tracking        :done, 2025-01, 2025-02
        Multi-user WebSocket sync     :done, 2025-02, 2025-03
        Dark mode map UI              :done, 2025-03, 2025-04
        GPS + IP fallback chain       :done, 2025-04, 2025-05
    section Planned
        JWT auth & named users        :active, 2025-06, 2025-08
        Private room tracking         :2025-08, 2025-10
        MongoDB location history      :2025-10, 2025-12
        React Native mobile app       :2026-01, 2026-06
        Redis pub/sub scaling         :2026-06, 2026-09
Loading
Version Feature Status
v1.0 Real-time multi-user tracking, GPS + IP fallback, dark UI βœ… Live
v2.0 JWT authentication, named users, persistent sessions πŸ”„ Planned
v2.1 Room-based private group tracking, Mapbox directions πŸ”„ Planned
v2.2 MongoDB location history, heatmaps, route replay πŸ”„ Planned
v3.0 React Native mobile app, push notifications πŸ”„ Planned
v3.1 Redis pub/sub for horizontal server scaling πŸ”„ Planned

🀝 Contributing

# 1. Fork on GitHub & clone your fork
git clone https://github.com/YOUR_USERNAME/tracking-device.git

# 2. Create a feature branch
git checkout -b feature/your-feature-name

# 3. Commit with convention
git commit -m "feat: what you added"

# 4. Push & open a Pull Request
git push origin feature/your-feature-name

Commit message convention:

Prefix Purpose
feat: New feature
fix: Bug fix
docs: Documentation update
style: CSS / UI change
refactor: Code restructure (no behavior change)
perf: Performance improvement

πŸ“„ License

Licensed under the ISC License β€” see LICENSE for full text.


Built with ❀️ by Saurabh Singh Rajput

Self-Taught Full-Stack Developer & Coder Β· IIIT Bhagalpur

GitHub Live Demo


⭐ If this helped you understand real-time systems β€” drop a star! ⭐

About

backend project

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages