Skip to main content

Overview

SmartShelf implements a comprehensive user management system with role-based access control (RBAC). Administrators can create, update, and manage user accounts with three distinct roles, each having specific permissions and access levels.

Role-Based Access Control

The system supports three user roles with hierarchical permissions:

Admin

Full System Access
  • All Manager permissions
  • User management (CRUD)
  • System configuration
  • Complete data access

Manager

Operational Management
  • Inventory management
  • Task creation/assignment
  • Analytics & reports
  • FEFO & forecasting

Worker

Task Execution
  • View inventory
  • View assigned tasks
  • Update task status
  • Limited dashboard

Permission Matrix

Detailed permission breakdown from README.md:
FeatureAdminManagerWorker
Dashboard
Dashboard Overview
Inventory
View Inventory
Add/Edit Inventory
Delete Inventory
User Management
User Management
Tasks
Create Tasks
View All Tasks
View My Tasks--
Update Task Status✅ (own)
Analytics
View Analytics
FEFO Ordering
Demand Forecast

User CRUD Operations

Get All Users

Retrieve all users with filtering (userController.js:7-57):
GET /api/users?role=Worker&isActive=true&search=john&page=1&limit=10
Query Parameters:
  • role - Filter by role (Admin, Manager, Worker)
  • isActive - Filter by active status (true/false)
  • search - Search by name or email
  • page - Page number (default: 1)
  • limit - Items per page (default: 10)
Implementation:
exports.getAllUsers = async (req, res) => {
  const query = {};
  
  // Filter by role
  if (req.query.role) {
    query.role = req.query.role;
  }

  // Filter by active status
  if (req.query.isActive !== undefined) {
    query.isActive = req.query.isActive === 'true';
  }

  // Search by name or email
  if (req.query.search) {
    query.$or = [
      { name: { $regex: req.query.search, $options: 'i' } },
      { email: { $regex: req.query.search, $options: 'i' } }
    ];
  }

  const users = await User.find(query)
    .select('-password')  // Exclude password from response
    .sort({ createdAt: -1 });
};
Response:
{
  "users": [
    {
      "id": "673ab12c5f8e9a001234abcd",
      "name": "John Doe",
      "email": "[email protected]",
      "role": "Worker",
      "isActive": true,
      "createdAt": "2025-11-15T10:30:00.000Z"
    }
  ],
  "pagination": {
    "currentPage": 1,
    "totalPages": 3,
    "totalUsers": 25,
    "limit": 10
  }
}

Create User

Admins can create new user accounts (userController.js:86-127):
POST /api/users
Request Body:
{
  "name": "Jane Smith",
  "email": "[email protected]",
  "password": "SecurePass123!",
  "role": "Manager"
}
Implementation:
exports.createUser = async (req, res) => {
  const { name, email, password, role } = req.body;

  // Validation
  if (!name || !email || !password || !role) {
    return sendErrorResponse(res, 'Please provide all required fields', 400);
  }

  // Check if user already exists
  const existingUser = await User.findOne({ email: email.toLowerCase() });
  if (existingUser) {
    return sendErrorResponse(res, 'User with this email already exists', 400);
  }

  // Create user
  const user = await User.create({
    name,
    email: email.toLowerCase(),
    password,  // Automatically hashed by User model pre-save hook
    role
  });

  // Return user without password
  sendSuccessResponse(res, 'User created successfully', {
    user: user.toSafeObject()
  }, 201);
};
Validations:
  • All fields required (name, email, password, role)
  • Email must be unique
  • Email automatically converted to lowercase
  • Password automatically hashed using bcrypt
  • Role must be: Admin, Manager, or Worker
Passwords are automatically hashed using bcrypt before storage. Never store plain-text passwords.

Update User

