VendorBridge is a comprehensive procurement ERP system that digitizes the entire vendor lifecycle. From initial Request for Quotation (RFQ) to vendor bidding, managerial approvals, purchase order generation, and final invoice settlement, VendorBridge replaces manual, spreadsheet-based processes with a structured, role-based workflow.
Built for the Odoo x KSV Hackathon.
Live Demo: https://vendorbridgeerp.vercel.app
| Link | Description |
|---|---|
| vendorbridgeerp.vercel.app | Production deployment |
Seed the database with 4 accounts and 7 ready-made scenarios by running:
cd backend
npm run scenarios| Role | What you can do | |
|---|---|---|
admin@test.com |
Admin | Full system access — see everything |
officer@test.com |
Officer | Create RFQs, view quotation comparisons |
manager@test.com |
Manager | Approve / Reject / Send-back quotations |
vendor@test.com |
Vendor | Submit quotations, view your POs & remarks |
| # | RFQ | State |
|---|---|---|
| S1 | Laptop Procurement Q3 2026 | PENDING → decide as manager@test.com |
| S2 | Office Stationery Bundle | APPROVED + PO → vendor@test.com sees PO |
| S3 | Packaging Materials Q2 2026 | RETURNED with remark → vendor@test.com sees remark |
| S4 | Data Centre Server Hardware | REJECTED |
| S5 | Security Camera Upgrade | DRAFT (officer only, not yet published) |
| S6 | Meeting Room Furniture | OVERDUE (deadline passed, no quotes) |
| S7 | Fleet Management Software | APPROVED + 2nd PO for vendor |
- Manager (
manager@test.com) → Quotations → open Laptop Procurement → Approve, Reject, or Send Back - Vendor (
vendor@test.com) → Purchase Orders → see the auto-generated PO (2 already exist from S2 + S7) - Vendor → Quotations → see the RETURNED remark on Packaging Materials (S3)
- Officer (
officer@test.com) → RFQs → open the DRAFT and publish it, or create a fresh RFQ - Admin (
admin@test.com) → full view of vendors, approvals, reports, activity log
| Category | Technology | Version |
|---|---|---|
| Frontend Framework | Next.js (App Router) | 16.x |
| UI Library | React | 19.x |
| Language | TypeScript | 6.x |
| Styling | Tailwind CSS | v4 |
| UI Components | shadcn/ui (Radix UI) | Latest |
| Icons | Lucide React | Latest |
| Charts | Recharts | v3 |
| Data Fetching | TanStack React Query | v5 |
| Authentication | NextAuth.js | v4 |
| HTTP Client | Axios | v1 |
| PDF Export | jsPDF + jspdf-autotable | Latest |
| Toast Notifications | Sonner | Latest |
| Forms | React Hook Form + Zod | Latest |
| Backend Framework | Express.js | v5 |
| ORM | Prisma | v6 |
| Database | PostgreSQL (Neon) | Latest |
| File Uploads | AWS S3 + Multer | Latest |
| Nodemailer (Gmail SMTP) | Latest | |
| Deployment | Vercel | Latest |
Dev ports: Frontend 3000 - Backend API 5000
VendorBridge/
├── frontend/ # Next.js 16 App Router
│ ├── src/
│ │ ├── app/ # Pages (dashboard, rfqs, vendors, invoices...)
│ │ ├── components/ # AppShell, UI components (shadcn/ui)
│ │ ├── hooks/ # TanStack Query hooks
│ │ ├── repositories/ # Data access layer
│ │ ├── lib/ # Auth, permissions, formatters
│ │ ├── store/ # Notifications store
│ │ └── types/ # Domain types
├── backend/ # Express + Prisma REST API
│ ├── src/
│ │ ├── controllers/ # Route handlers
│ │ ├── routes/ # Express routers
│ │ ├── middleware/ # JWT auth, file upload
│ │ ├── services/ # Business logic (auth)
│ │ └── utils/ # Prisma client, mailer, S3
│ └── prisma/
│ ├── schema.prisma # Database schema
│ └── seed.ts # Demo data seeder
└── README.md
- Node.js 18+
- PostgreSQL database (or Neon free tier)
- Gmail account with App Password enabled
- AWS S3 bucket (for file uploads)
git clone https://github.com/RhythmItaliya/VendorBridge.git
cd VendorBridgecd backend
npm installCopy and fill in the environment file:
cp .env.example .envEdit .env with your values (see Environment Variables section below).
Run database migrations and seed demo data:
npx prisma migrate dev
npm run seedStart the development server:
npm run dev
# API running at http://localhost:5000cd frontend
npm installCopy and fill in the environment file:
cp .env.example .env.localStart the development server:
npm run dev
# App running at http://localhost:3000NODE_ENV=development
PORT=5000
# PostgreSQL connection string
DATABASE_URL="postgresql://user:password@localhost:5432/vendorbridge"
# JWT
JWT_SECRET="your-jwt-secret-key"
# Frontend URL (for CORS)
FRONTEND_URL=http://localhost:3000
# SMTP - Gmail App Password
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM="VendorBridge <noreply@vendorbridge.com>"
# AWS S3
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_S3_BUCKET=your-bucket-name# Backend API URL
NEXT_PUBLIC_API_URL=http://localhost:5000/api
NEXT_PUBLIC_APP_ENV=development
# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-nextauth-secretProduction: Set all variables in your Vercel dashboard under Project -> Settings -> Environment Variables. Update FRONTEND_URL, NEXTAUTH_URL, and NEXT_PUBLIC_API_URL to your Vercel deployment URLs after the first deploy.
| Step | Actor | Action | Result |
|---|---|---|---|
| 1 | Admin | Register vendors and users | — |
| 2 | Officer | Create RFQ, assign vendors | ACTIVE |
| 3 | Vendor | View RFQ, fill unit prices, submit | PENDING |
| 4 | Manager | Compare quotations side-by-side | — |
| 5a | Manager | Approve quotation | APPROVED + PO auto-created |
| 5b | Manager | Reject quotation (optional remark) | REJECTED |
| 5c | Manager | Send Back with mandatory remark | RETURNED |
| 6 | Vendor | Re-submit after send-back (sees remark) | PENDING |
| 7 | Vendor | Fulfil PO by delivery deadline | — |
| 8 | Officer | Mark invoice paid | PAID |
| Page | Admin | Officer | Manager | Vendor |
|---|---|---|---|---|
| Dashboard | Yes | Yes | Yes | Yes |
| Vendors | Yes | Yes | view | — |
| RFQs | Yes | Yes + create | Yes | track only |
| Quotations | Yes | compare | compare | submit |
| Approvals | Yes decide | view only | Yes decide | — |
| Purchase Orders | Yes | Yes create | view | view |
| Invoices | Yes | Yes pay | view | view |
| Reports | Yes | Yes | Yes | — |
| Activity | Yes | Yes | Yes | Yes |
All routes require Authorization: Bearer <token> except /api/auth/*.
POST /api/auth/sign-in
POST /api/auth/sign-up
GET /api/vendors POST /api/vendors
GET /api/vendors/:id
GET /api/rfqs POST /api/rfqs
GET /api/rfqs/:id
GET /api/quotations POST /api/quotations
PATCH /api/quotations/:id/approve
PATCH /api/quotations/:id/reject
PATCH /api/quotations/:id/send-back
GET /api/approvals
POST /api/approvals/:id/approve
POST /api/approvals/:id/reject
GET /api/orders
GET /api/orders/:id
GET /api/invoices
PATCH /api/invoices/:id/pay
GET /api/activity
GET /api/reports/spend
GET /api/notifications
PATCH /api/notifications/read-all
- Money: All amounts stored as
BigIntpaise (1 INR = 100 paise). Frontend converts withNumber(p) / 100. - Status enum:
DRAFT | ACTIVE | PENDING | APPROVED | REJECTED | COMPLETED | PAID | OVERDUE - Roles:
ADMIN | OFFICER | VENDOR | MANAGER(Prisma/DB) vsadmin | officer | vendor | manager(frontend) - Cross-page links: Orders to Invoices use
?open=<id>URL param read byuseSearchParams.
| Name | GitHub |
|---|---|
| Rutanshu Bhayani | github.com/rutanshubhayani |
| Rhythm Italiya | github.com/RhythmItaliya |
This project was built for the Odoo x KSV Hackathon and is open for educational use.