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
2026-08-17 14:30:28 +02:00
parent 5c76fcc266
commit c7927f2883
240 changed files with 26096 additions and 137 deletions
+47
View File
@@ -0,0 +1,47 @@
// Generiert BEIDE Prisma-Client-Varianten (Postgres + MySQL) aus derselben
// prisma/schema.prisma, damit ein einzelnes Docker-Image zur Laufzeit per
// DATABASE_PROVIDER zwischen beiden waehlen kann (lib/prisma.ts,
// prisma/seed.ts) — ein einzelner generierter Client ist fest an EINEN
// Provider gebunden (Prisma unterstuetzt keinen Laufzeit-Wechsel desselben
// generierten Clients zwischen Providern). Anders als
// scripts/prisma-provider.mjs (schreibt genau EINEN Provider fuer
// db push/migrate/studio, die gegen eine konkrete Ziel-DB laufen) ist dieses
// Skript fuer dev/build/start/postinstall gedacht.
import { readFileSync, writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { execSync } from "node:child_process";
import path from "node:path";
const projectRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
const schemaPath = path.join(projectRoot, "prisma", "schema.prisma");
const VARIANTS = [
{ provider: "postgresql", output: "../src/generated/prisma" },
{ provider: "mysql", output: "../src/generated/prisma-mysql" },
];
const originalSchema = readFileSync(schemaPath, "utf8");
try {
for (const { provider, output } of VARIANTS) {
let schema = originalSchema.replace(
/(datasource db \{[^}]*provider\s*=\s*")[a-z]+(")/,
`$1${provider}$2`
);
schema = schema.replace(
/(generator client \{[^}]*output\s*=\s*")[^"]*(")/,
`$1${output}$2`
);
writeFileSync(schemaPath, schema);
console.log(`Generiere Prisma Client (${provider}) -> ${output} ...`);
// execSync (statt execFileSync) laeuft ueber die Shell — auf Windows ist
// "npx" ein .cmd-Batch-Skript, das execFileSync ohne shell:true nicht
// aufloest.
execSync("npx prisma generate", { stdio: "inherit", cwd: projectRoot });
}
} finally {
// schema.prisma unveraendert lassen: der eigentliche Provider fuer
// db push/migrate/studio wird separat von scripts/prisma-provider.mjs
// gesetzt, nicht von diesem Skript.
writeFileSync(schemaPath, originalSchema);
}
+40
View File
@@ -0,0 +1,40 @@
// Prisma erlaubt kein env() fuer datasource.provider (nur fuer url) — dieses
// Skript schreibt die provider-Zeile in prisma/schema.prisma daher vor jedem
// generate/db push/migrate anhand von DATABASE_PROVIDER neu. Wird von den
// package.json-Skripten aufgerufen, nicht direkt.
import { readFileSync, writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import path from "node:path";
const SUPPORTED_PROVIDERS = ["postgresql", "mysql"];
const DEFAULT_PROVIDER = "postgresql";
const schemaPath = path.join(
path.dirname(fileURLToPath(import.meta.url)),
"..",
"prisma",
"schema.prisma"
);
const provider = (process.env.DATABASE_PROVIDER ?? DEFAULT_PROVIDER).trim();
if (!SUPPORTED_PROVIDERS.includes(provider)) {
console.error(
`DATABASE_PROVIDER="${provider}" wird nicht unterstuetzt. Erlaubt: ${SUPPORTED_PROVIDERS.join(", ")}.`
);
process.exit(1);
}
const schema = readFileSync(schemaPath, "utf8");
const updated = schema.replace(
/(datasource db \{[^}]*provider\s*=\s*")([a-z]+)(")/,
`$1${provider}$3`
);
if (updated === schema && !schema.includes(`provider = "${provider}"`)) {
console.error("datasource-Block in prisma/schema.prisma nicht gefunden — provider konnte nicht gesetzt werden.");
process.exit(1);
}
writeFileSync(schemaPath, updated);
console.log(`prisma/schema.prisma: datasource provider = "${provider}"`);