NeighborNodes

🏑 NeighborNodes

A location-aware community borrowing platform β€” borrow what you need, lend what you don't use.

Node.js Express PostgreSQL Leaflet License


πŸ“Œ What is NeighborNodes?

NeighborNodes is a full-stack web application that lets people within the same neighborhood borrow and lend rarely-used household items β€” think power drills, projectors, camping tents, or kitchen appliances.

The Problem

Many expensive household items sit idle 99% of the time. You buy a β‚Ή15,000 drill for one weekend project, a β‚Ή50,000 projector for two movie nights a year, or a camping tent that collects dust in your closet. Meanwhile, your neighbor three streets away just bought the exact same thing.

The Solution

NeighborNodes connects neighbors within the same pincode into a trusted sharing community. Instead of buying, you borrow. Instead of hoarding, you lend β€” and earn.

In simple terms: It’s like a neighborhood library, but for everything.


✨ Key Features

Feature What it Does Why it Matters
πŸ—ΊοΈ Community Map Interactive Leaflet.js map showing available items near you Visual discovery β€” see what’s available at a glance
πŸ“ Pincode-Based Communities Items are filtered by pincode β€” you only see what’s in your area Ensures items are within walking/short-driving distance
πŸ” Privacy-First Addresses Exact addresses are hidden until a borrow request is accepted Protects user safety; only approximate locality shown on map
πŸ”„ Full Borrow Lifecycle Pending β†’ Accepted β†’ Collected β†’ Returned with status tracking Both parties always know where things stand
πŸ›‘οΈ Race Condition Prevention PostgreSQL row-level locking (SELECT ... FOR UPDATE) on borrow/accept Two people can’t accidentally borrow the same item simultaneously
πŸ€– AI Assistant Chatbot Keyword-driven chatbot that helps find items and answers FAQs Guided discovery without manual browsing
πŸ”” Notification Badges Dashboard badge showing pending incoming + outgoing request count Never miss a borrow request
πŸ“ Contact & Feedback Structured feedback form with category tagging Users can report issues, suggest features, or reach out
πŸ”‘ JWT Authentication Secure login/signup with bcrypt password hashing and JWT tokens Industry-standard auth β€” sessions survive page reloads
πŸ“¦ 7 Item Categories Utility Tools, Hardware, Electronics, Camping, Gaming, Home Appliances, Kitchen Organized browsing with emoji-tagged category bar

πŸ—οΈ Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        FRONTEND                             β”‚
β”‚  Vanilla HTML/CSS/JS β€’ Leaflet.js Maps β€’ No build step      β”‚
β”‚                                                             β”‚
β”‚  index.html ─── Landing page + Map + Item grid              β”‚
β”‚  auth.html ──── Login / Signup with pincode registration    β”‚
β”‚  Dashboard.html  Lender + Borrower request management       β”‚
β”‚  Borrow.html ── Item detail + date picker + reservation     β”‚
β”‚  ListItem.html ─ Form to post new item listings             β”‚
β”‚  Contact.html ── Feedback/support form                      β”‚
β”‚  script.js ───── All frontend logic (single shared file)    β”‚
β”‚  style.css ───── Complete design system (~50KB)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚  HTTP (REST API)
                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     BACKEND (Node.js + Express 5)           β”‚
β”‚                                                             β”‚
β”‚  server.js ─────── Entry point, middleware, route mounting  β”‚
β”‚  db.js ─────────── PostgreSQL connection pool (pg)          β”‚
β”‚                                                             β”‚
β”‚  Controllers/                                               β”‚
β”‚  β”œβ”€β”€ authController.js ────── Register (with pincode        β”‚
β”‚  β”‚                            coords) + Login (JWT)         β”‚
β”‚  β”œβ”€β”€ borrowController.js ──── Create request, pickup        β”‚
β”‚  β”‚                            address reveal, collect,      β”‚
β”‚  β”‚                            return (with transactions)    β”‚
β”‚  β”œβ”€β”€ lenderController.js ──── CRUD items, accept/reject     β”‚
β”‚  β”‚                            requests (row-level locking)  β”‚
β”‚  β”œβ”€β”€ locationController.js ── Nearby items by pincode       β”‚
β”‚  β”‚                            with Haversine distances      β”‚
β”‚  β”œβ”€β”€ assistantController.js ─ Keyword-based AI chatbot      β”‚
β”‚  β”œβ”€β”€ contactController.js ─── Feedback submission + admin   β”‚
β”‚  └── itemController.js ────── General item queries          β”‚
β”‚                                                             β”‚
β”‚  Utils/                                                     β”‚
β”‚  β”œβ”€β”€ haversine.js ──── Distance calculation (km)            β”‚
β”‚  β”œβ”€β”€ pincodeMap.js ──── 100+ Mumbai/Pune pincode β†’ lat/lng  β”‚
β”‚  └── geocode.js ─────── Geocoding helpers                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚  SQL (pg driver)
                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     DATABASE (PostgreSQL)                   β”‚
