Files
fragginwagon 76e40d7289
Quality / test (push) Canceled after 0s
feat: schedule pricing job retention cleanup
Schedule configurable completed pricing-job cleanup in the worker, broaden repository cleanup across sellers, add unit and integration coverage, and update pricing operational documentation.
2026-09-09 22:32:04 -04:00

152 lines
4.2 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.
Local development and CI may enable the deterministic `fixture-provider` with
`PRICING_FIXTURE_PROVIDER_ENABLED=true`. It exists only for repeatable
workflow/testing coverage and is disabled by default; production deployments
must register an approved external adapter instead.
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.
Refresh jobs allow three attempts. Failed attempts requeue with short
exponential backoff; the third failure becomes terminal `FAILED`. Completed-job
retention is handled explicitly through the repository cleanup operation. The
worker schedules cleanup across all sellers using `PRICING_JOB_RETENTION_DAYS`
(default `30`) and `PRICING_JOB_CLEANUP_INTERVAL_MS` (default one hour).
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.