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.
323 lines
10 KiB
SQL
323 lines
10 KiB
SQL
-- CreateEnum
|
|
CREATE TYPE "OrderStatus" AS ENUM ('NEU', 'BEZAHLT', 'IN_VORBEREITUNG', 'VERSANDBEREIT', 'VERSENDET', 'ABHOLBEREIT', 'ABGEHOLT', 'STORNIERT');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "FulfillmentMethod" AS ENUM ('VERSAND', 'ABHOLUNG');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "PaymentStatus" AS ENUM ('PENDING', 'SUCCEEDED', 'FAILED', 'REFUNDED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "BusinessPackage" AS ENUM ('KLASSIK', 'GESCHENK', 'INDIVIDUELL');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "InquiryStatus" AS ENUM ('NEU', 'IN_BEARBEITUNG', 'ABGESCHLOSSEN');
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "customers" (
|
|
"id" TEXT NOT NULL,
|
|
"email" TEXT NOT NULL,
|
|
"passwordHash" TEXT NOT NULL,
|
|
"firstName" TEXT NOT NULL,
|
|
"lastName" TEXT NOT NULL,
|
|
"phone" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "customers_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "addresses" (
|
|
"id" TEXT NOT NULL,
|
|
"customerId" TEXT NOT NULL,
|
|
"label" TEXT NOT NULL DEFAULT 'Zuhause',
|
|
"firstName" TEXT NOT NULL,
|
|
"lastName" TEXT NOT NULL,
|
|
"street" TEXT NOT NULL,
|
|
"zip" TEXT NOT NULL,
|
|
"city" TEXT NOT NULL,
|
|
"country" TEXT NOT NULL DEFAULT 'DE',
|
|
"isDefault" BOOLEAN NOT NULL DEFAULT false,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "addresses_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "harvests" (
|
|
"id" TEXT NOT NULL,
|
|
"year" INTEGER NOT NULL,
|
|
"type" TEXT NOT NULL,
|
|
"slug" TEXT NOT NULL,
|
|
"harvestDate" TIMESTAMP(3) NOT NULL,
|
|
"location" TEXT NOT NULL DEFAULT 'Altenmuenster',
|
|
"description" TEXT NOT NULL,
|
|
"images" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "harvests_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "batches" (
|
|
"id" TEXT NOT NULL,
|
|
"code" TEXT NOT NULL,
|
|
"harvestId" TEXT NOT NULL,
|
|
"fillDate" TIMESTAMP(3) NOT NULL,
|
|
"bestBeforeDate" TIMESTAMP(3) NOT NULL,
|
|
"glassCount" INTEGER NOT NULL,
|
|
"remainingGlasses" INTEGER NOT NULL,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "batches_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "products" (
|
|
"id" TEXT NOT NULL,
|
|
"slug" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"harvestId" TEXT NOT NULL,
|
|
"batchId" TEXT NOT NULL,
|
|
"description" TEXT NOT NULL,
|
|
"tasteTags" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
|
"intensityMild" INTEGER NOT NULL DEFAULT 3,
|
|
"intensityFloral" INTEGER NOT NULL DEFAULT 3,
|
|
"intensityKraeftig" INTEGER NOT NULL DEFAULT 3,
|
|
"consistency" TEXT NOT NULL DEFAULT 'feincremig',
|
|
"weightGrams" INTEGER NOT NULL,
|
|
"priceCents" INTEGER NOT NULL,
|
|
"pricePerKgCents" INTEGER NOT NULL,
|
|
"currency" TEXT NOT NULL DEFAULT 'EUR',
|
|
"images" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "products_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "inventory" (
|
|
"id" TEXT NOT NULL,
|
|
"productId" TEXT NOT NULL,
|
|
"quantity" INTEGER NOT NULL DEFAULT 0,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "inventory_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "orders" (
|
|
"id" TEXT NOT NULL,
|
|
"orderNumber" TEXT NOT NULL,
|
|
"customerId" TEXT,
|
|
"status" "OrderStatus" NOT NULL DEFAULT 'NEU',
|
|
"fulfillmentMethod" "FulfillmentMethod" NOT NULL DEFAULT 'VERSAND',
|
|
"email" TEXT NOT NULL,
|
|
"firstName" TEXT NOT NULL,
|
|
"lastName" TEXT NOT NULL,
|
|
"phone" TEXT,
|
|
"street" TEXT NOT NULL,
|
|
"zip" TEXT NOT NULL,
|
|
"city" TEXT NOT NULL,
|
|
"country" TEXT NOT NULL DEFAULT 'DE',
|
|
"subtotalCents" INTEGER NOT NULL,
|
|
"shippingCents" INTEGER NOT NULL DEFAULT 0,
|
|
"totalCents" INTEGER NOT NULL,
|
|
"currency" TEXT NOT NULL DEFAULT 'EUR',
|
|
"stripeCheckoutSessionId" TEXT,
|
|
"notes" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "orders_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "order_items" (
|
|
"id" TEXT NOT NULL,
|
|
"orderId" TEXT NOT NULL,
|
|
"productId" TEXT NOT NULL,
|
|
"batchId" TEXT NOT NULL,
|
|
"productName" TEXT NOT NULL,
|
|
"unitPriceCents" INTEGER NOT NULL,
|
|
"quantity" INTEGER NOT NULL,
|
|
"weightGrams" INTEGER NOT NULL,
|
|
"totalCents" INTEGER NOT NULL,
|
|
|
|
CONSTRAINT "order_items_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "payments" (
|
|
"id" TEXT NOT NULL,
|
|
"orderId" TEXT NOT NULL,
|
|
"provider" TEXT NOT NULL DEFAULT 'stripe',
|
|
"stripePaymentIntentId" TEXT,
|
|
"status" "PaymentStatus" NOT NULL DEFAULT 'PENDING',
|
|
"amountCents" INTEGER NOT NULL,
|
|
"currency" TEXT NOT NULL DEFAULT 'EUR',
|
|
"paidAt" TIMESTAMP(3),
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "payments_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "shipments" (
|
|
"id" TEXT NOT NULL,
|
|
"orderId" TEXT NOT NULL,
|
|
"carrier" TEXT,
|
|
"trackingNumber" TEXT,
|
|
"shippedAt" TIMESTAMP(3),
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "shipments_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "pickups" (
|
|
"id" TEXT NOT NULL,
|
|
"orderId" TEXT NOT NULL,
|
|
"location" TEXT NOT NULL DEFAULT 'Altenmuenster',
|
|
"readyAt" TIMESTAMP(3),
|
|
"pickedUpAt" TIMESTAMP(3),
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "pickups_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "invoices" (
|
|
"id" TEXT NOT NULL,
|
|
"orderId" TEXT NOT NULL,
|
|
"invoiceNumber" TEXT NOT NULL,
|
|
"issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"totalCents" INTEGER NOT NULL,
|
|
"pdfUrl" TEXT,
|
|
|
|
CONSTRAINT "invoices_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "newsletter_subscribers" (
|
|
"id" TEXT NOT NULL,
|
|
"email" TEXT NOT NULL,
|
|
"customerId" TEXT,
|
|
"confirmed" BOOLEAN NOT NULL DEFAULT false,
|
|
"subscribedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"unsubscribedAt" TIMESTAMP(3),
|
|
|
|
CONSTRAINT "newsletter_subscribers_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "business_inquiries" (
|
|
"id" TEXT NOT NULL,
|
|
"companyName" TEXT NOT NULL,
|
|
"contactPerson" TEXT NOT NULL,
|
|
"email" TEXT NOT NULL,
|
|
"phone" TEXT,
|
|
"desiredQuantity" INTEGER NOT NULL,
|
|
"desiredDeliveryDate" TIMESTAMP(3),
|
|
"package" "BusinessPackage" NOT NULL DEFAULT 'KLASSIK',
|
|
"message" TEXT,
|
|
"status" "InquiryStatus" NOT NULL DEFAULT 'NEU',
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "business_inquiries_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "customers_email_key" ON "customers"("email");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "harvests_slug_key" ON "harvests"("slug");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "harvests_year_type_key" ON "harvests"("year", "type");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "batches_code_key" ON "batches"("code");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "products_slug_key" ON "products"("slug");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "inventory_productId_key" ON "inventory"("productId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "orders_orderNumber_key" ON "orders"("orderNumber");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "payments_orderId_key" ON "payments"("orderId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "shipments_orderId_key" ON "shipments"("orderId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "pickups_orderId_key" ON "pickups"("orderId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "invoices_orderId_key" ON "invoices"("orderId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "invoices_invoiceNumber_key" ON "invoices"("invoiceNumber");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "newsletter_subscribers_email_key" ON "newsletter_subscribers"("email");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "newsletter_subscribers_customerId_key" ON "newsletter_subscribers"("customerId");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "addresses" ADD CONSTRAINT "addresses_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "customers"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "batches" ADD CONSTRAINT "batches_harvestId_fkey" FOREIGN KEY ("harvestId") REFERENCES "harvests"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "products" ADD CONSTRAINT "products_harvestId_fkey" FOREIGN KEY ("harvestId") REFERENCES "harvests"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "products" ADD CONSTRAINT "products_batchId_fkey" FOREIGN KEY ("batchId") REFERENCES "batches"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "inventory" ADD CONSTRAINT "inventory_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "orders" ADD CONSTRAINT "orders_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "customers"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "order_items" ADD CONSTRAINT "order_items_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "order_items" ADD CONSTRAINT "order_items_productId_fkey" FOREIGN KEY ("productId") REFERENCES "products"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "order_items" ADD CONSTRAINT "order_items_batchId_fkey" FOREIGN KEY ("batchId") REFERENCES "batches"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "payments" ADD CONSTRAINT "payments_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "shipments" ADD CONSTRAINT "shipments_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "pickups" ADD CONSTRAINT "pickups_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "invoices" ADD CONSTRAINT "invoices_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "newsletter_subscribers" ADD CONSTRAINT "newsletter_subscribers_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "customers"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|