Relatude.DB.Ecom
1.0.40
See the version list below for details.
dotnet add package Relatude.DB.Ecom --version 1.0.40
NuGet\Install-Package Relatude.DB.Ecom -Version 1.0.40
<PackageReference Include="Relatude.DB.Ecom" Version="1.0.40" />
<PackageVersion Include="Relatude.DB.Ecom" Version="1.0.40" />
<PackageReference Include="Relatude.DB.Ecom" />
paket add Relatude.DB.Ecom --version 1.0.40
#r "nuget: Relatude.DB.Ecom, 1.0.40"
#:package Relatude.DB.Ecom@1.0.40
#addin nuget:?package=Relatude.DB.Ecom&version=1.0.40
#tool nuget:?package=Relatude.DB.Ecom&version=1.0.40
Relatude.Ecom
A .NET 8 e-commerce backend layered on Relatude.CMS (package dependency), which in turn runs on the Relatude.DB node/graph database. Adds the commerce model (products, orders, carts), pricing, and pluggable providers (payment, shipping, tax, …).
Using an AI coding agent? This package ships a Claude Code skill (
relatude-ecom) with the same guidance below. Read theRelatude.CMSdocs (relatude-cmsskill) first — it covers the shared Relatude.DB fundamentals (host setup,NodeStore, modeling interfaces, relations, CRUD, queries) that this layer assumes.Relatude.CMSis pulled in transitively, so its docs travel alongside this package.
Commerce model
Entities are interfaces, like in CMS. Products extend the CMS content model so they are routable pages:
public interface IProduct : IItem, IPage {
decimal Price { get; set; }
int NumberInStock { get; set; }
ProductCategoryProducts.Category Category { get; set; } // one-end → category
ProductVariants.SubVariants Variants { get; set; } // many-end → variant products
[EmbeddedMapProperty(KeyProperty = nameof(IAlternativeCurrencyPrice.CurrencyCode))]
EmbeddedMap<string, IAlternativeCurrencyPrice> AlternativePrices { get; }
}
Core entities: IShop, IProduct, IProductCategory, IProductBundle, ISimpleVariant, IBrand, IOrder, IOrderItem, IEcomUser, ICurrency, IEcomCountry, IPaymentMethod, IShippingMethod, ITaxClass, ITaxRate, ISalesChannel, IDiscount. Relations live in Models/EcomRelations.cs, declared with the same OneToMany/ManyToMany marker-class pattern as CMS.
Carts (ShoppingCartService)
A cart is an IOrder with OrderStatus.Basket — there is no separate cart type; checkout advances the order's status. ShoppingCartService resolves the cart from IEcomUser.Orders for authenticated users (looked up via the ClaimTypes.NameIdentifier claim) or from a cookie (EcomSettings.CartCookieName, default ecom.cart) holding the order Guid for anonymous users. Every method takes NodeStore db. Items are managed via SetRelation/ClearRelation on IOrder.OrderItems; re-adding a product increments Quantity instead of duplicating. Settings come from IOptions<EcomSettings> (config section "Ecom").
Pricing (DefaultPricingService)
DefaultPricingService : IPricingService composes four injected collaborators — IPriceResolver (base price), IProductDiscountProvider, IOrderDiscountProvider, and ITaxCalculationProvider (VAT). A PricingContext flows through every calculation; it requires Shop and CurrencyCode and carries the NodeStore. Amounts are computed ex-VAT first, then VAT applied, rounded via CurrencyUtils.Round. CalculateProductVariantPrices prices the product plus its Variants.
VAT rates are percentages — ITaxRate.Rate, ITaxCalculationProvider.GetVatRate, BaseProductPrice.VatRate and ProductPrice.VatRate all use 25m for 25%. CurrencyUtils.Round is 2-decimal money rounding and is applied to amounts only, never to rates.
DefaultTaxCalculationProvider resolves VAT from the tax model — IProduct.TaxClass (falling back to IShop.DefaultTaxClass) → ITaxClass.TaxRates → the rate whose Countries matches PricingContext.CountryCode against IEcomCountry.Code (or Name while Code is unset). A class with a single rate uses it unconditionally; several rates and no country match throws rather than guess. A tax provider must never call IPricingService — pricing already depends on the tax provider through IPriceResolver, so calling back is a DI cycle and unbounded recursion. GetVatAmount is handed the ex-VAT amount; use it instead of re-pricing.
Currency resolution order. An authored IProduct.AlternativePrices entry for the target currency wins outright; only when there is none does BasePriceResolver convert Price from the shop's DefaultCurrency via ICurrencyConverter. Simple variants carry a bare Price with no alternatives, so they always convert. A shop with no DefaultCurrency is left alone, since nothing says what its prices are denominated in.
ICurrency.Rate is a cross-rate — each currency's value expressed in a common reference, so DefaultCurrencyConverter computes amount * from.Rate / to.Rate and the reference cancels out. Conventionally the shop's default currency has Rate = 1: with NOK as reference, EUR.Rate = 11.50 means 1 EUR = 11.50 NOK. Conversion returns full precision — only CurrencyUtils.Round turns an amount into money, so a rate is never truncated to two decimals. Rate defaults to 0 on nodes created before it existed, and converting against a non-positive rate throws rather than silently returning an unconverted amount.
Order pricing. CalculateOrderPrice prices each line through CalculateProductPrice, takes shipping from the amounts stored on the order (ShippingAmountNet/ShippingAmountGross) rather than calling a shipping provider, applies IOrderDiscountProvider, then totals via OrderPrice.RecalculateTotals(). To price shipping live, set OrderPrice.ShippingExVat/ShippingIncVat on the result and call RecalculateTotals() again. PricingContext.SimpleVariantId selects a simple variant's own price; VariantId selects a sub-product variant.
Providers (Providers/...)
Each pluggable concern is an IXxxProvider interface with a Default* implementation: Currency, Discounts, Inventory, Notification, Payment, Shipping, Tax. Multi-implementation concerns (Payment, Shipping) resolve a concrete provider by a string ProviderKey via a factory over IEnumerable<IXxxProvider>:
services.AddScoped<IPaymentProvider, StripePaymentProvider>(); // each exposes ProviderKey
services.AddScoped<IPaymentProvider, NetsPaymentProvider>();
services.AddScoped<IPaymentProviderFactory, PaymentProviderFactory>();
// at runtime:
var provider = factory.GetProvider(paymentMethod.ProviderKey); // throws on unknown key
The order/payment-method node stores which ProviderKey to use. This library supplies the contracts and Default* implementations; the host registers concrete third-party providers and wires the rest in DI.
Notes
- A cart is just an
IOrderinBasketstatus — there is no dedicated cart entity. CalculateOrderPricetakes shipping from the order's stored amounts, not from a shipping provider.PricingContextwithoutShop/CurrencyCodethrows — always set both.- All Relatude.DB rules from
Relatude.CMSapply (Createdoesn't persist, relation ends aren't lists, mutate-then-Update, …). - Relatude.DB source/API reference: https://github.com/Relatude/Relatude.DB
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.AspNetCore.Http (>= 2.3.10)
- Relatude.DB.CMS (>= 1.0.40)
- Relatude.DB.Server (>= 0.4.0.192-alpha)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Relatude.DB.Ecom:
| Package | Downloads |
|---|---|
|
Relatude.Core
Relatude .Net 10.0 Headless CMS and E-commerce solution |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.44-alpha | 59 | 10/12/2026 |
| 1.0.43 | 120 | 10/5/2026 |
| 1.0.42 | 117 | 9/23/2026 |
| 1.0.41 | 95 | 9/23/2026 |
| 1.0.40 | 91 | 9/23/2026 |
| 1.0.39 | 125 | 9/7/2026 |
| 1.0.38 | 155 | 9/1/2026 |
| 1.0.37 | 124 | 8/26/2026 |
| 1.0.36 | 112 | 8/21/2026 |
| 1.0.35 | 125 | 8/18/2026 |
| 1.0.34 | 112 | 8/17/2026 |
| 1.0.33 | 115 | 8/17/2026 |
| 1.0.32 | 158 | 8/5/2026 |
| 1.0.31 | 122 | 8/4/2026 |
| 1.0.29 | 119 | 7/26/2026 |
| 1.0.28 | 116 | 7/26/2026 |
| 1.0.27 | 118 | 7/26/2026 |
| 1.0.26 | 131 | 7/21/2026 |
| 1.0.25 | 116 | 7/21/2026 |
| 1.0.24 | 119 | 7/21/2026 |