1. Overview

The SKU Management module is a comprehensive inventory management system within the Nimbly Audit Admin platform. It provides functionality for creating, editing, bulk uploading, and managing Stock Keeping Units (SKUs) across multiple sites. The module integrates with the broader inventory management and stock audit scheduling features.

2. Architecture

2.1 High-Level Architecture

graph TB
    subgraph "Frontend Layer"
        A[SKU Management Pages] --> B[Components]
        B --> C[Redux Store]
        C --> D[API Layer]
    end
    
    subgraph "Backend Services"
        D --> E[SKU Service]
        D --> F[Stock Audit Service]
        D --> G[Site Service]
    end
    
    subgraph "Data Layer"
        E --> H[(SKU Database)]
        F --> I[(Audit Database)]
        G --> J[(Site Database)]
    end

3. Routing Structure

The SKU Management module utilizes React Router for navigation with the following route hierarchy:

Route PathComponentPurposeAccess Control
/admin/skuManagementSkuManagementPageMain SKU listing and management interfaceRoleResources.ADMIN_INVENTORY_ALL
/admin/skuManagement/newSingleSkuCreatePageCreate individual SKURoleResources.ADMIN_INVENTORY_ALL
/admin/skuManagement/bulkUploadBatchSkuCreatePageBulk SKU upload via CSV/ExcelRoleResources.ADMIN_INVENTORY_ALL
/admin/skuManagement/:idSingleSkuEditPageEdit existing SKURoleResources.ADMIN_INVENTORY_ALL
Route PathComponentPurposeAccess Control
/admin/stockAuditSchedulerStockAuditSchedulerPageSchedule stock auditsRoleResources.ADMIN_STOCKAUDIT_SCHEDULER_ALL
/admin/stockAuditScheduler/newStockAuditScheduleCreatePageCreate audit scheduleRoleResources.ADMIN_STOCKAUDIT_SCHEDULER_ALL
/admin/stockAuditScheduler/:idStockAuditScheduleEditPageEdit audit scheduleRoleResources.ADMIN_STOCKAUDIT_SCHEDULER_ALL

3.2 Route Configuration

All SKU Management routes are protected with:

  • Feature Flag: Features.INVENTORY_MANAGEMENT
  • Role-based Access: Requires inventory management permissions
  • Validation: Routes use withValidation HOC for access control

4. Components

4.1 Component Hierarchy

graph TB
    subgraph "Page Components"
        A[SkuManagementPage] --> B[SkuManagement]
        C[SingleSkuCreatePage] --> D[SingleSkuCreate]
        E[SingleSkuEditPage] --> F[SingleSkuEdit]
        G[BatchSkuCreatePage] --> H[BatchSkuCreate]
    end
    
    subgraph "Core Components"
        B --> I[SkuSearch]
        B --> J[SkuFilter]
        B --> K[SkuTable]
        D --> L[SingleSkuForm]
        F --> L
        H --> M[BatchSkuForm]
    end
    
    subgraph "Supporting Components"
        K --> N[SkuTableRowActionMenu]
        J --> O[FilterDrawer]
        L --> P[FormComponents]
    end

4.2 Main Components

4.2.1 SkuManagement Component

Location: src/components/skuManagement/SkuManagement.tsx

Purpose: Main SKU listing interface with search, filter, and management capabilities

Key Features:

  • Paginated SKU listing with customizable page size (10, 25, 50, 100 items)
  • Real-time search functionality
  • Advanced filtering by category, site, and unit of measure
  • Dropdown menu for single/bulk SKU creation
  • Empty state handling with appropriate messaging
  • Google Analytics integration for usage tracking

State Management:

  • Redux selectors: selectIsFilterActive, selectIsSkuEmpty, selectIsSkuNotFound, selectIsStateLoading
  • Redux state: skus, pageIndex, totalSkus, limit

4.2.2 SingleSkuCreate Component

Location: src/components/skuManagement/SingleSkuCreate.tsx

Purpose: Create individual SKUs with detailed form validation

Form Fields:

FieldTypeValidationDescription
skuNameTextRequired, Max 60 chars, No emojisDisplay name of the SKU
skuIdTextRequired, Max 50 chars, Alphanumeric onlyUnique identifier
descriptionTextareaOptional, Max 250 charsAdditional details
categoryCreatable SelectRequiredProduct category (can create new)
unitOfMeasureSelectRequiredUnit type (e.g., piece, kg, liter)
sitesMulti-SelectRequiredAssociated store locations
lowStockThresholdNumberRequired, Min 0Inventory alert threshold

Validation Logic:

  • Formik with Yup schema validation
  • Real-time field validation
  • Custom emoji detection and prevention
  • SKU ID uniqueness verification

4.2.3 SingleSkuEdit Component

Location: src/components/skuManagement/SingleSkuEdit.tsx

Purpose: Edit existing SKUs with change tracking

Key Features:

  • Change detection algorithm (only sends modified fields)
  • Preserves existing site-specific data (prices, counts)
  • Delete functionality with confirmation modal
  • Loading states during data fetch and save
  • Error handling with user-friendly messages

Business Logic:

// Change detection logic
const changedValues = Object.keys(values).reduce((acc, key) => {
  if (values[key] !== originalValues[key]) {
    acc[key] = values[key];
  }
  return acc;
}, {});

4.2.4 BatchSkuCreate Component

Location: src/components/skuManagement/BatchSkuCreate.tsx

Purpose: Bulk SKU upload via Excel template

Workflow:

  1. Download pre-formatted Excel template
  2. Fill template with SKU data
  3. Upload completed template
  4. Process batch with error handling

Error Handling:

  • File type validation (xlsx only)
  • Row-level error reporting
  • Error modal with detailed messages
  • Batch processing status updates

4.3 Supporting Components

4.3.1 SkuTable Component

Features:

  • Sortable columns (name, UOM, onHand quantity)
  • Clickable site availability indicators
  • Row action menu for editing
  • Modal display for detailed site information
  • Responsive design for mobile/desktop

4.3.2 SkuFilter Component

Filter Options:

  • Categories (multi-select)
  • Sites (multi-select with search)
  • Units of Measure (multi-select)
  • Apply/Reset functionality
  • Mobile drawer and desktop dropdown views

4.3.3 SkuSearch Component

Features:

  • Real-time search as you type
  • Debounced API calls
  • Search across SKU name and ID
  • Clear search functionality

5. Features

5.1 SKU Listing and Management

5.1.1 Pagination System

The SKU listing implements a robust pagination system with the following characteristics:

Page Size Options: 10, 25, 50, 100 items per page Navigation: Previous/Next buttons with current page indicator Total Count Display: Shows current range and total SKUs (e.g., “1-10 of 150”)

Implementation Logic:

// Pagination state management
const pageIndex = useSelector(selectPageIndex);
const limit = useSelector(selectLimit);
const totalSkus = useSelector(selectTotalSkus);
 
// Calculate display range
const startRange = pageIndex * limit + 1;
const endRange = Math.min((pageIndex + 1) * limit, totalSkus);

5.1.2 Search Functionality

Search Capabilities:

  • Real-time search with debouncing (300ms delay)
  • Searches across SKU name and SKU ID fields
  • Case-insensitive matching
  • Preserves search state during navigation

