feat: Feature 2.1 — Parlay Scan with correlation detection + monetization
POST /api/scan/parlay — authenticated parlay analysis: - Supabase JWT auth middleware (auth.getUser verification) - 5 correlation types detected between legs (same_game, same_team, same_player_conflicting, positive_correlation, blowout_cascade) - Overall parlay grading (A/B/C/D) with correlation penalty adjustments - Free tier: 5 scans/month, atomic scan count increment - Scan 5: full analysis + personalized upgrade pitch - Scan 6+: 403 block with upgrade pitch - Pitch personalization from scan history (top stats, grades, tier rec) - DB writes: picks + scan_sessions per scan 30 new tests, 158 total (131 Node.js + 27 Python), all passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -94,3 +94,17 @@ Outcome level (nested under market.outcomes[]):
|
||||
- Decision: Add `spreads` to the comma-separated markets list in the existing per-event API call. Zero additional API credits — the spreads data rides alongside the player prop data in the same request.
|
||||
- Alternatives considered: Skip blowout_risk for now — rejected because it's a high-value kill condition that prevents bad bets on blowout games.
|
||||
- Consequences: `oddsService.js` now returns a `spreads` array alongside `props`. The `extractSpreads()` function in `oddsNormalizer.js` parses game-level spread data separately from player-level props.
|
||||
|
||||
### DECISION-006: Auth via Supabase auth.getUser() (Feature 2.1)
|
||||
- Date: 2026-03-21
|
||||
- Context: Need to verify Supabase JWTs in the scan endpoint. Options were manual JWT verification with secret or using Supabase client.
|
||||
- Decision: Use `supabase.auth.getUser(token)` from `@supabase/supabase-js`. Simpler, no JWT secret management, automatically validates token expiry and revocation.
|
||||
- Alternatives considered: Manual JWT decode with `jsonwebtoken` library — rejected: more code, need to manage JWT secret, doesn't check revocation.
|
||||
- Consequences: Auth middleware depends on Supabase API being reachable (same DNS blocker in WSL2). In production this is fine.
|
||||
|
||||
### DECISION-007: Atomic Scan Count Increment (Feature 2.1)
|
||||
- Date: 2026-03-21
|
||||
- Context: Race condition risk — two concurrent scans from same free-tier user could both read scan_count=4 and both proceed past the limit.
|
||||
- Decision: Use atomic `UPDATE users SET scan_count = scan_count + 1 WHERE id = :id AND scan_count = :current_count RETURNING scan_count`. If no rows returned, another request incremented first.
|
||||
- Alternatives considered: Postgres advisory locks — rejected: overkill for this use case. Optimistic concurrency with the WHERE clause is simpler and sufficient.
|
||||
- Consequences: At worst, one of two concurrent requests will fail to increment and still proceed (the check happens before analysis). Acceptable for MVP — the 5-scan limit is soft, not a billing boundary.
|
||||
|
||||
Reference in New Issue
Block a user