Skip to content

Ayush-Vish/RuralSync-Backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

17 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🚜 RuralSync API

A robust, scalable backend API for the RuralSync rural services marketplace platform.

Node.js Express MongoDB TypeScript


πŸ“‹ Table of Contents


🎯 Overview

RuralSync API is a modular monolith backend that powers a marketplace connecting rural service providers (farmers, equipment rentals, repair services) with customers. The API supports three distinct user roles:

  • Clients - End users who search for and book services
  • Service Providers - Businesses that offer services and manage agents
  • Agents - Field workers assigned to fulfill bookings

Key Features

  • πŸ” Role-Based Authentication with JWT & HTTP-only Cookies
  • πŸ” AI-Powered Search using Vector Embeddings (Hugging Face)
  • πŸ“ Geospatial Queries for location-based service discovery
  • πŸ“Š Real-time Availability checking for bookings
  • ⭐ Review & Rating System for service quality
  • πŸ“ Audit Logging for tracking system changes
  • πŸ“– Swagger Documentation for API exploration

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              API Gateway                                 β”‚
β”‚                         (Express.js + CORS)                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚    Auth     β”‚  β”‚   Client    β”‚  β”‚  Provider   β”‚  β”‚    Agent    β”‚    β”‚
β”‚  β”‚   Module    β”‚  β”‚   Module    β”‚  β”‚   Module    β”‚  β”‚   Module    β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚         β”‚                β”‚                β”‚                β”‚            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚                     Shared Services Layer                       β”‚    β”‚
β”‚  β”‚  (Notification Strategies, AI Helpers, Validation, Utilities)   β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                  β”‚                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚                      Data Access Layer                          β”‚    β”‚
β”‚  β”‚              (Mongoose Models & Repositories)                   β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                  β”‚                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚         MongoDB             β”‚
                    β”‚   (Atlas with Vector Search) β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🎨 Design Principles

1. Modular Monolith Architecture

The codebase is organized into feature modules (auth, client, provider, agent) that are loosely coupled but deployed as a single unit. This provides:

  • βœ… Clear domain boundaries
  • βœ… Easier refactoring to microservices later
  • βœ… Simplified deployment and debugging
  • βœ… Shared infrastructure (DB, cache) without network overhead
modules/
β”œβ”€β”€ auth/          # Authentication & User Management
β”œβ”€β”€ client/        # Customer-facing features
β”œβ”€β”€ provider/      # Service Provider dashboard features
β”œβ”€β”€ agent/         # Agent mobile app features
└── shared/        # Cross-cutting concerns

2. Dependency Injection (Manual DI)

Controllers receive their dependencies (services) via constructor injection, making the code:

  • βœ… Testable - Easy to mock dependencies
  • βœ… Flexible - Swap implementations without changing consumers
  • βœ… Explicit - Dependencies are clearly visible
// modules/provider/index.ts - Composition Root
const profileService = new ProviderProfileService(Organization, ServiceProvider);
const profileController = new ProviderProfileController(profileService);

export { profileController };

3. Strategy Pattern for Notifications

Notifications use the Strategy Pattern, allowing different delivery mechanisms (Email, SMS, Push) to be plugged in without modifying business logic:

// Interface
interface INotificationStrategy {
  send(payload: INotificationPayload): Promise<boolean>;
}

// Concrete Strategy
class EmailNotificationStrategy implements INotificationStrategy {
  async send({ to, subject, message }) {
    // Send email logic
  }
}

// Usage in Service
const bookingService = new ProviderBookingService({
  notificationStrategies: { email: new EmailNotificationStrategy() }
});

4. Repository Pattern (Implicit)

Services interact with Mongoose Models through a consistent interface, abstracting database operations:

class ProviderInventoryService {
  constructor(
    private serviceModel: Model<IService>,
    private orgModel: Model<IOrganization>
  ) {}
  
  async addService(userId: string, data: any) {
    // Business logic + model operations
  }
}

5. Middleware Chain for Security

Authentication and authorization are handled through composable middleware:

// Route definition with middleware chain
router.post('/add-service',
  verifyJWT('SERVICE_PROVIDER'),      // 1. Verify token & role
  isAuthorized(['SERVICE_PROVIDER']), // 2. Check permissions
  upload.fields([...]),                // 3. Handle file uploads
  inventoryController.create           // 4. Execute business logic
);

6. Single Responsibility Principle (SRP)

Each class has one reason to change:

Layer Responsibility
Controllers HTTP request/response handling
Services Business logic & orchestration
Models Data structure & validation
Middleware Cross-cutting concerns (auth, logging)
Utils Reusable helper functions

7. Environment-Based Configuration

All configuration is externalized via environment variables with sensible defaults:

const getAllowedOrigins = (): string[] => {
  const envOrigins = process.env.CORS_ORIGINS;
  if (envOrigins) {
    return envOrigins.split(',').map(origin => origin.trim());
  }
  return ["http://localhost:3000"]; // Default
};

8. Error Handling with Custom ApiError

Consistent error responses using a custom error class:

