Dealer_Onboarding_Backend/back.md

29 KiB

Royal Enfield Dealership Onboarding System - Backend Documentation

📋 Overview

This is a comprehensive Node.js + Express backend for the Royal Enfield Dealership Onboarding System. It handles a multi-stage workflow with 13 different user roles, managing dealer applications, resignations, constitutional changes, relocations, and full F&F settlement processes.

🏗️ Architecture

Tech Stack:

  • Runtime: Node.js (v18+)
  • Framework: Express.js
  • Database: PostgreSQL (with Sequelize ORM)
  • Authentication: JWT (JSON Web Tokens)
  • File Storage: Multer + Local/Cloud storage
  • Email: Nodemailer
  • Validation: express-validator
  • Security: bcryptjs, helmet, cors

📁 Project Structure

backend/
├── back.md                    # This comprehensive documentation file
├── package.json               # Dependencies and scripts
├── .env.example              # Environment variables template
├── server.js                 # Main entry point
├── config/
│   ├── database.js           # Database configuration
│   ├── email.js              # Email service configuration
│   └── constants.js          # System constants (roles, statuses, stages)
├── models/
│   ├── index.js              # Sequelize model loader
│   ├── User.js               # User model
│   ├── Application.js        # Dealer application model
│   ├── Resignation.js        # Resignation request model
│   ├── ConstitutionalChange.js  # Constitutional change model
│   ├── RelocationRequest.js  # Relocation request model
│   ├── Outlet.js             # Dealership/Studio outlet model
│   ├── Worknote.js           # Discussion worknotes model
│   ├── Document.js           # Document uploads model
│   ├── AuditLog.js           # Audit trail model
│   ├── FinancePayment.js     # Finance payment tracking
│   ├── FnF.js                # Full & Final settlement
│   ├── Region.js             # Regional hierarchy model
│   └── Zone.js               # Zone model
├── controllers/
│   ├── authController.js     # Login, logout, token refresh
│   ├── userController.js     # User management
│   ├── applicationController.js  # Dealer applications
│   ├── resignationController.js  # Resignation workflow
│   ├── constitutionalController.js  # Constitutional changes
│   ├── relocationController.js   # Relocation requests
│   ├── outletController.js   # Outlet management
│   ├── worknoteController.js # Discussion platform
│   ├── financeController.js  # Finance operations
│   ├── masterController.js   # Master configuration
│   └── dashboardController.js # Dashboard statistics
├── routes/
│   ├── auth.js               # Authentication routes
│   ├── users.js              # User routes
│   ├── applications.js       # Application routes
│   ├── resignations.js       # Resignation routes
│   ├── constitutional.js     # Constitutional change routes
│   ├── relocations.js        # Relocation routes
│   ├── outlets.js            # Outlet routes
│   ├── worknotes.js          # Worknote routes
│   ├── finance.js            # Finance routes
│   ├── master.js             # Master configuration routes
│   └── dashboard.js          # Dashboard routes
├── middleware/
│   ├── auth.js               # JWT verification middleware
│   ├── roleCheck.js          # Role-based access control
│   ├── upload.js             # File upload middleware
│   ├── validation.js         # Input validation
│   └── errorHandler.js       # Global error handler
├── utils/
│   ├── emailTemplates.js     # Email HTML templates
│   ├── emailService.js       # Email sending utilities
│   ├── logger.js             # Winston logger
│   └── helpers.js            # Helper functions
└── migrations/               # Database migrations
    └── initial-setup.js      # Initial database schema

👥 User Roles & Permissions

The system supports 13 distinct roles with hierarchical permissions:

  1. DD (Dealer Development) - Creates applications, initial review
  2. DD-ZM (DD Zone Manager) - Zone-level approvals
  3. RBM (Regional Business Manager) - Regional approvals
  4. ZBH (Zonal Business Head) - Zonal head approvals
  5. DD Lead - Organization-wide DD leadership (singular position)
  6. DD Head - Head of DD department (singular position)
  7. NBH (National Business Head) - National head (singular position)
  8. DD Admin - Administrative operations
  9. Legal Admin - Legal clearance and document verification
  10. Super Admin - Full system access
  11. DD AM (Area Manager) - Area-level management
  12. Finance - Payment tracking and financial approvals
  13. Dealer - Dealer portal access (resignation, relocation, constitutional changes)

