FRE-4471: Scaffold DarkWatch MVP — monorepo, schema, services, API routes, tests

- Turborepo monorepo structure (packages: api, db, types, jobs; services: darkwatch)
- Prisma schema: User, WatchListItem, Exposure, Alert, ScanJob models
- WatchListService: CRUD with normalization, dedup, tier-based limits
- HIBPService: API integration with severity scoring
- MatchingEngine: exact-match with content hash dedup
- AlertPipeline: dedup window, email notifications
- ScanService: orchestrates watch list -> HIBP -> match -> alert flow
- BullMQ job workers for scan and alert processing
- Fastify API routes: watchlist, exposures, alerts, scan
- Docker Compose: PostgreSQL 16 + Redis 7
- 15 unit tests passing
- Implementation plan document uploaded
This commit is contained in:
Senior Engineer
2026-04-29 09:47:45 -04:00
committed by Michael Freno
parent f8f90502fa
commit 218de3b03b
40 changed files with 5225 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
import { describe, it, expect, beforeEach } from "vitest";
import { AlertPipeline } from "../src/alerts/AlertPipeline";
import prisma from "@shieldai/db";
import { Severity } from "@shieldai/types";
describe("AlertPipeline", () => {
let pipeline: AlertPipeline;
beforeEach(() => {
pipeline = new AlertPipeline();
});
it("creates alert with dedup key", async () => {
const user = await prisma.user.create({
data: { email: `alert-test-${Date.now()}@shieldai.local`, subscriptionTier: "BASIC" },
});
const item = await prisma.watchListItem.create({
data: {
userId: user.id,
identifierType: "EMAIL",
identifierValue: "test@example.com",
identifierHash: "hash-" + Date.now(),
},
});
const exposure = await prisma.exposure.create({
data: {
watchListItemId: item.id,
dataSource: "HIBP",
breachName: "TestBreach",
exposedAt: new Date(),
dataType: ["Email Address"],
severity: Severity.CRITICAL,
contentHash: "content-" + Date.now(),
},
});
const created = await pipeline.createAlert(user.id, exposure.id, Severity.CRITICAL);
expect(created).toBe(true);
});
it("deduplicates alerts within window", async () => {
const user = await prisma.user.create({
data: { email: `dedup-test-${Date.now()}@shieldai.local`, subscriptionTier: "BASIC" },
});
const item = await prisma.watchListItem.create({
data: {
userId: user.id,
identifierType: "EMAIL",
identifierValue: "dedup@example.com",
identifierHash: "dedup-hash-" + Date.now(),
},
});
const exposure = await prisma.exposure.create({
data: {
watchListItemId: item.id,
dataSource: "HIBP",
breachName: "DedupBreach",
exposedAt: new Date(),
dataType: ["Email Address"],
severity: Severity.CRITICAL,
contentHash: "dedup-content-" + Date.now(),
},
});
const first = await pipeline.createAlert(user.id, exposure.id, Severity.CRITICAL);
const second = await pipeline.createAlert(user.id, exposure.id, Severity.CRITICAL);
expect(first).toBe(true);
expect(second).toBe(false);
});
it("computes consistent dedup keys", () => {
const key1 = pipeline.computeDedupKey("user-1", "exposure-1");
const key2 = pipeline.computeDedupKey("user-1", "exposure-1");
expect(key1).toBe(key2);
expect(key1).toHaveLength(64);
});
});