diff --git a/backend/server/utils/mail-classifier.ts b/backend/server/utils/mail-classifier.ts index b101715..3f52c3b 100644 --- a/backend/server/utils/mail-classifier.ts +++ b/backend/server/utils/mail-classifier.ts @@ -77,7 +77,7 @@ export const SCORE_WEIGHTS = { // Subject-Indikatoren SUBJECT_GAMBLING_KEYWORD: 50, // Keyword im Betreff (casino, jackpot, freispiel …) SUBJECT_MONEY_PATTERN: 20, // €/$ + Zahl (z.B. "100€ Bonus") - SUBJECT_PERCENT_PATTERN: 10, // Zahl+% im Betreff (z.B. "400% Bonus") — allein nie Block-fähig + SUBJECT_PERCENT_PATTERN: 15, // Zahl+% im Betreff (z.B. "400% Bonus") — allein nie Block-fähig SUBJECT_URGENCY: 15, // "Nur heute", "Letzte Chance", "Ablaufdatum" SUBJECT_ALL_CAPS_WORD: 5, // EINZELNES ALL-CAPS-WORT im Betreff @@ -94,8 +94,8 @@ export const SCORE_WEIGHTS = { const SCORE_HARD_BLOCK_THRESHOLD = 80; // Pass-Below: Score < 25 → PASS (no-signal) const SCORE_PASS_BELOW = 25; -// Mid-range Block-Threshold: Score in [25, 80) → BLOCK ab 50, sonst PASS -const SCORE_BLOCK_MIDRANGE = 50; +// Mid-range Block-Threshold: Score in [25, 80) → BLOCK ab 40, sonst PASS +const SCORE_BLOCK_MIDRANGE = 40; // ─── Bekannte Gambling-Brands (für Brand-Match-Normalisierung) ───────────────── // Abgeleitet aus GAMBLING_KEYWORDS + typischen Blocklist-Domains. @@ -270,7 +270,12 @@ export function computeScore( // ── Sender-Name-Keywords: entfernt in v1.0 (Score-Beitrag via Display-Name // ist zu False-Positive-anfällig, Display-Name-Blocking nicht supported). - // keywordHitsName bleibt im ScoreResult für v1.1-Reaktivierung (immer leer). + // keywordHitsName bleibt im ScoreResult für v1.1-Reaktivierung. + // v1.2: "casino" im Display-Name ist stark genug für gezielten Score-Beitrag. + if (senderNameLower.includes("casino")) { + keywordHitsName.push("casino"); + score += 30; + } // ── Geld-Pattern im Betreff (€/$ + Zahl) ── if (/[€$£]\s*\d|\d\s*[€$£]/.test(subject)) { @@ -279,14 +284,28 @@ export function computeScore( } // ── Prozent-Pattern im Betreff (z.B. "400% Bonus", "200% Einzahlung") ── - // Separates Flag mit reduziertem Score: % allein (10 Punkte) reicht nie - // für einen Block (Threshold 50) — verhindert FP bei "10% Rabatt"-Mails. + // Separates Flag mit reduziertem Score: % allein (15 Punkte) reicht nie + // für einen Block allein — verhindert FP bei "10% Rabatt"-Mails. // Ergänzt das Currency-Pattern oben, das nur € / $ / £ kennt. if (/\d\s*%/.test(subject)) { styleFlags.push("percent-pattern"); score += SCORE_WEIGHTS.SUBJECT_PERCENT_PATTERN; } + // ── FS-Token im Betreff (z.B. "400 FS", "100FS") — Free-Spins-Abkürzung ── + // Word-Boundary sichert, dass "FFS" oder "OFS" nicht fälschlich matchen. + if (/\b\d+\s*FS\b/.test(subject)) { + styleFlags.push("free-spins-token"); + score += 20; + } + + // ── Extrem-Prozent im Betreff (>= 100%, z.B. "200%", "1000% Bonus") ── + // Retailer nutzen selten dreistellige Prozentwerte — Gambling-Mails sehr oft. + if (/\b[1-9]\d{2,}\s*%/.test(subject)) { + styleFlags.push("extreme-percent"); + score += 20; + } + // ── Urgency-Wörter im Betreff ── const URGENCY_PATTERNS = [ "nur heute", "letzte chance", "läuft ab", "ablaufdatum",