Skip to content

aditya-gore/Ride-Service

Repository files navigation

Ride Service (Backend)

Backend-only ride-hailing API built with Node.js, Express, JavaScript, MongoDB, microservices, and AWS SQS. Uses OSRM for distance/duration and Strategy pattern for driver matching and fare calculation.

Features

  • Microservices: Auth, Users, Drivers, Rides, Notifications (+ API Gateway)
  • Single MongoDB with one database per service
  • JWT access tokens + refresh tokens; roles: rider, driver, admin
  • Vehicle types with different fare (base + per-km + per-minute)
  • Driver matching strategies: nearest by distance, nearest by ETA (OSRM)
  • Fare calculation strategy: vehicle-type-based formula
  • OSRM (public API) for route distance and duration
  • AWS SQS for notifications (eventual consistency)
  • Email notifications via AWS SES (production) or SMTP/Mailpit (local); rider and driver get different, role-specific emails for ride_matched, ride_accepted, ride_completed
  • Transactions only for fare + payment in Rides service
  • Aggregated Swagger at API Gateway

Prerequisites

  • Node.js >= 18
  • MongoDB (run locally or via Docker)
  • AWS SQS optional: use real AWS or LocalStack for local notifications

Quick Start

1. Start MongoDB (Docker or local)

Option A – Docker Compose (recommended):

npm run docker:up