β”‚                                                             β”‚
β”‚  users ─────────── id, name, email, phone, password,        β”‚
β”‚                    role, trust_score, locality, pincode,    β”‚
β”‚                    full_address, latitude, longitude        β”‚
β”‚                                                             β”‚
β”‚  items ─────────── id, owner_id (FKβ†’users), item_name,      β”‚
β”‚                    description, category, price_per_day,    β”‚
β”‚                    status, image_url                        β”‚
β”‚                                                             β”‚
β”‚  borrow_requests ─ id, item_id (FKβ†’items),                  β”‚
│                    borrower_id (FK→users), start_date,      │
β”‚                    end_date, total_price, request_status    β”‚
β”‚                                                             β”‚
β”‚  feedback ──────── id, user_id (FKβ†’users), name, email,     β”‚
β”‚                    category, subject, message, status       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Getting Started

Prerequisites

Before you begin, make sure you have these installed on your machine:

Tool Version Download
Node.js v18 or higher nodejs.org
PostgreSQL v14 or higher postgresql.org
Git Any recent version git-scm.com

πŸ’‘ New to these tools?


Step 1 β€” Clone the Repository

git clone https://github.com/Bhushan0455/NeighborNodes.git
cd NeighborNodes

Step 2 β€” Set Up the Database

Open your PostgreSQL client (pgAdmin, psql CLI, or DBeaver) and run the SQL from Database_Queries.sql:

-- This creates 4 tables: users, items, borrow_requests, feedback
-- Open Database_Queries.sql and execute all CREATE TABLE statements

Then run the lifecycle migration to enable the full borrow status flow:

-- Open lifecycle_migration.sql and run it
-- This adds: pending, accepted, rejected, collected, returned

πŸ’‘ Beginner tip: If you’re using pgAdmin, open the Query Tool (Tools β†’ Query Tool), paste the SQL, and click the β–Ά Execute button.

Step 3 β€” Seed Sample Data (Optional)

The Database_Queries.sql file includes INSERT INTO items (...) statements with 42 sample items across 7 categories (utility tools, hardware, electronics, camping, gaming, home appliances, kitchen) β€” all with real Unsplash image URLs. Run those inserts to populate your database with demo data.

Step 4 β€” Configure Environment Variables

Create a .env file inside the Backend/ folder:

cd Backend

Create the file Backend/.env with the following content:

DB_USER=postgres
DB_HOST=localhost
DB_NAME=neighbornodes
DB_PASSWORD=your_postgres_password
DB_PORT=5432
JWT_SECRET=your_secret_key_here
Variable What it is
DB_USER Your PostgreSQL username (default is postgres)
DB_HOST Database host (localhost for local development)
DB_NAME Name of the database you created in Step 2
DB_PASSWORD Your PostgreSQL password
DB_PORT PostgreSQL port (default 5432)
JWT_SECRET Any random string β€” used to sign authentication tokens

⚠️ Security: The .env file is listed in .gitignore and will never be committed to Git. Do not share it publicly.

Step 5 β€” Install Dependencies

cd Backend
npm install

This installs the following packages:

Package Purpose
express Web server framework
pg PostgreSQL client for Node.js
bcrypt Password hashing (one-way encryption)
jsonwebtoken JWT token generation and verification
cors Cross-Origin Resource Sharing (lets the frontend talk to the backend)
dotenv Loads .env variables into process.env
nodemon (dev) Auto-restarts the server when you edit code