class ApiError extends Error {
  constructor(message: string, public status: number) {
    super(message);
  }
}

// Usage
throw new ApiError('Unauthorized: No token provided', 401);

// Global handler catches and formats
app.use((err, req, res, next) => {
  res.status(err.status || 500).json({
    success: false,
    message: err.message,
    stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
  });
});

9. AI-Enhanced Search with Vector Embeddings

Services are indexed with AI-generated vector embeddings for semantic search:

// Auto-generate embeddings on save
serviceSchema.pre('save', async function(next) {
  if (this.isModified('description')) {
    const text = `${this.name} ${this.description} ${this.category}`;
    this.embeddings = await generateEmbedding(text);
  }
  next();
});

// Vector search in aggregation pipeline
pipeline.push({
  $vectorSearch: {
    index: "vector_index",
    path: "embeddings",
    queryVector: await generateEmbedding(searchQuery),
    numCandidates: 100,
    limit: 15
  }
});

πŸ“ Project Structure

api/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app.ts                 # Express app configuration
β”‚   β”œβ”€β”€ server.ts              # Server entry point
β”‚   β”‚
β”‚   β”œβ”€β”€ config/
β”‚   β”‚   β”œβ”€β”€ db.ts              # MongoDB connection
β”‚   β”‚   β”œβ”€β”€ redis.ts           # Redis configuration (optional)
β”‚   β”‚   └── swagger.ts         # OpenAPI/Swagger setup
β”‚   β”‚
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   β”œβ”€β”€ auth.middleware.ts # JWT verification & RBAC
β”‚   β”‚   β”œβ”€β”€ error.middleware.ts# Global error handler
β”‚   β”‚   └── upload.middleware.ts # Multer file upload
β”‚   β”‚
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ agent.model.ts
β”‚   β”‚   β”œβ”€β”€ booking.model.ts
β”‚   β”‚   β”œβ”€β”€ client.model.ts
β”‚   β”‚   β”œβ”€β”€ organization.model.ts
β”‚   β”‚   β”œβ”€β”€ review.model.ts
β”‚   β”‚   β”œβ”€β”€ service.model.ts
β”‚   β”‚   └── serviceProvider.model.ts
β”‚   β”‚
β”‚   β”œβ”€β”€ modules/
β”‚   β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.routes.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.controller.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ auth.service.ts
β”‚   β”‚   β”‚   └── index.ts       # Composition root
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ client/
β”‚   β”‚   β”‚   β”œβ”€β”€ client.routes.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”‚   └── index.ts
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ provider/
β”‚   β”‚   β”‚   β”œβ”€β”€ provider.routes.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”‚   └── index.ts
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ agent/
β”‚   β”‚   β”‚   └── ...
β”‚   β”‚   β”‚
β”‚   β”‚   └── shared/
β”‚   β”‚       β”œβ”€β”€ interfaces/
β”‚   β”‚       β”‚   └── notification.interface.ts
β”‚   β”‚       └── providers/
β”‚   β”‚           └── email.provider.ts
β”‚   β”‚
β”‚   └── utils/
β”‚       β”œβ”€β”€ helpers.ts         # ApiError, JWT utils, Multer
β”‚       β”œβ”€β”€ ai.helper.ts       # Hugging Face embeddings
β”‚       └── s3.ts              # AWS S3 uploads (optional)
β”‚
β”œβ”€β”€ .env.example
β”œβ”€β”€ package.json
β”œβ”€β”€ tsconfig.json
└── README.md

πŸš€ Getting Started

Prerequisites

  • Node.js >= 18.x
  • MongoDB >= 7.x (or MongoDB Atlas)
  • npm or yarn

Installation

# Clone the repository
git clone https://github.com/Ayush-Vish/RS-Monolith.git
cd RS-Monolith/api

# Install dependencies
npm install

# Copy environment variables
cp .env.example .env

# Edit .env with your values
nano .env

# Start development server
npm run dev

Available Scripts

Command Description
npm run dev Start development server with hot-reload
npm run build Compile TypeScript to JavaScript
npm start Run production build

πŸ“‘ API Endpoints

Authentication (/auth)

Method Endpoint Description Auth
POST /auth/register Register new user Public
POST /auth/login Login user Public
POST /auth/agent-register Register agent (by provider) Provider
GET /auth/logout Logout user Any
GET /auth/user-detail/:role Get user profile Role-specific

Client (/client)

Method Endpoint Description Auth
GET /client/search Search services (geo + text) Public
GET /client/search/categories Get all categories Public
GET /client/search/advanced Advanced search with filters Public
GET /client/services List all services Public
GET /client/services/:id Get service details Public
GET /client/profile Get client profile Client
PUT /client/profile Update profile Client
POST /client/bookings Create booking Client
GET /client/bookings Get my bookings Client
DELETE /client/bookings/:id Cancel booking Client
POST /client/reviews Create review Client
GET /client/reviews/my Get my reviews Client

Provider (/provider)

