Skip to main content

Categories Domain

Overview

The Categories domain provides hierarchical product classification capabilities for the inventory system. It enables organizations to organize their item catalog into logical groupings that support navigation, reporting, analysis, and item management workflows. Categories use a simple self-referencing parent-child structure that can accommodate unlimited hierarchy depth.

Core Concepts

Hierarchical Classification

Categories implement a tree structure that mirrors real-world product taxonomy:

All Products (root)
├── Electronics
│ ├── Computers
│ │ ├── Laptops
│ │ ├── Desktops
│ │ └── Tablets
│ ├── Mobile Devices
│ │ ├── Smartphones
│ │ └── Accessories
│ └── Audio Equipment
├── Office Supplies
│ ├── Writing Instruments
│ ├── Paper Products
│ └── Desk Accessories
└── Raw Materials
├── Metals
├── Plastics
└── Chemicals

Classification Benefits

Navigation: Users browse items by category hierarchy Reporting: Category-based analytics and summaries Search: Filter items by category for focused results Organization: Logical grouping of related items Authorization: Future support for category-level permissions

Domain Structure

Aggregates

categories/
└── aggregates/
└── category.aggregate.md # Category aggregate documentation

Entities

categories/
└── entities/
└── category.md # Category entity (aggregate root)

Key Aggregates

Category

Aggregate Root: Category

Purpose: Represents a hierarchical classification node for organizing items.

Key Characteristics:

  • Self-referencing hierarchy (parent-child)
  • Unlimited depth support
  • Simple tree structure
  • Active/inactive status (soft delete)
  • Unique code identifier

Relationships:

  • Has one parent Category (optional - root categories have no parent)
  • Has many child Category instances (0 to many)
  • Referenced by many Item instances

Core Operations:

  • Create category with optional parent
  • Update category information
  • Check if root category
  • Check if has children
  • Get hierarchical path for display
  • Archive/unarchive category

Business Rules

Category Creation Rules

  1. Code Required: Category code must be unique and not empty
  2. Name Required: Category name cannot be empty
  3. Description Optional: Additional details can be provided
  4. Parent Optional: Categories can be root-level (no parent)
  5. Parent Must Be Active: Cannot create child category under inactive parent

Hierarchy Rules

  1. No Circular References: Category cannot be its own ancestor (validated at service level)
  2. Single Parent: Each category has at most one parent
  3. Unlimited Depth: No artificial limit on hierarchy depth
  4. Root Categories: Categories without parent are considered root

Update Rules

  1. Immutable Code: Category code cannot be changed after creation
  2. Name Updates: Category name can be freely updated
  3. Description Updates: Description can be added, updated, or cleared
  4. Parent Reassignment: Not supported directly (create new category instead)

Archive Rules

  1. Soft Delete: Categories archived via IsActive flag
  2. Child Impact: Archiving parent doesn't automatically archive children
  3. Item Reference: Items referencing archived categories retain reference
  4. Restoration: Archived categories can be unarchived

Integration Points

With Item Module

  • Item Classification: Items reference one category
  • Category Navigation: Browse items by category
  • Category Filtering: Filter item lists by category
  • Optional Assignment: Items can exist without category

With Reporting

  • Category Reports: Summarize inventory by category
  • Hierarchy Reports: Show category hierarchy with item counts
  • Category Analysis: Analyze patterns at category level
  • Drill-Down: Navigate from category summaries to item details

With User Interface

  • Category Trees: Display hierarchy in navigation
  • Breadcrumbs: Show category path in item views
  • Category Selectors: Dropdown or tree picker for category assignment
  • Search Filters: Category-based search filtering

Common Patterns

Creating Root Category

// Create top-level category (no parent)
var rootCategory = Category.Create(
code: "ELECTRONICS",
name: "Electronics",
description: "Electronic devices and components");

await categoryRepository.AddAsync(rootCategory);
await unitOfWork.CommitAsync();

Creating Child Category

// 1. Load parent category
var parentCategory = await categoryRepository
.GetByCodeAsync("ELECTRONICS");

// 2. Create child category
var childCategory = Category.Create(
code: "COMPUTERS",
name: "Computers",
description: "Desktop and laptop computers",
parentCategory: parentCategory);

await categoryRepository.AddAsync(childCategory);
await unitOfWork.CommitAsync();

// Result hierarchy: Electronics > Computers

Building Multi-Level Hierarchy

// Level 1: Root
var electronics = Category.Create("ELECTRONICS", "Electronics");

// Level 2: Sub-category
var computers = Category.Create("COMPUTERS", "Computers",
parentCategory: electronics);

// Level 3: Sub-sub-category
var laptops = Category.Create("LAPTOPS", "Laptops",
parentCategory: computers);

// Save all
await categoryRepository.AddAsync(electronics);
await categoryRepository.AddAsync(computers);
await categoryRepository.AddAsync(laptops);
await unitOfWork.CommitAsync();

// Result: Electronics > Computers > Laptops

Getting Category Path for Display

var category = await categoryRepository.GetByCodeAsync("LAPTOPS");

// Get full hierarchical path
string path = category.GetHierarchyPath();
// Result: "Electronics > Computers > Laptops"

