Iteration 3: Risikoanalyse + Menü-Trennung + Prozesskategorie

- Risiko-Modul (SPEC §4.2): Risk/RiskAsset-Schema mit RLS, laufende
  Nummer je Mandant (R-001), Brutto-/Rest-Bewertung (5×5), Behandlung,
  Status, Owner- und Prozess-Bezug, n:m betroffene Assets
- /risks im Mockup-Layout: 5×5-Heatmap (Farb-Bänder + R-Chips, Legende,
  Achsen) und Risikoregister mit Score-Pillen, Behandlungs-Tags, Status
- Risiko-Popups nach App-Muster: Read-only-Detail (Bewertungs-Band
  Brutto vs. Rest, betroffene Assets, Maßnahmen-Platzhalter für
  Iteration 4), Bearbeiten im Popup (Bewertung, Assets verknüpfen,
  Löschen), Anlegen; Server-Actions mit Zod, RBAC und Audit-Log
- Menü aufgetrennt: eigene Punkte "Asset-Inventar", "Business Impact
  Analyse" und "Risikoanalyse" (Modul-Tabs entfernt)
- Prozesskategorie (Kernprozess/Managementprozess/Unterstützender
  Prozess): Schema-Feld, Formulare, Listen-Spalte, Popup-Tag
- Asset-Detail-Popup optisch ans Prozess-Popup angeglichen (Stammdaten-
  Karte mit violettem Rand, Abhängigkeiten-Tabelle, Risiken-Band)
- "Zugeordnete Risiken" jetzt echt: im Asset-Popup (verknüpfte Risiken)
  und im Prozess-Popup (direkt + über Assets aggregiert); Dashboard-KPI
  "Offene Risiken" mit echten Zahlen; Seed mit 4 Beispiel-Risiken

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Martin
2026-07-02 15:43:25 +02:00
co-authored by Claude Fable 5
parent c5a1f0095b
commit df634e356d
20 changed files with 1633 additions and 106 deletions
+83 -3
View File
@@ -60,6 +60,7 @@ model User {
userRoles UserRole[]
ownedAssets Asset[] @relation("assetOwner")
ownedProcesses Process[] @relation("processOwner")
ownedRisks Risk[] @relation("riskOwner")
@@unique([tenantId, email])
@@index([tenantId])
@@ -135,6 +136,12 @@ enum ProcessAssetRole {
SECONDARY
}
enum ProcessCategory {
CORE // Kernprozess
MANAGEMENT // Managementprozess
SUPPORT // Unterstützender Prozess
}
model Asset {
id String @id @default(cuid())
tenantId String @map("tenant_id")
@@ -157,6 +164,7 @@ model Asset {
relationsFrom AssetRelation[] @relation("relationFrom")
relationsTo AssetRelation[] @relation("relationTo")
processAssets ProcessAsset[]
riskAssets RiskAsset[]
@@index([tenantId])
@@index([tenantId, type])
@@ -180,11 +188,12 @@ model AssetRelation {
}
model Process {
id String @id @default(cuid())
tenantId String @map("tenant_id")
id String @id @default(cuid())
tenantId String @map("tenant_id")
name String
description String?
ownerId String? @map("owner_id")
category ProcessCategory @default(CORE)
ownerId String? @map("owner_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
createdBy String? @map("created_by")
@@ -192,6 +201,7 @@ model Process {
owner User? @relation("processOwner", fields: [ownerId], references: [id])
processAssets ProcessAsset[]
bia BiaEntry?
risks Risk[]
@@index([tenantId])
@@map("processes")
@@ -236,6 +246,76 @@ model BiaEntry {
@@map("bia_entries")
}
// ── Risikoanalyse (SPEC §4.2) ───────────────────────────────────────────────
enum RiskTreatment {
AVOID // Vermeiden
MITIGATE // Vermindern
TRANSFER // Übertragen
ACCEPT // Akzeptieren
}
enum RiskStatus {
OPEN
IN_TREATMENT
ACCEPTED
CLOSED
}
model Risk {
id String @id @default(cuid())
tenantId String @map("tenant_id")
// Laufende Nummer je Mandant → Anzeige als "R-001"
refNo Int @map("ref_no")
title String
description String?
threat String? // Bedrohung (Katalog folgt, SPEC §5)
vulnerability String? // Schwachstelle
// Brutto-Bewertung: Eintrittswahrscheinlichkeit × Auswirkung (je 15)
likelihood Int @default(1)
impact Int @default(1)
score Int @default(1) // redundant für Listen/Heatmap
// Rest-Risiko nach Maßnahmen
residualLikelihood Int? @map("residual_likelihood")
residualImpact Int? @map("residual_impact")
residualScore Int? @map("residual_score")
treatment RiskTreatment @default(MITIGATE)
status RiskStatus @default(OPEN)
ownerId String? @map("owner_id")
processId String? @map("process_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
createdBy String? @map("created_by")
owner User? @relation("riskOwner", fields: [ownerId], references: [id])
process Process? @relation(fields: [processId], references: [id])
riskAssets RiskAsset[]
@@unique([tenantId, refNo])
@@index([tenantId])
@@index([tenantId, status])
@@map("risks")
}
model RiskAsset {
id String @id @default(cuid())
tenantId String @map("tenant_id")
riskId String @map("risk_id")
assetId String @map("asset_id")
risk Risk @relation(fields: [riskId], references: [id], onDelete: Cascade)
asset Asset @relation(fields: [assetId], references: [id], onDelete: Cascade)
@@unique([riskId, assetId])
@@index([tenantId])
@@map("risk_assets")
}
model AuditLog {
id String @id @default(cuid())
tenantId String @map("tenant_id")