Search Flow:

sequenceDiagram
    participant User
    participant SearchComponent
    participant Redux
    participant API
    
    User->>SearchComponent: Type search query
    SearchComponent->>SearchComponent: Debounce (300ms)
    SearchComponent->>Redux: Dispatch search action
    Redux->>API: GET /skus?search=query
    API-->>Redux: Return filtered results
    Redux-->>SearchComponent: Update SKU list

5.1.3 Advanced Filtering

Filter Categories:

  1. Category Filter

    • Multi-select dropdown
    • Dynamic category list from API
    • “All Categories” option for quick selection
  2. Site Filter

    • Multi-select with search
    • Shows site name and code
    • Hierarchical site structure support
  3. Unit of Measure Filter

    • Multi-select dropdown
    • Standard UOM list (piece, kg, liter, etc.)
    • Custom UOM support

Filter State Management:

// Redux filter state
{
  filters: {
    categories: ['category1', 'category2'],
    sites: ['site1', 'site2'],
    uoms: ['piece', 'kg']
  },
  isFilterActive: true
}

Filter Persistence:

  • Filters remain active during navigation
  • Clear all filters option available
  • Filter count badge on filter button

5.2 SKU Creation Workflows

5.2.1 Single SKU Creation

Process Flow:

graph LR
    A[Click Add SKU] --> B[Select Single SKU]
    B --> C[Fill Form]
    C --> D{Validate}
    D -->|Valid| E[Submit to API]
    D -->|Invalid| F[Show Errors]
    E --> G[Success Message]
    G --> H[Redirect to List]
    F --> C

Form Validation Rules:

FieldRuleError Message
SKU NameNo emojis, Max 60 chars”Emojis are not allowed”
SKU IDAlphanumeric only, Max 50 chars”Only letters and numbers allowed”
SKU IDUnique check”SKU ID already exists”
Low StockMin 0”Must be 0 or greater”
SitesAt least 1 selected”Select at least one site”

Success Handling:

  • Toast notification with success message
  • Automatic redirect to SKU list
  • New SKU appears at top of list

5.2.2 Bulk SKU Upload

Template Structure: The Excel template includes the following columns:

  • SKU Name (required)
  • SKU ID (required, unique)
  • Description (optional)
  • Category (required)
  • Unit of Measure (required)
  • Sites (required, comma-separated)
  • Low Stock Threshold (required)

Upload Process:

stateDiagram-v2
    [*] --> DownloadTemplate
    DownloadTemplate --> FillTemplate
    FillTemplate --> UploadFile
    UploadFile --> Validating
    Validating --> Success: All rows valid
    Validating --> PartialSuccess: Some rows valid
    Validating --> Error: All rows invalid
    Success --> [*]
    PartialSuccess --> ShowErrors
    Error --> ShowErrors
    ShowErrors --> FillTemplate: Fix and retry

Error Handling:

  • Row-level validation with specific error messages
  • Error modal shows affected rows and issues
  • Option to download error report
  • Partial success handling (valid rows processed)

5.3 SKU Editing

5.3.1 Change Detection Algorithm

The edit component implements smart change detection to optimize API calls:

// Only send changed fields to API
const getChangedValues = (original, current) => {
  const changes = {};
  Object.keys(current).forEach(key => {
    if (JSON.stringify(original[key]) !== JSON.stringify(current[key])) {
      changes[key] = current[key];
    }
  });
  return changes;
};

Editable Fields:

  • SKU Name
  • Description
  • Category
  • Sites (add/remove)
  • Low Stock Threshold

Non-Editable Fields:

  • SKU ID (immutable after creation)
  • Unit of Measure (requires data migration)
  • Created Date
  • Created By

5.3.2 Delete Functionality

Delete Process:

  1. Click delete button
  2. Confirmation modal appears
  3. Enter SKU name for confirmation
  4. API call to soft delete
  5. Success message and redirect

Delete Restrictions:

  • Cannot delete SKUs with active stock
  • Cannot delete SKUs in active audits
  • Requires special permission (ADMIN_INVENTORY_DELETE)

5.4 Stock Audit Integration

5.4.1 Audit Scheduling

SKU Selection for Audits:

  • Filter SKUs by site
  • Multi-select SKUs for audit
  • Bulk select all visible SKUs
  • Search within selection

Audit Frequency Options:

  • Daily
  • Weekly (select days)
  • Monthly (select date)
  • Custom schedule

5.4.2 Audit Reporting

SKU Metrics in Audits:

  • Current stock level
  • Expected stock level
  • Variance calculation
  • Variance percentage
  • Historical trends

6. API Endpoints

6.1 Base Configuration

ConfigurationValueSource
API Base URLprocess.env.REACT_APP_CLOUD_API_URLsrc/config/baseURL.ts
AuthenticationFirebase ID TokenBearer token in Authorization header
Content Typeapplication/jsonDefault for all endpoints

6.2 SKU Management Endpoints

6.2.1 Core CRUD Operations

OperationMethodEndpointRequest BodyResponseFile
Create SKUPOST/skusCreateSkuRequestSKU ID (string)src/services/sku/sku.service.ts
Get SKUGET/skus/{id}-FindBySKUIDResponsesrc/services/sku/sku.service.ts
Update SKUPATCH/skus/{id}UpdateSkuRequestUpdated SKU objectsrc/services/sku/sku.service.ts
Delete SKUDELETE/skus/{id}-voidsrc/services/sku/sku.service.ts

6.2.2 Search and List Operations

OperationMethodEndpointQuery ParametersResponseFile
Search SKUsGET/skus/searchpage, limit, sortFields, sortDirections, search, withDisabled, categories[], siteIDs[], uoms[]Paginated SKU listsrc/sagas/skuManagement/skus.actionSaga.ts
Fetch All SKUs (Compact)GET/skus/props=skuID&props=name&withDisabled=falseMinimal SKU datasrc/sagas/skuManagement/skus.actionSaga.ts
Fetch SKUs by SiteGET/skus/compactsiteID={siteID}FindSKUPerCategorysrc/services/sku/sku.service.ts

6.2.3 Settings and Metadata

OperationMethodEndpointRequest BodyResponseFile
Get CategoriesGET/skus/sku-settings/categories-Array of category stringssrc/services/sku/sku.service.ts
Create CategoryPOST/skus/sku-settings/categories{ category: string }Created category namesrc/services/sku/sku.service.ts
Get UOMsGET/miscellaneous/uoms-Array of UOM objectssrc/services/sku/sku.service.ts

6.2.4 Bulk Operations

OperationMethodEndpointRequest BodyResponseFile
Download TemplateGET/skus/bulk-upload-Template file datasrc/services/sku/sku.service.ts
Upload BatchPOST/skus/bulk-uploadFormData with filevoidsrc/services/sku/sku.service.ts

6.3 Request/Response Examples

6.3.1 Create SKU Request

interface CreateSkuRequest {
  skuId: string;
  name: string;
  description?: string;
  category: string;
  unitOfMeasure: string;
  sites: string[];
  lowStockThreshold: number;
}

6.3.2 Update SKU Request

