PersonalMarketplace Intelligence2026
PadelPrice
From noisy marketplace listings to traceable racket price history
A local price-intelligence pipeline for padel rackets: Tokopedia search, deterministic product matching, persistent price observations, scheduled refreshes, and Telegram alerts.

Overview
PadelPrice is a personal, locally run price-tracking application for padel rackets. I built it to turn inconsistent seller listings into canonical products, retain each price observation, schedule future checks, and make price changes actionable through alert rules. Tokopedia search currently runs through ReefAPI, a third-party data provider.

The Identity Problem
Marketplace titles mix model names, versions, materials, years, and seller shorthand. A near match can be a different racket. PadelPrice normalizes Tokopedia results, then applies domain-focused deterministic rules to brand, model, family, carbon, Alum, edition, and year. Results are classified as MATCH, RELATED_VARIANT, UNCERTAIN, or MISMATCH; only confident matches are tracked.
This is a deliberately limited rule set, not an LLM or a general product-identity engine. Missing attributes and unfamiliar editions still require review.

Tracking Architecture
One product identity connects marketplace offers, scheduled observations, and alert delivery.
Tokopedia via ReefAPI
The marketplace provider normalizes seller results into listing candidates.
Deterministic matcher
Only confident product matches become tracked seller listings.
PostgreSQL
Canonical products own listings; each listing accumulates price snapshots. The dashboard reads this state.
BullMQ + Redis worker
Per-product schedules request another search and observation without blocking the dashboard.
Alert event + Telegram
Rules create durable events; delivery records sent, failed, or skipped status.
The provider boundary keeps marketplace acquisition replaceable, while the current active path remains Tokopedia through ReefAPI. A CanonicalProduct represents the racket identity; multiple MarketplaceListing records represent seller offers. Provider ID and URL constraints protect listing identity. Each successful observation appends a PriceSnapshot instead of replacing the previous price. Listing updates, snapshot creation, and alert evaluation run in a database transaction.
Tracking intent lives in PostgreSQL. BullMQ job schedulers and Redis move recurring searches to a separate worker; a per-product deduplication key prevents equivalent pending refresh jobs. The Next.js dashboard reads the persisted products, listings, prices, rules, and notification states.

Alerts & Delivery State
Target-price, percentage-drop, and any-drop rules evaluate against each listing's previous live observation. A triggered rule creates a deduplicated NotificationEvent alongside its snapshot. Delivery then moves through explicit pending, sending, sent, failed, or skipped states. Telegram credentials are optional for the local application; missing credentials produce a visible skipped state rather than a claimed send.

Data-Source & Demo Boundaries
I investigated Blibli and Lazada without enabling them as tracking sources. Direct Blibli access encountered marketplace verification; a third-party API returned search and detail data, but I could not independently verify current price accuracy, price meaning, freshness, or repeatability. Keeping that integration experimental protects the meaning of the stored history.
Because PadelPrice runs locally, its portfolio charts also need an honest demonstration path. A deterministic seed creates 14 days of synthetic observations across five products and 18 listing histories. PriceSnapshot.source distinguishes DEMO from LIVE, with demo flags on seed-only products and listings. The seed and reset paths preserve live observations; demo history does not trigger alerts or Telegram delivery.
PadelPrice is a local portfolio project. Synthetic history demonstrates the tracking experience; it is not a record of marketplace prices observed on those dates.