Files
pokemon-inventory/docs/PRICING.md
T
2026-09-09 14:02:03 -04:00

3.8 KiB

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

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.