Case Study

Inventory Management System

An enterprise military-grade inventory tracking platform for managing item nomenclatures, stock ledgers, voucher-based receipt/issue workflows, condemnation board proceedings, and a dual-role dashboard for HQ Master and Establishment units.

Defence-Grade Inventory Tracking

This system was built for a military establishment unit hierarchy. It enforces strict Master HQ / Establishment role separation, atomic MongoDB transactions for stock balance consistency, and real-time Socket.IO push events for ledger updates and condemnation approvals.

Core Feature Overview

📦

Stock Ledger Engine

Every stock movement (receipt, issue, condemnation, seeding) is recorded as an immutable StockLedger transaction with opening/closing balance tracking per item per establishment.

Complete Project Structure

root
Inventory management system/
backend/
src/
config/
db.js— Mongoose Atlas connection
passport.js— Passport.js JWT strategy
redis.js— Redis client (session caching)
socket.js— Socket.IO initialization
controllers/
analytics.controller.js— Role-aware dashboard KPIs
auth.controller.js— Login, refresh token, register
condemnation.controller.js— Board creation, approval, disposal
item.controller.js— Nomenclature CRUD with ledger folio
notification.controller.js— In-app notification management
report.controller.js— Excel export generation
user.controller.js— Establishment profile management
voucher.controller.js— Receipt/Issue voucher lifecycle
models/
Item.model.js— Item nomenclature with ledger folio
StockLedger.model.js— Immutable stock transaction records
Voucher.model.js— Receipt/Issue vouchers with status machine
Condemnation.model.js— Condemnation board proceedings
User.model.js— Master HQ and Establishment accounts
Notification.model.js— Real-time notification feed
ActivityLog.model.js— Security audit trail
RefreshToken.model.js— JWT refresh token store
middleware/
auth.middleware.js— Bearer JWT verification
rbac.middleware.js— Master / Establishment role guard
upload.middleware.js— Multer for voucher scan attachments
validate.middleware.js— Joi schema validation
rateLimiter.middleware.js— API rate limiting
socket/
index.js— JWT-auth + room join logic
handlers/
notification.handler.js— Push notification to user rooms
order.handler.js— Voucher status push events
product.handler.js— Stock level change push events
services/
auth.service.js— JWT access/refresh pair management
email.service.js— Nodemailer transports
seeders/
dbSeeder.js— Initial nomenclature and HQ user seeding
utils/
constants.js— VOUCHER_TYPES, VOUCHER_STATUS, ITEM_UNITS
ApiError.js— Standardized error class
ApiResponse.js— Standardized response wrapper
helpers.js— createActivityLog, balance helpers
server.js
frontend/
src/
features/— Redux Toolkit slices (items, vouchers, stock)
store/— RTK store + RTK Query API definitions

Stock Movement Lifecycle

1

Item Nomenclature Registration

Master HQ registers item nomenclatures with `ledgerFolio` numbers (the official military ledger reference IDs), unit of issue (Nos/Kg/Ltrs/Mtrs/Pairs/Sets/Rolls), and minimum stock level thresholds for low-stock alerting.
2

Initial Stock Seeding

The `dbSeeder.js` seeds the initial stock positions per establishment using `transactionType: 'seeding'` ledger entries. Each seed entry records `openingBalance: 0`, `quantity: initialQty`, and `closingBalance: initialQty`.
3

Voucher Submission

An Establishment unit submits a Receipt or Issue voucher with `voucherNo`, origin/destination, and an items array. The voucher is created with `status: 'pending'` and triggers a Socket.IO event to the Master HQ room.
4

HQ Voucher Approval

Master HQ reviews and approves the voucher. The controller runs a MongoDB transaction: for each voucher item, it reads the latest `StockLedger` balance, computes the new closing balance, creates a new `StockLedger` entry, and advances the voucher status to `approved`.
5

Condemnation Board

Establishments initiate condemnation boards for damaged/unserviceable items. The board lists presiding officer, board members, and condemned items with quantities. Stock availability is validated before allowing submission.
6

Condemnation Approval & Write-Off

Master HQ approves the condemnation board inside a MongoDB session transaction. Each condemned item's current balance is decremented in the `StockLedger` with `transactionType: 'condemnation'`. The board status advances to `approved` and disposal status is set.

MongoDB Data Models

StockLedger — Immutable Transaction Records

javascript
// backend/src/models/StockLedger.model.js
import mongoose from 'mongoose';

