This page maps out how the major entities in Merchello relate to each other. Understanding these relationships will help you navigate the codebase, write queries, and build extensions.
Parent-level configuration. Holds the product name, tax group, product type, option definitions, collections, images, and package defaults.
Product
A specific variant (e.g., "Blue / Large"). Holds SKU, price, cost, stock levels, and optional package overrides.
ProductType
Categorization (e.g., "Clothing", "Electronics"). Each product root has exactly one type.
ProductCollection
Grouping for merchandising (e.g., "Summer Sale"). Many-to-many with product roots.
ProductOption
An option like "Size" or "Colour" with values. Controls variant generation when IsVariant = true.
ProductFilter / ProductFilterGroup
Faceted filtering for storefront browsing (e.g., filter by colour, price range).
Note: The ProductRoot is the "parent" that customers browse. Each Product is a purchasable variant. A product root with no variant options has a single default product.
A physical location that holds stock and defines shipping origins.
ProductWarehouse
Join table linking a Product (variant) to a Warehouse with Stock and Reserved quantities.
ProductRootWarehouse
Links a ProductRoot to a Warehouse with a Priority value for warehouse selection order.
Stock lifecycle for tracked inventory:
1. Reserve -- when a customer checks out: Reserved += qty
2. Allocate -- when an order is shipped: Stock -= qty, Reserved -= qty
3. Cancel/Release -- if the order is cancelled: Reserved -= qty
A vendor/supplier entity. Linked to products through ExtendedData["VendorId"] on ProductRoot. Used for vendor-based order grouping and supplier-direct fulfilment.
A shopping basket. Holds line items, currency info, and is linked to a customer (optional for guest checkout).
AbandonedCheckout
Tracks baskets that entered checkout but were not completed.
LineItem
A single item in a basket, order, or shipment. Polymorphic -- the LineItemType enum distinguishes Product, Addon, Shipping, Discount, Tax, and Custom types.
The financial document created at checkout. Links a customer to their orders and payments. Contains billing/shipping addresses, currency info, totals, and source tracking.
Order
A fulfilment unit within an invoice. An invoice can have multiple orders (e.g., when items ship from different warehouses). Each order is linked to one warehouse.
Payment
A payment attempt against an invoice. Tracks amount, provider, success/failure, idempotency keys, and risk scores.
TaxGroup
A tax classification (e.g., "Standard Rate 20%"). Products are assigned to tax groups via their product root.
TaxGroupRate
Country/region-specific tax rates within a tax group.
ShippingTaxOverride
Overrides for shipping tax behavior by country/region.
Tip: An invoice can have multiple payments (partial payments, failed attempts followed by a success). The PaymentService.CalculatePaymentStatus() method computes the aggregate status from all payments.
Key points:
- One invoice can have multiple orders when items ship from different warehouses.
- One order can have multiple shipments for partial fulfilment.
- Line items are copied (not shared) between basket, order, and shipment using the LineItemFactory.
- Discounts flow as LineItemType.Discount line items on orders, scaled proportionally when split across warehouses.
The MerchelloDbContext at Merchello.Core/Data/Context/MerchelloDbContext.cs is the single source of truth for all entity registrations and their EF Core mappings. Entity configurations are applied via modelBuilder.ApplyConfigurationsFromAssembly() from mapping classes in each feature's Mapping/ folder.