interface UpdateSkuRequest {
  name?: string;
  description?: string;
  category?: string;
  sites?: string[];
  lowStockThreshold?: number;
}

6.3.3 Search Response Structure

interface SearchResponse {
  data: {
    skus: SKU[];
    totalCount: number;
    page: number;
    limit: number;
  };
}

6.4 Error Handling

6.4.1 Custom Error Classes

SkuApiError

  • Used for general SKU API errors
  • Contains error message and status code
  • Thrown on non-2xx responses

BatchUploadSkuError

  • Specific to bulk upload operations
  • Contains row-level error details
  • Includes affected row numbers and error messages

6.4.2 Error Response Format

interface ErrorResponse {
  error: {
    code: string;
    message: string;
    details?: {
      row?: number;
      field?: string;
      value?: any;
    }[];
  };
}

6.5 API Integration Patterns

6.5.1 Redux-Saga Flow

sequenceDiagram
    participant Component
    participant Redux
    participant Saga
    participant API
    participant Backend
    
    Component->>Redux: Dispatch action
    Redux->>Saga: Handle action
    Saga->>API: Call service method
    API->>Backend: HTTP request
    Backend-->>API: Response
    API-->>Saga: Parsed response
    Saga->>Redux: Dispatch success/failure
    Redux-->>Component: Update state

6.5.2 Authentication Flow

All API calls include Firebase authentication:

const getAuthHeaders = async () => {
  const token = await firebase.auth().currentUser?.getIdToken();
  return {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  };
};

7. Data Models

7.1 Core SKU Entity

The primary SKU interface from @nimbly-technologies/nimbly-common:

interface SKU {
    _id: string;                    // MongoDB ObjectID
    skuID: string;                  // Unique identifier (user-defined)
    name: string;                   // Display name
    organizationID: string;         // Parent organization
    description: string;            // Optional description
    categories: string[];           // Array of category tags
    uom: string;                    // Unit of Measure reference
    sites: SiteSKUDetail[];         // Site-specific details
    threshold: number;              // Low stock threshold value
    thresholdType: string;          // 'percentage' or 'number'
    updatedAt: Date;                // Last modification timestamp
    updatedBy: string;              // User who last modified
    createdAt: Date;                // Creation timestamp
    createdBy: string;              // User who created
    disabled: boolean;              // Soft delete flag
}

7.2 Site-Specific SKU Details

Each SKU can have different configurations per site:

interface SiteSKUDetail {
    siteID: string;                 // Reference to site
    price: number;                  // Site-specific price
    count: number;                  // Current stock count
    disabled: boolean;              // Site-specific disable flag
}

7.3 Entity Relationships