🗄️ Database Schema

Key Tables:

1. users

- id (UUID, PK)
- email (STRING, UNIQUE)
- password (STRING, hashed)
- role (ENUM: DD, DD-ZM, RBM, ZBH, DD Lead, DD Head, NBH, DD Admin, Legal Admin, Super Admin, DD AM, Finance, Dealer)
- name (STRING)
- region (STRING) - East, West, North, South, Central
- zone (STRING)
- status (ENUM: active, inactive)
- createdAt, updatedAt

2. applications

- id (UUID, PK)
- applicationId (STRING, UNIQUE) - e.g., APP-2026-001
- applicantName (STRING)
- email (STRING)
- phone (STRING)
- businessType (ENUM: Dealership, Studio)
- proposedLocation (TEXT)
- city, state, pincode
- currentStage (ENUM: DD, DD-ZM, RBM, ZBH, DD Lead, DD Head, NBH, Legal, Finance, Approved, Rejected)
- status (ENUM: Pending, In Review, Approved, Rejected)
- ranking (INTEGER) - DD ranking system
- submittedBy (UUID, FK -> users)
- submittedAt (DATE)
- progressPercentage (INTEGER)
- documents (JSON) - Array of document references
- createdAt, updatedAt

3. outlets

- id (UUID, PK)
- code (STRING, UNIQUE) - e.g., DL-MH-001, ST-MH-002
- name (STRING)
- type (ENUM: Dealership, Studio)
- address (TEXT)
- city (STRING)
- state (STRING)
- pincode (STRING)
- latitude (DECIMAL)
- longitude (DECIMAL)
- status (ENUM: Active, Pending Resignation, Closed)
- establishedDate (DATE)
- dealerId (UUID, FK -> users)
- region (STRING)
- zone (STRING)
- createdAt, updatedAt

4. resignations

- id (UUID, PK)
- resignationId (STRING, UNIQUE) - e.g., RES-001
- outletId (UUID, FK -> outlets)
- dealerId (UUID, FK -> users)
- resignationType (ENUM: Voluntary, Retirement, Health Issues, Business Closure, Other)
- lastOperationalDateSales (DATE)
- lastOperationalDateServices (DATE)
- reason (TEXT)
- additionalInfo (TEXT)
- currentStage (ENUM: ASM, RBM, ZBH, NBH, DD Admin, Legal, Finance, Completed, Rejected)
- status (STRING)
- progressPercentage (INTEGER)
- submittedOn (DATE)
- documents (JSON)
- createdAt, updatedAt

5. constitutional_changes

- id (UUID, PK)
- requestId (STRING, UNIQUE) - e.g., CC-001
- outletId (UUID, FK -> outlets)
- dealerId (UUID, FK -> users)
- changeType (ENUM: Ownership Transfer, Partnership Change, LLP Conversion, Company Formation, Director Change)
- currentStructure (STRING)
- proposedStructure (STRING)
- reason (TEXT)
- effectiveDate (DATE)
- currentStage (ENUM: DD Admin Review, Legal Review, NBH Approval, Finance Clearance, Completed, Rejected)
- status (STRING)
- progressPercentage (INTEGER)
- submittedOn (DATE)
- documents (JSON)
- createdAt, updatedAt

6. relocation_requests

- id (UUID, PK)
- requestId (STRING, UNIQUE) - e.g., REL-001
- outletId (UUID, FK -> outlets)
- dealerId (UUID, FK -> users)
- relocationType (ENUM: Within City, Intercity, Interstate)
- currentAddress (TEXT)
- currentLatitude (DECIMAL)
- currentLongitude (DECIMAL)
- proposedAddress (TEXT)
- proposedLatitude (DECIMAL)
- proposedLongitude (DECIMAL)
- proposedCity (STRING)
- proposedState (STRING)
- proposedPincode (STRING)
- distance (DECIMAL) - in kilometers
- reason (TEXT)
- effectiveDate (DATE)
- currentStage (ENUM: DD Admin Review, RBM Review, NBH Approval, Legal Clearance, Completed, Rejected)
- status (STRING)
- progressPercentage (INTEGER)
- submittedOn (DATE)
- documents (JSON)
- createdAt, updatedAt

