Session 51: Complete Team Hub (2234 tests)

Research-depth team view: /team/[abbr] with roster, archetypes, stats, props.

- Team API: mlbStatsAdapter.getTeams/resolveTeam/getTeamRoster (statsapi, abbr→id
  + active roster, cached). teamService.getTeamHub assembles roster → per-player
  season stats (bounded concurrency) + archetype (snapshot grade or classify) +
  tonight's graded props from grades:{sport}; whole hub cached 15min. MLB real;
  NBA/WNBA graceful snapshot roster. GET /api/team/:abbr (404 unknown) + proxy.
- Team Hub page: server page.tsx (generateMetadata) + TeamHub client — header,
  sort (archetype/graded/A-Z), archetype filter chips, roster rows (archetype +
  player link + position + stats + graded props + parlay "+"), "No active props"
  greyed state, loading/error.
- Game cards: team abbreviations are now TeamLinks → /team/:abbr?sport= (green
  hover, stops propagation). Team Hub has "← Back to Slate".

Backend 2215 -> 2234 tests (+19), 190 suites. Web build clean (exit 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-06-19 11:55:10 -04:00
parent f1956dc953
commit f0674ca07d
14 changed files with 696 additions and 4 deletions
+21
View File
@@ -556,6 +556,27 @@ snapshot, locked to the line, and read from cache.
then-missing `/grade` endpoint). Floating badge bottom-right when closed; free
tier blurs the payout with a `window.__goPaywall` upsell.
## Team Hub (Session 51 — non-obvious)
- **`teamService.getTeamHub(sport, abbr)`** is the single payload builder for
`/team/:abbr`. MLB is the real path: `mlbStatsAdapter.resolveTeam` (abbr→id via
the cached `/teams` list) → `getTeamRoster` → per-player `getSeasonAverages(id)`
(bounded concurrency 8, reuses `playerIntelService._internals` mappers) →
archetype (the snapshot grade's locked archetype, else `classify`) → graded
props from `grades:{sport}`. The whole hub is cached 15 min (`teamhub:{sport}:
{abbr}`); each player's season stats cache 6h. NBA/WNBA have no free roster
feed → it returns a partial roster built from tonight's graded players + a note.
All deps injectable for tests.
- **To add a sport's roster**, add a real roster source in `getTeamHub` (the MLB
branch is the template); abbr→id mapping is fetched live from statsapi (no
hardcoded team table to maintain).
- **`GET /api/team/:abbr`** (public, cached) 404s an unknown MLB team. Browser
must use the Next proxy `app/api/team/[abbr]`.
- **Page split:** `team/[abbr]/page.tsx` is a server wrapper (for
`generateMetadata`) rendering the `TeamHub` client component (sort/filter/parlay
are interactive). Player names → `playerHref`; team abbrs on game cards →
`vyndr/GameCard`'s `TeamLink` (stops propagation from the open-game handler).
The roster "+" reuses the Parlay Lab (`useParlay`/`legKey`).
## Active Skills
- vyndr-voice (all user-facing output)
- prop-analysis (grading methodology)