erDiagram
    Organization ||--o{ SKU : contains
    SKU ||--o{ SiteSKUDetail : has
    Site ||--o{ SiteSKUDetail : references
    SKU }o--|| Category : belongs_to
    SKU }o--|| UOM : measured_by
    
    SKU {
        string id
        string skuID
        string name
        string description
        string[] categories
        string uom
        number threshold
        string thresholdType
    }
    
    SiteSKUDetail {
        string siteID
        number price
        number count
        boolean disabled
    }
    
    Category {
        string name
    }
    
    UOM {
        string name
        string abbr
    }

7.4 SKU Variants

7.4.1 SKUCompact

Used for dropdowns and lists where full details aren’t needed:

interface SKUCompact {
    _id: string;
    skuID: string;
    name: string;
    uom: string;
    threshold: number;
}

7.4.2 OrganizationSKU

Extended SKU with additional features:

class OrganizationSKU {
    photoURLs: string[];            // Product images
    tags: SKUTag;                   // Custom tags
    maxLimit: number;               // Maximum stock limit
    unit: BaseMeasure;              // Detailed unit type
    batches: { [key: string]: OrganizationSKUBatch };
    sites: { [siteKey: string]: boolean };  // Site mapping
}

7.4.3 SiteSKU

Site-level SKU tracking:

interface SiteSKU {
    skuKey: string;                 // Reference to parent SKU
    siteKey: string;                // Reference to site
    price: number;                  // Site-specific price
    stock: number;                  // Current stock level
    threshold: number;              // Alert threshold
    thresholdType: 'percentage' | 'number';
    batches: { [key: string]: SiteSKUBatch };
}

7.5 Supporting Types

7.5.1 Unit of Measure (UOM)

interface UOM {
    name: string;                   // Full name (e.g., "Kilogram")
    abbr: string;                   // Abbreviation (e.g., "kg")
}
 
type BaseMeasure = 'kg' | 'gr' | 'ltr' | 'ml' | 'can' | 'btl' | 'scht' | 
                   'pck' | 'pcs' | 'drj' | 'pail' | 'jar' | 'pch' | 'bag' | 
                   'book' | 'box' | 'case' | 'ctn' | 'ea' | 'gal' | 'pair' | 
                   'set' | 'sheet' | 'tank' | 'tin' | 'tub' | 'psc' | 'roll';

7.5.2 Category Types

interface QuestionCategory {
    organizationID: string;
    tag: string;                    // Internal identifier
    label: string;                  // Display name
    status: 'active' | 'disabled' | '' | undefined;
}
 
type FindSKUPerCategory = {
    category: string;
    skus: SKUCompact[];
}[];

7.5.3 Form Types

interface SingleSkuFormValues {
    skuName: string;
    skuId: string;
    description?: string;
    category: string;
    unitOfMeasure: string;
    sites: string[];
    lowStockThreshold: number | null;
}

7.6 Data Validation Rules

7.6.1 Field Constraints

FieldTypeMax LengthPatternRequired
skuIDstring50Alphanumeric onlyYes
namestring60No emojisYes
descriptionstring250-No
thresholdnumber->= 0Yes
pricenumber->= 0Yes

7.6.2 Business Rules

  1. SKU ID Uniqueness: Must be unique within organization
  2. Site Assignment: At least one site must be assigned
  3. Category Requirement: Must belong to at least one category
  4. UOM Immutability: Cannot be changed after creation
  5. Soft Delete: SKUs are never hard deleted, only disabled
  6. Threshold Types: Can be either percentage (0-100) or absolute number

8. Business Logic

8.1 Stock Management Calculations

8.1.1 Low Stock Threshold Calculation

The system supports two types of threshold calculations:

1. Absolute Number Threshold

const isLowStock = (currentStock, threshold) => {
  return currentStock <= threshold;
};

2. Percentage Threshold

const isLowStock = (currentStock, maxStock, thresholdPercentage) => {
  const thresholdValue = (maxStock * thresholdPercentage) / 100;
  return currentStock <= thresholdValue;
};

8.1.2 Stock Variance Calculation

Used in stock audits to measure discrepancies:

const calculateVariance = (expected, actual) => {
  const variance = actual - expected;
  const variancePercentage = expected !== 0 
    ? ((variance / expected) * 100).toFixed(2) 
    : 0;
  
  return {
    variance,
    variancePercentage,
    status: getVarianceStatus(variancePercentage)
  };
};
 
const getVarianceStatus = (percentage) => {
  if (Math.abs(percentage) <= 5) return 'acceptable';
  if (Math.abs(percentage) <= 10) return 'warning';
  return 'critical';
};

8.2 Site-Specific SKU Management

8.2.1 Multi-Site Price Management

Each SKU can have different prices across sites:

const updateSitePrice = (sku, siteId, newPrice) => {
  const siteDetail = sku.sites.find(s => s.siteID === siteId);
  if (siteDetail) {
    siteDetail.price = newPrice;
  } else {
    sku.sites.push({
      siteID: siteId,
      price: newPrice,
      count: 0,
      disabled: false
    });
  }
};

8.2.2 Site Assignment Logic

flowchart TD
    A[Add Site to SKU] --> B{Site Already Assigned?}
    B -->|Yes| C[Update Existing Entry]
    B -->|No| D[Create New Entry]
    C --> E[Set Default Values]
    D --> E
    E --> F[Price = 0]
    E --> G[Count = 0]
    E --> H[Disabled = false]

8.3 Category Management

8.3.1 Dynamic Category Creation

Categories can be created on-the-fly during SKU creation:

const handleCategoryCreation = async (inputValue) => {
  // Check if category exists
  const existingCategory = categories.find(
    cat => cat.toLowerCase() === inputValue.toLowerCase()
  );
  
  if (existingCategory) {
    return existingCategory;
  }
  
  // Create new category
  const newCategory = await createSkuCategory(inputValue);
  return newCategory;
};

8.3.2 Category Filtering Logic

const filterSkusByCategory = (skus, selectedCategories) => {
  if (selectedCategories.length === 0) return skus;
  
  return skus.filter(sku => 
    sku.categories.some(category => 
      selectedCategories.includes(category)
    )
  );
};

8.4 Bulk Upload Processing

8.4.1 Template Generation Logic

const generateBulkTemplate = () => {
  const headers = [
    'SKU Name*',
    'SKU ID*',
    'Description',
    'Category*',
    'Unit of Measure*',
    'Sites* (comma-separated)',
    'Low Stock Threshold*'
  ];
  
  const exampleRow = [
    'Product Name',
    'PROD001',
    'Product description',
    'Electronics',
    'piece',
    'SITE001,SITE002',
    '10'
  ];
  
  return { headers, exampleRow };
};

8.4.2 Bulk Validation Process

stateDiagram-v2
    [*] --> ValidateHeaders
    ValidateHeaders --> ValidateRows: Headers Valid
    ValidateHeaders --> Error: Headers Invalid
    
    ValidateRows --> ValidateSkuId: For Each Row
    ValidateSkuId --> ValidateRequiredFields
    ValidateRequiredFields --> ValidateSites
    ValidateSites --> ValidateDataTypes
    ValidateDataTypes --> RowValid
    
    RowValid --> NextRow: More Rows
    RowValid --> ProcessBatch: All Rows Valid
    
    NextRow --> ValidateSkuId
    ProcessBatch --> [*]

8.5 Search and Filter Optimization

8.5.1 Search Algorithm

The search functionality implements a multi-field search:

const searchSKUs = (skus, searchTerm) => {
  const term = searchTerm.toLowerCase();
  
  return skus.filter(sku => {
    const matchesName = sku.name.toLowerCase().includes(term);
    const matchesId = sku.skuID.toLowerCase().includes(term);
    const matchesDescription = sku.description?.toLowerCase().includes(term);
    
    return matchesName || matchesId || matchesDescription;
  });
};

8.5.2 Filter Combination Logic

Multiple filters are combined using AND logic:

const applyFilters = (skus, filters) => {
  let filtered = [...skus];
  
  // Category filter
  if (filters.categories?.length > 0) {
    filtered = filtered.filter(sku =>
      sku.categories.some(cat => filters.categories.includes(cat))
    );
  }
  
  // Site filter
  if (filters.siteIDs?.length > 0) {
    filtered = filtered.filter(sku =>
      sku.sites.some(site => 
        filters.siteIDs.includes(site.siteID) && !site.disabled
      )
    );
  }
  
  // UOM filter
  if (filters.uoms?.length > 0) {
    filtered = filtered.filter(sku =>
      filters.uoms.includes(sku.uom)
    );
  }
  
  return filtered;
};

8.6 Inventory Analytics

8.6.1 Stock Level Aggregation

const calculateTotalStock = (sku) => {
  return sku.sites.reduce((total, site) => {
    return site.disabled ? total : total + site.count;
  }, 0);
};
 
const calculateAveragePrice = (sku) => {
  const activeSites = sku.sites.filter(site => !site.disabled);
  if (activeSites.length === 0) return 0;
  
  const totalPrice = activeSites.reduce((sum, site) => sum + site.price, 0);
  return (totalPrice / activeSites.length).toFixed(2);
};

8.6.2 Inventory Value Calculation

const calculateInventoryValue = (skus) => {
  return skus.reduce((totalValue, sku) => {
    const skuValue = sku.sites.reduce((sum, site) => {
      return site.disabled ? sum : sum + (site.count * site.price);
    }, 0);
    return totalValue + skuValue;
  }, 0);
};

8.7 Performance Optimizations

8.7.1 Lazy Loading Strategy

// Components use React.lazy for code splitting
const SingleSkuCreate = lazy(() => 
  import('../../components/skuManagement/SingleSkuCreate')
);
 
// Data is paginated to reduce load
const DEFAULT_PAGE_SIZE = 25;
const MAX_PAGE_SIZE = 100;
const useDebounce = (value, delay = 300) => {
  const [debouncedValue, setDebouncedValue] = useState(value);
  
  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
    
    return () => clearTimeout(handler);
  }, [value, delay]);
  
  return debouncedValue;
};

9. Dependencies

9.1 Core Dependencies

PackageVersionPurpose
react^17.xCore React library
react-dom^17.xReact DOM rendering
react-router-dom^5.xRouting and navigation
redux^4.xState management
react-redux^7.xReact Redux bindings
redux-saga^1.xSide effects management

9.2 UI/UX Dependencies

PackageVersionPurpose
formik^2.xForm state management
yup^0.xSchema validation
react-select^5.xAdvanced select components
react-toastify^8.xToast notifications
styled-components^5.xCSS-in-JS styling
react-i18next^11.xInternationalization

9.3 Utility Dependencies

PackageVersionPurpose
axios^0.xHTTP client
lodash^4.xUtility functions
date-fns^2.xDate manipulation
file-saver^2.xFile download handling
xlsx^0.xExcel file processing

9.4 Internal Dependencies

PackagePurpose
@nimbly-technologies/nimbly-commonShared types and utilities
@loadable/componentCode splitting and lazy loading

9.5 Development Dependencies

PackagePurpose
typescriptType checking
@types/reactReact type definitions
@types/react-reduxRedux type definitions
@types/lodashLodash type definitions

10. Security & Permissions

10.1 Authentication & Authorization

10.1.1 Firebase Authentication

All API requests require Firebase authentication:

// Authentication middleware
const authMiddleware = async (request) => {
  const user = firebase.auth().currentUser;
  if (!user) {
    throw new Error('User not authenticated');
  }
  
  const token = await user.getIdToken();
  request.headers['Authorization'] = `Bearer ${token}`;
  return request;
};

10.1.2 Role-Based Access Control (RBAC)

