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:
1 parent
5c76fcc266
commit
c7927f2883
240 files changed
+26096
-137
No files matched your search
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user