7. worknotes

- id (UUID, PK)
- requestId (UUID) - Generic reference to any request
- requestType (ENUM: application, resignation, constitutional, relocation)
- userId (UUID, FK -> users)
- userName (STRING)
- userRole (STRING)
- message (TEXT)
- attachments (JSON)
- timestamp (DATE)
- createdAt, updatedAt

8. documents

- id (UUID, PK)
- filename (STRING)
- originalName (STRING)
- mimeType (STRING)
- size (INTEGER)
- path (STRING)
- uploadedBy (UUID, FK -> users)
- relatedTo (STRING) - application/resignation/etc
- relatedId (UUID)
- documentType (STRING) - GST, PAN, Aadhaar, etc
- uploadedAt (DATE)
- createdAt, updatedAt

9. audit_logs

- id (UUID, PK)
- userId (UUID, FK -> users)
- userName (STRING)
- userRole (STRING)
- action (STRING) - CREATED, UPDATED, APPROVED, REJECTED, etc
- entityType (STRING) - application, resignation, etc
- entityId (UUID)
- changes (JSON) - Before/after values
- ipAddress (STRING)
- timestamp (DATE)
- createdAt, updatedAt

10. finance_payments

- id (UUID, PK)
- applicationId (UUID, FK -> applications)
- outletId (UUID, FK -> outlets)
- dealerId (UUID, FK -> users)
- paymentType (ENUM: Security Deposit, License Fee, Setup Fee, Other)
- amount (DECIMAL)
- dueDate (DATE)
- paidDate (DATE)
- status (ENUM: Pending, Paid, Overdue, Waived)
- transactionId (STRING)
- paymentMode (STRING)
- remarks (TEXT)
- createdAt, updatedAt

11. fnf_settlements

- id (UUID, PK)
- fnfId (STRING, UNIQUE) - e.g., FNF-001
- resignationId (UUID, FK -> resignations)
- outletId (UUID, FK -> outlets)
- dealerId (UUID, FK -> users)
- totalDues (DECIMAL)
- securityDepositRefund (DECIMAL)
- otherCharges (DECIMAL)
- netSettlement (DECIMAL)
- status (ENUM: Initiated, DD Clearance, Legal Clearance, Finance Approval, Completed)
- settledDate (DATE)
- progressPercentage (INTEGER)
- createdAt, updatedAt

12. regions

- id (UUID, PK)
- name (STRING, UNIQUE) - East, West, North, South, Central
- code (STRING)
- headName (STRING)
- headEmail (STRING)
- isActive (BOOLEAN)
- createdAt, updatedAt

13. zones

- id (UUID, PK)
- name (STRING)
- code (STRING)
- regionId (UUID, FK -> regions)
- managerName (STRING)
- managerEmail (STRING)
- states (JSON) - Array of states covered
- isActive (BOOLEAN)
- createdAt, updatedAt

🔌 API Endpoints

Authentication

POST /api/auth/login

Request:
{
  "email": "user@example.com",
  "password": "password123"
}

Response:
{
  "success": true,
  "token": "jwt_token_here",
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "name": "John Doe",
    "role": "DD"
  }
}

POST /api/auth/logout

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "message": "Logged out successfully"
}

GET /api/auth/me

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "name": "John Doe",
    "role": "DD",
    "region": "West",
    "zone": "Mumbai"
  }
}

Outlets

GET /api/outlets/my-outlets

Get all outlets for logged-in dealer

Headers: { Authorization: "Bearer dealer_token" }

Response:
{
  "success": true,
  "outlets": [
    {
      "id": "uuid",
      "code": "DL-MH-001",
      "name": "Royal Enfield Mumbai",
      "type": "Dealership",
      "address": "Bandra West, Mumbai",
      "status": "Active",
      "hasActiveResignation": false
    }
  ]
}

Resignations

POST /api/resignations/create

Create resignation request (Dealer only)

Headers: { Authorization: "Bearer dealer_token" }