ResourcePermissionDescription
RoleResources.ADMIN_INVENTORY_ALLFull AccessCreate, read, update, delete SKUs
RoleResources.ADMIN_INVENTORY_READRead OnlyView SKUs and reports
RoleResources.ADMIN_INVENTORY_WRITEWriteCreate and update SKUs
RoleResources.ADMIN_INVENTORY_DELETEDeleteRemove SKUs

10.1.3 Feature Flags

The SKU Management module is protected by feature flags:

// Feature flag check
const isInventoryEnabled = useFeatureFlag(Features.INVENTORY_MANAGEMENT);
 
if (!isInventoryEnabled) {
  return <FeatureNotAvailable />;
}

10.2 Data Security

10.2.1 Input Validation

  1. XSS Prevention

    • All user inputs are sanitized
    • Emoji characters are blocked
    • HTML encoding for display
  2. SQL Injection Prevention

    • Parameterized queries
    • Input type validation
    • Character whitelisting
  3. File Upload Security

    • File type validation (xlsx only)
    • File size limits
    • Virus scanning integration

10.2.2 Data Privacy

  1. Audit Trail

    • All actions are logged with user ID and timestamp
    • Changes tracked in updatedBy and createdBy fields
  2. Data Encryption

    • HTTPS for all API communications
    • Encrypted data at rest
    • Secure token storage
  3. Access Logging

    // Activity logging
    const logActivity = (action, resource, details) => {
      analytics.track('sku_management_activity', {
        action,
        resource,
        userId: currentUser.uid,
        timestamp: new Date().toISOString(),
        details
      });
    };

11. Performance Considerations

11.1 Optimization Strategies

  1. Code Splitting

    • Lazy loading of route components
    • Dynamic imports for heavy components
    • Bundle size optimization
  2. Data Pagination

    • Server-side pagination
    • Configurable page sizes
    • Efficient query optimization
  3. Caching Strategy

    • Redux state caching
    • API response caching
    • Browser cache headers
  4. Rendering Optimization

    • React.memo for expensive components
    • UseCallback for event handlers
    • Virtual scrolling for large lists

11.2 Monitoring & Analytics

  1. Performance Metrics

    • Page load times
    • API response times
    • User interaction tracking
  2. Error Tracking

    • Client-side error boundaries
    • API error logging
    • User feedback collection
  3. Usage Analytics

    • Feature adoption rates
    • User flow analysis
    • Performance bottleneck identification

12. Common Workflows

12.1 End-to-End SKU Creation Workflow

sequenceDiagram
    participant User
    participant UI
    participant Redux
    participant API
    participant Database
    
    User->>UI: Navigate to SKU Management
    UI->>Redux: Dispatch fetchSkus
    Redux->>API: GET /skus/search
    API->>Database: Query SKUs
    Database-->>API: Return SKUs
    API-->>Redux: SKU list
    Redux-->>UI: Update view
    
    User->>UI: Click "Add SKU"
    UI->>User: Show create options
    User->>UI: Select "Single SKU"
    UI->>User: Navigate to create form
    
    User->>UI: Fill SKU details
    UI->>UI: Validate form
    UI->>Redux: Dispatch createSku
    Redux->>API: POST /skus
    API->>Database: Insert SKU
    Database-->>API: Success
    API-->>Redux: Created SKU ID
    Redux-->>UI: Success notification
    UI->>User: Redirect to list

12.2 Multi-Site SKU Management Workflow

  1. Initial Setup

    • Create SKU with basic information
    • Assign to multiple sites
    • Set default threshold
  2. Site-Specific Configuration

    • Navigate to SKU edit page
    • Configure per-site pricing
    • Set site-specific stock levels
    • Enable/disable for specific sites
  3. Inventory Updates

    • Update stock counts per site
    • Monitor low stock alerts
    • Generate inventory reports

12.3 Bulk Operations Workflow

flowchart LR
    A[Download Template] --> B[Fill Excel Data]
    B --> C[Validate Locally]
    C --> D[Upload File]
    D --> E{Server Validation}
    E -->|Valid| F[Process Batch]
    E -->|Invalid| G[Download Error Report]
    F --> H[Import Complete]
    G --> I[Fix Errors]
    I --> B

13. Troubleshooting Guide

13.1 Common Issues and Solutions

13.1.1 SKU Creation Failures

Issue: “SKU ID already exists” error Solution:

  • Verify SKU ID uniqueness
  • Check for soft-deleted SKUs with same ID
  • Use organization prefix for SKU IDs

Issue: Form validation errors Solution:

  • Remove emoji characters from text fields
  • Ensure all required fields are filled
  • Check character limits

13.1.2 Bulk Upload Problems

Issue: Excel template not downloading Solution:

  • Check browser popup blocker
  • Verify user permissions
  • Try different browser

Issue: Upload fails with format error Solution:

  • Use only .xlsx format (not .xls or .csv)
  • Don’t modify template structure
  • Check for hidden columns or rows

13.1.3 Filter/Search Issues

Issue: Filters not applying Solution:

  • Click “Apply” after selecting filters
  • Check if filters are mutually exclusive
  • Clear all filters and reapply

Issue: Search returns no results Solution:

  • Check search is case-insensitive

  • Try searching by SKU ID instead of name

  • Verify SKUs aren’t disabled

    • Set realistic thresholds
    • Use percentage for seasonal items
    • Use absolute numbers for stable items
  1. Regular Audits
    • Schedule weekly/monthly audits
    • Review variance reports
    • Update thresholds based on trends

14. State Management Details

14.1 Redux Store Structure

The SKU Management module uses a sophisticated Redux state structure:

interface SkuManagementState {
  skus: {
    data: SKU[];
    loading: boolean;
    error: Error | null;
    pagination: {
      page: number;
      limit: number;
      total: number;
    };
    filters: {
      search: string;
      categories: string[];
      sites: string[];
      uoms: string[];
      isActive: boolean;
    };
    sort: {
      field: 'name' | 'uom' | 'updatedAt';
      direction: 'asc' | 'desc';
    };
  };
  categories: {
    data: string[];
    loading: boolean;
    error: Error | null;
  };
  uoms: {
    data: UOM[];
    loading: boolean;
    error: Error | null;
  };
  currentSku: {
    data: SKU | null;
    loading: boolean;
    error: Error | null;
  };
}

14.2 Action Creators

// SKU List Actions
export const fetchSkusRequest = (params) => ({
  type: 'FETCH_SKUS_REQUEST',
  payload: params
});
 
export const fetchSkusSuccess = (data) => ({
  type: 'FETCH_SKUS_SUCCESS',
  payload: data
});
 
export const fetchSkusFailure = (error) => ({
  type: 'FETCH_SKUS_FAILURE',
  payload: error
});
 
// Filter Actions
export const setSkuFilter = (filterType, value) => ({
  type: 'SET_SKU_FILTER',
  payload: { filterType, value }
});
 
export const clearSkuFilters = () => ({
  type: 'CLEAR_SKU_FILTERS'
});
 
// CRUD Actions
export const createSkuRequest = (sku) => ({
  type: 'CREATE_SKU_REQUEST',
  payload: sku
});
 
export const updateSkuRequest = (id, changes) => ({
  type: 'UPDATE_SKU_REQUEST',
  payload: { id, changes }
});
 
