feat(kunden): Kundenverwaltung, Hostzuweisung und Token-Verwaltung (#006)

Kunden und Standorte pflegen, nicht zugeordnete Hosts in einem Schritt zuweisen,
Enrollment- und Host-Tokens verwalten, Audit-Log. Dashboard, Kundenseiten und
globale Suche laufen jetzt auf der Datenbank. 45 Tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-17 21:02:44 +02:00
co-authored by Claude Opus 5
parent f591b45aac
commit f9a5ad2daa
40 changed files with 2060 additions and 415 deletions
@@ -0,0 +1,65 @@
import { notFound } from "next/navigation";
import { ContentHeader } from "@/components/layout/ContentHeader";
import { KundeFormular } from "@/components/kunden/KundeFormular";
import { Card } from "@/components/ui/Card";
import { prisma } from "@/lib/db";
import { kundeLoeschen } from "@/server/actions/kunden";
export const metadata = { title: "Kunde bearbeiten" };
export default async function KundeBearbeitenSeite({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const kunde = await prisma.kunde.findUnique({
where: { id },
include: { _count: { select: { hosts: true } } },
});
if (!kunde) notFound();
return (
<>
<ContentHeader
titel={`${kunde.name} bearbeiten`}
brotkrumen={[
{ titel: "Kunden", href: "/kunden" },
{ titel: kunde.name, href: `/kunden/${kunde.id}` },
{ titel: "Bearbeiten" },
]}
/>
<div className="app-content">
<div className="container-fluid">
<div className="row">
<div className="col-lg-8">
<Card titel="Stammdaten" rahmen="primary">
<KundeFormular
werte={{
id: kunde.id,
name: kunde.name,
kundennummer: kunde.kundennummer,
ansprechpartner: kunde.ansprechpartner,
email: kunde.email,
telefon: kunde.telefon,
notizen: kunde.notizen,
}}
/>
</Card>
<Card titel="Kunde löschen" rahmen="danger">
<p>
Der Kunde wird mit allen Standorten und Kundenrechnungen entfernt. Seine{" "}
{kunde._count.hosts} Host(s) bleiben erhalten und erscheinen danach unter „Nicht
zugeordnet“.
</p>
<form action={kundeLoeschen}>
<input type="hidden" name="id" value={kunde.id} />
<button type="submit" className="btn btn-danger pl-touch-target">
Endgültig löschen
</button>
</form>
</Card>
</div>
</div>
</div>
</div>
</>
);
}