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:
@@ -0,0 +1,32 @@
|
||||
const { getSupabaseServiceClient } = require('../utils/supabase');
|
||||
|
||||
async function requireAuth(req, res, next) {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
|
||||
const token = authHeader.slice(7);
|
||||
const supabase = getSupabaseServiceClient();
|
||||
|
||||
const { data: { user }, error } = await supabase.auth.getUser(token);
|
||||
if (error || !user) {
|
||||
return res.status(401).json({ error: 'Invalid or expired token' });
|
||||
}
|
||||
|
||||
// Fetch user profile from our users table
|
||||
const { data: profile, error: profileError } = await supabase
|
||||
.from('users')
|
||||
.select('id, email, tier, scan_count, scan_reset_date, founder_status')
|
||||
.eq('id', user.id)
|
||||
.single();
|
||||
|
||||
if (profileError || !profile) {
|
||||
return res.status(401).json({ error: 'User profile not found' });
|
||||
}
|
||||
|
||||
req.user = profile;
|
||||
next();
|
||||
}
|
||||
|
||||
module.exports = { requireAuth };
|
||||
Reference in New Issue
Block a user