// Use in UI:
// - Breadcrumbs: Home > Electronics > Computers > Laptops
// - Item display: "Category: Electronics > Computers > Laptops"
// - Reports: Group by full category path

Checking Category Status

var category = await categoryRepository.GetByCodeAsync("COMPUTERS");

// Check if root category
bool isRoot = category.IsRoot(); // false (has parent)

// Check if has children
bool hasChildren = category.HasChildren(); // true (has laptops, desktops, etc.)

// Get children
var children = category.ChildCategories; // Collection of child categories

Updating Category

var category = await categoryRepository.GetByCodeAsync("COMPUTERS");

// Update name and description
category.Update(
name: "Computer Systems",
description: "Desktop computers, laptops, and workstations");

await unitOfWork.CommitAsync();

// Note: Code cannot be changed
// Note: Parent cannot be changed (create new category instead)

Archiving Category

var category = await categoryRepository.GetByCodeAsync("OBSOLETE-CATEGORY");

// Archive category (soft delete)
categoryRepository.Archive(category);
await unitOfWork.CommitAsync();

// Category is now inactive (IsActive = false)
// Items still reference it
// Can be restored later

// Later, restore if needed
categoryRepository.UnArchive(category);
await unitOfWork.CommitAsync();

Repository Pattern

ICategoryRepository

Query Methods:

  • GetByIdAsync(Guid id): Get single category with related data
  • GetAllAsync(): Get all active categories
  • GetByCodeAsync(string code): Find category by unique code
  • GetRootCategoriesAsync(): Get top-level categories (no parent)
  • GetChildrenAsync(Guid parentId): Get immediate children
  • GetDescendantsAsync(Guid parentId): Get all descendants (recursive)

Specialized Query Methods:

  • GetCategoryTreeAsync(): Load entire category tree
  • GetCategoriesWithItemCountAsync(): Categories with item counts
  • GetAncestorsAsync(Guid categoryId): Get all parent categories up to root
  • GetPathAsync(Guid categoryId): Get full path from root

Validation Methods:

  • ExistsByCodeAsync(string code): Check if category code exists
  • IsCodeUniqueAsync(string code, Guid? excludeId): Validate for updates
  • HasChildrenAsync(Guid categoryId): Check if category has children
  • HasItemsAsync(Guid categoryId): Check if items assigned to category

Command Methods:

  • AddAsync(Category category): Create new category
  • Update(Category category): Update existing category
  • Archive(Category category): Soft delete category
  • UnArchive(Category category): Restore archived category

Domain Services

CategoryHierarchyService (Future Enhancement)

Purpose: Validates complex hierarchy operations and provides advanced hierarchy queries.

Planned Methods:

Task<bool> WouldCreateCircularReference(Guid categoryId, Guid newParentId)
Task<IEnumerable<Category>> GetAllAncestorsAsync(Category category)
Task<IEnumerable<Category>> GetAllDescendantsAsync(Category category)
Task<int> GetHierarchyDepthAsync(Category category)
Task MoveCategory(Guid categoryId, Guid? newParentId)

Testing Strategy

Unit Tests

  • Factory Method Tests: Category creation with various combinations
  • Hierarchy Tests: Parent-child relationship management
  • Validation Tests: Business rule enforcement
  • Path Tests: Hierarchy path calculation
  • Status Tests: Root and children checks

Integration Tests

  • Repository Tests: Database operations and query correctness
  • Hierarchy Persistence: Multi-level hierarchies correctly saved/loaded
  • Relationship Tests: Parent-child navigation
  • Item Integration: Categories correctly associated with items
  • Circular Reference Tests: Prevention at database level

Performance Considerations

Optimization Strategies

  • Hierarchy Loading: Load full tree in single query for UI
  • Path Caching: Cache calculated paths for performance
  • Item Count Aggregation: Cached item counts per category
  • Indexed Queries: Fast lookups by code and parent ID

Scalability Metrics

  • Category Lookup: <5ms for code-based lookup
  • Tree Loading: <50ms for full category tree (100 categories)
  • Path Calculation: <10ms for path generation
  • Memory Footprint: ~500 bytes per category

Database Optimization

  • Clustered Index: Primary key on Category Id
  • Code Index: Unique non-clustered index on Code
  • Parent Index: Non-clustered index on ParentCategoryId
  • Hierarchy Queries: Recursive CTE support for descendants

Future Enhancements

Planned Features

  1. Category Attributes: Custom attributes per category
  2. Category Images: Visual representation for UI
  3. Category Templates: Default settings for items in category
  4. Multi-Path Categories: Items in multiple categories
  5. Category Authorization: Permission control at category level
  6. Category Sorting: Custom sort order within parent
  7. Category Tags: Additional classification beyond hierarchy

Extensibility Points

  1. Domain Events: Publish events for category changes

    • CategoryCreated
    • CategoryUpdated
    • CategoryArchived
  2. Hierarchy Service: Advanced hierarchy operations

  3. Integration Events: Cross-module communication

    • CategoryStructureChanged → Reporting
    • CategoryArchived → All consuming modules

Domain Documentation

API Documentation

Concept Documentation


Last Updated: 2025-10-24 | Status: Production Ready | Version: 1.0