Session 8: Frontend Stripe cutover, soccer pages, sport selector, grade result cards, beta badge

This commit is contained in:
Kev
2026-06-10 15:34:23 -04:00
parent ad5ea8d5a8
commit 4db1c1c539
15 changed files with 1583 additions and 161 deletions
+105 -1
View File
@@ -4,7 +4,111 @@
2026-06-10
## Current Phase
SHIP BUILD v7.2 — Soccer Intelligence + World Cup 2026 (Session 7j)
SHIP BUILD v8.0 — Frontend Stripe Cutover + Soccer Pages (Session 8)
## Session 8 (2026-06-10) — SHIPPED
Frontend layer that connects users to the Session 7h7j backend.
NexaPay → Stripe cutover on the pricing flow + a `/soccer` page that
exposes the soccer intelligence pipeline.
### Files created (frontend)
- `web/src/app/api/odds/soccer/[league]/route.ts` — Next.js proxy →
Express `GET /api/odds/soccer/:league`. Validates league against the
9 accepted codes upstream so a typo bounces at the Next boundary.
- `web/src/app/soccer/page.tsx` — live soccer odds feed. Hosts
`SportSelector`, fetches `/api/odds/soccer/:league`, groups props by
match → stat type. "Grade" button triggers inline scan via
`/api/scan` (sport: Soccer) and renders the result through
`SoccerGradeResult`. Soccer-only page; switching the selector to
another sport bounces to `/scan`.
- `web/src/app/upgrade/success/page.tsx` — Stripe success landing.
Reads `session_id`, refreshes AuthContext so the new tier flips
immediately. Does NOT verify against Stripe from the client (no
secret key on the browser) — the webhook is the source of truth.
- `web/src/app/upgrade/cancel/page.tsx` — Stripe cancel landing.
- `web/src/components/SportSelector.tsx` — pill tabs (NBA/WNBA/MLB/
Soccer); Soccer reveals a sub-row of the 9 league codes matching
Express's `SOCCER_SPORT_KEYS`. Emits `{ sport, league? }` via
`onChange` — pure UI, no fetches.
- `web/src/components/SoccerGradeResult.tsx` — soccer-themed result
card. Parses the engine's reasoning summary into visual chips
(⚽ goals/90, 📊 xG, 🎯 penalty taker, 🏹 free-kick taker, ⛳ corner
taker, 🏔️ altitude, 🟨 referee, ⏱️ minutes discount, 🛡️ opponent
defense, 🏆 tournament pedigree). Color-coded by tone
(positive / caution / warning / neutral). Free-tier responses
(carrying `tier_gated: true`) render the chip row blurred under an
upgrade CTA; the structured grade + confidence + edge stay visible.
Kept separate from `GradeCard` so the NBA/MLB/WNBA path is
untouched.
### Files modified (frontend)
- `web/src/app/api/checkout/route.ts` — full rewrite. Was a NexaPay
payment-link creator; is now a thin proxy that forwards `{ tier,
founder_code? }` + bearer to Express `/api/stripe/checkout`.
Response remap: `checkout_url``url` for callsite compat; both
fields shipped so either reads cleanly.
- `web/src/app/api/scan/route.ts` — accepts `Soccer` sport in addition
to NBA/MLB/WNBA. Soccer stat-type allowlist mirrors the backend
`VALID_STAT_TYPES` (goals, shots_on_target, shots, tackles, cards,
corners, saves, goals_conceded, passes, clean_sheet, assists).
- `web/src/components/Pricing.tsx` — CTAs converted from `<a href>` to
onClick handlers. Uses `useAuth()` for the bearer token, POSTs to
`/api/checkout`, `window.location.assign` to the returned Stripe URL.
Loading state on the active tier, inline error banner. Anonymous
visitors bounce to `/signup?return=/%23pricing`. Footnote rewritten
from "NexaPay" to "Stripe (test mode while we onboard founders)".
- `web/src/components/Nav.tsx` — small BETA tag next to the wordmark.
Glitch-styled, monospace, low-opacity green border. Renders on every
page that mounts Nav.
### Files modified (backend — ONE allowed change)
- `src/services/stripeService.js``success_url` / `cancel_url`
point at the frontend (`NEXT_PUBLIC_SITE_URL` with `BASE_URL`
fallback, default `http://localhost:3000`). Previously the routes
pointed at the Express origin which would have 404'd the redirect.
New URLs:
- `${frontendUrl}/upgrade/success?session_id={CHECKOUT_SESSION_ID}`
- `${frontendUrl}/upgrade/cancel`
All 23 Stripe tests still pass (none asserted on the URL strings).
### Files modified (docs)
- `docs/SYSTEM-MANIFEST.md``/api/odds/soccer/[league]` row in
Next.js routes, new section listing the three new Next.js pages,
the Session 7h "dual-provider divergence" callout flipped from
open-work to ✅ complete.
- `BUILD-STATE.md` — Session 8 entry.
### Honest verification status
Build-verified (passed `web/npm run build` after every component):
- All TypeScript types resolve
- All routes prerender / build correctly (24 pages, 30+ API routes)
- No ESLint errors
NOT runtime-verified in this session (I have no browser to click
through):
- Actual Stripe checkout redirect end-to-end (test mode card flow)
- Soccer odds rendering with live data (depends on
`FOOTBALL_DATA_API_KEY` being set in prod and the daily prefetch
having run)
- SoccerGradeResult signal parsing against a real engine response
(signal-chip regex tested against the exact phrasing
`buildSoccerReasoningLines` emits in `analyzeViaEngine1.js`, but
not against live engine output)
- AuthContext.refresh() actually triggering a profile re-read after
the Stripe redirect
These are the expected next-session sanity checks once Coolify
deploys this build.
### Quality gates
- `npm test` (backend): **1173 / 1173 passing**, 91 suites, 0 regressions
from Session 7j baseline
- `web/npm run build`: clean — all new routes prerendered, no type errors
- License audit: only permissive licenses
---
## Session 7j (2026-06-10) — SHIPPED