v2.1: Gutschein-/Rabatt-Engine + editierbare gebrandete 404

Feature 1 — Rabatt-Engine (store-sqlite.js):
- Tabellen discounts + discount_redemptions; orders um discount_code/discount_cents erweitert.
- Helper: getDiscountByCode, listDiscounts, create/update/deleteDiscount,
  validateDiscount (Zeitplan/Mindestwert/Limits/pro-Kunde), bestAutoDiscount, redeemDiscount.
- Seed: WILLKOMMEN10, NAEHEN5, GRATISVERSAND (geplant), AUTO15AB75 (auto).
- Checkout: /api/discount (serverseitige Subtotal-Berechnung) + /api/checkout re-validiert,
  wendet Rabatt/Gratisversand an, speichert + redeemt, auto-Discount-Fallback, Stripe-Coupon.
- Cart/Checkout-UI mit Code-Feld + Einlösen; Rabattzeile in Order-Detail + Erfolgsseite.
- Admin "Rabatte" (owner+redaktion) mit Status-Badges + Editor (Zufallscode, Typ-abh. Wertfeld).
- Popups: Typ discount zeigt Code + Kopieren-Button; Stile modal/slidein/bar (CSS ergaenzt).

Feature 2 — 404:
- src/pages/404.astro nutzt Base + BlockRenderer, laedt System-Seite slug 404.
- ensureSystemPages() legt 404 idempotent bei jedem Boot an (INSERT OR IGNORE, flache Bloecke).
- 404/system erscheint in Admin "Inhalte" und oeffnet im Block-Editor.

API/MCP: discounts in /api/admin/* (CRUD), Manifest + ai-admin.txt ergaenzt
(inkl. Hinweis: Block-Objekte sind flach); MCP list/upsert/delete_discount.
README + Versionen (2.1.0) aktualisiert.
This commit is contained in:
2026-06-17 15:12:07 +00:00
parent aec179db36
commit 430fa718fa
21 changed files with 572 additions and 52 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ function sectionOf(adminInner) {
const seg = adminInner.replace(/^\//, '').split('/')[0] || 'dashboard';
const map = {
'': 'dashboard', 'bestellungen': 'bestellungen', 'produkte': 'produkte', 'kunden': 'kunden',
'analytics': 'analytics', 'marketing': 'marketing', 'inhalte': 'inhalte', 'einstellungen': 'einstellungen',
'analytics': 'analytics', 'marketing': 'marketing', 'rabatte': 'rabatte', 'inhalte': 'inhalte', 'einstellungen': 'einstellungen',
'nutzer': 'nutzer', 'audit': 'audit', 'konto': 'dashboard', 'login': 'login', 'logout': 'logout',
};
return map[seg] || 'dashboard';