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 Path | Component | Purpose | Access Control |
|---|---|---|---|
/admin/skuManagement | SkuManagementPage | Main SKU listing and management interface | RoleResources.ADMIN_INVENTORY_ALL |
/admin/skuManagement/new | SingleSkuCreatePage | Create individual SKU | RoleResources.ADMIN_INVENTORY_ALL |
/admin/skuManagement/bulkUpload | BatchSkuCreatePage | Bulk SKU upload via CSV/Excel | RoleResources.ADMIN_INVENTORY_ALL |
/admin/skuManagement/:id | SingleSkuEditPage | Edit existing SKU | RoleResources.ADMIN_INVENTORY_ALL |
3.1 Related Routes
| Route Path | Component | Purpose | Access Control |
|---|---|---|---|
/admin/stockAuditScheduler | StockAuditSchedulerPage | Schedule stock audits | RoleResources.ADMIN_STOCKAUDIT_SCHEDULER_ALL |
/admin/stockAuditScheduler/new | StockAuditScheduleCreatePage | Create audit schedule | RoleResources.ADMIN_STOCKAUDIT_SCHEDULER_ALL |
/admin/stockAuditScheduler/:id | StockAuditScheduleEditPage | Edit audit schedule | RoleResources.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
withValidationHOC 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:
| Field | Type | Validation | Description |
|---|---|---|---|
| skuName | Text | Required, Max 60 chars, No emojis | Display name of the SKU |
| skuId | Text | Required, Max 50 chars, Alphanumeric only | Unique identifier |
| description | Textarea | Optional, Max 250 chars | Additional details |
| category | Creatable Select | Required | Product category (can create new) |
| unitOfMeasure | Select | Required | Unit type (e.g., piece, kg, liter) |
| sites | Multi-Select | Required | Associated store locations |
| lowStockThreshold | Number | Required, Min 0 | Inventory 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:
- Download pre-formatted Excel template
- Fill template with SKU data
- Upload completed template
- 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:
-
Category Filter
- Multi-select dropdown
- Dynamic category list from API
- “All Categories” option for quick selection
-
Site Filter
- Multi-select with search
- Shows site name and code
- Hierarchical site structure support
-
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:
| Field | Rule | Error Message |
|---|---|---|
| SKU Name | No emojis, Max 60 chars | ”Emojis are not allowed” |
| SKU ID | Alphanumeric only, Max 50 chars | ”Only letters and numbers allowed” |
| SKU ID | Unique check | ”SKU ID already exists” |
| Low Stock | Min 0 | ”Must be 0 or greater” |
| Sites | At 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:
- Click delete button
- Confirmation modal appears
- Enter SKU name for confirmation
- API call to soft delete
- 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
| Configuration | Value | Source |
|---|---|---|
| API Base URL | process.env.REACT_APP_CLOUD_API_URL | src/config/baseURL.ts |
| Authentication | Firebase ID Token | Bearer token in Authorization header |
| Content Type | application/json | Default for all endpoints |
6.2 SKU Management Endpoints
6.2.1 Core CRUD Operations
| Operation | Method | Endpoint | Request Body | Response | File |
|---|---|---|---|---|---|
| Create SKU | POST | /skus | CreateSkuRequest | SKU ID (string) | src/services/sku/sku.service.ts |
| Get SKU | GET | /skus/{id} | - | FindBySKUIDResponse | src/services/sku/sku.service.ts |
| Update SKU | PATCH | /skus/{id} | UpdateSkuRequest | Updated SKU object | src/services/sku/sku.service.ts |
| Delete SKU | DELETE | /skus/{id} | - | void | src/services/sku/sku.service.ts |
6.2.2 Search and List Operations
| Operation | Method | Endpoint | Query Parameters | Response | File |
|---|---|---|---|---|---|
| Search SKUs | GET | /skus/search | page, limit, sortFields, sortDirections, search, withDisabled, categories[], siteIDs[], uoms[] | Paginated SKU list | src/sagas/skuManagement/skus.actionSaga.ts |
| Fetch All SKUs (Compact) | GET | /skus/ | props=skuID&props=name&withDisabled=false | Minimal SKU data | src/sagas/skuManagement/skus.actionSaga.ts |
| Fetch SKUs by Site | GET | /skus/compact | siteID={siteID} | FindSKUPerCategory | src/services/sku/sku.service.ts |
6.2.3 Settings and Metadata
| Operation | Method | Endpoint | Request Body | Response | File |
|---|---|---|---|---|---|
| Get Categories | GET | /skus/sku-settings/categories | - | Array of category strings | src/services/sku/sku.service.ts |
| Create Category | POST | /skus/sku-settings/categories | { category: string } | Created category name | src/services/sku/sku.service.ts |
| Get UOMs | GET | /miscellaneous/uoms | - | Array of UOM objects | src/services/sku/sku.service.ts |
6.2.4 Bulk Operations
| Operation | Method | Endpoint | Request Body | Response | File |
|---|---|---|---|---|---|
| Download Template | GET | /skus/bulk-upload | - | Template file data | src/services/sku/sku.service.ts |
| Upload Batch | POST | /skus/bulk-upload | FormData with file | void | src/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
| Field | Type | Max Length | Pattern | Required |
|---|---|---|---|---|
| skuID | string | 50 | Alphanumeric only | Yes |
| name | string | 60 | No emojis | Yes |
| description | string | 250 | - | No |
| threshold | number | - | >= 0 | Yes |
| price | number | - | >= 0 | Yes |
7.6.2 Business Rules
- SKU ID Uniqueness: Must be unique within organization
- Site Assignment: At least one site must be assigned
- Category Requirement: Must belong to at least one category
- UOM Immutability: Cannot be changed after creation
- Soft Delete: SKUs are never hard deleted, only disabled
- 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;8.7.2 Debounced Search
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
| Package | Version | Purpose |
|---|---|---|
react | ^17.x | Core React library |
react-dom | ^17.x | React DOM rendering |
react-router-dom | ^5.x | Routing and navigation |
redux | ^4.x | State management |
react-redux | ^7.x | React Redux bindings |
redux-saga | ^1.x | Side effects management |
9.2 UI/UX Dependencies
| Package | Version | Purpose |
|---|---|---|
formik | ^2.x | Form state management |
yup | ^0.x | Schema validation |
react-select | ^5.x | Advanced select components |
react-toastify | ^8.x | Toast notifications |
styled-components | ^5.x | CSS-in-JS styling |
react-i18next | ^11.x | Internationalization |
9.3 Utility Dependencies
| Package | Version | Purpose |
|---|---|---|
axios | ^0.x | HTTP client |
lodash | ^4.x | Utility functions |
date-fns | ^2.x | Date manipulation |
file-saver | ^2.x | File download handling |
xlsx | ^0.x | Excel file processing |
9.4 Internal Dependencies
| Package | Purpose |
|---|---|
@nimbly-technologies/nimbly-common | Shared types and utilities |
@loadable/component | Code splitting and lazy loading |
9.5 Development Dependencies
| Package | Purpose |
|---|---|
typescript | Type checking |
@types/react | React type definitions |
@types/react-redux | Redux type definitions |
@types/lodash | Lodash 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)
| Resource | Permission | Description |
|---|---|---|
RoleResources.ADMIN_INVENTORY_ALL | Full Access | Create, read, update, delete SKUs |
RoleResources.ADMIN_INVENTORY_READ | Read Only | View SKUs and reports |
RoleResources.ADMIN_INVENTORY_WRITE | Write | Create and update SKUs |
RoleResources.ADMIN_INVENTORY_DELETE | Delete | Remove 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
-
XSS Prevention
- All user inputs are sanitized
- Emoji characters are blocked
- HTML encoding for display
-
SQL Injection Prevention
- Parameterized queries
- Input type validation
- Character whitelisting
-
File Upload Security
- File type validation (xlsx only)
- File size limits
- Virus scanning integration
10.2.2 Data Privacy
-
Audit Trail
- All actions are logged with user ID and timestamp
- Changes tracked in
updatedByandcreatedByfields
-
Data Encryption
- HTTPS for all API communications
- Encrypted data at rest
- Secure token storage
-
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
-
Code Splitting
- Lazy loading of route components
- Dynamic imports for heavy components
- Bundle size optimization
-
Data Pagination
- Server-side pagination
- Configurable page sizes
- Efficient query optimization
-
Caching Strategy
- Redux state caching
- API response caching
- Browser cache headers
-
Rendering Optimization
- React.memo for expensive components
- UseCallback for event handlers
- Virtual scrolling for large lists
11.2 Monitoring & Analytics
-
Performance Metrics
- Page load times
- API response times
- User interaction tracking
-
Error Tracking
- Client-side error boundaries
- API error logging
- User feedback collection
-
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
-
Initial Setup
- Create SKU with basic information
- Assign to multiple sites
- Set default threshold
-
Site-Specific Configuration
- Navigate to SKU edit page
- Configure per-site pricing
- Set site-specific stock levels
- Enable/disable for specific sites
-
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
- 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
-
API Endpoint Changes
OLD: /api/products NEW: /api/skus -
Data Model Changes
// Old model { productId: string, productName: string, sites: string[] } // New model { skuID: string, name: string, sites: SiteSKUDetail[] } -
Permission Changes
OLD: ADMIN_PRODUCTS_ALL NEW: ADMIN_INVENTORY_ALL
17.1.2 Migration Steps
-
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 -
Code Updates
- Update all imports from
@/productsto@/skuManagement - Replace
productIdwithskuIDthroughout codebase - Update Redux action types
- Update all imports from
-
Testing
- Run full test suite
- Perform manual testing of critical flows
- Validate data integrity
18. Integration Points
18.1 External Systems
-
ERP Integration
- SKU sync via API
- Batch import/export
- Real-time updates
-
POS Systems
- Stock level updates
- Price synchronization
- Transaction logging
-
Analytics Platforms
- Inventory metrics export
- Custom report generation
- Dashboard integration
18.2 Internal Modules
-
Stock Audit Scheduler
- Automated audit creation
- SKU selection for audits
- Variance tracking
-
Reporting Module
- Inventory value reports
- Stock movement analysis
- Low stock alerts
-
Site Management
- Site-SKU associations
- Multi-site inventory
- Transfer tracking
19. Development Workflow
19.1 Development Environment Setup
-
Prerequisites
# Install Node.js 16+ nvm install 16 nvm use 16 # Install dependencies npm install # Set up environment variables cp .env.example .env.local -
Environment Variables
REACT_APP_CLOUD_API_URL=http://localhost:3001 REACT_APP_FIREBASE_CONFIG={"apiKey":"..."} REACT_APP_FEATURE_FLAGS={"INVENTORY_MANAGEMENT":true} -
Database Setup
# Start MongoDB mongod --dbpath ./data/db # Seed test data npm run seed:skus
19.2 Component Development
-
Creating New Components
src/components/skuManagement/ ├── ComponentName/ │ ├── ComponentName.tsx │ ├── ComponentName.module.scss │ ├── ComponentName.test.tsx │ └── index.ts -
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
-
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; } }; -
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
-
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); }); }); -
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
-
Production Build
# Set production environment NODE_ENV=production # Build optimized bundle npm run build # Analyze bundle size npm run analyze -
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
-
Bundle Analysis
# Generate bundle report npx webpack-bundle-analyzer build/static/js/*.js # Check bundle size limits npm run size-limit -
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
-
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]); }; -
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
- Scalability: Handles large datasets with pagination and optimized queries
- Flexibility: Configurable fields and customizable workflows
- User Experience: Intuitive interface with advanced filtering and search
- Integration: Seamless integration with other platform modules
- Security: Role-based access control and audit trails
- Performance: Optimized for fast loading and responsive interactions
22.3 Support and Maintenance
For technical support, feature requests, or bug reports:
- GitHub Issues: https://github.com/Nimbly-Technologies/audit-admin/issues
- Documentation Updates: Submit pull requests to the documentation
- Community Forum: https://community.nimbly.tech
- Technical Support: support@nimbly.tech
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
-
POS Systems
- Stock level updates
- Price synchronization
- Transaction logging
-
Analytics Platforms
- Inventory metrics export
- Custom report generation
- Dashboard integration
18.2 Internal Modules
-
Stock Audit Scheduler
- Automated audit creation
- SKU selection for audits
- Variance tracking
-
Reporting Module
- Inventory value reports
- Stock movement analysis
- Low stock alerts
-
Site Management
- Site-SKU associations
- Multi-site inventory
- Transfer tracking