141 lines
3.5 KiB
Markdown
141 lines
3.5 KiB
Markdown
# Pricing Architecture
|
|
|
|
## Goals
|
|
|
|
Provide a defensible calculated market value while retaining provider provenance and uncertainty.
|
|
|
|
## Provider abstraction
|
|
|
|
All providers implement a common conceptual interface:
|
|
|
|
`PricingProvider`
|
|
|
|
A provider returns normalized observations containing:
|
|
- provider/source
|
|
- Product or Inventory Item context
|
|
- price
|
|
- currency
|
|
- condition
|
|
- timestamp
|
|
- source URL/identifier
|
|
- quality/confidence information
|
|
|
|
Provider adapters own provider-specific API behavior and normalization.
|
|
|
|
The application uses a validated provider registry. A refresh request selects a
|
|
registered provider, normalizes its observation array through the existing
|
|
pricing service, and recalculates the item valuation. Missing providers return
|
|
an explicit unavailable response; the application never fabricates observations
|
|
or values.
|
|
|
|
Use officially supported APIs or permitted sources. Do not invent APIs or bypass restrictions.
|
|
|
|
## Provider Product Mapping
|
|
|
|
Mapping occurs during new Product creation.
|
|
|
|
Workflow:
|
|
|
|
`Create Product → Search Providers → Candidate Matches → Admin Confirms Mapping`
|
|
|
|
The admin can also search/refine manually.
|
|
|
|
Mappings are persistent Product-level records and are reused for future physical copies.
|
|
|
|
Provider mapping is not required.
|
|
|
|
A provider can be:
|
|
- linked to a canonical product
|
|
- linked to a search/query
|
|
- marked Not Applicable
|
|
- left unlinked
|
|
|
|
### Mapping types
|
|
|
|
`PRODUCT`
|
|
- specific provider/catalog entity
|
|
|
|
`SEARCH`
|
|
- provider search/query definition
|
|
|
|
eBay supports both.
|
|
|
|
## Pricing pipeline
|
|
|
|
```text
|
|
Raw Provider Data
|
|
↓
|
|
Normalized Observations
|
|
↓
|
|
Quality / Confidence Analysis
|
|
↓
|
|
Valuation Strategy
|
|
↓
|
|
Calculated Market Value
|
|
↓
|
|
Optional Manual Override
|
|
↓
|
|
Display Currency Conversion
|
|
```
|
|
|
|
## Valuation
|
|
|
|
Default strategy: median.
|
|
|
|
Supported strategies should include:
|
|
- average
|
|
- median
|
|
- weighted average
|
|
|
|
The strategy is configurable.
|
|
|
|
Outliers remain in the underlying observations and are flagged with a reason. The valuation engine may account for outlier status according to the selected strategy, but raw observations are not silently discarded.
|
|
|
|
One valid source can produce a market value with low confidence.
|
|
|
|
No reliable condition-specific value means unavailable; never fabricate a value.
|
|
|
|
## Refresh
|
|
|
|
Refresh:
|
|
- one Inventory Item
|
|
- Product-level copies
|
|
- bulk selected inventory
|
|
|
|
Bulk refresh runs through BullMQ in the worker.
|
|
|
|
The worker-side refresh boundary is implemented with explicit `COMPLETED` and
|
|
`FAILED` outcomes. It resolves a registered provider, persists normalized
|
|
observations through the pricing service, and recalculates the valuation. A
|
|
provider that is missing or fails does not produce a fabricated value. Durable
|
|
refresh-job storage and row-locked worker claim/complete/fail lifecycle are
|
|
implemented in PostgreSQL. External provider configuration remains deployment
|
|
work.
|
|
|
|
Provider failure should not invalidate other valid observations. The failed provider is recorded for admin diagnostics.
|
|
|
|
## Overrides
|
|
|
|
Admin can manually override market value.
|
|
|
|
Override requires:
|
|
- value
|
|
- currency
|
|
- private reason
|
|
- actor
|
|
- timestamp
|
|
|
|
Overrides are never exposed publicly as provider-level information.
|
|
|
|
## Currency
|
|
|
|
Canonical stored/calculated market values use USD.
|
|
|
|
Visitor currency conversion occurs at presentation time using cached exchange rates.
|
|
|
|
The original USD value remains authoritative.
|
|
|
|
## Staleness
|
|
|
|
Pricing freshness is configurable. Dashboard and admin inventory can identify stale values. The exact default threshold is a configuration decision during implementation, not a hard-coded domain invariant.
|