feat: Wabenhain Honig-Shop Anwendung

Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei:
Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich
(Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare
Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung,
PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma-
Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
This commit is contained in:
Nick Szaunig committed 2026-08-17 14:30:28 +02:00
1 parent 5c76fcc266
commit c7927f2883
240 files changed
+26096 -137

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
import type { Metadata } from "next";
import { redirect } from "next/navigation";
import { getCurrentAdmin } from "@/lib/auth";
import { logoutAction } from "@/app/konto/actions";
import { AdminShell } from "@/components/admin-shell";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
// Admin-Daten (Bestellungen, Bestand) muessen immer aktuell sein; zudem
// entkoppelt das den Docker-Build-Schritt von einer DB-Verbindung.
export const dynamic = "force-dynamic";
// Einzelne Admin-Unterseiten (bestellungen, produkte, ...) haben bewusst
// keine eigene Metadata — der Bereich ist ueber robots.ts von der Indexierung
// ausgeschlossen. Dieses Template sorgt trotzdem fuer einen sinnvollen
// Browser-Tab-Titel statt des generischen Startseiten-Titels ueberall im
// Admin-Bereich, ohne jede Unterseite einzeln pflegen zu muessen.
export async function generateMetadata(): Promise<Metadata> {
const t = getDictionary(await getLocale());
return {
title: { default: t.account.navAdmin.title, template: `%s | ${t.account.navAdmin.title}` },
robots: { index: false, follow: false },
};
}
export default async function AdminLayout({ children }: LayoutProps<"/admin">) {
// Der Proxy (src/proxy.ts) blockt fremde Requests bereits vor dem Rendern;
// diese zweite, gegen die Datenbank autoritative Pruefung faengt u.a. den
// Fall ab, dass die ADMIN-Rolle eines eingeloggten Kontos nach dem Login
// entzogen wurde (das JWT traegt die Rolle nur als Snapshot vom Login-Zeitpunkt).
const admin = await getCurrentAdmin();
if (!admin) {
redirect("/konto?error=" + encodeURIComponent("Bitte melde dich mit einem Admin-Konto an."));
}
// Erzwungen statt nur empfohlen: Admin-Konten haben Zugriff auf
// Bestellungen, Rueckerstattungen und Kundendaten — ohne 2FA waere ein
// gestohlenes Passwort allein genug fuer vollen Zugriff. Weiterleitung
// statt Blockade, damit das Konto die Einrichtung direkt nachholen kann.
if (!admin.twoFactorEnabled) {
redirect(
"/konto/zwei-faktor?error=" +
encodeURIComponent("Für Admin-Konten ist Zwei-Faktor-Authentifizierung erforderlich. Bitte richte sie jetzt ein.")
);
}
return (
<AdminShell
adminName={`${admin.firstName} ${admin.lastName}`}
logoutAction={logoutAction}
>
{children}
</AdminShell>
);
}