export const deleteSkuRequest = (id) => ({
  type: 'DELETE_SKU_REQUEST',
  payload: id
});

14.3 Saga Patterns

// Main SKU Fetch Saga
function* fetchSkusSaga(action) {
  try {
    yield put({ type: 'SET_LOADING', payload: true });
    
    // Build query parameters
    const params = yield select(getSkuQueryParams);
    
    // Make API call
    const response = yield call(api.fetchSkus, params);
    
    // Update store
    yield put(fetchSkusSuccess(response.data));
    
    // Cache management
    yield call(cacheSkuData, response.data);
    
  } catch (error) {
    yield put(fetchSkusFailure(error));
    yield call(logError, error);
  } finally {
    yield put({ type: 'SET_LOADING', payload: false });
  }
}
 
// Optimistic Update Pattern
function* updateSkuSaga(action) {
  const { id, changes } = action.payload;
  const originalSku = yield select(getSkuById, id);
  
  try {
    // Optimistic update
    yield put({ type: 'UPDATE_SKU_OPTIMISTIC', payload: { id, changes }});
    
    // API call
    const updated = yield call(api.updateSku, id, changes);
    
    // Confirm update
    yield put({ type: 'UPDATE_SKU_SUCCESS', payload: updated });
    
  } catch (error) {
    // Rollback on failure
    yield put({ type: 'UPDATE_SKU_ROLLBACK', payload: originalSku });
    yield put({ type: 'UPDATE_SKU_FAILURE', payload: error });
  }
}

15. Advanced Features

15.1 Real-time Stock Updates

The system supports real-time stock updates through WebSocket connections:

// WebSocket connection for real-time updates
class SkuWebSocketService {
  constructor() {
    this.socket = null;
    this.subscribers = new Map();
  }
  
  connect(organizationId) {
    this.socket = new WebSocket(`${WS_URL}/sku-updates/${organizationId}`);
    
    this.socket.onmessage = (event) => {
      const update = JSON.parse(event.data);
      this.handleUpdate(update);
    };
    
    this.socket.onerror = (error) => {
      console.error('WebSocket error:', error);
      this.reconnect();
    };
  }
  
  handleUpdate(update) {
    const { type, data } = update;
    
    switch (type) {
      case 'STOCK_UPDATE':
        this.notifySubscribers('stock', data);
        break;
      case 'PRICE_UPDATE':
        this.notifySubscribers('price', data);
        break;
      case 'SKU_DELETED':
        this.notifySubscribers('delete', data);
        break;
    }
  }
  
  subscribe(type, callback) {
    if (!this.subscribers.has(type)) {
      this.subscribers.set(type, new Set());
    }
    this.subscribers.get(type).add(callback);
  }
  
  notifySubscribers(type, data) {
    const callbacks = this.subscribers.get(type) || [];
    callbacks.forEach(callback => callback(data));
  }
}

15.2 Advanced Search Implementation

// Full-text search with ranking
class SkuSearchService {
  constructor() {
    this.searchIndex = new Map();
    this.buildIndex();
  }
  
  buildIndex() {
    // Build inverted index for fast searching
    const skus = store.getState().skus.data;
    
    skus.forEach(sku => {
      // Index by name
      this.indexTokens(sku.name, sku._id);
      
      // Index by ID
      this.indexTokens(sku.skuID, sku._id);
      
      // Index by description
      if (sku.description) {
        this.indexTokens(sku.description, sku._id);
      }
      
      // Index by category
      sku.categories.forEach(cat => {
        this.indexTokens(cat, sku._id);
      });
    });
  }
  
  indexTokens(text, skuId) {
    const tokens = this.tokenize(text);
    
    tokens.forEach(token => {
      if (!this.searchIndex.has(token)) {
        this.searchIndex.set(token, new Set());
      }
      this.searchIndex.get(token).add(skuId);
    });
  }
  
  tokenize(text) {
    return text
      .toLowerCase()
      .split(/[\s\-_]+/)
      .filter(token => token.length > 2);
  }
  
  search(query) {
    const queryTokens = this.tokenize(query);
    const results = new Map();
    
    queryTokens.forEach(token => {
      const matches = this.searchIndex.get(token) || new Set();
      
      matches.forEach(skuId => {
        const score = results.get(skuId) || 0;
        results.set(skuId, score + 1);
      });
    });
    
    // Sort by relevance score
    return Array.from(results.entries())
      .sort((a, b) => b[1] - a[1])
      .map(([skuId]) => skuId);
  }
}

15.3 Export Functionality

// Advanced export with formatting options
class SkuExportService {
  async exportToExcel(skus, options = {}) {
    const {
      includeStock = true,
      includePricing = true,
      includeSites = true,
      format = 'xlsx'
    } = options;
    
    // Prepare data
    const exportData = skus.map(sku => {
      const row = {
        'SKU ID': sku.skuID,
        'Name': sku.name,
        'Description': sku.description || '',
        'Category': sku.categories.join(', '),
        'UOM': sku.uom,
        'Threshold': sku.threshold,
        'Threshold Type': sku.thresholdType
      };
      
      if (includeStock) {
        row['Total Stock'] = this.calculateTotalStock(sku);
      }
      
      if (includePricing) {
        row['Average Price'] = this.calculateAveragePrice(sku);
      }
      
      if (includeSites) {
        sku.sites.forEach(site => {
          row[`${site.siteID} - Stock`] = site.count;
          row[`${site.siteID} - Price`] = site.price;
        });
      }
      
      return row;
    });
    
    // Generate Excel file
    const worksheet = XLSX.utils.json_to_sheet(exportData);
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, 'SKUs');
    
    // Apply styling
    this.applyExcelStyling(worksheet);
    
    // Download
    XLSX.writeFile(workbook, `SKUs_Export_${Date.now()}.${format}`);
  }
  
  applyExcelStyling(worksheet) {
    // Header styling
    const range = XLSX.utils.decode_range(worksheet['!ref']);
    
    for (let C = range.s.c; C <= range.e.c; ++C) {
      const address = XLSX.utils.encode_col(C) + '1';
      if (!worksheet[address]) continue;
      
      worksheet[address].s = {
        font: { bold: true },
        fill: { fgColor: { rgb: "4F81BD" } },
        alignment: { horizontal: "center" }
      };
    }
    
    // Column widths
    worksheet['!cols'] = [
      { wch: 15 }, // SKU ID
      { wch: 30 }, // Name
      { wch: 50 }, // Description
      { wch: 20 }, // Category
      { wch: 10 }, // UOM
      { wch: 12 }, // Threshold
      { wch: 15 }, // Threshold Type
    ];
  }
}

15.4 Audit Trail Implementation

// Comprehensive audit logging
class SkuAuditService {
  logChange(action, sku, changes, userId) {
    const auditEntry = {
      timestamp: new Date().toISOString(),
      action,
      resourceType: 'SKU',
      resourceId: sku._id,
      resourceName: sku.name,
      userId,
      changes: this.formatChanges(changes),
      metadata: {
        userAgent: navigator.userAgent,
        ip: this.getUserIP(),
        sessionId: this.getSessionId()
      }
    };
    
    // Send to audit service
    return api.createAuditLog(auditEntry);
  }
  