This starts MongoDB on port 27017. To also start Mailpit (local inbox for email testing, Web UI at http://localhost:8025):

docker compose --profile mail up -d

Set EMAIL_PROVIDER=smtp, SMTP_HOST=localhost, SMTP_PORT=1025 in .env. Rider and driver emails will appear in Mailpit.

To also start LocalStack for SQS:

docker compose --profile sqs up -d

Then create the SQS queue and get the URL:

npm run localstack:init-sqs

Copy the printed URL into .env as SQS_NOTIFICATIONS_QUEUE_URL, and add AWS_ENDPOINT_URL=http://localhost:4566 when using LocalStack.

Option B – Local MongoDB: ensure mongod is running and MONGODB_URI=mongodb://localhost:27017 in .env.

2. Install dependencies

npm install
cd shared && npm install && cd ..
cd services/auth-service && npm install && cd ../..
cd services/users-service && npm install && cd ../..
cd services/drivers-service && npm install && cd ../..
cd services/rides-service && npm install && cd ../..
cd services/notifications-service && npm install && cd ../..
cd services/api-gateway && npm install && cd ../..

Or from repo root (if you use a single install script):

npm run install:all

3. Environment

Copy .env.example to .env and set at least:

  • MONGODB_URI (default mongodb://localhost:27017; use same when using Docker MongoDB)
  • JWT_ACCESS_SECRET, JWT_REFRESH_SECRET (use strong values in production)
  • SQS_NOTIFICATIONS_QUEUE_URL (optional; leave empty to skip SQS, or set after npm run localstack:init-sqs)
  • AWS_ENDPOINT_URL=http://localhost:4566 when using LocalStack for SQS
  • INTERNAL_API_SECRET (shared secret for service-to-service calls; Notifications uses it to fetch user email from Users)
  • Email: EMAIL_PROVIDER=smtp (local with Mailpit) or ses (AWS SES); for SMTP set SMTP_HOST=localhost, SMTP_PORT=1025 when using Mailpit

4. Start services

Start MongoDB, then run each service in a separate terminal (or use npm run dev:all if you have concurrently):

# Terminal 1 – Auth
npm run dev --prefix services/auth-service

# Terminal 2 – Users
npm run dev --prefix services/users-service

# Terminal 3 – Drivers
npm run dev --prefix services/drivers-service

# Terminal 4 – Rides
npm run dev --prefix services/rides-service

# Terminal 5 – Notifications (SQS consumer)
npm run dev --prefix services/notifications-service

# Terminal 6 – API Gateway
npm run dev --prefix services/api-gateway

Default ports: Gateway 3000, Auth 3001, Users 3002, Drivers 3003, Rides 3004, Notifications 3005.

Monitoring (local – optional): To run Prometheus, Grafana, and Jaeger:

docker compose --profile monitoring up -d
  • Prometheus: http://localhost:9090 (metrics; scrapes each service at host.docker.internal:3000–3005)
  • Grafana: http://localhost:3100 (login admin / admin). Prometheus and Jaeger are pre-provisioned; open Dashboards → Ride Service → Services overview for request rate and p95 latency by service.
  • Jaeger UI: http://localhost:16686 (traces). Select a service (e.g. gateway) and Find Traces to see request flow across services.

Start the app with npm run dev:all so services expose /metrics and send traces; then you can query in Prometheus, build dashboards in Grafana, and view traces in Jaeger. Optional: set OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 in .env if Jaeger is not on the default.

5. API docs and seed data

Seed admin user (once):

npm run seed:admin

Creates an admin in users_db and auth credentials in auth_db. Default login: admin@ride-service.local / Admin123!. Override with env: ADMIN_EMAIL, ADMIN_PASSWORD, ADMIN_NAME.

Seed vehicle types (recommended):

npm run seed:vehicle-types

Creates Economy, Premium, and XL vehicle types in rides_db. Run once (with MongoDB up).

Create more vehicle types (admin):

  • Use the access token of an admin user.
  • POST /vehicle-types with name, baseFare, perKm, perMinute (e.g. Economy: 2, 1.5, 0.3).
  • Riders need a vehicleTypeId when requesting a ride.

Project structure

RideService-Node/
├── docs/
│   ├── ARCHITECTURE.md      # High-level architecture, Notifications structure
│   └── DESIGN_DECISIONS.md  # Design choices, trade-offs, service-to-service auth (interview prep)
├── shared/                  # Shared lib (errors, logger, JWT, OSRM, config)
├── services/
│   ├── auth-service/
│   ├── users-service/       # + internal route for Notifications (email lookup)
│   ├── drivers-service/
│   ├── rides-service/       # Strategies (matching, fare), OSRM, transactions
│   ├── notifications-service/  # SQS consumer; Strategy (SMTP/SES); handler → service → providers/templates
│   └── api-gateway/         # Proxy + aggregated Swagger
├── monitoring/           # Prometheus config, Grafana provisioning and dashboards
├── .env.example
└── README.md

Design highlights

  • Strategy pattern: Driver matching and fare calculation (Rides) and email delivery (Notifications: SmtpEmailProvider / SesEmailProvider) use the same pattern; see services/rides-service/src/strategies/ and services/notifications-service/src/providers/.
  • Layered Notifications: Thin handler → notificationService (orchestrate) → userClient, templates, emailSender (delegates to EmailProvider). Keeps structure consistent with other services.
  • Service-to-service auth: Internal APIs (e.g. Notifications → Users) use a shared secret (INTERNAL_API_SECRET) for v1; production alternatives (OAuth2 client credentials, mTLS) are documented in docs/DESIGN_DECISIONS.md.
  • Transactions: Used only when completing a ride (update ride + insert payment in one transaction).
  • OSRM: Public API for distance/duration; production would use dedicated routing or self-hosted OSRM.
  • SQS: Notifications are sent as messages; the Notifications service consumes and sends rider/driver–specific emails (idempotent handling recommended).

Full rationale and trade-offs: docs/DESIGN_DECISIONS.md.

NPM scripts (root)

Script Description
npm run install:all Install root, shared, and all services
npm run dev:all Start all services (needs concurrently)
npm run seed:admin Create admin user (optional: ADMIN_EMAIL, ADMIN_PASSWORD, ADMIN_NAME)
npm run seed:vehicle-types Seed Economy, Premium, XL vehicle types
npm run docker:up Start MongoDB (and optionally --profile sqs or --profile monitoring)
npm run docker:down Stop Docker Compose services
npm run localstack:init-sqs Create SQS queue in LocalStack and print URL
npm test Run all unit and API tests (Jest)
npm run test:watch Run tests in watch mode
npm run test:coverage Run tests with coverage report; enforces thresholds

Testing

Tests use Jest (unit) and Supertest (API), with mongodb-memory-server for in-memory MongoDB in API tests. One command from repo root runs everything.

Commands

  • npm test – Run all tests (unit + API).
  • npm run test:watch – Run tests in watch mode.
  • npm run test:coverage – Run tests and generate coverage; fails if global thresholds are not met (statements/lines 70%, branches 60%, functions 65%).

Layout

  • Unit tests: Next to source or in __tests__:
    • shared: shared/__tests__/*.test.js – errors, JWT, OSRM, metrics, auth middleware.
    • Rides strategies: services/rides-service/src/strategies/*.test.js – fare, nearest-by-distance, nearest-by-ETA.
    • Services: services/*/src/services/*.test.js – auth, users, drivers, rides, notifications (Mongoose and HTTP mocked).
  • API tests: services/*/src/__tests__/*.api.test.js – Supertest against each service’s Express app; Auth, Users, Drivers, Rides use in-memory MongoDB (started once via Jest global setup).

Behaviour

  • Unit tests mock external deps (Mongoose models, axios, bcrypt, SQS, OSRM) so no real DB or network is needed.
  • API tests require the service’s app from src/app.js, connect to mongodb-memory-server in beforeAll, and assert HTTP status and body. Auth API test mocks the Users service HTTP call; Rides API test mocks OSRM and Drivers service.
  • Coverage is collected from shared/**/*.js and services/*/src/**/*.js; index.js, db.js, app.js, and tracing.js are excluded.

Coverage thresholds (global)

Metric Threshold
Statements 70%
Branches 60%
Functions 65%
Lines 70%

Coverage report

Running npm run test:coverage generates:

  • Console: A text summary and a per-file table (% Stmts, Branch, Funcs, Lines).
  • HTML report: Written to coverage/index.html. Open this file in a browser to see an interactive report with line-by-line coverage (green = covered, red = uncovered). Example:
    open coverage/index.html
  • lcov: The coverage/lcov-report/index.html directory contains the same data in lcov-report form; coverage/ is listed in .gitignore and should not be committed.

Environment variables (summary)

Variable Description Default
MONGODB_URI MongoDB connection string mongodb://localhost:27017
JWT_ACCESS_SECRET Secret for access JWT (set in .env)
JWT_REFRESH_SECRET Secret for refresh JWT (set in .env)
JWT_ACCESS_EXPIRY Access token TTL 15m
JWT_REFRESH_EXPIRY Refresh token TTL 7d
OSRM_BASE_URL OSRM server https://router.project-osrm.org
SQS_NOTIFICATIONS_QUEUE_URL SQS queue for notifications (optional)
AWS_ENDPOINT_URL Use LocalStack for SQS (optional, e.g. http://localhost:4566)
AWS_REGION AWS region for SQS/SES us-east-1
INTERNAL_API_SECRET Secret for internal APIs (e.g. Notifications → Users) (set in .env)
EMAIL_PROVIDER smtp (Mailpit/local) or ses (AWS SES) smtp
EMAIL_FROM From address for emails (e.g. Ride Service <noreply@…>)
SMTP_HOST / SMTP_PORT For local Mailpit localhost / 1025
DRIVER_MATCHING_STRATEGY distance or eta distance
OTEL_EXPORTER_OTLP_ENDPOINT Jaeger OTLP HTTP endpoint (when using monitoring profile) http://localhost:4318
PORT Per-service port (set in each service) 3001–3005, 3000 gateway

License

MIT

About

Backend-only ride-hailing API built with Node.js, Express, JavaScript, MongoDB, microservices, and AWS SQS. Uses OSRM for distance/duration and Strategy pattern for driver matching and fare calculation.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors