feat: pre-check global blocklist on add + collapse Mails on load

User found that adding bet365.com (which is in the 208k global filter)
silently took a custom-domain slot — they paid a slot for something
the global blocklist already covered. Two pieces:

1. backend/custom-domains/index.post.ts: before any slot-limit check or
   DB insert, look the domain up in blocklist_domain (active rows). If
   present, return 200 { alreadyGlobal: true, domain }. No row gets
   written, no slot consumed. The existing frontend hook + AddSheet
   already handle the alreadyGlobal flag — they surface the
   "bereits global blockiert" alert and don't refresh as if the entry
   landed in the user's list.

2. blocker.tsx default mailOpen state flipped from true to false so the
   Eigene Mails section starts collapsed on page load. Domains stays
   the primary affordance; mail-patterns are an opt-in expansion.
This commit is contained in:
chahinebrini 2026-05-16 02:42:42 +02:00
parent 1215356990
commit f19d00017a
2 changed files with 16 additions and 1 deletions

View File

@ -61,7 +61,7 @@ export default function BlockerScreen() {
}, [refreshDomains, syncBlocklist, refresh]);
useDomainSubmissionRealtime(onDomainChange, true);
const [mailOpen, setMailOpen] = useState(true);
const [mailOpen, setMailOpen] = useState(false);
// AddSheet state: tracks which section opened it
const [addSheetOpen, setAddSheetOpen] = useState(false);

View File

@ -7,6 +7,7 @@ import {
} from "../../db/domains";
import { getProfile } from "../../db/profile";
import { getPlanLimits } from "../../utils/plan-features";
import { usePrisma } from "../../utils/prisma";
// Regex: Domain muss mindestens eine TLD haben (z.B. "casino.de", "x.co.uk")
const DOMAIN_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;
@ -128,6 +129,20 @@ export default defineEventHandler(async (event) => {
});
}
// Pre-check: domain already on the global blocklist? Don't burn a slot for
// something the 208k-domain global filter already covers. Return 200 with a
// flag so the frontend can surface "already protected, no slot needed"
// without the user paying for it. mail_domain is included in the same check
// because mail-domains land in the same blocklist set the daemon scans.
const db = usePrisma();
const globalMatch = await db.blocklistDomain.findFirst({
where: { domain: value, isActive: true },
select: { domain: true },
});
if (globalMatch) {
return { alreadyGlobal: true, domain: value };
}
// Per-type Slot-Limit prüfen
const profile = await getProfile(user.id);
const limits = getPlanLimits(profile?.plan ?? "free");