Here is the technical architectural blueprint summarizing the modern inventory and Kardex system we designed, tailored for enterprise flexibility and high performance. The goal of system is that can handle assets like uniforms with its assignation complexity as the same time its refined design can be used in the future to handle another type of assets like hardware, office elements etc
Architecture Blueprint: Flexible Inventory & Kardex System
This architecture abandons the rigid, legacy approach of "wide tables" with dozens of nullable attribute columns. Instead, it adopts a Hybrid Relational-Document Paradigm, strictly separating concerns into three distinct layers:
- The Catalog (What exists): A hierarchical definition of items using flexible JSON payloads to support vastly different physical goods (Uniforms vs. IT Hardware) without schema changes.
- The Stock Position (What we have): A materialized, highly-optimized snapshot of current availability per physical location.
- The Kardex (How we got here): An immutable, append-only ledger inspired by double-entry accounting. It acts as the absolute source of truth for all inventory calculations and audits.
2. Product Catalog Topology (Template vs. Variant)
To solve the "Variant Explosion" problem and maintain clean Master Data Management (MDM), products are split into a Parent-Child relationship.
Defines the general, abstract item. It holds properties shared across all physical manifestations of the item.
- Fields: ID, Name, Category, Base Cost, Active Status.
- Example: "Camisa Polo Reflectiva", "Laptop Dell Rugged".
Defines the lowest trackable unit of inventory. Every variant represents a unique physical footprint and is assigned a unique SKU and Barcode.
- Fields: ID, Template ID (FK), SKU, Barcode, JSON Attributes.
- JSON Payload: Stores all variant-specific data (size, color, gender fit, serial numbers, MAC addresses).
| Layer | Entity | Identifier | JSON Attributes Payload |
|---|---|---|---|
| Template | Camisa Polo Reflectiva | ID: 10 | (None - Abstract Concept) |
| Variant | Polo Reflectiva - Medium | SKU: POLO-M | {"size": "M", "gender": "F", "color": "Navy"} |
| Variant | Polo Reflectiva - Large | SKU: POLO-L | {"size": "L", "gender": "F", "color": "Navy"} |
| Template | Multímetro Digital Fluke | ID: 11 | (None - Abstract Concept) |
| Variant | Fluke 117 - Unit #1 | SKU: FLK-001 | {"serial": "991A", "cal_date": "2026-10"} |
3. Organizational & Location Hierarchy
Locations must represent the physical reality of the supply chain, including the end-user holding company assets.
Locations are hierarchical, rolling up from broad regions to specific shelves or people.
- Regional Node: Master DWH (e.g., Region Occidental).
- Local Node: Operational DWH (e.g., DWH Santa Ana).
- Virtual Node (Asset Accountability): Employee Locker.
By treating an Employee as a strictly mapped 1:1 Location ID, the Kardex treats assigning a laptop or uniform identically to transferring stock between two warehouses.
- Benefit: Instant accountability. Querying current stock where location_id = Employee_X_Locker instantly yields the offboarding/return checklist.
4. The Immutable Ledger (Kardex)
The Kardex is an append-only transaction log. Rows are never updated or deleted. Mistakes are corrected via compensating entries (Reversals).
Every physical movement requires two balanced Kardex entries linked by a shared Document/Transaction ID:
- OUT (-1) from the Source Location.
- IN (+1) to the Destination Location.
Movements are strictly typed using an integer-based catalog table (not raw strings) to define the behavior of the transaction.
- 1 = Purchase Receipt (IN)
- 2 = Transfer Out (OUT)
- 3 = Issue to Employee (OUT)
- 4 = Receive Return (IN)
| Txn ID | Date | Movement Type (FK) | Dir | Location (FK) | Variant (FK / SKU) | Qty | Qty Before | Qty After |
|---|---|---|---|---|---|---|---|---|
| 501 | 03-01 | (2) Transfer Out | -1 | DWH Santa Ana | POLO-M | 2 | 20 | 18 |
| 501 | 03-01 | (3) Receive Uniform | +1 | Emp: Maria L. | POLO-M | 2 | 0 | 2 |
Note: Qty Before and Qty After are denormalized snapshots taken at the exact millisecond of the transaction. This guarantees instant UI rendering of historical Kardex views without recalculating years of data.
5. Uniform Allocation Rules Engine
To automate what an employee should receive based on HR data, a bridging matrix dictates inventory requirements.
- Inputs: Employee Position (e.g., Mecánico), Employee Sex (e.g., F).
- Outputs: Required Product Templates & Default Quantities.
| Position (FK) | Sex | Required Template (FK) | Default Qty |
|---|---|---|---|
| Personal Lab. | M | Camisa Manga Larga Admin | 2 |
| Personal Lab. | M | Gabacha Blanca | 1 |
| Mecánicos | F | Pantalón Jeans Reflectivo | 3 |
When HR triggers an onboarding event, the system queries this matrix, prompts the warehouse worker for the specific Sizes (Variants) matching those Templates, and generates the Kardex movements.
This allocation rules engines comes from this diagram that shows how uniforms distribution works based on employees’s department/position:
6. Technical & Performance Considerations
Storing attributes in JSON provides infinite flexibility but destroys read performance if queried directly. Solution: Indexed Computed Columns (Persisted).
- The database engine is instructed to extract heavily queried JSON keys (e.g., size, color, serial_number) into virtual columns.
- These virtual columns are strictly typed (cast to small strings) and physically saved (Persisted) to disk alongside the row.
- Standard B-Tree indexes are applied to these computed columns.
- Result: Queries like "Find all Size M shirts" hit the B-Tree index instantly (O(log N) complexity), never parsing the raw JSON during the search phase.
The system is consider to be develop in sql server 2019 engine
- Relational Core: Entities that change state, location, or quantity (Stock Position, Locations, Kardex, Employees) rely exclusively on strict Integer Foreign Keys.
- Denormalized JSON: Physical properties of a SKU that never mutate once created (e.g., the fact that a boot is Size 38, or a Laptop is a Dell) are stamped as raw text into the JSON payload.
- Why? This prevents massive, costly SQL JOIN operations to dozens of arbitrary attribute catalogs during routine Kardex reads. Input validation (ensuring the user selects "Dell" and not "Del") is handled by the Application/UI layer during variant creation via standardized frontend catalogs.
Updates to the Stock Position (materialized view) and inserts into the Kardex (ledger) must always occur within the same strict database Transaction (BEGIN TRAN / COMMIT). If the Kardex insert succeeds but the Stock Position update fails, the entire transaction rolls back to prevent phantom inventory discrepancies.
System Entity Relationship Overview
erDiagram
LOCATION ||--o{ EMPLOYEE : "Assigns Virtual Locker"
EMPLOYEE }o--|| POSITION : "Holds"
POSITION ||--o{ UNIFORM_RULE : "Requires"
UNIFORM_RULE }o--|| PRODUCT_TEMPLATE : "Dictates Template"
`PRODUCT_TEMPLATE ||--|{ PRODUCT_VARIANT : "Generates SKUs"`
`PRODUCT_VARIANT ||--o{ STOCK_POSITION : "Tracked In"`
`LOCATION ||--o{ STOCK_POSITION : "Holds Stock"`
`PRODUCT_VARIANT ||--o{ KARDEX_LEDGER : "Moves"`
`LOCATION ||--o{ KARDEX_LEDGER : "Source/Dest"`
`MOVEMENT_CATALOG ||--o{ KARDEX_LEDGER : "Defines Txn"`