Files
vyndr/web/src/app/api/stats/player/[name]/route.ts
T
builtbykev 8bc79f3c38 Session 42: Player Intelligence System — archetypes, stat strips, player profile, enhanced cards (2011 tests)
Built from the Claude Design "VYNDR Player Intelligence" bundle (10 sections).

- Archetypes: src/services/archetypeService.js — 41 archetypes (15 NBA / 5
  WNBA-unique / 15 MLB / 6 soccer), classify -> primary+secondary+blend.
  Frontend visual map web/src/lib/archetypes.js (colors verified == backend).
  ArchetypeBadge (full/ghost/tint + glyphs) + ArchetypeBlend (DNA bar).
- StatStrip (compact/expanded): player name once, horizontal mono stats,
  inline GradeBadge props, onPlayerClick -> profile.
- Stats API: extended src/routes/stats.js with /player/:name, /leaders,
  /game/:id (rate-limited). Aggregation in playerIntelService.js (sanitizes
  name param; grades cache; graceful on cold cache). Next proxies added.
- Player Profile /player/[name]: all 9 design sections, graceful empty states.
- Enhanced GameCard (MLB pitchers + player-grouped StatStrips) + GradeResultCard
  (archetype strip + stat context + VYNDR intelligence, optional/self-hiding via
  gradeAdapter.buildIntelFields). Player-name links wired everywhere.
- Settings page replaces the S41 redirect (account/subscription/notifications/
  display/responsible-play/danger-zone with DELETE-gated delete). LINKS to the
  real /settings/security MFA page — does not replace it. + BookChip.
- Bonus: Stats Explorer /explore (real /api/stats/leaders leaderboard); added
  Explore + Settings to Nav MORE.

Deferred (need data pipelines, Session 43): Team Hub, Offseason Intel, Slate
redesign, Stats Explorer sub-panels.

Backend 1940 -> 2011 tests (+71), 157 suites. Web build clean (exit 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:12:24 -04:00

26 lines
1.0 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
/**
* Player intelligence proxy (Session 42). Forwards GET /api/stats/player/:name
* to the Express stats route (which sanitizes the name + aggregates archetype /
* props / VYNDR intelligence). Thin pass-through; preserves ?sport=.
*/
export async function GET(req: NextRequest, ctx: { params: Promise<{ name: string }> }) {
const { name } = await ctx.params;
const qs = req.nextUrl.search;
try {
const upstream = await fetch(`${BACKEND_URL}/api/stats/player/${encodeURIComponent(name)}${qs}`, {
method: 'GET',
headers: { Accept: 'application/json' },
});
const data = await upstream.json().catch(() => ({}));
return NextResponse.json(data, { status: upstream.ok ? 200 : upstream.status });
} catch {
return NextResponse.json({ error: 'Player service is unreachable. Try again in a moment.' }, { status: 502 });
}
}