Modify user account details (userController.js:132-181):
PUT /api/users/:id
Request Body:
{
  "name": "Jane Smith Updated",
  "email": "[email protected]",
  "role": "Admin",
  "isActive": true
}
Implementation:
exports.updateUser = async (req, res) => {
  const { name, email, role, isActive } = req.body;

  const user = await User.findById(req.params.id);

  if (!user) {
    return sendErrorResponse(res, 'User not found', 404);
  }

  // Update fields
  if (name) user.name = name;
  if (role) user.role = role;
  if (typeof isActive !== 'undefined') user.isActive = isActive;
  
  if (email) {
    // Check if email is already taken by another user
    const existingUser = await User.findOne({ 
      email: email.toLowerCase(),
      _id: { $ne: user._id }
    });
    
    if (existingUser) {
      return sendErrorResponse(res, 'Email already in use', 400);
    }
    
    user.email = email.toLowerCase();
  }

  await user.save();
};
Features:
  • Partial updates supported
  • Email uniqueness validation
  • Cannot set duplicate email
  • Active status toggle (enable/disable user)
  • Role changes allowed

Delete User

Remove user accounts (userController.js:186-212):
DELETE /api/users/:id
Implementation:
exports.deleteUser = async (req, res) => {
  const user = await User.findById(req.params.id);

  if (!user) {
    return sendErrorResponse(res, 'User not found', 404);
  }

  // Prevent admin from deleting themselves
  if (user._id.toString() === req.user.id) {
    return sendErrorResponse(res, 'You cannot delete your own account', 400);
  }

  await user.deleteOne();
};
Safety Features:
  • Admins cannot delete their own account
  • Deletion is permanent (no soft delete)
  • Associated tasks remain but show “Unknown” worker
Consider implementing soft delete (isActive: false) instead of permanent deletion to preserve audit trails.

User Management UI

User List Table

Comprehensive user management interface (UserManagementPage.tsx:110-254):
<table className="w-full text-left">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Role</th>
      <th>Actions</th>
    </tr>
  </thead>
  <tbody>
    {users.map(user => (
      <tr key={user.id}>
        <td className="font-medium">{user.name}</td>
        <td className="text-slate-500">{user.email}</td>
        <td>
          <span className={getRoleBadgeColor(user.role)}>
            {user.role}
          </span>
        </td>
        <td className="flex space-x-2 justify-end">
          <button onClick={() => handleEdit(user)}>
            <Edit className="w-5 h-5" />
          </button>
          <button onClick={() => handleDelete(user.id)}>
            <Delete className="w-5 h-5" />
          </button>
        </td>
      </tr>
    ))}
  </tbody>
</table>

Role Badge Colors

Color-coded role indicators:
const getRoleBadgeColor = (role: string) => {
  if (role === 'Admin') {
    return 'bg-red-100 text-red-800 dark:bg-red-900/50 dark:text-red-300';
  } else if (role === 'Manager') {
    return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/50 dark:text-yellow-300';
  } else {
    return 'bg-blue-100 text-blue-800 dark:bg-blue-900/50 dark:text-blue-300';
  }
};

Add/Edit User Form

Modal form for user creation/editing (UserManagementPage.tsx:7-108):
const AddEditUserForm: React.FC<{ 
  user: User | null; 
  onSave: (userData: any) => void; 
  onCancel: () => void; 
}> = ({ user, onSave, onCancel }) => {
  const [formData, setFormData] = useState({
    name: user?.name || '',
    email: user?.email || '',
    role: user?.role || 'Worker',
    password: '',  // Only for new users
  });

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="name" required />
      <input type="email" name="email" required />
      
      {!user && (
        <input 
          type="password" 
          name="password" 
          required={!user}
          minLength={6}
          placeholder="Minimum 6 characters"
        />
      )}
      
      <select name="role">
        <option value="Admin">Admin</option>
        <option value="Manager">Manager</option>
        <option value="Worker">Worker</option>
      </select>
    </form>
  );
};
Form Features:
  • Password field only shown for new users
  • Email validation
  • Minimum password length: 6 characters
  • Role dropdown with all three options
  • Loading states during save

User Statistics

