CYART // SCHEMA · ALERT-CORRELATION6 NODES · 6 LINKSACTOR · Alerts — 10k/day, many dupesACTOR01Alerts10k/day, many dupesSERVICE · Fingerprint — rule + entity + windowSERVICE02Fingerprintrule + entity + windowSERVICE · Dedupe — same key → count++SERVICE03Dedupesame key → count++SERVICE · Group — same host / userSERVICE04Groupsame host / userSERVICE · Score — severity × asset × recencySERVICE05Scoreseverity × asset × recencyDATA · Case — one per incidentDATA06Caseone per incident

Design an alert deduplication and correlation engine

Design the component that takes 10,000 alerts a day and produces a few dozen cases: fingerprinting, time-windowed dedupe, entity-based grouping, scoring and the state machine of a case.

● Must know for interviews● Medium🔒 PRODesign problem·11 min read·Intermediate → Advanced
correlationdedupestate machineTypeScript

01Understand the problem and interfaces

✓What you will learn
  • Define a fingerprint that is stable but not too coarse
  • Dedupe in a sliding window with counts, not copies
  • Group by shared entities into cases
  • Model the case lifecycle as an explicit state machine
◎Interview radar

What they probe: the fingerprint choice, how windows expire, how grouping avoids merging everything into one mega-case, what reopens a closed case. Where candidates slip: dedupe by exact message text, unbounded memory, no case states.

Contractsts
export interface Alert { id: string; ruleId: string; severity: 1 | 2 | 3 | 4; time: Date; entities: { host?: string; user?: string; ip?: string }; summary: string }

export interface Case {
  id: string;
  state: "open" | "acknowledged" | "resolved" | "closed";
  score: number;
  entities: Set<string>;                  // "host:web-01", "user:priya"
  groups: Map<string, { alertIds: string[]; count: number; first: Date; last: Date }>; // by fingerprint
  openedAt: Date; updatedAt: Date;
}

export interface Fingerprinter { fingerprint(a: Alert): string }
export interface Scorer { score(c: Case): number }
export interface CaseStore {
  /** Cases touching this entity, updated since `since`, in one of `states`. */
  findByEntity(entity: string, since: Date, states: Case["state"][]): Case[];
  save(c: Case): void;
}

export interface CorrelationEngine { ingest(a: Alert): { caseId: string; action: "created" | "deduped" | "grouped" | "reopened" } }

This is an advanced module

Problems: Advanced components is part of the Pro pass. 1 more section — the deep dives, the final design, follow-ups and the test — unlock with it.

Already a cyart.io or studio.cyart.io member? Your pass code is in your Studio account.