  formatChanges(changes) {
    const formatted = [];
    
    Object.entries(changes).forEach(([field, value]) => {
      formatted.push({
        field,
        oldValue: value.old,
        newValue: value.new,
        type: this.getChangeType(value.old, value.new)
      });
    });
    
    return formatted;
  }
  
  getChangeType(oldValue, newValue) {
    if (oldValue === undefined) return 'CREATE';
    if (newValue === undefined) return 'DELETE';
    return 'UPDATE';
  }
}

16. Testing Guidelines

16.1 Unit Testing

// Component Testing Example
describe('SingleSkuCreate Component', () => {
  let store;
  let wrapper;
  
  beforeEach(() => {
    store = mockStore({
      skus: { data: [], loading: false },
      categories: { data: ['Electronics', 'Clothing'] },
      sites: { data: mockSites }
    });
    
    wrapper = mount(
      <Provider store={store}>
        <SingleSkuCreate />
      </Provider>
    );
  });
  
  it('should render form fields', () => {
    expect(wrapper.find('input[name="skuName"]')).toHaveLength(1);
    expect(wrapper.find('input[name="skuId"]')).toHaveLength(1);
    expect(wrapper.find('select[name="category"]')).toHaveLength(1);
  });
  
  it('should validate emoji characters', async () => {
    const nameInput = wrapper.find('input[name="skuName"]');
    nameInput.simulate('change', { target: { value: 'Test 😀' } });
    
    await act(async () => {
      wrapper.find('form').simulate('submit');
    });
    
    wrapper.update();
    expect(wrapper.find('.error').text()).toContain('Emojis are not allowed');
  });
  
  it('should create SKU on valid submission', async () => {
    // Fill form
    wrapper.find('input[name="skuName"]').simulate('change', 
      { target: { value: 'Test Product' } });
    wrapper.find('input[name="skuId"]').simulate('change', 
      { target: { value: 'TEST001' } });
    
    // Submit
    await act(async () => {
      wrapper.find('form').simulate('submit');
    });
    
    // Verify action dispatched
    const actions = store.getActions();
    expect(actions).toContainEqual({
      type: 'CREATE_SKU_REQUEST',
      payload: expect.objectContaining({
        skuName: 'Test Product',
        skuId: 'TEST001'
      })
    });
  });
});

16.2 Integration Testing

