Skip to content

Commit b0393d7

Browse files
ralyodioclaude
andcommitted
fix: drop daily free-quota gate for signed-in users
Logged-in users no longer hit the 10/day rule-engine ceiling — the per-target back-to-back limit (checkPerTargetLimit) is sufficient abuse protection for authenticated accounts. The daily IP / per-URL caps still apply to anonymous hero-form scans, where they actually guard against drive-by abuse. Also removes the now-meaningless "X/10 free today" pill from the project dashboard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 519536b commit b0393d7

2 files changed

Lines changed: 5 additions & 42 deletions

File tree

‎app/(app)/projects/[id]/page.tsx‎

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { ScoreTrend } from "@/components/charts/score-trend";
99
import { StatusPie } from "@/components/charts/status-pie";
1010
import { SectionBar, type SectionRow } from "@/components/charts/section-bar";
1111
import { PriorityBar } from "@/components/charts/priority-bar";
12-
import { checkFreeManualQuota, FREE_MANUAL_PER_DAY } from "@/lib/rateLimit";
1312

1413
type AuditRow = {
1514
id: string;
@@ -109,7 +108,6 @@ export default async function ProjectPage({
109108
Diff vs previous
110109
</Link>
111110
)}
112-
<FreeQuotaPill ownerId={project.owner_id} url={project.url} />
113111
</div>
114112

115113
<EnginesPanel
@@ -246,25 +244,6 @@ function groupByRun(rows: AuditRow[]): RunGroup[] {
246244
return Array.from(groups.values());
247245
}
248246

249-
async function FreeQuotaPill({
250-
ownerId,
251-
url,
252-
}: {
253-
ownerId: string;
254-
url: string;
255-
}) {
256-
const q = await checkFreeManualQuota(ownerId, url);
257-
const remaining = Math.max(0, q.cap - q.used);
258-
return (
259-
<span
260-
className="badge"
261-
title={`Free manual scans: ${remaining}/${FREE_MANUAL_PER_DAY} per 24h on this URL`}
262-
>
263-
{remaining}/{q.cap} free today
264-
</span>
265-
);
266-
}
267-
268247
function Metric({
269248
label,
270249
value,

‎app/actions/runAudit.ts‎

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { createClient } from "@/lib/supabase/server";
66
import { serviceClient } from "@/lib/supabase/service";
77
import {
88
checkAnonymousLimit,
9-
checkFreeManualQuota,
109
checkPerTargetLimit,
1110
consumeCredit,
1211
hashIp,
@@ -107,13 +106,9 @@ export async function startAuditFromForm(input: {
107106
if (!ok.ok) {
108107
return { ok: false, error: `Need ${cost} credits for ${engines.length} engine${engines.length === 1 ? "" : "s"}; not enough balance. Buy credits in Billing.` };
109108
}
110-
} else {
111-
// Free rule engine: check 10/day-per-URL quota.
112-
const quota = await checkFreeManualQuota(user.id, target);
113-
if (!quota.free) {
114-
return { ok: false, error: `Free quota (${quota.cap}/day on this URL) used. Pick a paid engine.` };
115-
}
116109
}
110+
// Signed-in users have no daily ceiling on the free rule engine —
111+
// the per-target back-to-back gate above is enough abuse protection.
117112
}
118113

119114
const svc = serviceClient();
@@ -189,19 +184,11 @@ export async function runScanForProject(input: {
189184
return { ok: false, error: `${ENGINES[unavailable].label} isn't wired up yet.` };
190185
}
191186

192-
const paidEngines = engines.filter((e) => ENGINES[e].cost > 0);
193-
const hasRule = engines.includes("rule");
194187
const cost = selectionCost(engines);
195188

196-
// Rule engine quota gate. Only enforced when the scan is rule-only —
197-
// if the user is paying for at least one engine, the rule engine rides
198-
// along for free without consulting the daily ceiling.
199-
if (hasRule && paidEngines.length === 0) {
200-
const quota = await checkFreeManualQuota(user.id, target);
201-
if (!quota.free) {
202-
return { ok: false, error: `Free quota (${quota.cap}/day on this URL) used. Pick a paid engine or wait for the daily reset.` };
203-
}
204-
}
189+
// No daily free-quota gate for signed-in users — the per-target
190+
// back-to-back limit is the only rate guard. Rate-limiting / daily
191+
// caps apply to anonymous (logged-out) users only.
205192

206193
// Atomic multi-credit deduction up front. If anything below fails we
207194
// refund the lot.
@@ -258,9 +245,6 @@ export async function runScanForProject(input: {
258245
);
259246
for (const r of rows) await notifyWorker(r.id, pdfEmail ?? undefined);
260247

261-
// Suppress unused-warning on paidEngines (it's documentation for now).
262-
void paidEngines;
263-
264248
return {
265249
ok: true,
266250
creditsSpent: cost,

0 commit comments

Comments
 (0)