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

@@ -9,8 +9,9 @@
"lint": "eslint src/"
},
"dependencies": {
"@shieldai/db": "0.1.0",
"@shieldai/types": "0.1.0",
"@shieldai/db": "workspace:*",
"@shieldai/types": "workspace:*",
"@shieldai/correlation": "workspace:*",
"node-cache": "^5.1.2"
},
"exports": {

View File

@@ -1,5 +1,6 @@
import prisma from "@shieldai/db";
import { AlertChannel, AlertStatus, Severity } from "@shieldai/types";
import { emitDarkWatchAlert } from "@shieldai/correlation";
import { createHash } from "crypto";
import NodeCache from "node-cache";
@@ -28,7 +29,7 @@ export class AlertPipeline {
if (existing) return false;
await prisma.alert.create({
const alert = await prisma.alert.create({
data: {
userId,
exposureId,
@@ -39,6 +40,24 @@ export class AlertPipeline {
},
});
const exposure = await prisma.exposure.findUnique({
where: { id: exposureId },
include: { watchListItem: true },
});
if (exposure) {
emitDarkWatchAlert(
userId,
exposureId,
alert.id,
exposure.breachName,
severity,
channel,
exposure.dataType,
exposure.dataSource
).catch((err) => console.error(`[Correlation] DarkWatch emit failed:`, err));
}
this.cache.set(dedupKey, true, this.dedupWindowMs / 1000);
return true;
}