Request:
{
  "outletId": "uuid",
  "resignationType": "Voluntary",
  "lastOperationalDateSales": "2026-02-28",
  "lastOperationalDateServices": "2026-02-28",
  "reason": "Personal health issues",
  "additionalInfo": "Optional details"
}

Response:
{
  "success": true,
  "resignationId": "RES-001",
  "message": "Resignation request submitted successfully"
}

GET /api/resignations/list

Get resignations (role-based filtering)

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "resignations": [
    {
      "resignationId": "RES-001",
      "outlet": { "code": "DL-MH-001", "name": "..." },
      "resignationType": "Voluntary",
      "currentStage": "ASM Review",
      "status": "Pending",
      "progressPercentage": 15
    }
  ]
}

GET /api/resignations/:id

Get resignation details

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "resignation": {
    "resignationId": "RES-001",
    "outlet": {...},
    "resignationType": "Voluntary",
    "reason": "...",
    "timeline": [...],
    "worknotes": [...]
  }
}

POST /api/resignations/:id/approve

Approve resignation at current stage

Headers: { Authorization: "Bearer jwt_token" }

Request:
{
  "remarks": "Approved by ASM"
}

Response:
{
  "success": true,
  "message": "Resignation approved and moved to next stage"
}

POST /api/resignations/:id/reject

Reject resignation

Headers: { Authorization: "Bearer jwt_token" }

Request:
{
  "reason": "Incomplete documentation"
}

Response:
{
  "success": true,
  "message": "Resignation rejected"
}

Constitutional Changes

POST /api/constitutional/create

Create constitutional change request (Dealer only)

Headers: { Authorization: "Bearer dealer_token" }

Request:
{
  "outletId": "uuid",
  "changeType": "Partnership Change",
  "currentStructure": "Sole Proprietorship",
  "proposedStructure": "Partnership Firm",
  "reason": "Business expansion",
  "effectiveDate": "2026-03-01"
}

Response:
{
  "success": true,
  "requestId": "CC-001"
}

GET /api/constitutional/list

Get constitutional change requests

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "requests": [...]
}

Relocation Requests

POST /api/relocations/create

Create relocation request (Dealer only)

Headers: { Authorization: "Bearer dealer_token" }

Request:
{
  "outletId": "uuid",
  "relocationType": "Within City",
  "proposedAddress": "New location address",
  "proposedLatitude": 19.0760,
  "proposedLongitude": 72.8777,
  "proposedCity": "Mumbai",
  "proposedState": "Maharashtra",
  "proposedPincode": "400050",
  "reason": "Better footfall location",
  "effectiveDate": "2026-04-01"
}

Response:
{
  "success": true,
  "requestId": "REL-001"
}

GET /api/relocations/calculate-distance

Calculate distance between two locations

Headers: { Authorization: "Bearer jwt_token" }

Query: ?fromLat=19.0760&fromLng=72.8777&toLat=19.1196&toLng=72.9046

Response:
{
  "success": true,
  "distance": 5.2,
  "unit": "km"
}

Worknotes

POST /api/worknotes/create

Add worknote to any request

Headers: { Authorization: "Bearer jwt_token" }

Request:
{
  "requestId": "uuid",
  "requestType": "resignation",
  "message": "Please provide updated documents"
}

Response:
{
  "success": true,
  "worknote": {...}
}

GET /api/worknotes/:requestId/:requestType

Get all worknotes for a request

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "worknotes": [
    {
      "id": "uuid",
      "userName": "John Doe",
      "userRole": "DD Admin",
      "message": "...",
      "timestamp": "2026-01-13T10:30:00Z"
    }
  ]
}

Applications

POST /api/applications/create

Create new dealer application (public endpoint)

Request:
{
  "applicantName": "Rajesh Kumar",
  "email": "rajesh@example.com",
  "phone": "+91-9876543210",
  "businessType": "Dealership",
  "proposedLocation": "Full address",
  "city": "Mumbai",
  "state": "Maharashtra",
  "pincode": "400001"
}

Response:
{
  "success": true,
  "applicationId": "APP-2026-001"
}

GET /api/applications/list

Get applications (role-based filtering)

Headers: { Authorization: "Bearer jwt_token" }
Query: ?status=Pending&region=West&page=1&limit=10