Step 6 β€” Start the Backend Server

npm start

You should see:

πŸš€ Server running on http://localhost:5000

To verify the database connection, open your browser and visit:

http://localhost:5000/

You should get a JSON response like:

{
  "message": "NeighborNodes Backend is Live",
  "db_time": "2026-04-17T15:19:00.000Z"
}

Step 7 β€” Open the Frontend

The frontend is plain HTML β€” no build step required. Simply open any .html file in your browser:

πŸ’‘ Why Live Server? It auto-reloads the page when you edit HTML/CSS/JS, and avoids some browser file:// restrictions with fetch requests.


πŸ“‘ API Reference

All endpoints are prefixed with http://localhost:5000/api.

Authentication

Method Endpoint Body Description
POST /api/auth/register { name, email, phone, password, role, locality, pincode, address } Create a new user account. Pincode is validated against the supported pincode map. Coordinates are auto-assigned based on pincode center + random offset (~200m).
POST /api/auth/login { email, password } Authenticate and receive a JWT token + userId.

Items & Discovery

Method Endpoint Description
GET /api/location/nearby/:userId Get all available items within the user’s pincode, with map coordinates and distances.
GET /api/lender/items/:id Get a single item’s details with owner info.
GET /api/items Get all items (general query).

Borrowing Lifecycle

Method Endpoint Body Description
POST /api/borrow { item_id, borrower_id, start_date, end_date } Submit a borrow request (uses row-level locking).
GET /api/borrow/address/:requestId/:userId β€” Get pickup address (only visible after request is accepted).
PATCH /api/borrow/:requestId/collect { borrower_id } Borrower marks item as physically collected.
PATCH /api/borrow/:requestId/return { borrower_id } Borrower marks item as returned (item becomes available again).

Lender Dashboard

Method Endpoint Description
GET /api/lender/my-items/:ownerId Get all items listed by a specific user.
GET /api/lender/dashboard/:userId Get all incoming borrow requests for the lender’s items.
POST /api/lender/list-item Post a new item listing.
PATCH /api/lender/request/:requestId Accept or reject a borrow request ({ status: "accepted" | "rejected" }).
DELETE /api/lender/item/:itemId Delete an item listing.

Borrower Dashboard

Method Endpoint Description
GET /api/borrower/requests/:userId Get all borrow requests made by a specific user.

Notifications

Method Endpoint Description
GET /api/notifications/count/:userId Get total pending request count (incoming + outgoing).

AI Assistant

Method Endpoint Body Description
POST /api/assistant/chat { message } Send a message to the keyword-based chatbot. Returns category-matched items or FAQ responses.

Contact & Feedback

Method Endpoint Body Description
POST /api/contact { name, email, category, subject, message, user_id } Submit feedback or contact message.
GET /api/contact/all β€” Admin: retrieve all feedback entries.

πŸ—„οΈ Database Schema

Entity Relationship

users (1) ──────< (N) items
  β”‚                     β”‚
  β”‚                     β”‚
  (1)                   (1)
  β”‚                     β”‚
  β–Ό                     β–Ό
  (N) borrow_requests (N)
  β”‚
  (1)
  β”‚
  β–Ό
  (N) feedback

Borrow Request Lifecycle

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    Lender accepts     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    Borrower picks up   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ PENDING  β”‚ ──────────────────►   β”‚ ACCEPTED β”‚ ─────────────────────► β”‚ COLLECTED β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                                                                       β”‚
         β”‚  Lender rejects                                      Borrower returns β”‚
         β–Ό                                                                       β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ REJECTED β”‚                                                          β”‚ RETURNED β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                                     (item β†’ available)

    * OVERDUE is computed dynamically: if status = 'collected' AND end_date < today

πŸ“‚ Project Structure