// API Integration Tests
describe('SKU API Integration', () => {
  it('should fetch SKUs with filters', async () => {
    const filters = {
      categories: ['Electronics'],
      sites: ['SITE001'],
      search: 'laptop'
    };
    
    const response = await api.fetchSkus(filters);
    
    expect(response.status).toBe(200);
    expect(response.data.skus).toBeInstanceOf(Array);
    expect(response.data.skus.every(sku => 
      sku.name.toLowerCase().includes('laptop') ||
      sku.categories.includes('Electronics')
    )).toBe(true);
  });
  
  it('should handle bulk upload', async () => {
    const file = new File(
      [mockExcelData], 
      'skus.xlsx', 
      { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
    );
    
    const response = await api.uploadBulkSKUs(file);
    
    expect(response.status).toBe(200);
    expect(response.data.processed).toBe(10);
    expect(response.data.errors).toHaveLength(0);
  });
});

16.3 E2E Testing

// Cypress E2E Tests
describe('SKU Management E2E', () => {
  beforeEach(() => {
    cy.login('admin@test.com', 'password');
    cy.visit('/admin/skuManagement');
  });
  
  it('should complete full SKU lifecycle', () => {
    // Create SKU
    cy.contains('Add SKU').click();
    cy.contains('Single SKU').click();
    
    cy.get('[name="skuName"]').type('E2E Test Product');
    cy.get('[name="skuId"]').type('E2E001');
    cy.get('[name="category"]').select('Electronics');
    cy.get('[name="unitOfMeasure"]').select('piece');
    cy.get('[name="lowStockThreshold"]').type('10');
    
    cy.contains('Create SKU').click();
    cy.contains('SKU created successfully').should('be.visible');
    
    // Edit SKU
    cy.contains('E2E Test Product').click();
    cy.get('[name="description"]').type('Updated description');
    cy.contains('Save Changes').click();
    cy.contains('SKU updated successfully').should('be.visible');
    
    // Delete SKU
    cy.contains('Delete').click();
    cy.contains('Are you sure').should('be.visible');
    cy.contains('Confirm').click();
    cy.contains('SKU deleted successfully').should('be.visible');
  });
});

17. Migration Guide

17.1 Upgrading from v1.x to v2.x

The SKU Management module underwent significant changes in v2.0:

17.1.1 Breaking Changes

  1. API Endpoint Changes

    OLD: /api/products
    NEW: /api/skus
    
  2. Data Model Changes

    // Old model
    {
      productId: string,
      productName: string,
      sites: string[]
    }
     
    // New model
    {
      skuID: string,
      name: string,
      sites: SiteSKUDetail[]
    }
  3. Permission Changes

    OLD: ADMIN_PRODUCTS_ALL
    NEW: ADMIN_INVENTORY_ALL
    

17.1.2 Migration Steps

  1. Database Migration

    -- Rename collections/tables
    ALTER TABLE products RENAME TO skus;
     
    -- Update field names
    UPDATE skus SET skuID = productId;
    UPDATE skus SET name = productName;
     
    -- Migrate site data
    -- Run migration script: scripts/migrate-sites-v2.js
  2. Code Updates

    • Update all imports from @/products to @/skuManagement
    • Replace productId with skuID throughout codebase
    • Update Redux action types
  3. Testing

    • Run full test suite
    • Perform manual testing of critical flows
    • Validate data integrity

18. Integration Points

18.1 External Systems

  1. ERP Integration

    • SKU sync via API
    • Batch import/export
    • Real-time updates
  2. POS Systems

    • Stock level updates
    • Price synchronization
    • Transaction logging
  3. Analytics Platforms

    • Inventory metrics export
    • Custom report generation
    • Dashboard integration

18.2 Internal Modules

  1. Stock Audit Scheduler

    • Automated audit creation
    • SKU selection for audits
    • Variance tracking
  2. Reporting Module

    • Inventory value reports
    • Stock movement analysis
    • Low stock alerts
  3. Site Management

    • Site-SKU associations
    • Multi-site inventory
    • Transfer tracking

19. Development Workflow

19.1 Development Environment Setup

  1. Prerequisites

    # Install Node.js 16+
    nvm install 16
    nvm use 16
     
    # Install dependencies
    npm install
     
    # Set up environment variables
    cp .env.example .env.local
  2. Environment Variables

    REACT_APP_CLOUD_API_URL=http://localhost:3001
    REACT_APP_FIREBASE_CONFIG={"apiKey":"..."}
    REACT_APP_FEATURE_FLAGS={"INVENTORY_MANAGEMENT":true}
  3. Database Setup

    # Start MongoDB
    mongod --dbpath ./data/db
     
    # Seed test data
    npm run seed:skus

19.2 Component Development

  1. Creating New Components

    src/components/skuManagement/
    ├── ComponentName/
    │   ├── ComponentName.tsx
    │   ├── ComponentName.module.scss
    │   ├── ComponentName.test.tsx
    │   └── index.ts
    
  2. Component Template

    import React from 'react';
    import { useSelector, useDispatch } from 'react-redux';
    import styles from './ComponentName.module.scss';
     
    interface ComponentNameProps {
      // Define props
    }
     
    export const ComponentName: React.FC<ComponentNameProps> = (props) => {
      const dispatch = useDispatch();
      
      return (
        <div className={styles.container}>
          {/* Component content */}
        </div>
      );
    };
     
    export default ComponentName;

19.3 API Development

  1. Service Structure

    // src/services/sku/sku.service.ts
    import { apiClient } from '../api/client';
     
    export const skuService = {
      async fetchSkus(params: SkuQueryParams): Promise<SkuListResponse> {
        const response = await apiClient.get('/skus/search', { params });
        return response.data;
      },
      
      async createSku(sku: CreateSkuRequest): Promise<string> {
        const response = await apiClient.post('/skus', sku);
        return response.data.id;
      }
    };
  2. Redux Integration

    // src/sagas/sku/sku.saga.ts
    function* fetchSkusSaga(action: PayloadAction<SkuQueryParams>) {
      try {
        const response = yield call(skuService.fetchSkus, action.payload);
        yield put(fetchSkusSuccess(response));
      } catch (error) {
        yield put(fetchSkusFailure(error));
      }
    }

19.4 Testing Strategy

  1. Unit Tests

    // Component testing
    describe('SkuTable', () => {
      it('renders SKU data correctly', () => {
        const mockSkus = [createMockSku()];
        render(<SkuTable skus={mockSkus} />);
        
        expect(screen.getByText(mockSkus[0].name)).toBeInTheDocument();
      });
    });
     
    // Service testing
    describe('skuService', () => {
      it('fetches SKUs with correct parameters', async () => {
        const params = { page: 1, limit: 10 };
        mock.onGet('/skus/search').reply(200, mockResponse);
        
        const result = await skuService.fetchSkus(params);
        expect(result.data).toEqual(mockResponse.data);
      });
    });
  2. Integration Tests

    describe('SKU Management Integration', () => {
      it('creates SKU end-to-end', async () => {
        const store = createTestStore();
        const { getByRole } = render(
          <Provider store={store}>
            <SingleSkuCreate />
          </Provider>
        );
        
        // Fill form and submit
        fireEvent.change(getByRole('textbox', { name: /sku name/i }), 
          { target: { value: 'Test SKU' } });
        fireEvent.click(getByRole('button', { name: /create/i }));
        
        // Verify API call
        await waitFor(() => {
          expect(mockApiCall).toHaveBeenCalledWith(
            expect.objectContaining({ name: 'Test SKU' })
          );
        });
      });
    });

20. Deployment Guide

20.1 Build Configuration

  1. Production Build

    # Set production environment
    NODE_ENV=production
     
    # Build optimized bundle
    npm run build
     
    # Analyze bundle size
    npm run analyze
  2. Environment-Specific Builds

    # Staging build
    npm run build:staging
     
    # Production build
    npm run build:prod
     
    # Development build with source maps
    npm run build:dev

20.2 Performance Optimization

  1. Bundle Analysis

    # Generate bundle report
    npx webpack-bundle-analyzer build/static/js/*.js
     
    # Check bundle size limits
    npm run size-limit
  2. Optimization Techniques

    • Code splitting at route level
    • Lazy loading of heavy components
    • Image optimization and compression
    • CSS minification and tree shaking
    • Service worker for caching

20.3 Monitoring and Alerting

  1. Performance Metrics

    // Performance monitoring
    export const trackPerformance = (metric: string, value: number) => {
      if (process.env.NODE_ENV === 'production') {
        analytics.track('performance', { metric, value });
      }
    };
     
    // Component render tracking
    const usePerformanceTracking = (componentName: string) => {
      useEffect(() => {
        const startTime = performance.now();
        return () => {
          const renderTime = performance.now() - startTime;
          trackPerformance(`${componentName}_render_time`, renderTime);
        };
      }, [componentName]);
    };
  2. Error Monitoring

    // Error boundary with logging
    class SkuErrorBoundary extends Component {
      componentDidCatch(error: Error, errorInfo: ErrorInfo) {
        logger.error('SKU Component Error', {
          error: error.message,
          stack: error.stack,
          componentStack: errorInfo.componentStack
        });
      }
    }

21. Configuration Management

21.1 Feature Flags

The SKU Management module supports feature flags for gradual rollouts:

interface FeatureFlags {
  INVENTORY_MANAGEMENT: boolean;
  BULK_SKU_UPLOAD: boolean;
  ADVANCED_FILTERING: boolean;
  REAL_TIME_UPDATES: boolean;
  ANALYTICS_INTEGRATION: boolean;
}
 
// Usage in components
const isAdvancedFilteringEnabled = useFeatureFlag('ADVANCED_FILTERING');
 
if (isAdvancedFilteringEnabled) {
  return <AdvancedSkuFilter />;
}
return <BasicSkuFilter />;

21.2 Configuration Schema

interface SkuModuleConfig {
  pagination: {
    defaultPageSize: number;
    maxPageSize: number;
    pageSizeOptions: number[];
  };
  search: {
    debounceDelay: number;
    minSearchLength: number;
    maxResults: number;
  };
  validation: {
    skuIdMaxLength: number;
    nameMaxLength: number;
    descriptionMaxLength: number;
    allowEmojis: boolean;
  };
  export: {
    maxRecords: number;
    supportedFormats: string[];
    includeImages: boolean;
  };
  realtime: {
    enabled: boolean;
    reconnectInterval: number;
    maxReconnectAttempts: number;
  };
}

22. Conclusion

The SKU Management module represents a comprehensive inventory management solution within the Nimbly Audit Admin platform. Its modular architecture, robust API design, and extensive feature set make it a critical component for organizations managing complex inventory across multiple locations.

22.1 Key Strengths

  1. Scalability: Handles large datasets with pagination and optimized queries
  2. Flexibility: Configurable fields and customizable workflows
  3. User Experience: Intuitive interface with advanced filtering and search
  4. Integration: Seamless integration with other platform modules
  5. Security: Role-based access control and audit trails
  6. Performance: Optimized for fast loading and responsive interactions

22.3 Support and Maintenance

For technical support, feature requests, or bug reports:


Document Information

  • Last Updated: December 2024
  • Version: 2.1.0
  • Authors: Nimbly Technologies Development Team
  • Review Cycle: Quarterly
  • Next Review: March 2025
    • SKU sync via API
    • Batch import/export
    • Real-time updates
  1. POS Systems

    • Stock level updates
    • Price synchronization
    • Transaction logging
  2. Analytics Platforms

    • Inventory metrics export
    • Custom report generation
    • Dashboard integration

18.2 Internal Modules

  1. Stock Audit Scheduler

    • Automated audit creation
    • SKU selection for audits
    • Variance tracking
  2. Reporting Module

    • Inventory value reports
    • Stock movement analysis
    • Low stock alerts
  3. Site Management

    • Site-SKU associations
    • Multi-site inventory
    • Transfer tracking