Watch the demo: Play video on Google Drive
StockMaster is a comprehensive, full-stack inventory management system designed to digitize and streamline stock operations. It provides a modern web interface for managing products, warehouses/locations, receipts, deliveries, internal transfers, adjustments, and real-time inventory tracking with audit logging.
- Product Management: Create, update, delete, and search products with SKU tracking
- Location/Warehouse Management: Manage multiple storage locations with unique codes
- Inventory Movements:
- Receipts: Record incoming stock from suppliers
- Deliveries: Track outgoing stock to customers
- Transfers: Move stock between locations
- Adjustments: Correct inventory discrepancies
- Real-time Dashboard: View KPIs, low stock alerts, and recent movements
- Audit Logging: Complete audit trail of all inventory operations
- CSV Import: Bulk import products with stock quantities
- Role-based Access Control: Admin and Staff roles with different permissions
- Modern, responsive React frontend with Tailwind CSS
- Interactive charts and visualizations (Recharts)
- Smooth animations (Framer Motion)
- Real-time notifications (React Hot Toast)
- Protected routes with authentication
- Product search and pagination
- Detailed product views with location breakdown
- Runtime: Node.js 18+
- Framework: Express.js 4
- Database: MongoDB with Mongoose ODM
- Authentication: JWT (JSON Web Tokens) with bcrypt password hashing
- Validation: express-validator
- Security: express-rate-limit for API protection
- File Upload: Multer for CSV imports
- Testing: Jest + Supertest + mongodb-memory-server
- Framework: React 19 with Vite
- Routing: React Router DOM
- State Management: React Context API + TanStack React Query
- Styling: Tailwind CSS
- UI Components: Custom components with Lucide React icons
- Charts: Recharts
- Animations: Framer Motion
- Forms: React Hook Form
- HTTP Client: Axios
- Notifications: React Hot Toast
graph TB
subgraph "Client Layer"
Browser[Web Browser]
React[React Frontend<br/>Vite + React 19]
end
subgraph "API Layer"
Express[Express.js Server<br/>REST API]
Middleware[Middlewares<br/>Auth, Validation, Rate Limit]
end
subgraph "Business Logic Layer"
Controllers[Controllers]
Services[Services<br/>Business Logic]
end
subgraph "Data Layer"
MongoDB[(MongoDB Database)]
Models[Models<br/>User, Product, Location, Movement, AuditLog]
end
Browser -->|HTTP/HTTPS| React
React -->|API Calls| Express
Express --> Middleware
Middleware --> Controllers
Controllers --> Services
Services --> Models
Models --> MongoDB
style Browser fill:#e1f5ff
style React fill:#61dafb
style Express fill:#000000,color:#fff
style MongoDB fill:#47a248,color:#fff
graph LR
subgraph "Request Flow"
Request[HTTP Request] --> Routes[Route Handlers]
Routes --> Auth[Auth Middleware]
Auth --> Validation[Validation Middleware]
Validation --> Role[Role Middleware]
Role --> Controller[Controller]
end
subgraph "Business Logic"
Controller --> Service[Service Layer]
Service --> Transaction[Transaction Handler]
end
subgraph "Data Access"
Transaction --> Model[Mongoose Models]
Model --> MongoDB[(MongoDB)]
end
subgraph "Audit & Logging"
Service --> Audit[Audit Service]
Audit --> AuditLog[(Audit Logs)]
end
style Request fill:#e1f5ff
style Controller fill:#ffd700
style Service fill:#90ee90
style MongoDB fill:#47a248,color:#fff
style AuditLog fill:#ff6b6b,color:#fff
graph TB
subgraph "Presentation Layer"
Pages[Page Components<br/>Dashboard, Products, etc.]
Components[UI Components<br/>Forms, Cards, Modals]
end
subgraph "State Management"
Context[Auth Context<br/>User State]
ReactQuery[React Query<br/>Server State Cache]
end
subgraph "Data Layer"
Hooks[Custom Hooks<br/>useApi, useAuth]
ApiClient[API Client<br/>Axios with Interceptors]
end
subgraph "External"
BackendAPI[Backend API<br/>Express Server]
end
Pages --> Components
Pages --> Context
Pages --> ReactQuery
ReactQuery --> Hooks
Hooks --> ApiClient
ApiClient -->|HTTP Requests| BackendAPI
Context -->|Auth Token| ApiClient
style Pages fill:#61dafb
style Context fill:#ffd700
style ReactQuery fill:#ff6b6b
style BackendAPI fill:#000000,color:#fff
sequenceDiagram
participant User
participant Frontend
participant API
participant Service
participant Database
participant Audit
User->>Frontend: User Action
Frontend->>API: HTTP Request (with JWT)
API->>API: Validate Token & Role
API->>Service: Process Request
Service->>Database: Start Transaction
Service->>Database: Update Data
Service->>Audit: Log Action
Database->>Service: Commit Transaction
Service->>API: Return Result
API->>Frontend: JSON Response
Frontend->>User: Update UI
sequenceDiagram
participant User
participant Frontend
participant AuthAPI
participant AuthService
participant Database
participant JWT
User->>Frontend: Login Request
Frontend->>AuthAPI: POST /api/auth/login
AuthAPI->>AuthService: Validate Credentials
AuthService->>Database: Find User
Database->>AuthService: User Data
AuthService->>AuthService: Verify Password (bcrypt)
AuthService->>JWT: Generate Token
JWT->>AuthService: JWT Token
AuthService->>AuthAPI: Token + User Data
AuthAPI->>Frontend: Response with Token
Frontend->>Frontend: Store Token (localStorage)
Frontend->>User: Redirect to Dashboard
Note over Frontend,Database: Subsequent Requests
User->>Frontend: Access Protected Route
Frontend->>AuthAPI: Request with Bearer Token
AuthAPI->>JWT: Verify Token
JWT->>AuthAPI: Decoded User Info
AuthAPI->>Frontend: Authorized Response
erDiagram
User ||--o{ Movement : creates
User ||--o{ AuditLog : performs
Product ||--o{ Movement : "has movements"
Product ||--o{ ProductLocation : "stored in"
Location ||--o{ ProductLocation : "contains"
Location ||--o{ Movement : "from/to"
User {
ObjectId _id
string name
string email
string password
string role
string resetOtp
date resetOtpExpiresAt
}
Product {
ObjectId _id
string name
string sku
string category
string uom
number reorderLevel
boolean isActive
number totalQuantity
array locations
}
Location {
ObjectId _id
string name
string code
string description
}
Movement {
ObjectId _id
string type
ObjectId product
number qty
ObjectId fromLocation
ObjectId toLocation
ObjectId createdBy
string referenceId
string status
string note
}
ProductLocation {
ObjectId location
number qty
}
AuditLog {
ObjectId _id
ObjectId user
string action
string entity
ObjectId entityId
object payload
}
flowchart TD
Start[User Initiates Movement] --> Validate{Validate Input}
Validate -->|Invalid| Error[Return Error]
Validate -->|Valid| StartTx[Start MongoDB Transaction]
StartTx --> ProcessLines[Process Each Line]
ProcessLines --> CheckProduct{Product Exists?}
CheckProduct -->|No| Rollback[Rollback Transaction]
CheckProduct -->|Yes| CheckLocation{Location Exists?}
CheckLocation -->|No| Rollback
CheckLocation -->|Yes| CheckStock{Sufficient Stock?}
CheckStock -->|No| Rollback
CheckStock -->|Yes| UpdateProduct[Update Product Stock]
UpdateProduct --> CreateMovement[Create Movement Record]
CreateMovement --> LogAudit[Log Audit Entry]
LogAudit --> CommitTx[Commit Transaction]
CommitTx --> Success[Return Success Response]
Rollback --> Error
style Start fill:#e1f5ff
style Success fill:#90ee90
style Error fill:#ff6b6b
style Rollback fill:#ff6b6b
Odoo_StockMaster/
βββ backend/ # Node.js/Express backend
β βββ config/
β β βββ db.js # MongoDB connection
β βββ controllers/ # Request handlers
β β βββ authController.js
β β βββ dashboardController.js
β β βββ locationController.js
β β βββ movementController.js
β β βββ productController.js
β βββ middlewares/ # Express middlewares
β β βββ authMiddleware.js
β β βββ errorMiddleware.js
β β βββ rateLimitMiddleware.js
β β βββ roleMiddleware.js
β β βββ validateMiddleware.js
β βββ models/ # Mongoose models
β β βββ AuditLog.js
β β βββ Location.js
β β βββ Movement.js
β β βββ Product.js
β β βββ User.js
β βββ routes/ # API routes
β β βββ authRoutes.js
β β βββ dashboardRoutes.js
β β βββ locationRoutes.js
β β βββ movementRoutes.js
β β βββ productRoutes.js
β βββ services/ # Business logic
β β βββ auditService.js
β β βββ authService.js
β β βββ dashboardService.js
β β βββ inventoryService.js
β β βββ productService.js
β βββ scripts/ # Utility scripts
β β βββ seed.js # Database seeding
β β βββ setAdminPassword.js
β βββ tests/ # Test files
β β βββ inventoryFlows.test.js
β β βββ productModel.test.js
β β βββ setup.js
β βββ utils/ # Utility functions
β β βββ pagination.js
β β βββ response.js
β βββ app.js # Express app configuration
β βββ server.js # Server entry point
β βββ package.json
β
βββ Frontend/ # React frontend
βββ src/
β βββ components/ # Reusable components
β β βββ Layout.jsx
β β βββ MovementForm.jsx
β β βββ ProductForm.jsx
β β βββ ProductImportModal.jsx
β β βββ ProtectedRoute.jsx
β β βββ ui/ # UI components
β β βββ Button.jsx
β β βββ Card.jsx
β β βββ Input.jsx
β β βββ Modal.jsx
β βββ context/ # React Context
β β βββ AuthContext.jsx
β βββ hooks/ # Custom hooks
β β βββ useApi.js
β β βββ useAuth.js
β βββ lib/ # Utilities
β β βββ apiClient.js
β β βββ utils.js
β βββ pages/ # Page components
β β βββ Dashboard.jsx
β β βββ Products.jsx
β β βββ ProductDetails.jsx
β β βββ Locations.jsx
β β βββ Receipts.jsx
β β βββ Deliveries.jsx
β β βββ Transfers.jsx
β β βββ Adjustments.jsx
β β βββ Movements.jsx
β β βββ Debug.jsx
β β βββ Login.jsx
β β βββ Register.jsx
β β βββ ForgotPassword.jsx
β β βββ Profile.jsx
β βββ App.jsx # Main app component
β βββ main.jsx # Entry point
β βββ index.css
βββ vite.config.js
βββ tailwind.config.js
βββ package.json
- Node.js 18+ and npm
- MongoDB (local or cloud instance like MongoDB Atlas)
- Git
-
Clone the repository
git clone <repository-url> cd Odoo_StockMaster
-
Install Backend Dependencies
cd backend npm install -
Install Frontend Dependencies
cd ../Frontend npm install
-
Create
.envfile in thebackenddirectory:# Server PORT=4000 NODE_ENV=development # Database MONGO_URI=mongodb://localhost:27017/stockmaster # Or for MongoDB Atlas: # MONGO_URI=mongodb+srv://username:password@cluster.mongodb.net/stockmaster # JWT JWT_SECRET=your-super-secret-jwt-key-change-this-in-production JWT_EXPIRES_IN=7d # Email (for password reset - optional) SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASS=your-app-password
-
Start MongoDB (if using local instance)
# On Windows (if installed as service, it should auto-start) # On Linux/Mac: sudo systemctl start mongod # Or: mongod
-
Seed the database (optional but recommended)
cd backend node scripts/seed.js # Or with demo data: node scripts/seed.js --demo
The frontend is configured to connect to https://odoo-stockmaster-backend.onrender.com/api by default. To change this, edit Frontend/src/lib/apiClient.js:
const API_BASE_URL = 'http://your-backend-url/api';-
Start the Backend Server
cd backend npm run dev # Development mode with nodemon # Or: npm start # Production mode
The API will be available at
https://odoo-stockmaster-backend.onrender.com -
Start the Frontend Development Server
cd Frontend npm run devThe frontend will be available at
http://localhost:5173(or another port if 5173 is busy) -
Access the Application
- Open your browser and navigate to
http://localhost:5173 - Register a new account or use the seeded admin account
- Default admin (if seeded):
admin@stockmaster.test(password needs to be set via reset)
- Open your browser and navigate to
https://odoo-stockmaster-backend.onrender.com/api
All protected endpoints require a JWT token in the Authorization header:
Authorization: Bearer <token>
POST /api/auth/register - Register a new user
{
"name": "John Doe",
"email": "john@example.com",
"password": "securePassword123",
"role": "staff" // or "admin" (first user can be admin)
}POST /api/auth/login - Login
{
"email": "john@example.com",
"password": "securePassword123"
}Response includes token and user object.
GET /api/auth/me - Get current user (protected)
POST /api/auth/request-reset - Request password reset OTP
{
"email": "john@example.com"
}POST /api/auth/reset-password - Reset password with OTP
{
"email": "john@example.com",
"otp": "123456",
"newPassword": "newSecurePassword123"
}GET /api/products - List products (with pagination and search)
- Query params:
page,size,q(search term)
GET /api/products/:id - Get single product
POST /api/products (Admin only) - Create product
{
"name": "Steel Rods",
"sku": "SR-001",
"category": "Raw Material",
"uom": "kg",
"reorderLevel": 20
}PUT /api/products/:id (Admin only) - Update product
DELETE /api/products/:id (Admin only) - Soft delete product
POST /api/products/import (Admin only) - Import products from CSV
- Content-Type:
multipart/form-data - Field:
file(CSV file) - CSV format:
name,sku,category,uom,reorderLevel,locationCode,qty
GET /api/locations - List all locations
GET /api/locations/:id - Get single location
POST /api/locations (Admin only) - Create location
{
"name": "Main Warehouse",
"code": "MAIN",
"description": "Primary storage facility"
}PUT /api/locations/:id (Admin only) - Update location
DELETE /api/locations/:id (Admin only) - Delete location
GET /api/movements - List movements
- Query params:
limit,type,productId,locationId,status
POST /api/receipts - Create receipt (incoming stock)
{
"referenceId": "PO-001",
"note": "Vendor delivery",
"lines": [
{
"productId": "<productId>",
"qty": 100,
"toLocationId": "<locationId>"
}
]
}POST /api/deliveries - Create delivery (outgoing stock)
{
"referenceId": "SO-001",
"note": "Customer shipment",
"lines": [
{
"productId": "<productId>",
"qty": 10,
"fromLocationId": "<locationId>"
}
]
}POST /api/transfers - Create transfer (move between locations)
{
"referenceId": "TR-001",
"note": "Move to production",
"lines": [
{
"productId": "<productId>",
"qty": 20,
"fromLocationId": "<fromLocationId>",
"toLocationId": "<toLocationId>"
}
]
}POST /api/adjustments - Create adjustment (correct inventory)
{
"referenceId": "ADJ-001",
"note": "Physical count difference",
"lines": [
{
"productId": "<productId>",
"qty": -3, // Can be positive or negative
"toLocationId": "<locationId>"
}
]
}GET /api/dashboard - Get dashboard data
Returns:
totalProducts: Total number of active productstotalStock: Sum of all product quantitieslowStockItems: Array of products below reorder levelrecentMovements: Last 10 movements with populated data
GET /api/debug/state - Get complete inventory state
Returns:
perProduct: Stock breakdown by productperLocation: Stock breakdown by location
- Dashboard: Overview with KPIs, charts, low stock alerts, and recent movements
- Products: Product list with search, pagination, create/edit/delete, and CSV import
- Product Details: Detailed view showing stock per location, movement history
- Locations: Manage warehouse locations
- Receipts: Record incoming stock
- Deliveries: Record outgoing stock
- Transfers: Move stock between locations
- Adjustments: Correct inventory discrepancies
- Movements: View all inventory movements with filtering
- Debug: Admin-only view of complete inventory state
- Profile: User profile management
- Responsive Design: Works on desktop, tablet, and mobile
- Real-time Updates: React Query for efficient data fetching and caching
- Form Validation: Client-side validation with React Hook Form
- Error Handling: Comprehensive error handling with user-friendly messages
- Loading States: Loading indicators for better UX
- Toast Notifications: Success and error notifications
- Protected Routes: Authentication and role-based route protection
- Search & Filter: Advanced search and filtering capabilities
- Pagination: Efficient pagination for large datasets
cd backend
npm testTests use mongodb-memory-server and don't require a real database connection.
- Product model tests
- Inventory flow tests (receipts, deliveries, transfers, adjustments)
- Transaction integrity tests
- JWT Authentication: Secure token-based authentication
- Password Hashing: bcrypt for password security
- Rate Limiting: Protection against brute force attacks
- Input Validation: Server-side validation with express-validator
- CORS: Configurable CORS for API security
- Role-based Access Control: Admin and Staff roles
- Audit Logging: Complete audit trail of all operations
name,email,password,role(admin/staff)resetOtp,resetOtpExpiresAt(for password reset)
name,sku(unique),category,uom(unit of measure)reorderLevel,isActive(soft delete)locations: Array of{ location: ObjectId, qty: Number }totalQuantity: Auto-calculated from locationsversion: For optimistic locking
name,code(unique),description
type: receipt, delivery, transfer, adjustmentproduct,qty,fromLocation,toLocationcreatedBy,referenceId,status,notecreatedAt,updatedAt
user,action,entity,entityId,payloadcreatedAt
- Set environment variables in your hosting platform
- Ensure MongoDB is accessible (MongoDB Atlas recommended for production)
- Build and start:
npm start
-
Build for production:
cd Frontend npm run build -
Deploy the
distfolder to a static hosting service (Vercel, Netlify, etc.) -
Update
API_BASE_URLinapiClient.jsto point to your production backend
- Use strong
JWT_SECRET - Set
NODE_ENV=production - Use secure MongoDB connection string
- Configure CORS for your frontend domain
- Set up proper email service for password resets
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License.
-
MongoDB Connection Error
- Verify MongoDB is running
- Check
MONGO_URIin.env - Ensure network access if using MongoDB Atlas
-
Port Already in Use
- Change
PORTin backend.env - Update frontend
API_BASE_URLaccordingly
- Change
-
CORS Errors
- Verify CORS configuration in
backend/app.js - Check frontend URL matches allowed origins
- Verify CORS configuration in
-
JWT Token Errors
- Ensure
JWT_SECRETis set - Check token expiration
- Verify token format in Authorization header
- Ensure
StockMaster - Streamline your inventory management with modern technology.