NeighborNodes/
β”‚
β”œβ”€β”€ Frontend/                    # Client-side (no build tools needed)
β”‚   β”œβ”€β”€ index.html               # Landing page β€” hero, map, item grid, chatbot
β”‚   β”œβ”€β”€ auth.html                # Login / Signup with pincode + locality fields
β”‚   β”œβ”€β”€ Dashboard.html           # Lender items, incoming requests, borrower requests
β”‚   β”œβ”€β”€ Borrow.html              # Item detail page with date picker + reservation
β”‚   β”œβ”€β”€ ListItem.html            # Form to post a new item for lending
β”‚   β”œβ”€β”€ Contact.html             # Feedback / Contact Us form
β”‚   β”œβ”€β”€ script.js                # All frontend JavaScript logic (~48KB)
β”‚   └── style.css                # Complete design system (~50KB)
β”‚
β”œβ”€β”€ Backend/                     # Server-side (Node.js + Express)
β”‚   β”œβ”€β”€ server.js                # Entry point β€” middleware, routes, notification endpoint
β”‚   β”œβ”€β”€ db.js                    # PostgreSQL connection pool configuration
β”‚   β”œβ”€β”€ package.json             # Dependencies and scripts
β”‚   β”œβ”€β”€ .env                     # ⚠️ Not committed β€” database + JWT credentials
β”‚   β”‚
β”‚   β”œβ”€β”€ Controller/              # Business logic (one file per domain)
β”‚   β”‚   β”œβ”€β”€ authController.js    # Register (pincode β†’ coords) + Login (JWT)
β”‚   β”‚   β”œβ”€β”€ borrowController.js  # Create request, address reveal, collect, return
β”‚   β”‚   β”œβ”€β”€ lenderController.js  # Item CRUD, accept/reject with row-level locking
β”‚   β”‚   β”œβ”€β”€ locationController.js# Nearby items query with Haversine distance
β”‚   β”‚   β”œβ”€β”€ assistantController.js# Keyword-based AI chatbot
β”‚   β”‚   β”œβ”€β”€ contactController.js # Feedback submission + retrieval
β”‚   β”‚   └── itemController.js    # General item queries
β”‚   β”‚
β”‚   β”œβ”€β”€ routes/                  # Express route definitions (thin layer)
β”‚   β”‚   β”œβ”€β”€ authRoutes.js
β”‚   β”‚   β”œβ”€β”€ borrowRoutes.js
β”‚   β”‚   β”œβ”€β”€ lenderRoutes.js
β”‚   β”‚   β”œβ”€β”€ locationRoutes.js
β”‚   β”‚   β”œβ”€β”€ assistantRoutes.js
β”‚   β”‚   β”œβ”€β”€ contactRoutes.js
β”‚   β”‚   └── itemRoutes.js
β”‚   β”‚
β”‚   └── utils/                   # Shared helper functions
β”‚       β”œβ”€β”€ haversine.js         # Haversine formula for distance (km) between coordinates
β”‚       β”œβ”€β”€ pincodeMap.js        # 100+ Indian pincodes β†’ { lat, lng, area } mapping
β”‚       β”œβ”€β”€ geocode.js           # Geocoding utility functions
β”‚       └── geocode-existing-users.js  # One-time migration script for existing user coords
β”‚
β”œβ”€β”€ Database_Queries.sql         # Full schema + 42 seed items across 7 categories
β”œβ”€β”€ lifecycle_migration.sql      # Adds collected/returned statuses to borrow_requests
β”œβ”€β”€ fix_user_coordinates.sql     # Migration to fix user lat/lng from pincode centers
β”œβ”€β”€ .gitignore                   # Excludes .env, node_modules, logs, OS files
└── README.md                    # You are here

πŸ”§ Technical Deep Dives

