Echtes Bestellsystem: Cloudflare D1 statt Beispieldaten in der Verwaltung

Ersetzt die Phase-1-Beispieldaten in /verwaltung/ durch ein echtes, funktionierendes
Bestellsystem:

- Neue D1-Datenbank (vans-diy-bastelbedarf-db) mit orders/order_items-Tabellen,
  an das Pages-Projekt gebunden (wrangler.toml).
- Neue API-Routen (Pages Functions): POST /api/orders legt beim Checkout eine echte
  Bestellung an (mit Validierung); GET/PATCH /api/verwaltung/orders(/:id) listen bzw.
  ändern Bestellungen — beide zusätzlich zur Middleware nochmal eigenständig gegen die
  Zugangscode-Sitzung geprüft (Verteidigung in der Tiefe). Gemeinsame Auth-Logik aus
  _middleware.js nach functions/_shared/auth.js ausgelagert.
- Checkout (4 Sprachen) sendet beim Absenden die echte Bestellung an die API, zeigt bei
  einem Fehler eine klare Meldung statt einfach auf die Danke-Seite weiterzuleiten.
- /verwaltung/ lädt Bestellungen jetzt live per fetch(), mit Lade-/Fehlerzustand, und
  erlaubt direktes Ändern des Bestellstatus per Dropdown (sofort in der Datenbank
  gespeichert). Neuer Status "storniert" (zählt nicht in Umsatz/Auswertung mit).

Vollständig lokal end-to-end getestet (wrangler pages dev + lokale D1): echter
Browser-Checkout -> Bestellung landet in der Datenbank -> erscheint sofort in der
Verwaltung -> Status ändern bleibt nach Neuladen bestehen.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-03 20:32:46 +02:00
co-authored by Claude Sonnet 5
parent 9170b9bb22
commit fb7a7b76c2
14 changed files with 1030 additions and 333 deletions
+17
View File
@@ -1704,6 +1704,7 @@ a:focus-visible, button:focus-visible {
.order-card-versandVorbereitet { --status-color: #e3b23c; }
.order-card-versendet { --status-color: var(--c-accent); }
.order-card-abgeschlossen { --status-color: #7ec8a0; }
.order-card-storniert { --status-color: var(--c-sale); }
.order-status { display: inline-flex; align-items: center; gap: 0.4em; }
.order-status::before { font-size: 0.95em; }
@@ -1712,12 +1713,28 @@ a:focus-visible, button:focus-visible {
.order-status-versandVorbereitet::before { content: "📦"; }
.order-status-versendet::before { content: "🚚"; }
.order-status-abgeschlossen::before { content: "✅"; }
.order-status-storniert::before { content: "❌"; }
.order-status-bezahlt { background: color-mix(in srgb, #9b7fd6 32%, transparent); border-color: color-mix(in srgb, #9b7fd6 55%, transparent); color: #d9cdf5; }
.order-status-bearbeitung { background: color-mix(in srgb, #e3b23c 30%, transparent); border-color: color-mix(in srgb, #e3b23c 55%, transparent); color: #f6dda0; }
.order-status-versandVorbereitet { background: color-mix(in srgb, #e3b23c 30%, transparent); border-color: color-mix(in srgb, #e3b23c 55%, transparent); color: #f6dda0; }
.order-status-versendet { background: color-mix(in srgb, var(--c-accent) 34%, transparent); border-color: color-mix(in srgb, var(--c-accent) 55%, transparent); }
.order-status-abgeschlossen { background: rgba(126, 200, 160, 0.28); border-color: rgba(126, 200, 160, 0.5); color: #cfeee0; }
.order-status-storniert { background: color-mix(in srgb, var(--c-sale) 30%, transparent); border-color: color-mix(in srgb, var(--c-sale) 55%, transparent); color: #ffd7de; }
/* Status-Dropdown direkt in der Bestellkarte (Verwaltungsseite) — sofortiges Ändern ohne
separate Bearbeiten-Seite, mit kurzer "gespeichert"-Bestätigung statt stillem Erfolg. */
.verwaltung-status-edit { display: flex; align-items: center; gap: 0.6rem; }
.verwaltung-status-select {
padding: 0.4rem 0.7rem;
border-radius: var(--radius-s);
border: 1.5px solid rgba(244, 241, 247, 0.18);
background: var(--c-anthracite);
color: var(--c-text);
font-size: 0.85rem;
font-family: inherit;
}
.verwaltung-status-saved { color: #7ec8a0; font-weight: 600; white-space: nowrap; }
.order-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.order-items li { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.95rem; color: var(--c-text-muted); }
.order-item-price { color: var(--c-text); white-space: nowrap; }