Session 7h: Stripe products, tier config, scan limits, response gating, free tier

This commit is contained in:
Kev
2026-06-10 13:24:11 -04:00
parent 4e18eb1efe
commit d4e5e76452
16 changed files with 750 additions and 6 deletions
+14 -2
View File
@@ -8,6 +8,8 @@ const express = require('express');
const { analyzeViaEngine1 } = require('../services/intelligence/analyzeViaEngine1');
const { cacheGet, cacheSet } = require('../utils/redis');
const { createRateLimit } = require('../middleware/rateLimit');
const { scanLimit } = require('../middleware/scanLimit');
const { applyTierGating } = require('../utils/tierGating');
const router = express.Router();
@@ -17,6 +19,11 @@ const router = express.Router();
const analyzeLimit = createRateLimit({ windowMs: 60_000, max: 10 });
router.use(analyzeLimit);
// Tier scan-limit (this session): per-tier daily quota. Free users
// (including anonymous demo via IP) are capped at 3 scans/day. Paid
// tiers get higher caps from src/config/tiers.js.
router.use(scanLimit());
// PERF-1 (Session 7d): cache analyze results in Redis. Same prop hit
// twice within 60s reuses the previous analysis instead of re-doing the
// upstream chain. 60s is short enough that line moves still surface.
@@ -70,7 +77,12 @@ router.post('/prop', async (req, res) => {
try {
const result = await cachedAnalyze(req.body);
return res.json(result);
// Tier gating — unauthenticated demo callers and free-tier users
// get the grade + confidence + edge_pct, but the reasoning and
// kill condition details are redacted. Paid tiers pass through
// untouched.
const gated = applyTierGating(result, req.user?.tier || 'free');
return res.json(gated);
} catch (err) {
if (err.response && err.response.status === 404) {
return res.status(404).json({ error: `Player not found: ${req.body.player}` });
@@ -99,7 +111,7 @@ router.post('/batch', async (req, res) => {
try {
const result = await cachedAnalyze(prop);
results.push(result);
results.push(applyTierGating(result, req.user?.tier || 'free'));
} catch (err) {
results.push({
error: err.response?.status === 404
+2 -1
View File
@@ -1,5 +1,6 @@
const express = require('express');
const { requireAuth } = require('../middleware/auth');
const { scanLimit } = require('../middleware/scanLimit');
const { scanParlay } = require('../services/parlayScanService');
const router = express.Router();
@@ -33,7 +34,7 @@ function validateLegs(legs) {
return null;
}
router.post('/parlay', requireAuth, async (req, res) => {
router.post('/parlay', requireAuth, scanLimit(), async (req, res) => {
const { legs } = req.body;
const validationError = validateLegs(legs);