πŸ”’ How Race Conditions Are Prevented ### The Problem If two users click "Borrow" on the same item at the exact same millisecond, without protection, both requests could succeed β€” double-booking the item. ### The Solution We use **PostgreSQL transactions with row-level locking** (`SELECT ... FOR UPDATE`): ```sql BEGIN; SELECT id, status FROM items WHERE id = $1 FOR UPDATE; -- Locks this specific row -- If another transaction tries to lock the same row, it BLOCKS here until we finish UPDATE items SET status = 'unavailable' WHERE id = $1; UPDATE borrow_requests SET request_status = 'accepted' WHERE id = $2; COMMIT; ``` **What happens behind the scenes:** 1. Transaction A reaches `FOR UPDATE` first β†’ acquires an exclusive lock on the item row. 2. Transaction B reaches the same query β†’ **blocks** (waits). 3. Transaction A sets the item to `unavailable` and commits. 4. Transaction B unblocks, reads the updated row, sees `status = 'unavailable'`, and fails gracefully. This pattern is used in both `borrowController.js` (creating requests) and `lenderController.js` (accepting requests).
πŸ“ How Pincode-Based Location Works ### Registration Flow 1. User enters their pincode during signup (e.g., `400601` for Thane West). 2. Backend looks up the pincode in `pincodeMap.js` β†’ gets center coordinates `{ lat: 19.1964, lng: 72.9631 }`. 3. A small **random offset** (~200m) is added so users in the same pincode don't stack on the exact same point. 4. Coordinates are stored in the `users` table. ### Item Discovery 1. When a user opens the home page, the frontend calls `/api/location/nearby/:userId`. 2. Backend reads the user's pincode β†’ filters items to **only** those owned by users with the **same pincode**. 3. Each item is placed on the map using a **seeded random position** (deterministic based on item ID) within ~400m of the pincode center. 4. Distance from user to each item is calculated using the **Haversine formula** and returned for display. ### Privacy Model - **Before request accepted:** Only approximate locality is shown (e.g., "Thane West"). Map shows scattered approximate positions. - **After request accepted:** The borrower can call `/api/borrow/address/:requestId/:userId` to see the lender's full address, phone number, and item name.
πŸ€– How the AI Assistant Works The chatbot in `assistantController.js` uses a **keyword-matching approach**: 1. User sends a message (e.g., "I need a drill for weekend"). 2. Backend converts to lowercase and checks against category keyword maps: - `"drill"` matches `utility_tools` β†’ queries available items in that category. 3. If no category matches, it checks for FAQ keywords (`"borrow"`, `"trust score"`, `"list item"`). 4. If nothing matches, it returns a fallback message with usage hints. The chatbot **directly queries the database**, so it always returns real, currently-available items.

🌍 Supported Coverage Areas

The platform currently supports 100+ pincodes across:

Region Example Areas
Thane District Thane West/East, Naupada, Wagle Estate, Kolshet, Manpada, Ghodbunder Road
Kalyan / Dombivli Kalyan West/East, Dombivli West/East, Ambernath
Navi Mumbai Vashi, Nerul, Kopar Khairane, Airoli, Ghansoli, Panvel, Kharghar, Kamothe
Mumbai City Fort, Kalbadevi, Girgaon, Grant Road, Byculla, Parel, Dadar, Worli, Sion
Mumbai Suburbs Bandra, Andheri, Goregaon, Malad, Kandivali, Borivali, Powai, Mulund
Mira-Bhayander Mira Road, Bhayander West/East
Vasai / Virar Virar West/East, Vasai West, Nalasopara
Pune Camp, Station, Deccan, Shivajinagar, Hinjewadi, Hadapsar, Kothrud, Baner, Wakad

To add a new pincode, simply add an entry to the PINCODE_COORDS object in Backend/utils/pincodeMap.js.


πŸ› οΈ Tech Stack

Layer Technology Why this choice
Frontend HTML5, CSS3, Vanilla JavaScript Zero build step β€” open and run. Fast iteration.
Maps Leaflet.js + OpenStreetMap Free, open-source, no API key needed.
Backend Node.js + Express 5 Lightweight, async-native, huge ecosystem.
Database PostgreSQL ACID transactions, row-level locking, robust for concurrent operations.
Auth bcrypt + JWT Industry-standard password hashing + stateless token-based sessions.
DB Driver pg (node-postgres) Direct SQL β€” no ORM overhead, full control over queries.

πŸ§ͺ Quick Verification Checklist

After setup, verify everything works by checking these endpoints:

# Test Expected Result
1 Visit http://localhost:5000/ JSON with "NeighborNodes Backend is Live"
2 Open Frontend/index.html in browser Landing page loads with hero, category bar, and map
3 Sign up with a supported pincode (e.g., 400601) Account created, redirected to explore page
4 Check the dashboard after login Shows β€œItems Listed”, β€œPending Requests”, β€œItems Borrowed” stats
5 Click any item β†’ Reserve with dates Borrow request created, visible on dashboard

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the ISC License.


Built with πŸ’š for communities β€” NeighborNodes