Iteration 2: Assets & BIA als gemeinsames Modul
- App-Shell mit Seitennavigation (alle 12 Module, kommende ausgegraut), shadcn/ui-Setup (Base-UI-Variante) mit hellem Theme - Asset-Inventar: filterbare Liste (Suche/Typ/Status), Anlegen/Bearbeiten/ Löschen, Detailansicht mit Schutzbedarf (C/I/A 1–4), Abhängigkeiten (beide Richtungen, hinzufügen/entfernen), zugeordneten Prozessen mit Primär-/Sekundär-Rolle und Platzhalter für zugeordnete Risiken - Prozesse & BIA: Liste mit Kritikalität/RTO/MTD, Prozess-Detail mit Asset-Zuordnung nach Rolle (primär/sekundär), BIA-Formular (RTO/RPO/MTD, Schadenshöhe je Schutzziel, Kritikalität nach Max-Prinzip) - Server-Actions mit Zod-Validierung, requirePermission und Audit-Log für jede schreibende Aktion; Tenant-Guard um upsert-Injektion erweitert - Prisma: Asset, AssetRelation, Process, ProcessAsset, BiaEntry inkl. RLS-Policies; Seed mit Beispiel-Assets, Prozessen und BIA - Im Browser verifiziert: CRUD, Relationen, BIA-Speichern, Audit-Einträge Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+114
@@ -81,6 +81,120 @@ async function main() {
|
||||
}
|
||||
}
|
||||
console.log(`✔ ${demoUsers.length} Demo-Nutzer (Passwort: ${DEMO_PASSWORD})`);
|
||||
|
||||
// 5. Beispiel-Assets, -Prozesse und BIA (nur wenn noch keine Assets existieren)
|
||||
const assetCount = await prisma.asset.count({ where: { tenantId: tenant.id } });
|
||||
if (assetCount === 0) {
|
||||
const isb = await prisma.user.findUniqueOrThrow({
|
||||
where: { tenantId_email: { tenantId: tenant.id, email: "admin@demo.example" } },
|
||||
});
|
||||
const owner = await prisma.user.findUniqueOrThrow({
|
||||
where: { tenantId_email: { tenantId: tenant.id, email: "owner@demo.example" } },
|
||||
});
|
||||
|
||||
const mk = (data: {
|
||||
name: string;
|
||||
type: "INFORMATION" | "SYSTEM" | "APPLICATION" | "LOCATION" | "SUPPLIER" | "PERSON" | "DATA";
|
||||
c: number;
|
||||
i: number;
|
||||
a: number;
|
||||
ownerId?: string;
|
||||
location?: string;
|
||||
tags?: string[];
|
||||
description?: string;
|
||||
}) =>
|
||||
prisma.asset.create({
|
||||
data: {
|
||||
tenantId: tenant.id,
|
||||
name: data.name,
|
||||
type: data.type,
|
||||
confidentiality: data.c,
|
||||
integrity: data.i,
|
||||
availability: data.a,
|
||||
ownerId: data.ownerId,
|
||||
location: data.location,
|
||||
tags: data.tags ?? [],
|
||||
description: data.description,
|
||||
},
|
||||
});
|
||||
|
||||
const erp = await mk({ name: "ERP-System", type: "SYSTEM", c: 3, i: 4, a: 3, ownerId: owner.id, location: "RZ Frankfurt", tags: ["kritisch", "kern"] });
|
||||
const crm = await mk({ name: "Kundendatenbank", type: "DATA", c: 4, i: 3, a: 2, ownerId: isb.id, tags: ["dsgvo"] });
|
||||
const auftraege = await mk({ name: "Auftragsdaten", type: "INFORMATION", c: 3, i: 4, a: 3, ownerId: owner.id });
|
||||
const hoster = await mk({ name: "Cloud-Hoster (IaaS)", type: "SUPPLIER", c: 2, i: 3, a: 4, description: "Betreibt das Rechenzentrum für ERP und CRM." });
|
||||
const buero = await mk({ name: "Bürostandort München", type: "LOCATION", c: 2, i: 2, a: 2 });
|
||||
const itTeam = await mk({ name: "IT-Administration", type: "PERSON", c: 3, i: 3, a: 3 });
|
||||
|
||||
await prisma.assetRelation.createMany({
|
||||
data: [
|
||||
{ tenantId: tenant.id, assetId: erp.id, relatedAssetId: hoster.id, type: "depends_on" },
|
||||
{ tenantId: tenant.id, assetId: crm.id, relatedAssetId: hoster.id, type: "depends_on" },
|
||||
{ tenantId: tenant.id, assetId: erp.id, relatedAssetId: itTeam.id, type: "depends_on" },
|
||||
],
|
||||
});
|
||||
|
||||
const auftrag = await prisma.process.create({
|
||||
data: {
|
||||
tenantId: tenant.id,
|
||||
name: "Auftragsabwicklung",
|
||||
description: "Vom Kundenauftrag bis zur Auslieferung.",
|
||||
ownerId: owner.id,
|
||||
},
|
||||
});
|
||||
await prisma.processAsset.createMany({
|
||||
data: [
|
||||
{ tenantId: tenant.id, processId: auftrag.id, assetId: auftraege.id, role: "PRIMARY" },
|
||||
{ tenantId: tenant.id, processId: auftrag.id, assetId: erp.id, role: "SECONDARY" },
|
||||
{ tenantId: tenant.id, processId: auftrag.id, assetId: crm.id, role: "SECONDARY" },
|
||||
{ tenantId: tenant.id, processId: auftrag.id, assetId: itTeam.id, role: "SECONDARY" },
|
||||
],
|
||||
});
|
||||
await prisma.biaEntry.create({
|
||||
data: {
|
||||
tenantId: tenant.id,
|
||||
processId: auftrag.id,
|
||||
rtoHours: 8,
|
||||
rpoHours: 4,
|
||||
mtdHours: 24,
|
||||
impactC: 2,
|
||||
impactI: 4,
|
||||
impactA: 3,
|
||||
criticality: 4,
|
||||
notes: "Ausfall > 1 Tag führt zu Lieferverzug und Vertragsstrafen.",
|
||||
},
|
||||
});
|
||||
|
||||
const vertrieb = await prisma.process.create({
|
||||
data: {
|
||||
tenantId: tenant.id,
|
||||
name: "Kundenbetreuung",
|
||||
description: "Anfragen, Angebote, Support.",
|
||||
ownerId: isb.id,
|
||||
},
|
||||
});
|
||||
await prisma.processAsset.createMany({
|
||||
data: [
|
||||
{ tenantId: tenant.id, processId: vertrieb.id, assetId: crm.id, role: "PRIMARY" },
|
||||
{ tenantId: tenant.id, processId: vertrieb.id, assetId: buero.id, role: "SECONDARY" },
|
||||
],
|
||||
});
|
||||
await prisma.biaEntry.create({
|
||||
data: {
|
||||
tenantId: tenant.id,
|
||||
processId: vertrieb.id,
|
||||
rtoHours: 24,
|
||||
rpoHours: 24,
|
||||
mtdHours: 72,
|
||||
impactC: 3,
|
||||
impactI: 2,
|
||||
impactA: 2,
|
||||
criticality: 3,
|
||||
notes: "Kundenkommunikation kann kurzfristig über Ausweichkanäle laufen.",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("✔ Beispiel-Assets, -Prozesse und BIA angelegt");
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user