Backend Contexts: Specs & Pricing
Relevant source files
The following files were used as context for generating this wiki page:
The Specs and Pricing contexts form the core of the ProductCompare engine, enabling typed attribute management, claim validation, and historical price tracking. These modules are built within a Phoenix modular monolith architecture, utilizing PostgreSQL 18 for durable storage and Relay-first GraphQL for data transport.
The Specs context manages product attributes, unit conversions, and the lifecycle of "claims" (proposals for product data), while the Pricing context tracks merchants, listings, and price history to provide real-time offer data to users.
Sources: README.md:15-16, 2026-03-03-product-compare-backend-mvp-plan.md:10-14
Specs Context: Attributes and Claims
The Specs context is responsible for maintaining a structured set of product attributes. It utilizes an append-only "claim" system where users or automated sources propose values, which are then moderated before becoming the "current" selected value for a product.
Data Architecture
Attributes are defined with specific data types (bool, numeric, enum) and can be associated with dimensions and units for normalization. Numeric values are normalized to a value_num_base to facilitate fast filtering and comparison across different units (e.g., converting inches to millimeters).
The diagram above illustrates the relationship between products, their attributes, and the claim lifecycle.
Sources: 2026-03-03-product-compare-backend-mvp-plan.md:112-140, 2026-03-03-product-compare-backend-mvp-plan.md:154-160
Key Functions and Workflows
| Function | Responsibility |
|---|---|
propose_claim/4 | Validates typed-values and links optional provenance/evidence. |
accept_claim/2 | Transition a claim status to accepted (moderator gate). |
select_current_claim/4 | Transactionally updates the product_attribute_current record for a product/attribute pair. |
convert_to_base/3 | Normalizes numeric values using multiplier_to_base and offset_to_base. |
Sources: 2026-03-03-product-compare-backend-mvp-plan.md:197-208
Pricing Context: Merchants and History
The Pricing context manages external market data. It tracks Merchants (the stores), MerchantProducts (the specific listing URLs), and PricePoints (the historical record of prices).
Pricing Data Flow
Pricing data is optimized for two main queries: retrieving the latest active price for a product detail page and fetching historical trends.
The flow shows how pricing data moves from ingestion to the end-user query.
Sources: 2026-03-03-product-compare-backend-mvp-plan.md:215-220, assets/src/routes/products/api.ts:46-68
API and Data Structures
The backend utilizes Dataloader for batching latest-price lookups to avoid N+1 query problems in GraphQL connections.
- MerchantProduct: Represents a link between a product and a merchant.
- PricePoint: An append-only record of a price at a specific
observed_attimestamp. - GraphQL Input:
MerchantProductsInputfilters foractiveOnlylistings and supports pagination.
Sources: ARCHITECTURE.md:27-28, assets/src/routes/products/api.ts:46-68
Implementation Standards
Both contexts follow the project's strict architectural guidelines for consistency and performance.
Database Conventions
- Primary Keys: Standard
bigintfor internal foreign keys. - Public IDs:
entropy_id(UUIDv7) used for all public-facing Relay global IDs. - Timestamps: Always use
:utc_datetime_usec. - Concurrency:
select_current_claim/4uses transactional locks to prevent race conditions during claim swaps.
Sources: backend_starting_guide.md:7-15, 2026-03-03-product-compare-backend-mvp-plan.md:206-208
Filtering and Performance
To maintain fast filtering, the system maintains composite indexes on the product_attribute_current and product_attribute_claims tables:
- Unique index on
(product_id, attribute_id)in the current table. - Partial indexes on
value_num_base,value_bool, andenum_option_idfor efficient range and value scans.
Sources: 2026-03-03-product-compare-backend-mvp-plan.md:154-162
Summary
The Specs & Pricing backend modules provide a robust foundation for product comparison. By separating raw claims from the "current" selected data and maintaining a strict append-only pricing history, the system ensures data integrity and high performance for complex filtering and historical analysis. These contexts are designed to scale through Phoenix modular boundaries while providing a consistent Relay-compliant GraphQL API to the frontend.