import { redirect } from "next/navigation"; import { Plus, Gauge, ClipboardList, AlertTriangle, CheckCircle2 } from "lucide-react"; import { requireSession } from "@/server/auth"; import { dbForTenant } from "@/server/db"; import { hasPermission } from "@/server/rbac"; import { PageHead, Pill } from "@/components/mockup-ui"; import { Button } from "@/components/ui/button"; import { createKpi, recordKpiValue, createManagementReview, updateManagementReview, addReviewDecision, setReviewDecisionStatus, createNonconformity, addCorrectiveAction, updateCorrectiveAction, updateNonconformity, } from "@/server/actions/review"; /** * Managementklauseln (AP4 · ISO/IEC 27001 9.1, 9.3, 10.2). Kennzahlen mit Zielwerten * und Messwerten je Periode, Managementbewertung entlang der 9.3.2-Agenda und * Nichtkonformitäten mit Korrekturmaßnahme inkl. dokumentierter Wirksamkeitsprüfung. */ const inp = "h-8 w-full rounded-md border border-input bg-transparent px-2 text-[12.5px]"; const ta = "w-full rounded-md border border-input bg-transparent px-2 py-1 text-[12.5px]"; const AGENDA_9_3_2 = "Status Vormaßnahmen · Änderungen (intern/extern) · Rückmeldungen zur Leistung (Nichtkonformitäten, Kennzahlen, Auditergebnisse, Zielerreichung) · Rückmeldungen interessierter Parteien · Risikobewertungsergebnisse & Risikobehandlungsplan · Verbesserungsmöglichkeiten"; const fmtDate = (d: Date | null) => (d ? new Date(d).toLocaleDateString("de-DE") : "—"); export default async function ReviewPage() { const session = await requireSession(); const canRead = hasPermission(session, "review:manage") || hasPermission(session, "report:read"); if (!canRead) redirect("/dashboard"); const canWrite = hasPermission(session, "review:manage"); const db = dbForTenant(session.user.tenantId); const [kpis, reviews, ncs, users] = await Promise.all([ db.kpi.findMany({ orderBy: { createdAt: "asc" }, include: { values: { orderBy: { period: "desc" }, take: 6 } } }), db.managementReview.findMany({ orderBy: { reviewDate: "desc" }, include: { decisions: true } }), db.nonconformity.findMany({ orderBy: { detectedAt: "desc" }, include: { actions: true } }), db.user.findMany({ where: { status: "ACTIVE" }, select: { id: true, name: true }, orderBy: { name: "asc" } }), ]); const ownerSel = (name: string, val?: string | null) => ( ); return (
{/* ── 9.1 Kennzahlen ─────────────────────────────────────────────── */}

9.1 Kennzahlen

{kpis.length === 0 &&

Noch keine Kennzahlen.

}
{kpis.map((k) => (
{k.name} {k.target && Ziel: {k.target}{k.unit ? ` ${k.unit}` : ""}} {k.cadence} {k.values.map((v) => {v.period}: {v.value})}
{k.description &&

{k.description}

} {k.dataSource &&

Datenquelle: {k.dataSource}

} {canWrite && (
)}
))}
{canWrite && (
)}
{/* ── 9.3 Managementbewertung ────────────────────────────────────── */}

9.3 Managementbewertung

{reviews.length === 0 &&

Noch keine Managementbewertung.

}
{reviews.map((r) => (
{fmtDate(r.reviewDate)} {r.status} {r.decisions.length} Beschluss/-e ({r.decisions.filter((d) => d.status === "offen").length} offen)
{canWrite ? (