Response:
{
  "success": true,
  "applications": [...],
  "total": 50,
  "page": 1,
  "pages": 5
}

POST /api/applications/:id/assign-ranking

DD assigns ranking (1-5)

Headers: { Authorization: "Bearer dd_token" }

Request:
{
  "ranking": 4
}

Response:
{
  "success": true,
  "message": "Ranking assigned"
}

POST /api/applications/:id/move-stage

Move application to next stage

Headers: { Authorization: "Bearer jwt_token" }

Request:
{
  "action": "approve", // or "reject"
  "remarks": "All documents verified"
}

Response:
{
  "success": true,
  "nextStage": "DD-ZM"
}

Finance

GET /api/finance/onboarding-payments

Get all pending onboarding payments

Headers: { Authorization: "Bearer finance_token" }

Response:
{
  "success": true,
  "payments": [...]
}

POST /api/finance/payment/:id/mark-paid

Mark payment as received

Headers: { Authorization: "Bearer finance_token" }

Request:
{
  "transactionId": "TXN123456",
  "paidDate": "2026-01-13",
  "paymentMode": "NEFT"
}

Response:
{
  "success": true,
  "message": "Payment marked as paid"
}

GET /api/finance/fnf-list

Get F&F settlement requests

Headers: { Authorization: "Bearer finance_token" }

Response:
{
  "success": true,
  "fnfRequests": [...]
}

Dashboard

GET /api/dashboard/stats

Get dashboard statistics (role-based)

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "stats": {
    "totalApplications": 150,
    "pendingApplications": 45,
    "approvedApplications": 95,
    "rejectedApplications": 10,
    "pendingResignations": 5,
    "pendingRelocations": 3
  }
}

Master Configuration

GET /api/master/regions

Get all regions

Headers: { Authorization: "Bearer jwt_token" }

Response:
{
  "success": true,
  "regions": [
    {
      "id": "uuid",
      "name": "East",
      "code": "EAST",
      "zones": [...]
    }
  ]
}

POST /api/master/regions/create

Create region (Super Admin only)

Headers: { Authorization: "Bearer admin_token" }

Request:
{
  "name": "East",
  "code": "EAST",
  "headName": "Amit Kumar",
  "headEmail": "amit@example.com"
}

Response:
{
  "success": true,
  "region": {...}
}

File Upload

POST /api/upload/document

Upload document

Headers: { 
  Authorization: "Bearer jwt_token",
  Content-Type: "multipart/form-data"
}

FormData:
- file: (binary)
- relatedTo: "resignation"
- relatedId: "uuid"
- documentType: "GST Certificate"

Response:
{
  "success": true,
  "document": {
    "id": "uuid",
    "filename": "unique-filename.pdf",
    "originalName": "gst-certificate.pdf",
    "url": "/uploads/documents/unique-filename.pdf"
  }
}

🔐 Authentication & Authorization

JWT Authentication Flow:

  1. Login: User sends credentials → Server validates → Returns JWT token
  2. Protected Routes: Client sends token in Authorization header
  3. Token Verification: Middleware validates token before processing request
  4. Token Expiry: 24 hours (configurable)

Role-Based Access Control (RBAC):

Middleware checks user role against route permissions:

// Example: Only DD Lead can access opportunity requests
router.get('/opportunity-requests', 
  auth, 
  roleCheck(['DD Lead']), 
  getOpportunityRequests
);

// Example: Multiple roles can approve resignations
router.post('/resignations/:id/approve',
  auth,
  roleCheck(['DD Admin', 'RBM', 'ZBH', 'NBH', 'Legal Admin']),
  approveResignation
);

Permission Matrix:

Feature DD DD-ZM RBM ZBH DD Lead DD Head NBH DD Admin Legal Finance Dealer
Create Application
View All Applications
Approve Application Stage
Create Resignation
Approve Resignation
Constitutional Change
Relocation Request
Master Configuration

📧 Email Notifications

