apexGemTracker — Core Architecture & Context

This Val tracks Apex Manager market listings to find "hidden gems": players who displayed BELOW A- potential on the market but actually retired with A- or higher potential (i.e., fog hid their true quality)[cite: 1]. This is strictly a data collection and comparison pipeline with a web dashboard, entirely separate from notification/alert Vals[cite: 1].

⚠️ Core Business Logic

  1. The Gem Rule (db.ts) is_gem = isBelowAMinus(marketPotential) && !isBelowAMinus(retiredPotential)[cite: 1, 4] CRITICAL: Always compare LETTER GRADES (estimatedRank / estimatedPotential), never the numeric trueRating or potentialRating[cite: 1]. The game's numeric ratings do not map to a reliable letter grade scale (e.g., a potential rating of 1986 might retire as a C/B, not an A)[cite: 1]. The authoritative "true" grade is the revealed letter grade on the retired card at 100% confidence[cite: 1].

  2. Fog Semantics fogConfidence (API) = INTEL[cite: 1]. Displayed "Fog %" = 100 - (fogConfidence * 100)[cite: 3]. High intel (low fog) = well-scouted; low intel (high fog) = obscured/lottery[cite: 1].

Data Model (SQLite)

  • listings: Snapshot of every market listing (keyed by auction_id)[cite: 1]. Captures the first-seen state (est rank/potential, intel, fog, salary, full player_json)[cite: 1, 3]. Upserted every run[cite: 1]. left_at is set when a listing stops appearing in the active auctions API[cite: 1, 3].
  • retired: Resolved players[cite: 1]. Compares market display vs. retired revealed grade (retired_rank / retired_potential)[cite: 1]. Stores market age/salary snapshot + true numeric ratings + is_gem flag + card_url[cite: 1, 2].
  • player_checks: Dedupe and backoff tracking table (checked every 10 minutes) so we don't spam the API for unresolved players[cite: 1, 2].

Scheduled Jobs (Cron)

  • collect.ts (*/15 mins): Snapshots all /api/auctions listings[cite: 1]. Inserts new listings and updates left_at for expired auctions[cite: 3].
  • check.ts (Hourly): Looks at listings that left the market >=1h ago[cite: 1]. Fetches /api/players/{id}[cite: 1]. If retired, calculates gem status and moves to retired table[cite: 1, 2]. If still active, backs off and checks again later[cite: 1].

Web & API Endpoints (HTTP)

  • site.ts: The main frontend UI and API router[cite: 9]. Serves a rich HTML/JS dashboard at the root (/) with tabs for Live Market, Retired Players, and Advanced Analytics charts[cite: 6, 9]. Serves JSON endpoints at /api/stats, /api/live, /api/retired, and /api/analytics[cite: 9].
  • report.ts: Spreadsheet export router[cite: 1, 7]. Serves raw JSON and CSVs (e.g., /csv for gems, /csv/listings for active market)[cite: 1, 7]. Designed to be ingested directly by Google Sheets using the IMPORTDATA() function[cite: 1].
  • main.ts: A utility script to initialize the DB schema and print current table row counts[cite: 1, 5].

Environment

  • APEX_TOKEN: The bearer token required to authenticate against the Apex Manager API[cite: 1]. All scripts will fail if this is missing or expired[cite: 1, 2, 3].