Skip to content

static: public Reverse Watch dashboard#71

Open
ZukwiZ wants to merge 1 commit into
masterfrom
feat/public-dashboard-ui
Open

static: public Reverse Watch dashboard#71
ZukwiZ wants to merge 1 commit into
masterfrom
feat/public-dashboard-ui

Conversation

@ZukwiZ
Copy link
Copy Markdown
Collaborator

@ZukwiZ ZukwiZ commented May 27, 2026

Summary

Single self-contained `static/index.html` (inline CSS + JS, no build step) plus the icons / favicons / chart-event data it consumes.

Layout

  • Three KPI cards: Traders indexed, Traders flagged, Traders flagged 24h
  • Volume chart with period picker (7d / 30d / 3m / 6m / 1y) powered by uPlot
  • Recent-reversals table with client-side paging
  • Single-Steam-ID search with avatar + display name + Steam/CSFloat profile-link result chip
  • CS2 event annotation chips on the chart — data driven by `static/cs2-events.json`, edit that file to add or update events
  • Responsive mobile layout (single-column, condensed KPI row)

Dependencies

  • Material Symbols (Google Fonts CDN)
  • uPlot 1.6.x (unpkg CDN)
  • No bundler, no NPM, no build step

Heads-up for review

  • Steam display names are dev placeholders. The current implementation deterministically hashes a Steam ID into a placeholder string so the search-result chip has something to show against locally seeded synthetic data. For production we need a real source — three options worth a quick decision before this merges:
    1. Extension-side enrichment (the extension already has Steam Web API access).
    2. Server-side batched Steam Web API call with short cache.
    3. DB-cached column populated lazily on first lookup.
  • Depends on Add Models #1 and Core Infrastructure #2 for the dashboard to actually function (in-memory static serving + the three new public endpoints). Reviewable in isolation against master — the HTML/JS is self-contained — but won't render real data until those land.

Test plan

  • After merging Add Models #1 + Core Infrastructure #2 + fix cursor proto field usage #3 (or locally on a branch that has all four): run `go run ./cmd/seed`, then load `http://localhost:80/\`
  • Click through every period in the picker (7d / 30d / 3m / 6m / 1y) — chart re-renders with the right number of buckets
  • CS2 event annotation chips appear at expected dates (see `static/cs2-events.json`)
  • Submit a known flagged Steam ID — result chip shows avatar + display name + working Steam + CSFloat profile links
  • Submit a clean Steam ID — result chip shows the clean state
  • DevTools mobile viewport (e.g. iPhone 14) — single-column layout, KPI cards stack, chart is readable, table paging still works
  • `curl -I http://localhost:80/\` returns the right `Content-Length` (depends on Add Models #1)

Made with Cursor


Note

Low Risk
Static HTML/JSON and CDN assets only; no server auth or data-model changes in this PR. Main follow-up is replacing placeholder Steam display names before production.

Overview
Replaces the minimal landing search page with a self-contained public dashboard in static/index.html (inline CSS/JS, no build). The page now loads KPI stats, a uPlot reversal volume chart with a 7d–1y period picker, a recent reversals table with client-side “load more,” and an upgraded Steam ID lookup that shows a compact result chip (verdict, placeholder avatar/name, Steam/CSFloat links). CS2 timeline annotations come from new static/cs2-events.json, rendered as stacked chips on the chart for the selected window.

README.md fixes a typo and documents that the dashboard is served at / from static/index.html. Trader display names are deterministic placeholders derived from Steam ID until real profile data exists; chart/table/search call the existing public /api/v1/... endpoints and Material Symbols + uPlot via CDN.

Reviewed by Cursor Bugbot for commit 0865861. Bugbot is set up for automated code reviews on this repo. Configure here.

Single self-contained static/index.html (no build step) plus the
icons / favicons / chart-event data it consumes.

Layout
- three KPI cards (Traders indexed, Traders flagged, Traders flagged 24h)
- volume chart with period picker (7d / 30d / 3m / 6m / 1y), powered by
  uPlot from the unpkg CDN
- recent-reversals table with client-side paging
- single-Steam-ID search with avatar + display name + Steam/CSFloat
  profile link result chip
- CS2 event annotation chips on the chart, data driven by
  static/cs2-events.json — edit that file to add or update events
- responsive mobile layout (single-column, condensed KPI row)

Dependencies
- Material Symbols (Google Fonts CDN)
- uPlot 1.6.x (unpkg CDN)
- No bundler, no NPM dependencies, no build step.

This PR depends on #1 (in-memory static serving) and #2 (public
stats / recent endpoints) being merged for the dashboard to function,
but is reviewable in isolation against master.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0865861. Configure here.

Comment thread static/index.html
width: 2,
fill: (u) => {
const ctx = u.ctx;
const grad = ctx.createLinearGradient(0, 0, 0, u.bbox.height);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chart fill gradient misaligned from plot area

Low Severity

The area-fill gradient is created with createLinearGradient(0, 0, 0, u.bbox.height), but u.bbox describes the plot area within the canvas — it starts at u.bbox.top, not at y=0. The correct coordinates are (0, u.bbox.top, 0, u.bbox.top + u.bbox.height). Without this, the gradient is offset from the actual fill region by u.bbox.top pixels, causing a slight opacity mismatch at the top and bottom of the filled area.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0865861. Configure here.

Comment thread static/index.html
els.chipAvatar.textContent = name.charAt(0).toUpperCase();
els.chipAvatar.style.background = avatarGradient(steamId);
els.chipSteamLink.href = 'https://steamcommunity.com/profiles/' + encodeURIComponent(steamId);
els.chipCsfloatLink.href = 'https://csfloat.com/stall/' + encodeURIComponent(steamId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Steam ID precision loss corrupts profile links

Medium Severity

SteamID is uint64 in Go (domain/models/steamid.go). Typical Steam IDs like 76561198012345678 exceed JavaScript's Number.MAX_SAFE_INTEGER (≈9×10¹⁵). When data.steam_id is parsed from JSON as a number, the last digits can be silently rounded, causing chipSteamLink and chipCsfloatLink to navigate to the wrong Steam/CSFloat profile. The same issue affects row.steam_id in the recent-reversals table.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0865861. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants