/** * Zentrale Konstanten/Helfer für das Modul „Vorfälle" (client-safe). * Kategorien (§4-Taxonomie), Status (§3-Lebenszyklus) und die refNo-Anzeige. */ import type { IncidentSeverity } from "@/lib/incident-severity"; export const INCIDENT_CATEGORIES = [ "malware", "phishing", "unauthorized_access", "data_loss", "outage", "physical", "misconfiguration", "supplier", "prototype_customer_data", "other", ] as const; export type IncidentCategory = (typeof INCIDENT_CATEGORIES)[number]; export const INCIDENT_STATUSES = [ "neu", "triage", "in_bearbeitung", "eingedaemmt", "behoben", "abgeschlossen", "wiedereroeffnet", ] as const; export type IncidentStatus = (typeof INCIDENT_STATUSES)[number]; export const INCIDENT_SOURCES = ["manual", "email"] as const; export type IncidentSource = (typeof INCIDENT_SOURCES)[number]; export const INCIDENT_PRIORITIES = ["niedrig", "mittel", "hoch", "kritisch"] as const; /** * Erlaubte Statusübergänge (§3). Jeder Übergang wird serverseitig geprüft; * bestimmte Übergänge verlangen zusätzlich Pflichtfelder (siehe TRANSITION_REQUIRES). */ export const STATUS_TRANSITIONS: Record = { neu: ["triage", "in_bearbeitung"], triage: ["in_bearbeitung", "eingedaemmt"], in_bearbeitung: ["eingedaemmt", "behoben"], eingedaemmt: ["behoben", "in_bearbeitung"], behoben: ["abgeschlossen", "wiedereroeffnet"], abgeschlossen: ["wiedereroeffnet"], wiedereroeffnet: ["triage", "in_bearbeitung"], }; /** * Pflichtfelder je Zielstatus (§8). Ein Übergang nach „behoben" verlangt Ursache + * Lösung; „abgeschlossen" zusätzlich Abschlussnotiz + Lessons Learned. */ export const TRANSITION_REQUIRES: Partial> = { behoben: ["rootCause", "resolution"], abgeschlossen: ["rootCause", "resolution", "closingNote", "lessonsLearned"], }; export function canTransition(from: IncidentStatus, to: IncidentStatus): boolean { return STATUS_TRANSITIONS[from]?.includes(to) ?? false; } /** * Ob der Nutzer vertrauliche Vorfälle sehen darf (§11): nur Rollen mit * incident:manage oder incident:close. Der owner sieht seine eigenen zusätzlich * über den ownerId-Filter (serverseitig in der Liste). Pure/client-safe. */ export function canSeeRestricted(session: { user?: { permissions?: string[] } }): boolean { const p = session.user?.permissions ?? []; return p.includes("incident:manage") || p.includes("incident:close"); } /** * Fehlende Pflichtfelder für einen Zielstatus (§8). Prüft die effektiven Werte * (bereits gesetzt oder beim Übergang mitgeliefert). Leeres Array = alles erfüllt. * Pure Funktion — von Action und Test gemeinsam genutzt. */ export function missingRequiredFields( target: IncidentStatus, values: Record, ): string[] { const required = TRANSITION_REQUIRES[target] ?? []; return required.filter((field) => { const v = values[field]; return v === null || v === undefined || (typeof v === "string" && v.trim() === ""); }); } /** Farb-Ton (mockup-ui Pill) je Severity. */ export const SEVERITY_TONE: Record = { niedrig: "mut", mittel: "info", hoch: "warn", kritisch: "risk", }; /** Farb-Ton je Status. */ export const STATUS_TONE: Record = { neu: "risk", triage: "warn", in_bearbeitung: "info", eingedaemmt: "info", behoben: "ok", abgeschlossen: "mut", wiedereroeffnet: "warn", }; /** Farb-Ton je Meldung-Track-Status (reportStatus, §3 Parallel-Track). */ export const REPORT_STATUS_TONE: Record = { none: "mut", pruefung: "warn", erstmeldung: "orange", folgemeldung: "info", abschluss: "ok", };