Email Triggers:

  1. Application Submitted → Notify assigned DD
  2. Application Approved/Rejected → Notify applicant
  3. Stage Changed → Notify next approver
  4. Deadline Approaching → Reminder email (3 days, 1 day before)
  5. Resignation Submitted → Notify DD Admin
  6. Constitutional Change → Notify Legal team
  7. Relocation Request → Notify RBM
  8. Payment Due → Notify dealer
  9. F&F Initiated → Notify Finance team

Email Templates:

Located in utils/emailTemplates.js:

  • Application confirmation
  • Approval notification
  • Rejection notification
  • Stage progression
  • Deadline reminder
  • Password reset

🚀 Setup Instructions

1. Prerequisites

Install the following on your system:

2. Install Dependencies

cd backend
npm install

3. Database Setup

Create PostgreSQL database:

CREATE DATABASE royal_enfield_onboarding;
CREATE USER re_admin WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE royal_enfield_onboarding TO re_admin;

4. Environment Configuration

Copy .env.example to .env and configure:

# Server
NODE_ENV=development
PORT=5000

# Database
DB_HOST=localhost
DB_PORT=5432
DB_NAME=royal_enfield_onboarding
DB_USER=re_admin
DB_PASSWORD=your_password

# JWT
JWT_SECRET=your_super_secret_jwt_key_here_make_it_long_and_random
JWT_EXPIRES_IN=24h

# Email (Gmail example)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your-email@gmail.com
EMAIL_PASSWORD=your-app-specific-password
EMAIL_FROM=Royal Enfield <noreply@royalenfield.com>

# File Upload
UPLOAD_PATH=./uploads
MAX_FILE_SIZE=10485760

# Frontend URL (for CORS)
FRONTEND_URL=http://localhost:5173

# Admin Default Password (for initial setup)
ADMIN_DEFAULT_PASSWORD=Admin@123

5. Run Migrations

npm run migrate

This creates all tables and seeds initial data:

  • Super Admin user
  • 5 Regions (East, West, North, South, Central)
  • Sample zones
  • Sample users for each role

6. Start Server

Development:

npm run dev

Production:

npm start

Server runs on: http://localhost:5000

7. Test API

Use Postman/Thunder Client:

# Login as Super Admin
POST http://localhost:5000/api/auth/login
Body: {
  "email": "admin@royalenfield.com",
  "password": "Admin@123"
}

# Get dashboard stats
GET http://localhost:5000/api/dashboard/stats
Headers: Authorization: Bearer <token_from_login>

🔗 Frontend Integration

Update Frontend API Calls

In your frontend, update API base URL:

Create /src/lib/api.ts:

const API_BASE_URL = process.env.NODE_ENV === 'production' 
  ? 'https://your-backend-domain.com/api'
  : 'http://localhost:5000/api';