Method Endpoint Description Auth
GET /provider/org-detail Get organization details Provider
POST /provider/register-org Register organization Provider
GET /provider/services Get my services Provider
POST /provider/add-service Add new service Provider
DELETE /provider/delete-service/:id Delete service Provider
GET /provider/agents Get all agents Provider
POST /provider/assign-agent Assign agent to service Provider
GET /provider/bookings Get all bookings Provider
POST /provider/assign-booking Assign agent to booking Provider

Agent (/agent)

Method Endpoint Description Auth
GET /agent/bookings Get assigned bookings Agent
PATCH /agent/bookings/:id/status Update booking status Agent
GET /agent/profile Get agent profile Agent

πŸ” Authentication

JWT Token Flow

1. User logs in with email/password
2. Server validates credentials
3. Server generates JWT tokens:
   - accessToken (15 mins expiry)
   - refreshToken (7 days expiry)
4. Tokens are sent as HTTP-only cookies
5. Client includes cookies in subsequent requests
6. Server validates token on protected routes

Role-Based Cookie Names

Role Cookie Name
Client accessTokenClient
Service Provider accessTokenServiceProvider
Agent accessTokenAgent

Protecting Routes

// Single role
router.get('/profile', verifyJWT('CLIENT'), controller.getProfile);

// Multiple roles allowed
router.get('/dashboard', 
  verifyJWT('ANY'),
  isAuthorized(['CLIENT', 'SERVICE_PROVIDER']),
  controller.getDashboard
);

βš™οΈ Environment Variables

# Server Configuration
NODE_ENV=development          # development | production
PORT=5000                     # Server port

# Database
MONGO_URI=mongodb://127.0.0.1:27017/ruralsync

# JWT Secret (use strong secret in production!)
JWT_SECRET=your-super-secret-jwt-key-change-in-production

# CORS Origins (comma-separated for production)
CORS_ORIGINS=http://localhost:3000,http://localhost:5173

# AI Features (Optional - Hugging Face)
HF_TOKEN=your-huggingface-token

# AWS S3 (Optional - File Uploads)
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_BUCKET_NAME=your-bucket-name

πŸ“Š Database Models

Entity Relationship Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ServiceProvider│──────▢│  Organization   β”‚
β”‚    (User)       β”‚  1:1  β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                         β”‚
         β”‚ 1:N                     β”‚ 1:N
         β–Ό                         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     Agent       │◀──────│    Service      β”‚
β”‚                 β”‚  N:M  β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                         β”‚
         β”‚ 1:N                     β”‚ 1:N
         β–Ό                         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Booking      │◀──────│    Client       β”‚
β”‚                 β”‚  N:1  β”‚    (User)       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                         β”‚
         β”‚ 1:1                     β”‚ 1:N
         β–Ό                         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   AuditLog      β”‚       β”‚    Review       β”‚
β”‚                 β”‚       β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Model Features

Model Key Features
Service Geo-indexed location, AI embeddings, availability schedule
Booking Status workflow, agent assignment, extra tasks support
Organization Business hours, social media, verification status
Review Rating aggregation, linked to service & provider

πŸ€– AI Features

Semantic Search with Vector Embeddings

The API uses Hugging Face Inference API to generate embeddings for services, enabling semantic search:

// Generate embedding for text
import { HfInference } from "@huggingface/inference";

const hf = new HfInference(process.env.HF_TOKEN);

export const generateEmbedding = async (text: string): Promise<number[]> => {
  const result = await hf.featureExtraction({
    model: "sentence-transformers/all-MiniLM-L6-v2", // 384 dimensions
    inputs: text,
  });
  return result as number[];
};

MongoDB Atlas Vector Search

Create a vector search index in Atlas:

{
  "mappings": {
    "dynamic": true,
    "fields": {
      "embeddings": {
        "type": "knnVector",
        "dimensions": 384,
        "similarity": "cosine"
      }
    }
  }
}

Search Pipeline

// 1. Convert query to vector
const queryVector = await generateEmbedding("tractor repair near me");

// 2. Vector search stage
{ $vectorSearch: { 
    index: "vector_index",
    path: "embeddings",
    queryVector,
    numCandidates: 100,
    limit: 15
}}

// 3. Geo filter stage
{ $match: { 
    location: { 
      $geoWithin: { 
        $centerSphere: [[lng, lat], radiusKm / 6378.1] 
      }
    }
}}

// 4. Category filter
{ $match: { category: "Farm Equipment" }}

πŸ“– API Documentation

Interactive API documentation is available via Swagger UI:

http://localhost:5000/api-docs

πŸ§ͺ Testing

# Run tests (when implemented)
npm test

# Run with coverage
npm run test:coverage

🚒 Deployment

Vercel (Serverless)

The API is configured for Vercel deployment with:

  • Memory storage for file uploads (4MB limit)
  • Environment variables via Vercel dashboard

Docker

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
EXPOSE 5000
CMD ["node", "dist/server.js"]

πŸ“ License

This project is licensed under the ISC License.


πŸ‘₯ Contributors


πŸ™ Acknowledgements

About

A robust, scalable backend API for the RuralSync rural services marketplace platform.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors