Session 8: Frontend Stripe cutover, soccer pages, sport selector, grade result cards, beta badge
This commit is contained in:
+28
-23
@@ -99,19 +99,26 @@ Mounted in `src/app.js`. Auth column meanings:
|
||||
These are proxies or thin wrappers; they hit Express via `BACKEND_URL`
|
||||
or the Python service via `NEXT_PUBLIC_NBA_SERVICE_URL`.
|
||||
|
||||
- `/api/checkout` (POST/GET) — NexaPay checkout
|
||||
- `/api/checkout` (POST/GET) — Stripe checkout proxy (Session 8 cutover — was NexaPay)
|
||||
- `/api/games/[id]` and `/api/games/tonight` — list / detail
|
||||
- `/api/games/[id]/props` — props for a game
|
||||
- `/api/intelligence/feed` — homepage live signals
|
||||
- `/api/ledger`, `/api/ledger/accuracy` — Ledger feed
|
||||
- `/api/odds/soccer/[league]` — soccer odds proxy → Express `/api/odds/soccer/:league` (Session 8)
|
||||
- `/api/parlay/add-leg`, `/api/parlay/grade` — proxy to `/api/scan/parlay`
|
||||
- `/api/players/search` — proxy to Python `/players/search`
|
||||
- `/api/props/live`, `/api/props/most-parlayed`, `/api/props/top-graded`
|
||||
- `/api/scan` — bare scan endpoint
|
||||
- `/api/scan` — bare scan endpoint (Session 8 — accepts `Soccer` sport in addition to NBA/MLB/WNBA)
|
||||
- `/api/stats/parlays-graded`, `/api/stats/public` — proxy
|
||||
- `/api/user/profile`, `/api/user/scans`, `/api/user/recent-scans`
|
||||
- `/api/waitlist` — proxy
|
||||
- `/api/webhook/nexapay` — NexaPay webhook
|
||||
- `/api/webhook/nexapay` — NexaPay webhook (legacy — Stripe cutover Session 8; webhook still listening for any in-flight NexaPay events)
|
||||
|
||||
### Next.js pages (Session 8 additions)
|
||||
|
||||
- `/soccer` — live soccer odds feed + inline prop grading. Hosts `SportSelector` + per-league match cards, scans selected props through `/api/scan` → Express `/api/analyze/prop` with `sport: 'Soccer'`. Results render in `SoccerGradeResult` (parses the engine's reasoning summary into visual signal chips: ⚽ goals/90, 📊 xG, 🏔️ altitude, 🟨 referee, 🎯 penalty taker, 🏆 WC pedigree). Free tier gets a blurred preview + upgrade CTA.
|
||||
- `/upgrade/success` — Stripe checkout success landing. Reads `session_id` query param, refreshes the AuthContext so the new tier flips immediately. Stripe webhook is the source of truth; this page does not verify the session against Stripe (no secret key on the client).
|
||||
- `/upgrade/cancel` — Stripe checkout cancel landing. No judgment, links back to `/#pricing` and `/scan`.
|
||||
|
||||
---
|
||||
|
||||
@@ -615,28 +622,26 @@ All frontend API paths discovered are either:
|
||||
handler. Spot-checked: `/api/players/search` (Next → Python),
|
||||
`/api/scan` (Next → Express), `/api/intelligence/feed` (Next direct DB).
|
||||
|
||||
#### Payments: dual-provider divergence (Session 7h)
|
||||
#### Payments: Stripe cutover (Session 8 — COMPLETE)
|
||||
|
||||
The frontend `/api/checkout` (Next.js) creates **NexaPay** payment
|
||||
links and is what `web/src/components/Pricing.tsx` CTAs currently hit.
|
||||
The Express `POST /api/stripe/checkout` (Stripe Checkout Sessions) is
|
||||
fully wired, tested in test mode against real Stripe resources
|
||||
(products + prices + webhook all created), and ready for traffic —
|
||||
but no frontend caller invokes it yet. Cutover work for a follow-up
|
||||
session:
|
||||
The dual-provider divergence flagged in 7h is closed:
|
||||
|
||||
1. Replace `web/src/app/api/checkout/route.ts` body to fetch
|
||||
`${BACKEND_URL}/api/stripe/checkout` with the user's bearer token
|
||||
instead of calling NexaPay's `createPaymentLink`.
|
||||
2. Wire `Pricing.tsx` CTAs through that same Next.js route (response
|
||||
shape is already `{ url, ... }`-compatible; Express returns
|
||||
`{ checkout_url, session_id }`, so the proxy needs to remap
|
||||
`checkout_url → url`).
|
||||
3. Add `/upgrade/success?session_id=...` and `/upgrade/cancel` pages.
|
||||
Current Stripe `success_url` points at `/scan?upgraded=true` and
|
||||
`cancel_url` at `/#pricing` — those work but a confirmation page
|
||||
reads better.
|
||||
4. Decide on NexaPay: keep as fallback, remove, or feature-flag.
|
||||
1. ✅ `web/src/app/api/checkout/route.ts` now forwards to
|
||||
`${BACKEND_URL}/api/stripe/checkout` with the user's bearer token.
|
||||
The route remaps `{ checkout_url, session_id }` → `{ url, … }` so
|
||||
the existing client field shape still works.
|
||||
2. ✅ `Pricing.tsx` CTAs were converted from `<a href>` to onClick
|
||||
handlers that POST to `/api/checkout` and `window.location.assign`
|
||||
the returned Stripe URL. Loading state during redirect; error
|
||||
surfaced inline.
|
||||
3. ✅ `/upgrade/success?session_id=…` and `/upgrade/cancel` pages
|
||||
shipped. Express `stripeService.js` updated to point `success_url`
|
||||
and `cancel_url` at the new frontend pages via `NEXT_PUBLIC_SITE_URL`
|
||||
(the only backend file touched in Session 8).
|
||||
4. NexaPay is still wired but no UI calls it. Disposition (remove vs
|
||||
keep as fallback) is a follow-up call — leaving it in place doesn't
|
||||
cost anything and gives the team a fallback if Stripe goes down
|
||||
during the World Cup window.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user