Problem statement
Design the object model and core APIs for a component that resolves the correct unit price of a product given quantity breaks, customer segment, contract price lists, and currency, for a single B2B/B2C commerce catalogue.
Operating context. A product can be priced by several sources at once: a base list price, volume tiers (quantity breaks), customer-group prices, a negotiated contract price, and a time-bounded promotional price. Given a query (product, customer, quantity, date, currency) the resolver selects the applicable price via a precedence policy (e.g. contract beats customer-group beats list) and returns the unit price together with which source and rule won, so the outcome is explainable. Lookups are read-heavy and concurrent, and the whole thing is a single in-process component.
Out of scope. Computing the cart total, tax, and discount stacking (a separate concern), sourcing currency FX rates, the catalogue-authoring UI, and persistence.
What to produce. The class hierarchy (Product, the price-source types, PriceList/TierTable, the PriceResolver, and the query/result value objects), the public API each exposes, and the resolution algorithm. Be explicit about: how a new price-source type plugs in without editing the resolver core, how precedence and ties are decided deterministically, and how the winning source is reported for explainability.
Functional requirements
- Resolve the unit price for a (product, customer, quantity, date, currency) query from all applicable price sources.
- Apply quantity-break tiers so the price reflects the band the requested quantity falls into.
- Honor a precedence policy when several sources match (e.g. contract beats customer-group beats list).
- Return which source and rule produced the price, so the outcome is explainable.
- Fall back to a defined default (the list price) when no specialised source matches.
Non-functional requirements
- A resolution is O(S) in the matching sources, with tier lookup O(log B) over B quantity bands.
- Price sources are pluggable; a new source type is added without editing the resolver core (open/closed).
- Resolution is a pure function of its inputs and thread-safe for concurrent reads.
- Precedence is declared as policy/data, not hard-coded branches, so it can be reconfigured.
- Currency is a value object; a mismatched-currency query fails fast rather than returning a wrong number.
- The resolver is unit-testable with in-memory fixtures and an injected clock for time-bounded prices.
Topics
- System Design LLD
- Commerce Pricing
- Patterns Chain
- Patterns Strategy
- Oop Solid