Get user account statistics (userController.js:240-271):
GET /api/users/stats
Response:
{
  "stats": {
    "totalUsers": 45,
    "activeUsers": 42,
    "inactiveUsers": 3,
    "byRole": {
      "Admin": 2,
      "Manager": 8,
      "Worker": 35
    }
  }
}
Implementation:
exports.getUserStats = async (req, res) => {
  const totalUsers = await User.countDocuments();
  const activeUsers = await User.countDocuments({ isActive: true });
  const inactiveUsers = await User.countDocuments({ isActive: false });
  
  const usersByRole = await User.aggregate([
    {
      $group: {
        _id: '$role',
        count: { $sum: 1 }
      }
    }
  ]);

  const stats = {
    totalUsers,
    activeUsers,
    inactiveUsers,
    byRole: usersByRole.reduce((acc, item) => {
      acc[item._id] = item.count;
      return acc;
    }, {})
  };
};

Authentication Integration

User management integrates with JWT authentication:

Password Security

Passwords are hashed using bcrypt:
// User model pre-save hook
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

Safe User Object

Exclude password from responses:
userSchema.methods.toSafeObject = function() {
  const obj = this.toObject();
  delete obj.password;
  return obj;
};

Access Control Middleware

Role-based route protection:
// Admin-only routes
router.get('/users', authMiddleware, roleMiddleware(['Admin']), getAllUsers);
router.post('/users', authMiddleware, roleMiddleware(['Admin']), createUser);

// Manager/Admin routes
router.post('/tasks', authMiddleware, roleMiddleware(['Manager', 'Admin']), createTask);

// All authenticated users
router.get('/inventory', authMiddleware, getAllInventory);

Active Status Management

Enable/Disable Users

Toggle user active status without deletion:
// Disable user
PUT /api/users/:id
{
  "isActive": false
}

// Enable user
PUT /api/users/:id
{
  "isActive": true
}
Effects of Disabled Status:
  • User cannot log in
  • Existing sessions invalidated
  • Cannot be assigned new tasks
  • Existing task assignments remain
  • User data preserved for audit trails

Best Practices

  • Minimum 6 characters (consider increasing to 8+)
  • Encourage strong passwords with:
    • Uppercase and lowercase letters
    • Numbers
    • Special characters
  • Implement password complexity validation
  • Consider password expiration policies
Onboarding:
  1. Create user account with Worker role
  2. Send welcome email with login credentials
  3. Assign initial training tasks
  4. Monitor first-week activity
Offboarding:
  1. Disable account (set isActive: false)
  2. Reassign active tasks to other workers
  3. Archive user data for compliance
  4. Keep account for audit purposes
  • Start new users as Workers
  • Promote to Manager after proven competence
  • Limit Admin accounts to 2-3 key personnel
  • Regular review of role assignments
  • Document role change reasons
  • Never share Admin credentials
  • Regularly audit user access logs
  • Disable inactive accounts after 90 days
  • Implement two-factor authentication (future)
  • Monitor for suspicious login attempts

User Model Schema

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    trim: true
  },
  password: {
    type: String,
    required: true,
    minlength: 6
  },
  role: {
    type: String,
    enum: ['Admin', 'Manager', 'Worker'],
    default: 'Worker'
  },
  isActive: {
    type: Boolean,
    default: true
  }
}, {
  timestamps: true  // Adds createdAt and updatedAt
});

API Summary

MethodEndpointDescriptionAccess
GET/api/usersGet all usersAdmin
GET/api/users/:idGet user by IDAdmin
POST/api/usersCreate userAdmin
PUT/api/users/:idUpdate userAdmin
DELETE/api/users/:idDelete userAdmin
GET/api/users/workersGet active workersManager/Admin
GET/api/users/statsGet user statisticsAdmin

Task Management

Assign tasks to workers

Analytics Dashboard

Role-based dashboards

Authentication

Login and JWT tokens

User Management API

User endpoints and permissions

Build docs developers (and LLMs) love