Add cross-service alert correlation system FRE-4500

- Unified alert types (AlertSource, AlertCategory, CorrelationStatus, EntityType)
- NormalizedAlert and CorrelationGroup Prisma models
- AlertNormalizer for all 4 services (DarkWatch, SpamShield, VoicePrint, CallAnalysis)
- CorrelationEngine with temporal + entity-based correlation detection
- CorrelationService orchestrator with dashboard API
- Correlation API routes (/api/v1/correlation/*)
- Service emitters wired to DarkWatch, SpamShield, VoicePrint
- pnpm workspace config for monorepo
This commit is contained in:
Senior Engineer
2026-05-02 01:10:44 -04:00
committed by Michael Freno
parent 685fb57e53
commit 03276dde2d
35 changed files with 8072 additions and 31 deletions

View File

@@ -10,8 +10,9 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@shieldai/db": "0.1.0",
"@shieldai/types": "0.1.0",
"@shieldai/db": "workspace:*",
"@shieldai/types": "workspace:*",
"@shieldai/correlation": "workspace:*",
"@prisma/client": "^6.2.0",
"libphonenumber-js": "^1.10.50",
"ws": "^8.16.0"

View File

@@ -1,6 +1,7 @@
import { PrismaClient, SpamFeedback, SpamRule, SpamAuditLog } from '@prisma/client';
import { FieldEncryptionService } from '@shieldai/db';
import { generateRequestId } from '@shieldai/types';
import { emitSpamShieldAlert } from '@shieldai/correlation';
import { spamConfig, spamFeatureFlags } from '../config/spamshield.config';
import { CircuitBreaker, CircuitBreakerError, CircuitState, CircuitBreakerMetrics } from '../circuit-breaker';
import { validatePhoneNumber as validateE164 } from '../utils/phone-validation';
@@ -213,7 +214,7 @@ export class SpamShieldService {
confidence = Math.min(confidence, 1.0);
const decision = confidence > 0.8 ? 'BLOCK' : confidence > 0.5 ? 'FLAG' : 'ALLOW';
await prisma.spamAuditLog.create({
const auditLog = await prisma.spamAuditLog.create({
data: {
userId: 'system',
phoneNumber: validated,
@@ -223,6 +224,17 @@ export class SpamShieldService {
},
});
if (decision === 'BLOCK' || decision === 'FLAG') {
emitSpamShieldAlert(
'system',
auditLog.id,
validated,
decision,
confidence,
ruleMatches
).catch((err) => console.error(`[Correlation] SpamShield emit failed:`, err));
}
return { decision, confidence, ruleMatches };
}