Iteration Teil D: Lieferantenmanagement (VDA-ISA 2027 Kap. 6 + NIS2)

Datenmodell (Prisma, RLS): Supplier + SupplierAsset, SupplierAssessment,
Contract, Nda, SupplierEvidence, ServiceResponsibility, Subcontractor,
ManagementDecision, SupplierControl (globaler Katalog) +
SupplierControlMaturity.

- VDA-ISA-2027-Kap.-6-Mini-Katalog (Controls 6.1.1–6.1.3) mit Zielbild,
  Muss/Soll, Anforderungen für hoch/sehr hoch, Simplified Group
  Assessment, Ziel-Reifegrad 3 und Cross-Referenzen (ISO/NIST/BSI); im
  Seed befüllt
- Lieferantenverzeichnis mit KPIs (gesamt, NIS2-relevant, ablaufend,
  Reviews fällig), Kritikalität, NIS2-Flag, Review-Fristen
- Detail-Popup: Stammdaten (Sektor/Leistung/Datenkategorien/CIA),
  betroffene Assets, VDA-ISA-Reifegrade je Control (Ziel 3, farbige
  Balken), Nachweise (Angemessenheit + Ablauf), Assessments, Verträge
  (AV/DPA, Flow-down, Fristen), NDAs (Fristen), Shared-Responsibility-
  Matrix, Subunternehmer, Managemententscheidungen
- Bearbeiten-Popup: Stammdaten (ein Speichern), Reifegrad je Control,
  Add/Delete für alle Kind-Entitäten, Löschen im ⋯-Menü
- Regel 6.1.1: fehlt geprüfter Audit-/TISAX-Nachweis → Warnung, dass
  eine dokumentierte risikobasierte Managemententscheidung nötig ist
- Server-Actions mit Zod/RBAC/Audit-Log; Seed mit Demo-Lieferant
  (TISAX-Label, AV/DPA, NDA, Assessment, RACI, Reifegrade)
- Menüpunkt „Lieferanten" aktiv; Lieferant ↔ Asset verknüpft (Graph)

Verifiziert: Register/Detail/Bearbeiten dunkel & vollständig, Reifegrad-
Save (6.1.2→4 mit Audit), Managemententscheidungs-Logik.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Martin
2026-07-03 10:23:02 +02:00
co-authored by Claude Opus 4.8
parent 18bd82e54a
commit 32ab91efbf
12 changed files with 2110 additions and 1 deletions
+45
View File
@@ -0,0 +1,45 @@
export function supplierRef(refNo: number): string {
return `L-${String(refNo).padStart(3, "0")}`;
}
export const SUPPLIER_STATUS_TONE = {
ACTIVE: "ok",
ONBOARDING: "info",
UNDER_REVIEW: "warn",
OFFBOARDED: "mut",
} as const;
const DAY = 24 * 3600 * 1000;
/** true, wenn valid_to innerhalb der nächsten `days` Tage liegt (oder bereits abgelaufen). */
export function isExpiring(validTo: Date | null | undefined, days = 90): boolean {
if (!validTo) return false;
return validTo.getTime() - Date.now() < days * DAY;
}
export function isExpired(validTo: Date | null | undefined): boolean {
if (!validTo) return false;
return validTo.getTime() < Date.now();
}
/** Review innerhalb der nächsten `days` Tage fällig (oder überfällig)? */
export function isReviewDue(nextReview: Date | null | undefined, days = 30): boolean {
if (!nextReview) return false;
return nextReview.getTime() < Date.now() + days * DAY;
}
/**
* NIS2/VDA-ISA 6.1.1: Ist eine risikobasierte Managemententscheidung nötig?
* → wenn KEIN gültiger, angemessenheitsgeprüfter Audit-/TISAX-Nachweis vorliegt.
*/
export function needsManagementDecision(
evidence: { kind: string; adequacyChecked: boolean; validTo: Date | null }[]
): boolean {
const hasAdequate = evidence.some(
(e) =>
(e.kind === "AUDIT_REPORT" || e.kind === "TISAX_LABEL" || e.kind === "CERTIFICATE") &&
e.adequacyChecked &&
!isExpired(e.validTo)
);
return !hasAdequate;
}