const stockLedgerSchema = new mongoose.Schema({
  item:           { type: mongoose.Schema.Types.ObjectId, ref: 'Item', required: true },
  establishment:  { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  openingBalance: { type: Number, required: true, min: 0 },
  quantity:       { type: Number, required: true }, // + for receipts, - for issues/condemnation
  closingBalance: { type: Number, required: true, min: 0 },
  transactionType: {
    type: String, required: true,
    enum: ['receipt', 'issue', 'condemnation', 'seeding']
  },
  voucherId: { type: mongoose.Schema.Types.ObjectId, ref: 'Voucher' },
  remarks:   { type: String, trim: true },
}, { timestamps: true });

stockLedgerSchema.index({ establishment: 1, item: 1 });
stockLedgerSchema.index({ createdAt: -1 });

Voucher Model — Receipt/Issue State Machine

javascript
// backend/src/models/Voucher.model.js
const voucherSchema = new mongoose.Schema({
  voucherNo:   { type: String, required: true, unique: true, trim: true },
  type:        { type: String, required: true, enum: Object.values(VOUCHER_TYPES) }, // 'receipt' | 'issue'
  date:        { type: Date, required: true, default: Date.now },
  origin:      { type: String, required: true, trim: true },      // Source unit/depot
  destination: { type: String, required: true, trim: true },      // Receiving unit
  items: [{
    item: { type: mongoose.Schema.Types.ObjectId, ref: 'Item', required: true },
    qty:  { type: Number, required: true, min: 1 },
    remarks: String,
    _id: false,
  }],
  status:      { type: String, enum: Object.values(VOUCHER_STATUS), default: 'pending' },
  submittedBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  approvedBy:  { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  approvedAt:  { type: Date },
  attachment:  { type: String },  // Local file path for scanned voucher copy
  remarks:     { type: String, trim: true },
}, { timestamps: true });

Condemnation Board — Atomic Approval Transaction

javascript
// backend/src/controllers/condemnation.controller.js
export const approveCondemnationBoard = asyncHandler(async (req, res) => {
  if (req.user.role !== USER_ROLES.MASTER)
    throw ApiError.forbidden('Only Master HQ can approve condemnation boards');

  const board = await Condemnation.findById(req.params.id);
  if (!board) throw ApiError.notFound('Condemnation board record not found');
  if (board.status !== 'pending') throw ApiError.badRequest(`Board status is already "${board.status}"`);

  const session = await mongoose.startSession();
  session.startTransaction();

  try {
    // Apply ledger decrements for each condemned item inside the transaction
    for (const itemObj of board.items) {
      const lastTx = await StockLedger.findOne({
        item: itemObj.item, establishment: board.establishment
      }).sort({ createdAt: -1 });

      const currentBal = lastTx ? lastTx.closingBalance : 0;
      const newBal = currentBal - itemObj.qty;

      if (newBal < 0) throw new Error(`Insufficient stock for condemned item: ${itemObj.item}`);

      await StockLedger.create([{
        item: itemObj.item, establishment: board.establishment,
        openingBalance: currentBal, quantity: -itemObj.qty, closingBalance: newBal,
        transactionType: 'condemnation',
        remarks: `Condemnation Board: ${board.boardNo}`,
      }], { session });
    }

    board.status         = 'approved';
    board.disposalStatus = 'Approved for Disposal';
    board.approvedBy     = req.user._id;
    await board.save({ session });

    await session.commitTransaction();

    // Notify via Socket.IO
    const io = getIO();
    if (io) {
      io.emit(SOCKET_EVENTS.CONDEMNATION_APPROVED, { boardId: board._id, boardNo: board.boardNo });
      io.emit(SOCKET_EVENTS.LEDGER_UPDATED, { establishmentId: board.establishment });
    }

    res.status(200).json(ApiResponse.success(board, 'Condemnation approved and items written-off from stock register'));
  } catch (err) {
    await session.abortTransaction();
    throw ApiError.internal(`Transaction failed: ${err.message}`);
  } finally {
    session.endSession();
  }
});

Role-Aware Dashboard Analytics

javascript
// backend/src/controllers/analytics.controller.js
export const getDashboardStats = asyncHandler(async (req, res) => {
  const { role, _id } = req.user;

  if (role === USER_ROLES.MASTER) {
    // HQ sees cross-establishment aggregates
    const nomenclatureCount    = await Item.countDocuments({ isActive: true });
    const establishmentCount   = await User.countDocuments({ role: 'establishment', isActive: true });
    const pendingVouchers      = await Voucher.countDocuments({ status: 'pending' });
    const pendingCondemnations = await Condemnation.countDocuments({ status: 'pending' });

    return res.json(ApiResponse.success({ summary: { nomenclatureCount, establishmentCount, pendingVouchers, pendingCondemnations } }));
  }

  // Establishment sees own unit stats
  const pendingVouchers = await Voucher.countDocuments({ submittedBy: _id, status: 'pending' });

  // Aggregate latest balances per item via running ledger
  const ledgerItems = await StockLedger.aggregate([
    { $match: { establishment: _id } },
    { $sort: { createdAt: -1 } },
    { $group: { _id: '$item', lastBalance: { $first: '$closingBalance' } } },
    { $match: { lastBalance: { $gt: 0 } } },
  ]);

  // Count items below minimum stock threshold
  let lowStockCount = 0;
  for (const { _id: itemId } of ledgerItems) {
    const item = await Item.findById(itemId);
    const lastTx = await StockLedger.findOne({ item: itemId, establishment: _id }).sort({ createdAt: -1 });
    if (lastTx && item && lastTx.closingBalance < item.minStockLevel) lowStockCount++;
  }

  res.json(ApiResponse.success({ pendingVouchers, stockItemsCount: ledgerItems.length, lowStockCount }));
});

Transaction Integrity

All stock-mutating operations (voucher approval, condemnation write-off) use `mongoose.startSession()` + `session.startTransaction()` to guarantee atomicity. If any part of the multi-item loop fails, the entire transaction is rolled back — ensuring ledger balances always remain consistent.