deckhearth/.convoys/pricing-online-local/brief-2-pricing-foundation-lib.md
Randall Stillwell d0468015eb
Some checks failed
CI / Lint (pull_request) Has been cancelled
CI / Schema map up to date (pull_request) Has been cancelled
CI / Forbidden patterns (9 checks) (pull_request) Has been cancelled
CI / Migrations apply (node-pg-migrate) (pull_request) Has been cancelled
Visual diff / Should run? (pull_request) Has been cancelled
CI / Unit tests (vitest) (pull_request) Has been cancelled
Convoy metrics gate / Require role-event telemetry on convoy PRs (pull_request) Has been cancelled
PR Health rollup / Aggregate gate status (pull_request) Has been cancelled
Preview smoke / Should run? (pull_request) Has been cancelled
Preview smoke / Playwright smoke (pull_request) Has been cancelled
Visual diff / Screenshot diff (pull_request) Has been cancelled
feat(pricing): convoy for online prices and local stores
Add pricing schema, free API integrations (MTG bulk, TCGdex, Foolio),
valuation and sort-by-price, card detail pricing UI, and nearby store
discovery via home zip and OSM geo clients.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 22:47:46 -05:00

56 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
convoy: pricing-online-local
brief_number: 2
depends_on: [1]
recommended_model: composer-2.5
model_tier: standard
files:
- lib/pricing/card-price.js
- lib/pricing/price-history.js
- lib/pricing/collection-valuation.js
- lib/pricing/outbound-links.js
- test/lib/pricing/card-price.test.js
- test/lib/pricing/price-history.test.js
- test/lib/pricing/collection-valuation.test.js
cross_brief_commitments:
- brief: 3
description: |
Briefs 3–5 import `recordPriceSnapshots` from `lib/pricing/price-history.js`
and set `prices_updated_at` after successful price writes. They must call
the shared helpers rather than duplicating snapshot SQL.
---
# Brief 2: Pricing foundation lib
## Goal (1 sentence)
Create shared pricing helpers for foil-aware unit prices, daily history snapshots, collection valuation SQL, and outbound buy links.
## Files in scope (do not edit anything else)
- `lib/pricing/card-price.js`
- `lib/pricing/price-history.js`
- `lib/pricing/collection-valuation.js`
- `lib/pricing/outbound-links.js`
- `test/lib/pricing/card-price.test.js`
- `test/lib/pricing/price-history.test.js`
- `test/lib/pricing/collection-valuation.test.js`
## Conventions to follow
- ESM (`import`/`export`); DB via `import { sql } from '../sql.js'` (relative from `lib/pricing/`).
- `card-price.js`: export `resolveUnitPrice({ currentPrice, marketPrice, isFoil })` — nonfoil prefers `current_price`, foil prefers `market_price`; export `PRICE_STALE_HOURS = 24`.
- `collection-valuation.js`: export `effectiveUnitPriceExpr({ cardAlias = 'c', userCardAlias = 'uc' })` returning SQL `CASE WHEN uc.is_foil THEN c.market_price ELSE COALESCE(c.current_price, c.market_price) END`; export `listUnitPriceExpr({ cardAlias = 'c' })` → `COALESCE(c.current_price, c.market_price)`.
- `price-history.js`: export `recordPriceSnapshots(rows)` where each row is `{ cardId, source, priceType, currency, amount }`; upsert on daily UNIQUE key.
- `outbound-links.js`: extract TCGPlayer + eBay URL logic currently inline in `CardDetailView.js` (game-aware).
- Mirror test style from `test/lib/collection-vocabulary.test.js`.
## Acceptance criteria
- [ ] `resolveUnitPrice` returns foil vs nonfoil correctly for MTG-shaped data
- [ ] `recordPriceSnapshots` is idempotent for same card/day/source/type
- [ ] `effectiveUnitPriceExpr` produces valid SQL fragment (unit-tested via known inputs or integration mock)
- [ ] `buildTcgplayerUrl(card)` and `buildEbayUrl(card)` exported
- [ ] All three test files pass (`npm run test:run`)
- [ ] No scope expansion
## Rationale (≤3 sentences)
Centralizes pricing semantics so bulk sync, valuation fix, and APIs cannot drift. The foil bug (`market_price` = Scryfall `usd_foil`) is fixed once at the helper layer. Snapshot writer gives Briefs 3–5 a single hook.