export const api = {
  async login(email: string, password: string) {
    const response = await fetch(`${API_BASE_URL}/auth/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password })
    });
    return response.json();
  },

  async getMyOutlets(token: string) {
    const response = await fetch(`${API_BASE_URL}/outlets/my-outlets`, {
      headers: { 'Authorization': `Bearer ${token}` }
    });
    return response.json();
  },

  async createResignation(token: string, data: any) {
    const response = await fetch(`${API_BASE_URL}/resignations/create`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify(data)
    });
    return response.json();
  }
};

Replace Mock Data

Before (Mock):

const mockOutlets = [...]; // Hardcoded data

After (Real API):

useEffect(() => {
  const fetchOutlets = async () => {
    const token = localStorage.getItem('token');
    const result = await api.getMyOutlets(token);
    setOutlets(result.outlets);
  };
  fetchOutlets();
}, []);

📊 Workflow State Machines

Application Workflow:

Initial → DD Review → DD-ZM Review → RBM Review → ZBH Review 
→ DD Lead Review → DD Head Review → NBH Approval → Legal Clearance 
→ Finance Payment → Approved ✅

Resignation Workflow:

Submitted → ASM Review → RBM Review → ZBH Review → NBH Approval 
→ DD Admin Clearance → Legal Clearance → F&F Initiation 
→ Finance Settlement → Completed ✅

Constitutional Change Workflow:

Submitted → DD Admin Review → Legal Verification → NBH Approval 
→ Finance Clearance → Completed ✅

Relocation Workflow:

Submitted → DD Admin Review → RBM Assessment → NBH Approval 
→ Legal Clearance → Completed ✅

🛡️ Security Features

  1. Password Hashing: bcryptjs with salt rounds
  2. JWT Tokens: Secure token-based authentication
  3. CORS: Configured for frontend domain only
  4. Helmet: Security headers
  5. Rate Limiting: Prevent brute force attacks
  6. Input Validation: express-validator on all inputs
  7. SQL Injection Prevention: Sequelize ORM parameterized queries
  8. File Upload Validation: Type and size restrictions
  9. Audit Logging: All actions logged with user/timestamp

📝 Logging

Winston logger with multiple transports:

  • Console: Development logging
  • File: logs/error.log - Error logs
  • File: logs/combined.log - All logs

🧪 Testing

# Run tests
npm test

# Run with coverage
npm run test:coverage

🚢 Deployment

  1. Create account on railway.app
  2. Connect GitHub repository
  3. Add PostgreSQL plugin
  4. Set environment variables
  5. Deploy automatically

Option 2: Render

  1. Create account on render.com
  2. Create Web Service
  3. Connect repository
  4. Add PostgreSQL database
  5. Set environment variables
  6. Deploy

Option 3: AWS/DigitalOcean

  1. Set up EC2/Droplet
  2. Install Node.js, PostgreSQL
  3. Clone repository
  4. Configure environment
  5. Use PM2 for process management
  6. Set up Nginx reverse proxy

Environment Variables for Production:

NODE_ENV=production
DB_HOST=<production-db-host>
DB_NAME=<production-db-name>
DB_USER=<production-db-user>
DB_PASSWORD=<production-db-password>
JWT_SECRET=<strong-random-secret>
EMAIL_HOST=<smtp-host>
EMAIL_USER=<email>
EMAIL_PASSWORD=<password>
FRONTEND_URL=https://your-frontend-domain.com

📦 Dependencies

Core:

  • express: Web framework
  • sequelize: ORM
  • pg, pg-hstore: PostgreSQL driver
  • jsonwebtoken: JWT authentication
  • bcryptjs: Password hashing

Middleware:

  • cors: Cross-origin resource sharing
  • helmet: Security headers
  • express-validator: Input validation
  • multer: File uploads

Utilities:

  • nodemailer: Email sending
  • winston: Logging
  • dotenv: Environment variables
  • uuid: Unique IDs

Dev Dependencies:

  • nodemon: Auto-restart on changes
  • jest: Testing framework

🔧 Maintenance

Database Backup:

pg_dump -U re_admin royal_enfield_onboarding > backup.sql

Restore Database:

psql -U re_admin royal_enfield_onboarding < backup.sql

Clear Logs:

npm run clear-logs

📞 Support & Troubleshooting

Common Issues:

1. Database Connection Error:

  • Check PostgreSQL is running: sudo service postgresql status
  • Verify credentials in .env
  • Check database exists: psql -l

2. Port Already in Use:

  • Change PORT in .env
  • Kill process: lsof -ti:5000 | xargs kill

3. JWT Token Invalid:

  • Check JWT_SECRET is same across restarts
  • Verify token expiry time
  • Clear old tokens from frontend

4. File Upload Failing:

  • Check UPLOAD_PATH directory exists and is writable
  • Verify MAX_FILE_SIZE setting
  • Check disk space

5. Email Not Sending:

  • Verify SMTP credentials
  • Check firewall/port 587 access
  • Enable "Less secure apps" for Gmail or use App Password

🎯 Next Steps for AI Assistant (Cursor/Windsurf/etc)

When you provide this backend to your AI IDE, it will understand:

  1. Complete architecture and file structure
  2. Database schema and relationships
  3. All API endpoints and their contracts
  4. Authentication and authorization flow
  5. Environment setup requirements
  6. Deployment options
  7. Integration points with frontend

The AI can then:

  • Help you set up the database
  • Debug any issues
  • Add new features
  • Optimize queries
  • Handle deployment
  • Write tests
  • Generate documentation

📄 License

Proprietary - Royal Enfield Dealership Onboarding System


Created: January 2026
Version: 1.0.0
Last Updated: January 13, 2026

For questions or support, refer to this documentation first, then consult with your development team.