Changelog
Public change history of Skin Trackers. Features, fixes, editorial updates + compliance. Each entry references the commit or more detailed doc when applicable.
May 2026
- Feature·
Unified chart system — shared palette, tooltips, axis props, and formatters
Refactored 6 chart components (IndexLandingHero, IndexDetailChart, SkinDetailChart, MarketOverview, AllocationDonut, SpendingTimeline) into a single source of truth. Before: hex values (#20252F, #14171D, #6b7280, #F5C518) repeated inline in every chart, tooltip styles duplicated, ad-hoc tickFormatters. After: lib/chart-colors.ts canonical (CHART_COLORS + CHART_TOOLTIP_PROPS + CHART_GRID_PROPS + CHART_AXIS_PROPS), lib/chart-fmt.ts with fmtAxisCompact/Currency/Date/Pct, <ChartEmpty> primitive with role=status. Brand token tweak now propagates to the entire family in one edit.
April 2026
- Feature·
Screener polish wave — URL state, CSV export, USD/BRL toggle, 9 improvements
9 polish phases on /screener (the route with 75% visitor concentration). R6: filters now sync to the querystring (shareable links like /screener?sti=sti-100&mindd=20&liq=1, distribution via Reddit/Twitter/ChatGPT scales). R1: live 'Showing: 1y · all · sorted by biggest drops first' line. R4+R11: helper text on numeric inputs + Reset filters CTA. F1: Download CSV of visible rows with auto-labeled filename. F4: USD/BRL toggle with locale-aware default and localStorage persistence. R2/R3: consistent KPIs (filtered avg + X/Y ratio). R5: ATH badge on positive drawdown. R7/R8: tooltips on Bid/Ask + Hist. R9: sparkline tooltip 'start → end (Δ%)'. R10: search clear button. R12: STI label normalized to 'All'.
- Feature·
Full EN coverage — 11 mirror routes in English
/en/* now covers the entire PT surface: /en/analise (hub redirect) + /en/analise/{top-skins, cheap-vs-ath, best-knives, most-expensive-skins} (4 aggregators with EN FAQPage schema), /en/inventario, /en/watchlist, /en/settings (auth-gated mirrors), /en/comece-aqui (3-level onboarding), /en/changelog, /en/privacidade (LGPD + DPO in EN), /en/termos, /en/indices/[id]/basket (full sortable basket), /en/skin/[id] (full skin detail). All with hreflang alternates (pt-BR/en-US/x-default) + en-US locale formatting. Sitemap registers all (including per-skin /en/skin/<slug>). TabNav PT_TO_EN_SLUG complete.
- Fix·
PostHog SDK missing from production bundle — env var build cache
Diagnosis: prod bundle had 0 PostHog references (0 chunks with 'posthog'/'phc_'/'capture_pageview') despite NEXT_PUBLIC_POSTHOG_KEY being set in Railway. Root cause: previous deploy was made before the var was added, and empty-commit doesn't force a Nixpacks rebuild (cache by file hash). Fix: commit 8ae730f with a real change in PostHogProvider.tsx forced a fresh rebuild. Bundle now has chunk 9da6db1e (186KB) with the full SDK. Capture endpoint validated via 4 test events ingested in the project. Temporary diagnostic console.log until first organic event is confirmed.
- Fix·
PT description leak in /en/indices/[id]
/en/indices/[id] route was rendering PT description directly from CANONICAL_COPY ('Top 30 por market cap entre skins com histórico'). Fix: IndexDefinition.description_en field populated for all 7 indices (sti-30/100/500/1000/cases/stickers/agents); /en/indices/[id] prefers description_en with fallback to description.
- Feature·
STI Cases uncap — all cases that meet methodology
STI Cases cap raised from 30 to 200 (effectively uncapped) to include EVERY case passing the filters (price min, liquidity min, history min). Basket grew from 30 → 40 cases (10 new: eSports 2013, Huntsman, Vanguard, Chroma, Shadow, Falchion + others). Cumulative return goes from +763.9% → +779.3% since 03/2021. Decision: STI Cases shouldn't mirror STI 30 cap — the container universe is finite and the product should reflect every eligible item.
- Feature·
Steam scrape Railway-immune — daily scrape via direct GH Actions runner
Daily Steam Market scrape (~31k items, 2.5h) migrated from Railway detached spawn (which suffered SIGTERM kills during deploys) to a direct GH Actions runner. Production validation: 25k items inserted in 2h15m, 735ms endpoint latency. Pattern also applied to granular price_history (top 500 skins, ~17k points per skin). Daily freshness guaranteed.
- Feature·
Coverage gap fix — skins table populated (529 → 24,476)
import-prices endpoint now upserts skins along with market_prices in an atomic transaction. Result: 96% of market_prices skins that were orphans (didn't appear in /skin/[id]) now have a row in the skins table. Includes JOIN with catalog_items for weapon/wear/image_url metadata.
- Feature·
Automatic cross-source validation — DMarket weekly
Workflow scrape-cross-source-weekly.yml (direct GH Actions runner) scrapes DMarket for 297/298 skins in the STI universe, generates a cross-source delta report flagging >25%/>50%, auto-commits dated MD in docs/audits/cross-source-delta-YYYY-MM-DD.md. Average delta 13.8% (healthy, within fee differential band).
- Docs·
Statistical rigor — confidence intervals on STI returns
New section /methodology#rigor-estatistico publishes 95% CI (SE-based + non-parametric bootstrap) for STI 30/100/500/Cases returns. Strongest quantitative finding: STI Cases is the only series with 95% CI entirely positive (+7% to +99%/year), defensible evidence of real alpha. Other series cross zero — declared honestly.
- Feature·
External R2 archival + Cloudflare backups
SQLite backups now also push monthly to Cloudflare R2 (free tier 10GB) in addition to GitHub Releases. Workflow backup-r2-archival.yml runs day 1 of the month at 06:00 UTC. Defense against the unlikely scenario of GitHub account deletion / repo wipe.
- Docs·
Correlation reported in 3 dimensions — audit finding applied
Correlation sensitivity audit identified that the published r=0.77 was levels correlation. /methodology#correlacao now publishes r=0.82 levels + r=0.26 returns + r≈0 rolling 12m, with statistical interpretation of each. Consistent with academic literature (Frontiers AI Nov/2025). Zero impact on backtest — it's a framing change, not a formula change.
- Fix·
Skin detail page — 'out of universe' banner for untracked skins
Pages /skin/[id] for skins catalogued but outside the STI universe (without price_history) used to render the template with empty dashes. An aside role=note banner now explicitly explains the skin is outside active tracking + provides useful links to explore the covered universe.
- Feature·
Full universe export — STI 30/100/500 + Cases + 56 containers
Docs/universe/ now has exportable lists: STI 30 (30 constituents), STI 100 (100), STI 500 (260 — theoretical cap of 500 not reached, documented), STI Cases (30 — cap reached 2026-04-23, later raised to 200/uncapped on 2026-04-25), 56 containers in the catalog. Scripts scrape-csfloat-universe.ts + scrape-pricempire-universe.ts ready for users to run cross-source.
- Feature·
Launch readiness plan executed — Silver → Gold 60 days
Formal plan with 10 gaps to move the product from Silver (self-assessed) to Gold (with external validation). 8 internal gaps closed, 2 awaiting external review (LGPD lawyer + quant methodology). Target launch: 2026-06-24.
- Feature·
RUM (Real User Monitoring) enabled
Web Vitals (LCP, CLS, INP, FCP, TTFB) are now collected via the web-vitals lib for 100% of users, reporting to Sentry + Plausible. Replaces sole reliance on synthetic Lighthouse CI.
- Security·
Pre-commit hook detects commented-out auth on critical routes
Husky hook now blocks commits with commented authentication code in /api/admin/**, lib/auth-*, lib/session. Lesson from the IR tabletop exercise simulating a P1 data breach.
- Compliance·
Steam® + CS2® trademark disclaimer in footer
Explicit disclaimer of non-affiliation with Valve Corporation + attribution of Steam Community Market as data source. Compliance with good-faith scraping practices.
- Fix·
Mobile: drawer doesn't trigger horizontal scroll + universal sticky header
3 bugs found in real-viewport responsive audit: (1) MobileNav drawer with translate-x-full contributed 315px to body.scrollWidth, (2) newsletter form overflow on tablet 3-col grid, (3) .nav-root { position: relative } in globals.css silently overrode Tailwind .sticky. Header was never sticky on any device — fixed.
- Feature·
Table of Contents on /methodology
22k-char doc now has navigation: sticky sidebar on desktop, horizontal scroll on mobile. 22 anchors covering 11 main sections. Anchor navigation with scroll-margin-top 96px so it doesn't hide behind the header.
- Docs·
New section /methodology#replicabilidade
4 layers explaining why the product is hard to replicate even with open methodology: (1) 6 years of history, (2) empirical calibration of formulas, (3) r=0.77 correlation with confidence in cleaned data, (4) public disclosures as a credibility moat.
- Compliance·
LGPD — data map + privacy rights process + DPO designation
Formal inventory of data collected (art. 37), operational process to fulfill rights within 15 business days (art. 18-19), Data Protection Officer designation (art. 41), templates for responses A/B/C/D, inventory of 8 third-party processors.
- Security·
Weekly health check workflow + nightly security probe
Drift detection automation: Sunday 06h UTC probes 11 core routes + HTML structure + SEO markers. Complementary to nightly security-post-deploy-probe (03h UTC). Both auto-open issues on failure.
- Fix·
STI 30 periodicity bug fixed
Volatility annualization always used √365. Monthly series had vol inflated 5.5×. Fix: detectPeriodicity computes the correct factor via median gap (daily=365, weekly=52, monthly=12) + a mixed-cadence filter drops heterogeneous transitions before stdev.
- Feature·
STI Cases v1 published
Separate index for containers (30 cases by market cap). Disjoint universe from skin STI. Reported return: +763.9% over 6 years, +52.8% CAGR.
- Docs·
Methodology audit Lane 1 + Lane 2 complete
3 blockers fixed: inverted fee breakdown (5% Steam + 10% publisher), STI 30 quarterly rebalance (table by tier), factsheets with fee disclosure fineprint.