Sitzungs-Cookie ohne maxAge/expires statt 90-Tage-Cookie (auch fuer die
zweite Verwaltungs-Schranke); zusaetzlich Notbremse von 12 Stunden im
signierten Token, falls ein Browser sehr lange offen bleibt.
Kundenkonten (customer-auth.js, 30 Tage) bleiben bewusst unveraendert.
Produktkarte statt direkt unter dem Banner
Auf den anderen Seitentypen (Kategorie, Sale) stand die Zahl schon immer direkt
über dem Produkt-Grid. Auf den Unterkategorie-Seiten (Charakter-Familien wie
Glasperlenarmbänder, Kuh, Wal, ...) saß sie dagegen in einem eigenen Container
direkt unter dem Banner-Bild, mit teils viel Abstand zur ersten echten Karte
(z.B. wenn vorher noch eine Charakter-Story-Box kommt). Jetzt wird sie direkt
in der Sektion angezeigt, die auch wirklich die erste Produktkarte enthält —
in allen 4 Sprachen (de/en/fr/ch).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf den drei anderen Seitentypen (Kategorie, Sale) stand die Anzahl bereits korrekt unter dem
Banner — nur auf den Unterkategorie-Seiten (z.B. /shop/modeschmuck-accessoires/
glasperlenarmbaender/) landete sie versehentlich VOR dem Bannerbild, direkt nach der Breadcrumb.
Jetzt hinter das Banner verschoben, in allen 4 Sprachen.
Bisher zeigte nur /shop/ (die Hauptübersicht) an, wie viele Produkte gerade zu sehen sind. Auf
ausdrücklichen Wunsch jetzt auch auf: Kategorie-Seiten, Unterkategorie-Seiten (Gesamtzahl aus
Charakter-Karten + "weitere Modelle", ohne reine Platzhalterkarten) und der Sale-Seite — jeweils
in allen 4 Sprachen. Server-seitig fest berechnet (kein Filter-JS wie im Haupt-Shop nötig, da
diese Seiten keine Live-Filterung haben), gleiche Optik/Wortlaut wie im Shop-Filter
(t.shop.resultCount), neue gemeinsame CSS-Klasse .result-count-static für den Abstand vor dem
Grid. Nur sichtbar, wenn tatsächlich Produkte da sind (bei leeren Kategorien bleibt der bisherige
Hinweistext ohne zusätzliche "0 Produkte"-Zeile).
Per Build + Browsertest über alle drei Seitentypen verifiziert.
Neue Farbvariablen --c-lila/--c-lila-hover (sattes, kräftiges Violett) ersetzen das bisherige
Gold/Gelb überall dort, wo es verwendet wurde: "Noch nicht öffentlich"-Badge, Verlaufsrand der
Kopf-Kiste, sowie komplett das VanVan-Fenster (Rand, Avatar-Glow, Name, Eingabefeld-Fokus,
Button). Gelbes Herz-Emoji im VanVan-Button ebenfalls zu einem violetten Herz gewechselt, damit
nichts mehr gold/gelb übrig bleibt. Dogis Cyan-Fenster bleibt unverändert.
Per Build + Browsertest verifiziert: neue Farbe korrekt angezeigt, Login-Funktion unverändert.
Gemeldeter Bug: Bei kleineren Fensterhöhen (z.B. Laptop mit wenig Höhe, manche Handy-Größen) hat
"overflow: hidden" auf <body> zusammen mit der vertikal zentrierten Flexbox den oberen Teil des
Inhalts (Badge/Überschrift) und/oder die unteren Fenster einfach abgeschnitten, OHNE dass man
dorthin scrollen konnte — der Inhalt war schlicht nicht mehr erreichbar. Behoben:
- "align-items: safe center" statt nur "center" — zentriert normal, springt aber auf
Start-Ausrichtung um, sobald der Inhalt höher als der sichtbare Bereich ist.
- overflow-y: auto statt hidden — falls "safe center" von einem Browser nicht unterstützt wird,
kann trotzdem ganz normal zu den restlichen Fenstern heruntergescrollt werden.
- Logo-Wasserzeichen von position:absolute auf position:fixed umgestellt, damit es IMMER exakt in
der Mitte des sichtbaren Fensters bleibt, unabhängig von der tatsächlichen Seitenhöhe.
Zusätzlich auf ausdrücklichen Wunsch: der Kopfbereich (Badge + Überschrift + Text) sitzt jetzt in
einer eigenen "speziellen" Kiste im selben Stil wie die beiden Personen-Fenster darunter
(wandernder Verlaufsrand aus allen drei Markenfarben + Glanz-Sweep) statt als loser Text über den
Kisten zu schweben — liest sich jetzt sichtbar als gemeinsames "Dach" über beiden Fenstern.
Per Browsertest über mehrere Fenstergrößen (inkl. absichtlich sehr niedriger Höhe) verifiziert:
Inhalt vollständig erreichbar/scrollbar, Login-Funktion beider Fenster weiterhin unverändert.
- qciga-Fenster zeigt jetzt Dogi (Name + echtes Foto) statt Icon-Platzhalter — Rolle/Code-Prüfung
im Hintergrund bleibt unverändert "qciga" (nur die Anzeige wurde umbenannt).
- VanVan-Fenster bekommt ein neues, eigenes Foto für die Zugangsseite.
- Beide Quellfotos (~1,8 MB PNG) auf 400×400 zugeschnitten (gesichtsfokussiert) und als WebP
komprimiert (7–14 KB) — eigene Dateien nur für diese Seite, NICHT die sitehweit verwendete
öffentliche vanvan-portrait.png ersetzt oder angetastet.
- Schlüssel-Emoji im Dogi-Button durch 🩵 (Baby-Blau-Herz) ersetzt, passend zur Cyan-Akzentfarbe
seines Fensters.
- functions/_middleware.js: alte Freigabe von /img/vanvan-portrait.png entfernt, stattdessen
gezielt nur die zwei neuen Avatar-Dateien freigegeben (kein Shop-/Kundendatum).
Per Build + wrangler pages dev + Browsertest verifiziert: beide Avatare laden korrekt (200),
alte Foto-Freigabe korrekt entfernt (wieder 302), Layout/Funktion unverändert intakt.
Auf ausdrücklichen Wunsch im Stil einer bereits bestehenden Zwei-Personen-Zugangsseite umgebaut,
aber komplett an Van's eigene Marke angepasst (Farben/Schrift/Wasserzeichen unverändert: Lila/
Anthrazit/Hellblau/Gold statt fremder Projektfarben). Jede Person bekommt ihr eigenes Fenster mit
Avatar (VanVan: ihr echtes Porträtfoto; qciga: passendes Icon, da noch kein Foto in diesem Projekt
hinterlegt ist), eigenem Codefeld und eigenem "Öffnen"-Button in unterschiedlicher Akzentfarbe
(Cyan/Violett für qciga, Gold/Violett für VanVan). Technisch unverändert: /gate-auth erkennt die
Rolle weiterhin selbst anhand des eingegebenen Codes, unabhängig vom benutzten Fenster.
Dabei gefundener und behobener Bug: /img/vanvan-portrait.png wurde von der Zugangs-Schranke selbst
blockiert (302) — das für den Avatar gebrauchte Foto zeigte deshalb nur einen leeren Kreis. Gezielt
nur diese eine Datei freigegeben (kein Shop-/Kundendatum, ohnehin VanVans öffentliches Porträtfoto).
Per echtem Browsertest verifiziert: beide Fenster funktional getrennt (falscher Code im einen
Fenster zeigt den Fehler nur dort, richtiger Code im anderen Fenster loggt korrekt ein), Layout auf
Desktop nebeneinander und auf schmalen Bildschirmen sauber gestapelt.
Neues Kästchen "🔥 Nur Bestseller (Top 6)" im Shop-Filter (alle 4 Sprachen) — zeigt beim Anhaken
genau die 6 Produkte mit den meisten echten Verkäufen. Keine manuelle Pflege nötig: neuer
öffentlicher Endpunkt GET /api/bestseller berechnet die Rangliste live per SQL-Aggregation aus
den echten Bestelldaten (order_items JOIN orders, GROUP BY Produkt-Slug, SUM der Menge), NICHT
die manuell im Admin-Bereich setzbare "Bestseller"-Auszeichnung.
Zählweise: stornierte und noch nicht bezahlte (zahlungOffen) Bestellungen zählen nicht mit (sonst
würden Fehlbestellungen/nie eingegangene Zahlungen die Rangliste verfälschen), ebenso wenig
kostenlose Positionen wie der Abo-Teddy (kein echtes Kaufinteresse). Liefert ausschließlich
Produkt-Slugs zurück, keinerlei Bestell-/Kundendaten — bleiben weiterhin nur in /api/verwaltung/*.
Verifiziert: SQL-Aggregation mit Testdaten geprüft (korrekte Rangfolge, korrekter Ausschluss von
storniert/zahlungOffen/gratis, LIMIT 6 exakt). Frontend-Verdrahtung (Checkbox -> fetch -> Filter)
per echtem Browsertest mit vorgetäuschter API-Antwort bestätigt (checken zeigt genau die
vorgegebenen Produkte, abwählen zeigt wieder alle).
Neuer Endpunkt POST /gate-logout (functions/_middleware.js) löscht alle drei Zugangs-Cookies auf
einmal (normale 90-Tage-Sitzung, Rollen-Anzeige, tägliche Verwaltungs-Sitzung) — "abmelden"
bedeutet also wirklich abmelden von allem, nicht nur einen Teil der Schranke offen lassen. Button
im selben "besonderen" Look wie die Hero-Kiste darunter (wandernder Verlaufsrand in den drei
Markenfarben + Funkeln) statt eines schlichten Standard-Buttons.
Per curl (Cookie-Löschung + anschließende 302-Sperre auf /verwaltung/ und /) und per echtem
Browser-Klicktest (Playwright) end-to-end verifiziert.
Live per Browsertest gefunden: Auf /admin/ (das die Haupt-Schranke bewusst umgeht) versucht ein
eigenes Skript, den Service Worker unter /sw.js zu registrieren (für die "Installieren"-Funktion) —
das schlug mit einem echten Browserfehler fehl ("script resource is behind a redirect"), weil
/sw.js und /manifest.webmanifest bisher nicht auf der Liste öffentlich erreichbarer Dateien standen
und deshalb selbst einen 302 auf die Zugangscode-Seite bekamen. Betrifft jeden Aufruf von /admin/
ohne aktive Haupt-Gate-Sitzung (z.B. direkt per Lesezeichen). Beide Dateien enthalten keinerlei
Shop-/Kundendaten (reines Caching-Skript bzw. App-Metadaten), Freigabe also unbedenklich — vor der
Änderung geprüft, dass wirklich nichts Sensibles drin steht.
Bisher hätte SITE_PUBLIC=true (gedacht für den Go-Live der eigenen Domain) versehentlich auch die
interne *.pages.dev-Werkstatt-Adresse für jede/n im Internet geöffnet, weil die Middleware nur den
Pfad, nie den aufgerufenen Hostnamen geprüft hat. Jetzt hart anhand des Hostnamens geprüft: nur ein
Hostname außerhalb von *.pages.dev darf durch SITE_PUBLIC öffentlich werden. Per wrangler pages dev
mit Host-Header-Overrides verifiziert (pages.dev -> weiterhin 302 Gate-Redirect, andere Domain -> 200).
Nebenbei: totes, seit 04.08.2026 ungenutztes Secret VERWALTUNG_ACCESS_CODE live + lokal entfernt
(Code prüft seitdem denselben Zugangscode wie der normale Seitenzugang), sowie zwei veraltete
Kommentare bereinigt, die noch auf die längst entfernte Seite /demo-abo/ verwiesen.
Beide <script>-Blöcke am Ende von shop/index.astro (+en/ch/fr) liefen bisher direkt beim Parsen,
statt wie in Layout.astro etabliert in "astro:page-load" gekapselt zu sein. Da <ClientRouter
fallback="swap" /> Inline-Skripte bei einem clientseitigen Seitenwechsel nicht erneut ausführt,
wurden die Klick-Listener der beiden eigenen Dropdowns nie angehängt, wenn man per Link (statt
Direktaufruf) auf /shop/ navigiert ist — Preis-Regler/Checkbox blieben unbemerkt funktionsfähig,
weil das natives Browser-Verhalten ohne JS ist.
Auf ausdrücklichen Wunsch: das rotierende Logo-Wasserzeichen im Hintergrund der Verwaltungs-
Hauptseite wirkte als EIN großer zentraler Fleck (zwei große, zentrierte Ebenen). Jetzt sechs
kleinere Logos (150-260px statt 950-1500px), über den ganzen Viewport verteilt (obere/mittlere/
untere Zeile, je links und rechts), weiterhin gegenläufig rotierend, jetzt zusätzlich mit einer
dritten Markenfarbe (Cyan) neben Gold/Violett für mehr Abwechslung. Reine Markup-/CSS-Änderung.
Zusätzlich: die Standard-Browser-Scrollbar im Kategorie-Dropdown des Shop-Filters (schwarz-weiß,
wirkte fremd im dunklen Design) durch eine gestylte, schlanke, markenfarbene Verlaufs-Scrollbar
ersetzt (Firefox über scrollbar-color/-width, Chrome/Edge/Safari über ::-webkit-scrollbar).
Lokal mit wrangler pages dev getestet (beide Änderungen im ausgelieferten CSS bestätigt).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: oben auf jeder Produktseite jetzt ein "← Zurück"-Button vor dem
Breadcrumb. Nutzt den Browser-Verlauf (history.back()) statt fest zur Kategorieseite zu
springen — landet man z.B. von der Startseite, einer Suche oder "Das könnte dir gefallen" auf
einer Produktseite, kommt man genau dahin zurück. Fällt sauber auf einen normalen Link zur
Kategorieseite zurück, wenn kein echter vorheriger Seitenaufruf im Verlauf existiert (Direkt-
aufruf, neuer Tab, Suchmaschine). In allen 4 Sprachversionen (de/en/ch/fr) umgesetzt.
Nebenbei behoben: t.common.skipToContent (Skip-Link aus der BFSG-Barrierefreiheits-Arbeit vom
04.08.) war nur für "de" gepflegt und dadurch auf den en/ch/fr-Seiten leer — jetzt für alle
4 Sprachen ergänzt (gleicher Commit, da hier ohnehin dieselbe common-Sektion bearbeitet wurde).
Lokal mit wrangler pages dev end-to-end getestet (Login, echtes Produkt, Button + Skript im
gerenderten HTML bestätigt).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch NUR die Haupt-Bestellverwaltungsseite (nicht die Zugangscode-Seite,
nicht deren Formular-Logik) grundlegend aufgewertet:
- Rollenbasierte, tageszeitabhängige Begrüßung ("Guten Morgen, VanVan!") aus dem vorhandenen
Vorschau-Rollen-Cookie
- Van's-Logo als großes, fix positioniertes, warm eingefärbtes Wasserzeichen im gesamten
Seitenhintergrund (zwei gegenläufig rotierende Ebenen, derselbe CSS-Trick wie auf der
Zugangscode-Seite, aber eigenständig für diese scrollbare Seite nachgebaut)
- Handgebaute SVG-Sparkline (Umsatztrend der letzten 14 Tage) + Wochenvergleich-Badge
- Sanft hochzählende Kennzahlen-Kacheln statt abruptem Zahlensprung
- Sichtbarer Status-Fortschrittsbalken pro Bestellkarte + Ein-Klick-"nächster Schritt"-Knopf
neben dem bisherigen Dropdown
- Konfetti + Erfolgs-Banner bei runden Bestell-Meilensteinen (10er/25er/50er-Schritte)
- Tab-Titel zeigt die Anzahl offener Bestellungen, auch wenn der Tab im Hintergrund ist
- Optionaler Ton (Web-Audio-Glöckchen, keine Audio-Datei) und Desktop-Benachrichtigungen bei
neuen Bestellungen, beides einzeln togglebar und in localStorage gemerkt
Alles handgebaut ohne externe Bibliotheken/Kosten, respektiert prefers-reduced-motion. Lokal mit
wrangler pages dev + echter D1-Bindung end-to-end getestet (Login, Bestell-API, Status-PATCH,
alle neuen UI-Elemente im Seiten-HTML verifiziert).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bug: bei Produkten mit mehreren Fotos (z.B. Armbändern) sprang ein Klick auf den ‹/›-Pfeil
zum Bildwechsel kurz zum nächsten Foto und öffnete dann trotzdem sofort die volle
Produktseite. Ursache: Astros <ClientRouter /> (View-Transitions, siehe Layout.astro) fängt
Klicks auf <a>-Links über einen eigenen, früher registrierten document-Klick-Listener in der
Bubble-Phase ab und startet die Navigation, BEVOR der Karussell-Klick-Handler von ProductCard
(der ebenfalls in der Bubble-Phase lief) preventDefault()/stopPropagation() aufrufen konnte.
Fix: Karussell-Klick-Handler läuft jetzt in der Capture-Phase (wie schon beim benachbarten
Wisch-Sperr-Handler etwas weiter unten in derselben Datei) — läuft dadurch garantiert vor
ClientRouters eigenem Listener und verhindert die Navigation zuverlässig, bevor sie startet.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Fix für gemeldetes Problem: VanVans Code funktionierte nicht auf der Verwaltungsseite. Ursache
war ein dritter, komplett separater, gemeinsamer Code (6GAM4AST), den sich niemand gemerkt
hatte — VanVan gab stattdessen ihren normalen persönlichen Zugangscode ein, der dort aber nicht
galt. Jetzt auf ausdrücklichen Wunsch vereinheitlicht: die Verwaltungsseite prüft denselben
persönlichen Code wie der normale Seitenzugang (SITE_ACCESS_CODE_QCIGA/_VANVAN). Die tägliche
Neueingabe-Pflicht bleibt bestehen (eigene Sitzung mit 24h statt 90 Tagen Gültigkeit) — nur der
geprüfte Code ist jetzt kein separater dritter mehr. Das alte Secret VERWALTUNG_ACCESS_CODE wird
nicht mehr verwendet. Lokal mit wrangler pages dev end-to-end getestet (beide Codes + alter Code
korrekt abgelehnt).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch NUR diese eine Zugangsseite (öffentliche Startseite und die
eingeloggte Verwaltung selbst bleiben unangetastet): zwei groß und gegenläufig rotierende,
warm golden bzw. violett eingefärbte Van's-Logo-Wasserzeichen im gesamten Fensterhintergrund,
plus das echte Logo als sich drehendes "Siegel" im Kästchen mit pulsierendem Glanz-Kreis und
drei zeitversetzt aufblitzenden Funkel-Emojis. Ziel: die tägliche Pflicht-Eingabe soll Freude
machen statt trockene Sicherheitsabfrage zu sein. Alle Animationen respektieren weiterhin
prefers-reduced-motion. Reine Design-Änderung, Formular-/Auth-Logik unverändert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Technisches Accessibility-Audit ergab sechs behebbare Punkte, alle jetzt gefixt:
- Skip-to-Content-Link ganz oben auf jeder Seite (WCAG 2.4.1)
- Fehler-/Statusmeldungen (Checkout, Login, Rezension, Gate-/Verwaltungs-Code) jetzt mit
role="alert"/aria-live, damit Screenreader sie automatisch ansagen (WCAG 4.1.3)
- Warenkorb-Icon hatte fälschlich das "Konto"-Label geerbt, sagt jetzt korrekt "Warenkorb"
(WCAG 4.1.2/2.4.4), dafür t.nav.cart in allen 4 Sprachen neu ergänzt
- Sichtbarer Fokus-Ring beim Mengenfeld auf der Produktseite wiederhergestellt (WCAG 2.4.7)
- Placeholder-only Formularfelder (Gate-Zugangscode, Verwaltungs-Suche/Filter/Tracking) haben
jetzt echte Labels (sichtbar per sr-only-Klasse oder aria-label) statt nur Platzhaltertext
(WCAG 1.3.1/3.3.2)
- Übersprungene Überschriften-Ebenen (h1→h3 ohne h2) in Checkout, Warenkorb, Kontakt, Konto
korrigiert (WCAG 1.3.1)
Reine Accessibility-Nachrüstung, keine funktionale Änderung. Kleinstunternehmer-Ausnahme
(§3 Abs.3 BFSG) greift hier vermutlich, aber vorsorglich sauber umgesetzt.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der Name "Tages-Code" konnte fälschlich als sich täglich änderndem/rotierendem Code
verstanden werden. Tatsächlich bleibt der Code dauerhaft gleich (6GAM4AST) — nur die
24h-Sitzung läuft ab, wodurch derselbe Code einmal pro Tag erneut eingegeben werden
muss. Reine Text-/Kommentar-Korrektur, keine Verhaltensänderung.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: /verwaltung/ + /api/verwaltung/* verlangen jetzt ZUSÄTZLICH zum
normalen 90-Tage-Seitenzugang einen zweiten, eigenen Code, den nur qciga und VanVan kennen —
und der nach 24 Stunden automatisch abläuft (muss also einmal täglich neu eingegeben werden).
Der Rest der Seite ist davon unberührt, nur die Bestellübersicht ist betroffen.
Bewusst als eigenständiges System (eigenes Cookie vandiy_verwaltung_session, eigenes Geheimnis
VERWALTUNG_SESSION_SECRET, eigener HMAC-Signaturcode statt geteiltem mit dem normalen
Seitenzugang) — gleiches Trennungsprinzip wie bei den Kundenkonten: ein Leck bei einer
Sitzungsart darf nie die andere gefährden.
Neue Dateien: functions/_shared/verwaltung-auth.js (Session-Logik), public/verwaltung-code.html
(Eingabemaske im selben Stil wie die Haupt-Zugangsseite). functions/_middleware.js prüft nach
erfolgreicher Haupt-Sitzung zusätzlich diese zweite Sitzung für /verwaltung*-Pfade. Beide
API-Routen (orders.js, orders/[id].js) prüfen die zweite Schranke zusätzlich eigenständig,
nach demselben Verteidigungs-in-der-Tiefe-Prinzip wie die bestehende Haupt-Prüfung.
Lokal vollständig durchgetestet (wrangler pages dev): kompletter Ablauf ohne jeden Zugang ->
Haupt-Gate -> Redirect zum Tages-Code -> falscher Code abgelehnt -> richtiger Code setzt
24-Stunden-Cookie -> Seite und API danach erreichbar. Bestätigt: der Rest der Seite bleibt
unberührt (kein Tages-Code nötig), UND dass VanVan mit nur dem Haupt-Zugang (ohne Tages-Code)
ebenfalls noch ausgesperrt bleibt, wie gewünscht.
Zwei neue Cloudflare-Secrets in Produktion gesetzt: VERWALTUNG_SESSION_SECRET (zufällig
erzeugt) und VERWALTUNG_ACCESS_CODE (der eigentliche Tages-Code, an qciga und VanVan zu
verteilen).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: statt der vagen Ersatzformulierung "Teddy aus einer früheren
Einlösung" zeigt die Liste "Diese Teddys hast du schon bekommen" jetzt fuer JEDEN Eintrag
den echten Produktnamen + eine kleine Vorschau — auch fuer Einloesungen von vor diesem
Feature, bei denen kein Name gespeichert war. Das geht zuverlaessig, weil es je Groesse
aktuell nur EIN konfiguriertes Teddy-Produkt gibt (aboEinstellungen.kleinTeddySlug/
grossTeddySlug) — es gibt also keine Mehrdeutigkeit, welcher Teddy es war.
Mini-Foto: echtes Produktfoto, sobald VanVan eins im Adminbereich hochlaedt (automatisch,
ohne Code-Aenderung) — bis dahin ein gestalteter Platzhalter statt eines kaputten Bildes,
da beide Teddy-Produkte aktuell noch kein Foto hinterlegt haben.
Dabei einen echten Datenfehler gefunden und behoben: der KLEINE Teddy trug auf Englisch
"Large Teddy" und auf Schweizerdeutsch "Grosse Teddy" (Kopierfehler vom grossen Teddy) —
war nicht nur in dieser Liste sichtbar, sondern auch auf der Produktseite selbst in allen
nicht-deutschen Sprachen. Jetzt korrekt "Small Teddy" / "Chliine Teddy" / "Petit ours en peluche".
Getestet (Browser): genau der Fall aus der Rückmeldung nachgestellt (2 alte Einlösungen ohne
Namensverlauf) — zeigt jetzt Name + Link statt "unbekannt". Gemischter Fall (echter + alter
Eintrag) korrekt sortiert. Vorhandenes Foto ersetzt den Platzhalter automatisch. Korrigierte
Produktnamen in allen 4 Sprachen bestätigt.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: die Visa-/Mastercard-Badges in der unteren Hälfte sehen jetzt genauso
"fertig" aus wie das PayPal-Badge oben — größer (48x48 statt 40x27), mit demselben weichen
Glanz-Verlauf, kräftigem Schlagschatten in der jeweiligen Markenfarbe und Lift-Effekt beim
Hovern. Die Markenfarben selbst bleiben unverändert (Visa weiß, Mastercard schwarz).
Die untere Hälfte hat jetzt außerdem eine EIGENE Farbgebung statt eines Blau-Abklatschs der
PayPal-Hälfte darüber: dezentes Visa-Blau unten links, Mastercard-Orange/Rot oben rechts,
beide nur angedeutet (niedrige Deckkraft) auf dunklem Grund, damit Text und Karten weiterhin
klar lesbar bleiben.
Getestet: Breiten-Sweep 390–1440px ohne Überlappung mit der Radio-Markierung (die Karten sind
jetzt größer, deshalb erneut geprüft), Screenshots Desktop + Mobil, Markup in allen 4 Sprachen
bestätigt.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: die PayPal-Zahlungsoption ist jetzt eine "besondere" Kachel statt
der schlichten Icon-Zeile — exakt in der Mitte horizontal geteilt, obere Hälfte PayPal-
Markenverlauf mit Logo + zweifarbiger Wortmarke, untere Hälfte die Visa-/Mastercard-Hinweise.
Animierter Verlaufsrand, leuchtender Mittelsteg, Glanzeffekt und Glitzer-Akzente — dieselbe
Formsprache wie die anderen "besonderen" Karten der Seite (z.B. .account-head). Alle 4 Sprachen.
Feste Höhe (statt min-height) auf der Kachel, damit die Trennlinie IMMER exakt mittig sitzt,
unabhängig vom Inhalt jeder Hälfte — mit auto-Höhe hätte der Flex-Container sich sonst am
längeren Inhalt orientiert und die Linie wäre verrutscht (nachgemessen: vorher 106,6px oben vs.
141px unten, jetzt 109px/109px exakt).
Dabei zwei echte Bugs gefunden und behoben:
1. Eine generische Farb-Regel (".pay-card:has(input:checked) .pay-option span:not(.pay-icon)")
hätte die neue zweifarbige Wortmarke und den Kartenhinweis auf die einfarbige Markenfarbe
umgefärbt und auf dem blauen Verlaufshintergrund fast unlesbar gemacht — mit gezielt
spezifischeren Regeln überschrieben.
2. Die Radio-Markierung überlappte bei bestimmten Fensterbreiten (ca. 800–1000px) die
Mastercard-Karte, weil zwei VERSCHACHTELTE Zweispalten-Layouts (.checkout-layout und
.checkout-split) bei ZU ÄHNLICHEN Umbruchpunkten (800px bzw. 760px) gleichzeitig aktiv
blieben und die Zahlungsspalte auf ca. 90px zusammenquetschten — ein vorbestehender
Layout-Fehler, der die ganze Zahlungsspalte betraf, nicht nur die neue Kachel. Behoben,
indem die innere Spalte jetzt deutlich früher umbricht (1024px statt 760px), lange bevor
die äußere Spalte eng wird.
Getestet (Browser, alle 4 Sprachen): Kontrastprüfung im markierten Zustand, Geometrie der
Trennlinie, Breiten-Sweep von 390px bis 1600px ohne Überlappung mehr, Mobil-Ansicht.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: der Knopf war bisher unter allen aktuellen Bestellungen platziert.
Jetzt steht er direkt unter der Überschrift "Meine Bestellungen", noch vor der neuesten
Bestellung — beim Aufklappen erscheinen Suchfeld und ältere Bestellungen also ganz oben,
noch vor der aktuellen Liste. Alle 4 Sprachen.
Rein eine Markup-Verschiebung (das <div class="order-archive"> wandert vor <div id="order-list">
im DOM) — die JavaScript-Logik, die ältere Karten per appendChild() in den Aufklappbereich
verschiebt, funktioniert unabhängig von der Position weiter, da sie über getElementById auf
beide Container zugreift. CSS entsprechend angepasst: margin-top wurde zu margin-bottom, weil
der Abstand jetzt VOR der ersten Bestellkarte gebraucht wird statt danach.
Getestet (Browser): DOM-Reihenfolge in allen 4 Sprachen bestätigt (order-archive vor
order-list), Auf-/Zuklappen weiterhin funktionsfähig, Karten wandern korrekt in den
Archiv-Bereich und wieder zurück, Sichtprüfung per Screenshot.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Statt "Bereits erhalten: 1x kleiner Teddy, 1x grosser Teddy" steht im Abo-Bereich jetzt eine
Liste mit dem tatsaechlichen Teddy-Namen, dem Einloesedatum und einem Link zum Produkt —
damit Kundinnen sehen, welchen Teddy sie schon besitzen, und keinen doppelt waehlen.
Dafuer haelt das Konto beim Einloesen fest, WELCHER Teddy vergeben wurde (neues Feld
abo.erhalteneTeddys mit Slug, Name und Datum). Bewusst als Verlauf gespeichert statt aus der
aktuellen Abo-Einstellung abgeleitet: VanVan kann die hinterlegten Teddy-Produkte jederzeit im
Adminbereich austauschen — eine nachtraeglich berechnete Liste wuerde dann einen Teddy
anzeigen, den die Kundin nie bekommen hat. Die Anzeige nimmt den aktuellen, uebersetzten
Produktnamen und faellt auf den gespeicherten Namen zurueck, falls das Produkt spaeter
umbenannt oder entfernt wird.
Nebenbei behoben: Beim Einloesen wanderte der Teddy in den Warenkorb, BEVOR geprueft wurde, ob
ueberhaupt eine Praemie offen ist. Bei einem zweiten Klick landete er dadurch erneut gratis im
Warenkorb, ohne im Konto gezaehlt zu werden. Jetzt wird zuerst geprueft.
Ausserdem sichert getAccount() nun auch die Listenfelder gegen kaputte Speicherwerte ab.
Getestet (Browser): Leerzustand, Einloesen beider Arten, Speicherung im Konto, zweiter Klick
ohne offene Praemie, Altkonto ohne Namensliste (ehrlicher Ersatztext) und entferntes Produkt
(gespeicherter Name greift). Beschriftungen in allen 4 Sprachen geprueft.
Co-Authored-By: Claude Opus 5 <[email protected]>
Impressum, Datenschutz, AGB, Widerruf und Muster-Widerrufsformular liegen jetzt vor der
Zugangsschranke. Grund: PayPal prueft vor der Freischaltung von "Log in with PayPal" die
angegebene Datenschutz- und AGB-Adresse tatsaechlich nach — hinter der Schranke haette deren
Pruefteam nur die Code-Eingabe gesehen und die Freischaltung waere gescheitert. Google verlangt
beim Veroeffentlichen ebenfalls eine erreichbare Datenschutzerklaerung. Rechtlich ist das
ohnehin die saubere Seite; diese Seiten enthalten keine Shop- oder Kundendaten.
Bewusst eng gefasst: feste Liste der fuenf Seiten (kein Praefix-Match), dazu nur Stylesheets
und Logo/Favicons, damit die Seiten beim Pruefteam gestaltet ankommen. Die JS-Buendel aus
/_astro/ bleiben gesperrt — darin stecken u.a. die Produktdaten.
Lokal geprueft: die fuenf Rechtstexte + CSS + Logo liefern 200, waehrend Startseite, Shop,
Warenkorb, Checkout, Konto, Verwaltung, Produktseiten und alle JS-Buendel weiterhin auf die
Zugangscode-Seite umleiten und /api/verwaltung/ weiterhin 401 liefert.
Co-Authored-By: Claude Opus 5 <[email protected]>
Im Kundenbereich stehen jetzt nur noch Bestellungen aus dem letzten Monat direkt in der Liste.
Aeltere werden gebuendelt hinter einem kleinen Knopf "Aeltere Bestellungen (N)" gezeigt und
lassen sich dort nach Bestellnummer, Artikel oder Datum durchsuchen. Alle 4 Sprachen.
Die Monatsgrenze wird bewusst ERST IM BROWSER berechnet (echte Kalendermonate, nicht "30 Tage"):
Die Seite ist statisch vorgebaut, eine schon beim Bauen gezogene Grenze waere ab dem naechsten
Tag falsch. Bestelldatum steht dafuer jetzt als ISO-Datum in den Daten, die Anzeige wird daraus
abgeleitet — nur noch eine Quelle fuers Datum.
Nebenbei gefunden und behoben: getAccount() hat gespeicherte Kontodaten reind flach mit den
Standardwerten zusammengefuehrt. Stand im Speicher ein kaputtes/fehlendes abo-Objekt (null),
hat das den Standardwert ueberschrieben und jeder Zugriff wie a.abo.bezahltBisDatum warf einen
Fehler, der das GESAMTE Konto-Dashboard lahmgelegt hat (keine Bestellungen, keine Tabs mehr).
Das verschachtelte abo-Objekt wird jetzt ausdruecklich mit Standardwerten aufgefuellt.
Getestet (Browser, alle Faelle): Aufteilung nach Datum, Auf-/Zuklappen, Suche nach Artikel und
nach Bestellnummer, Suche ohne Treffer, Zusammenspiel mit den Tabs "Offene Sendungen"/
"Bestellungen", sowie Markup und Uebersetzungen in allen 4 Sprachen.
Co-Authored-By: Claude Opus 5 <[email protected]>
Konto- und Sprachmenü hatten feste Breiten (190px bzw. 168px). Die passen nie zu jedem Fall,
weil der Konto-Knopf je nach Länge des Benutzernamens unterschiedlich breit ist: Bei einem
kurzen Namen wie "qciga" ragte die Kiste sichtbar über den Knopf hinaus.
Jetzt: min-width 100% (nie schmaler als der Knopf) + width max-content (sonst genau so breit
wie der Inhalt). Passt sich damit automatisch an Name und Sprache an.
Nachgemessen, Überstand pro Seite:
Konto "qciga" 27,6px -> 8,6px
Konto "Van Van" 22,4px -> 3,4px
Konto langer Name 0px
Sprache DE/FR 0px (EN 1,8px, CH 0,3px)
Alle weiterhin exakt mittig (Versatz 0), auch mobil innerhalb des Fensters.
Co-Authored-By: Claude Opus 5 <[email protected]>
Das Konto-Aufklappmenü war mit min-width 190px fest breiter gesetzt als sein Inhalt braucht
(~130px) und ragte dadurch sichtbar weiter über den Knopf hinaus als das Sprachmenü daneben.
Jetzt beide 168px — die Kopfzeilen-Menüs sehen gleich aus.
Nachgemessen: Überstand pro Seite vorher 33,4px (Konto) vs 20,7px (Sprache),
jetzt 22,4px vs 20,7px; beide weiterhin exakt mittig (Versatz 0).
Co-Authored-By: Claude Opus 5 <[email protected]>
Das Sprach-Aufklappmenü hing sichtbar nach links versetzt unter seinem Knopf, weil es mit
"right: 0" an dessen rechter Kante ausgerichtet war und breiter ist als der Knopf selbst.
Jetzt echt zentriert (left: 50% + translateX(-50%)) — dasselbe Muster wie auf der
Dogfather-Referenzseite (.nav-dropdown) und wie beim Konto-Menü, das das schon hatte.
Nachgemessen bei 1440/1024/390 px: Versatz jeweils exakt 0 px, kein Überlauf am Bildrand.
Co-Authored-By: Claude Opus 5 <[email protected]>
Kundenkonten sind jetzt genauso echt wie die PayPal-Zahlung: server-geprüftes OAuth 2.0 mit
PKCE für Google und "Log in with PayPal" (functions/_shared/oauth.js, oauth-handlers.js),
neue D1-Tabelle "customers" (bewusst ohne Passwort-Feld), eigene von der Zugangscode-Schranke
getrennte Sitzungs-Logik (customer-auth.js). Echte DSGVO-Rechte direkt im Kontobereich:
Daten herunterladen (Art. 15/20) und Konto unwiderruflich löschen (Art. 17), Bestellungen
bleiben aus gesetzlichen Gründen erhalten. Datenschutzerklärung entsprechend ergänzt.
Ohne echte Google-/PayPal-Zugangsdaten zeigt der Login-Button ehrlich einen
"noch nicht eingerichtet"-Hinweis statt eine Anmeldung vorzutäuschen.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch, mit Fokus auf rechtliche Absicherung:
- Klarna komplett entfernt (hätte eigene Händlerprüfung + Bonitätsprüfungs-
Pflichten nach der neuen EU-Verbraucherkreditrichtlinie vorausgesetzt).
- Eigene Kreditkarten-Eingabemaske komplett entfernt (wäre PCI-DSS-pflichtig
gewesen — für einen kleinen Shop praktisch nicht stemmbar). Kartenzahlung
bleibt möglich: PayPals eigener, PCI-zertifizierter Gast-Checkout bietet
Kredit-/Debitkarte an, ohne dass Kartendaten je unsere Seite berühren.
- PayPal ist jetzt ECHT server-seitig verifiziert statt dem Browser blind zu
vertrauen: eigener Cloudflare-Function-Flow (functions/_shared/paypal.js +
functions/api/paypal/) legt die PayPal-Bestellung server-seitig an, zieht
die Zahlung nach Bestätigung server-seitig ein und prüft den eingezogenen
Betrag gegen die Bestellsumme — die Bestellung wird ausschließlich bei
bestätigter, betragsgleicher Zahlung angelegt. /api/orders lehnt direkte
PayPal-Bestellungen jetzt ausdrücklich ab (verhindert vorgetäuschte
"bezahlte" Bestellungen ohne echte Zahlung).
- Neuer, ehrlicherer Bestellstatus "zahlungOffen": Überweisungs-Bestellungen
starten jetzt so (Geld noch nicht da) statt fälschlich sofort "bezahlt" zu
heißen — Schutz vor Warenversand, bevor das Geld wirklich angekommen ist.
Eigene Kachel/Filter/Badge-Farbe in der Verwaltung, Umsatz-/Auswertungs-
Zahlen zählen "zahlungOffen" bewusst nicht mit.
- Rechtstexte (AGB, Datenschutzerklärung, FAQ, Versand & Zahlung) auf allen
4 Sprachen aktualisiert: nur noch PayPal + Überweisung erwähnt, inkl. DSGVO-
Hinweis zur internationalen Datenübertragung an PayPal (Data Privacy
Framework-Zertifizierung).
- D1-Migration 0003: neue Spalte paypal_order_id (Zahlungsbeleg) + erweiterter
Status-Wertebereich, auf Live-Datenbank angewendet, bestehende Daten intakt.
Mit echten Testbestellungen lokal verifiziert: Überweisung legt korrekt
"zahlungOffen" an, direkter PayPal-Bypass-Versuch an /api/orders wird
abgelehnt, PayPal-Route meldet sauber "noch nicht eingerichtet" ohne
Zugangsdaten. Checkout-UI zeigt nur noch 2 Zahlungsarten, Bestellknopf ist bei
PayPal ausgeblendet (Zahlung läuft exklusiv über den echten PayPal-Button).
Für den echten Zahlungseingang fehlt noch VanVans eigenes PayPal-Business-
Konto (Client-ID + Secret) — Details in der Vault-Dokumentation.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch: "Mit Apple anmelden" raus aus allen 4 Sprachversionen
der Kontoseite (Buttons, Übersetzungsstrings, Kommentare). Bleiben: Google +
PayPal, beide ohne laufende Kosten nutzbar — anders als Apple, das zwingend das
kostenpflichtige Apple Developer Program (99 $/Jahr) fürs Web-Login voraussetzt.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Jede der 6 Kisten (Bestellstatus, Kennzahlen, Bestseller je Kategorie, Herkunft,
Stammkundschaft, Alle Bestellungen) bekommt jetzt:
- einen schimmernden Aurora-Rand in der eigenen Box-Farbe (derselbe Verlaufs-
Trick wie beim Hero-Kopf, nur pro Kiste individuell eingefärbt)
- ihr eigenes Icon riesig und ganz dezent als Wasserzeichen im Hintergrund
- einen "Radar-Ping"-Ring, der leise vom Icon-Abzeichen ausgeht
- eine kleine farbige Eyebrow-Kennzeichnung über dem Titel (z.B. "TOP-VERKÄUFE",
"GEOGRAFIE", "TREUE & WIEDERKEHR")
Die Kennzahlen-Kacheln bekommen zusätzlich einen Lichtstreif, der beim Hover
einmal quer durchläuft. Alles respektiert prefers-reduced-motion.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Gleiche Ursache wie beim vorherigen Fix: "Alle Bestellungen" steckte noch in
einer eigenen <section>, deren Innenabstand sich mit dem der Auswertungs-
Section addiert hat. Jetzt alles eine Section — Abstand jetzt einheitlich
~22px wie zwischen allen anderen Kisten.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher gab es nur "Heute"/"Letzte 7 Tage" — der ganze aktuelle Kalendermonat
fehlte. Neue Kachel zeigt Bestellanzahl + Umsatz diesen Monat, anklickbar wie
die anderen Kennzahlen-Kacheln (filtert die Bestellliste direkt danach). Auch
als neue Option "Dieser Monat" im Zeitraum-Dropdown ergänzt — bewusst als
echter Kalendermonat (ab dem 1.) berechnet, nicht einfach "letzte 30 Tage".
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Die Auswertungs-Kisten steckten in einer eigenen <section>, deren Innenabstand
sich mit dem der vorherigen Section zu einem viel zu großen Zwischenraum
addierte. Jetzt in derselben Section wie Bestellstatus/Kennzahlen — Abstand
zwischen allen Kisten jetzt einheitlich ~22px statt teils 150px+.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der separate "Auswertung anzeigen"-Knopf war nicht der Plan — stattdessen sind
jetzt die drei Kisten (Bestseller je Kategorie / Herkunft der Bestellungen /
Stammkundschaft) selbst klickbar und klappen unabhängig voneinander ihren
eigenen Inhalt auf, per sanfter CSS-Grid-Animation und rotierendem Chevron.
Startzustand: alle drei eingeklappt (nur Kopfzeile sichtbar).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Jede Kategorie/jedes Land/jede Stammkundin ist jetzt eine eigene, klickbare Kachel
im selben Look wie die Bestellstatus-Kacheln oben (Wunsch: "sollen aussehen wie
screen2"). Klick auf eine Kachel öffnet direkt darunter ein Panel mit der
vollständigen Liste (nicht mehr nur den Top 4/8) — nochmal klicken klappt es
wieder ein.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
context.waitUntil() lief in dieser Pages-Functions-Umgebung nicht zuverlässig zu
Ende, bevor die Anfrage beendet wurde - Bestellungen wurden korrekt gespeichert,
aber die Benachrichtigungs-Mail an [email protected] kam nie an.
Mit echten Live-Bestellungen verifiziert: mit waitUntil kam nichts bei Resend an,
mit await kam die Mail sofort und zuverlässig an.
Außerdem: "Auf Lager"-Feld im Produkt-Formular (Admin) steht jetzt über "Kategorie"
statt darunter, wie gewünscht.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bestseller/Herkunft/Stammkundschaft nahmen bisher immer Platz auf der Seite ein, auch
ohne Bestellungen zum Auswerten. Jetzt standardmäßig eingeklappt hinter einem
"📊 Auswertung anzeigen"-Knopf direkt unter der Bestellstatus-/Kennzahlen-Kiste — ein
Klick blendet alle drei Auswertungs-Kisten sofort an genau dieser Stelle ein (vor der
Bestellliste), erneuter Klick klappt sie wieder ein. Mit echtem Klick-Test verifiziert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
War rechtsbündig an der Knopfkante ausgerichtet, dadurch je nach Länge des Benutzernamens
optisch "nicht zentriert" zum Knopf. Jetzt wie auf der Dogfather-Referenzseite
(.nav-dropdown: left:50% + translateX(-50%)) — bleibt immer exakt mittig unterm Knopf.
Dropdown-Einträge außerdem etwas kompakter (kleinere Schrift/Padding, näher an der
Dogfather-Vorlage) statt für nur zwei Einträge unnötig groß zu wirken. Per Geometrie-Messung
verifiziert: 0px Abweichung zwischen Knopf- und Dropdown-Mitte.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf Feedback ("das ist mir zu einfach, ich will das alles in Kisten ist") die komplette
Auswertungsseite umgebaut: jede zusammengehörige Gruppe (Bestellstatus, Kennzahlen, Alle
Bestellungen, Bestseller je Kategorie, Herkunft der Bestellungen, Stammkundschaft) steckt
jetzt in einer eigenen, klar abgegrenzten Box mit eigenem Icon-Abzeichen, eigener
Akzentfarbe (Cyan/Lila/Gold/Grün/Pink) und dezent pulsierendem Glanzrand — statt lose auf
der Seite zu stehen.
Genauso wichtig: die Leerzustände (bevor die erste echte Bestellung eingeht) sehen jetzt
nicht mehr trostlos aus — großes Icon + freundlicher Text statt nacktem Fließtext, jeweils
passend zur Box (📭 Bestellungen, 🧶 Bestseller, 🗺️ Herkunft, 💌 Stammkundschaft). Mit
echtem Screenshot-Vergleich (befüllt UND leer, per fetch-Mock simuliert) verifiziert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
1) Gutscheincodes können jetzt im Adminbereich auf "nur einmal pro Person einlösbar"
gestellt werden. Wird serverseitig durchgesetzt (neue Spalte orders.gutschein_code +
Prüfung in functions/api/orders.js gegen die echte Bestelldatenbank, case-insensitiv
nach E-Mail-Adresse) — kann also NICHT durch Löschen von localStorage/einen anderen
Browser umgangen werden, anders als die bisherige rein clientseitige Rabattlogik.
Stornierte Bestellungen zählen nicht als "schon benutzt". Ausführlich getestet: echter
Browser-Checkout mit Einmal-Code funktioniert beim ersten Versuch, wird beim zweiten
Versuch (gleiche E-Mail) korrekt mit klarer Fehlermeldung abgelehnt, mit anderer E-Mail
weiterhin nutzbar.
2) Bestell-E-Mail-Benachrichtigung an [email protected]: recherchiert und
vorbereitet (existierte vorher nirgends im Code). Läuft über Resend (kostenlos bis
3.000 E-Mails/Monat), im Hintergrund per context.waitUntil() nach jeder neuen
Bestellung — verzögert nie die Antwort an die Kundschaft und kann eine Bestellung
niemals zum Scheitern bringen, selbst wenn der Versand fehlschlägt (mit ungültigem
Testschlüssel verifiziert: Bestellung bleibt trotzdem erfolgreich gespeichert). Wird
automatisch aktiv, sobald ein RESEND_API_KEY als Secret hinterlegt wird.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
1) Versandkostenfreigrenze ist jetzt länderabhängig statt einer einzigen Zahl für alle:
Deutschland 75 €, Österreich/Luxemburg 85 €, Schweiz 100 € (im Adminbereich unter
"Versandkosten-Staffel" änderbar). Betrifft Warenkorb (live je nach gewähltem Land),
Checkout-Berechnung, sowie alle Text-Hinweise (Topbar, FAQ, AGB) in allen 4 Sprachen.
2) Neues Feld "USt-IdNr." im Impressum (optional, admin-editierbar) — erscheint nur, wenn
ausgefüllt.
3) Impressum, AGB, Datenschutzerklärung, Widerrufsbelehrung und FAQ sind jetzt vollständig
im Adminbereich editierbar (neue Collection "⚖️ Rechtstexte & FAQ") statt fest im Code zu
stehen. Jede Rechtsseite besteht aus frei bearbeitbaren Abschnitten (Überschrift + Text) —
VanVan kann selbst Abschnitte ergänzen, ändern oder löschen. Freitext wird beim Anzeigen
sicher escaped (kein kaputtes HTML durch Tippfehler möglich) und nackte Links automatisch
klickbar gemacht. FAQ bleibt dabei weiterhin in allen 4 Sprachen separat pflegbar.
Ausführlich getestet: Freigrenze pro Land im echten Warenkorb verifiziert (Puppeteer,
84€ Warenwert -> DE kostenlos, AT/LU "noch 1€", CH "noch 16€"), Rechtstexte/FAQ/USt-ID
gegen den fertigen Build geprüft, EU-Streitschlichtung-Link-Bug (Satzzeichen wurde
mitverlinkt) gefunden und behoben.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf ausdrücklichen Wunsch ("perfektioniere diese Seite aufs Maximum") die interne
Verwaltungsseite um alles erweitert, was ein echtes kleines Shop-Team im Alltag
braucht, aber vorher fehlte:
- Suchfeld (Bestellnummer/Name/E-Mail), Zeitraum-Filter (Heute/7/30 Tage), vier
Sortiermodi — alle gleichzeitig mit dem bestehenden Status-Filter kombinierbar.
- CSV-Export der aktuell gefilterten Liste (für Buchhaltung/Steuer, Excel-taugliche
UTF-8-Kodierung mit BOM).
- Tracking-Nummer direkt in der Bestellkarte editierbar (Enter oder Speichern-Knopf).
- Ein-Klick-Kopieren von E-Mail/Lieferadresse fürs Versandlabel.
- Echte PDF-Rechnung pro Bestellung per Klick (nutzt dieselbe jsPDF-Funktion wie im
Kundenkonto, keine neue Abhängigkeit).
- Zwei neue Kennzahlen-Kacheln (Bestellungen heute/letzte 7 Tage, Ø Bestellwert) plus
eine automatisch erscheinende Warn-Kachel für offene Bestellungen, die schon länger
liegen (Schwelle 3 Tage) — sowohl als Kachel als auch als Warn-Chip direkt an der
betroffenen Bestellung.
- "🆕 Neu"- und "🔁 Stammkundin"-Kennzeichnung pro Bestellung, neuer Abschnitt "Beste
Kundinnen" (Umsatz nach wiederkehrender Kundschaft).
- Dezenter Hintergrund-Hinweis ("🔔 X neue Bestellungen"), wenn während des Arbeitens
neue Bestellungen eingehen — unterbricht die aktuelle Ansicht/Filterung nicht.
- Neuer, deutlich premiumerer Seitenkopf (Farbverlauf-Rand, Funkeln) passend zum Rest
der Seite.
Alle neuen Funktionen einzeln end-to-end gegen die echte lokale D1-Datenbank getestet
(Suche, Zeitraum, Sortierung, Tracking-Speichern, Kopieren, PDF-Erzeugung, Warn-/Neu-/
Stammkunden-Kennzeichnung) — keine Konsolenfehler, Screenshot-verifiziert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Auf Screenshot-Feedback: die beiden Menüpunkte im Konto-Dropdown sollen zentriert stehen statt
am linken Rand der Box zu kleben.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
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]>
Die Treuebonus-Karte im Konto zeigte bisher nur einen nackten Fortschrittsbalken
mit einem Satz Text. Jetzt: (1) zehn Meilenstein-Striche direkt im Balken plus
Geschenk-Symbol am Ziel, (2) vier Kennzahl-Kacheln im gleichen Stil wie beim Abo-
Status (Gesammelt, Noch nötig, Bonus bei Ziel, Bisher eingelöst), (3) ein neues
Datenfeld "wie oft insgesamt schon eingelöst + wann zuletzt" (account.ts), das in
einer eigenen, gold→grün abgewandelten "Bonus bereit"-Karte mit Glow-Effekt landet
statt eines einfachen Links, (4) eine kurze Icon-Liste mit den Sammelregeln statt
einem einzelnen Erklärsatz. Alles in 4 Sprachen, mit echten Vorschau-Zuständen
(Fortschritt/bereit/gesperrt) per Screenshot verifiziert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Treuebonus-Kiste im Konto-Dashboard bekam bisher das normale kleine ✨ wie
Bestellungen/Sendungen/Wunschliste. Jetzt nutzt sie denselben großen, kräftig
pulsierenden 🌟-Stern wie die Abo-Kiste (4 Sprachen). Die CSS-Regel dafür gilt
jetzt für beide Kisten gemeinsam und färbt den Glanz automatisch in der jeweils
eigenen --nav-color ein (Abo = Gold, Treuebonus = Grün) statt eines fest codierten
Goldtons — Stil bleibt identisch, nur die Farbe unterscheidet die beiden klar.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Vorschau-Umschalter (🎭) nach unten links verschoben, damit unten rechts Platz für
den neuen Musik-Button ist. Astro ClientRouter (View Transitions) eingeführt, damit
der Spotify-Player beim Seitenwechsel als echtes, unverändertes DOM-Element bestehen
bleibt (transition:persist) statt neu zu laden — die Musik läuft beim Weiterklicken
einfach weiter. Der Button-Farbverlauf passt sich per Canvas-Farbanalyse an das
Hauptbild der jeweiligen Seite an, mit einem seiten-spezifischen Fallback-Farbpaar
für bildlose Seiten (Warenkorb, Rechtstexte, ...).
Da Astro Skripte bei Client-seitigen Übergängen nicht automatisch neu ausführt, musste
das komplette Header-Skript (Warenkorb-Zähler, Konto-Menü, Hamburger, Installations-
Button) auf das "astro:page-load"-Ereignis umgestellt werden; echte Dauer-Listener
(document/window) wurden dabei bewusst nur einmal registriert, um Duplikate bei jeder
Navigation zu vermeiden. Ausführlich mit einem headless-Chrome-Testskript verifiziert:
Iframe-Persistenz über mehrere Navigationen hinweg, keine doppelten Klick-Listener,
keine Konsolenfehler.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Neue Seite, dauerhaft nur für qciga/vanvan sichtbar (functions/_middleware.js
schützt /verwaltung/* jetzt IMMER — unabhängig vom SITE_PUBLIC-Schalter, mit
dem der Rest der Seite später öffentlich geschaltet wird):
- Status-Kacheln: Offen / In Bearbeitung / Versendet / Abgeschlossen (klickbar
als Filter) + Gesamtumsatz-Kachel
- Filterbare Bestellliste (nutzt dieselben Status-Badges/-Farben wie die
Kunden-Kontoseite)
- Auswertung "Meistverkaufte Produkte je Kategorie" (Balken nach verkaufter
Menge, aus den echten Produktdaten berechnet)
- Auswertung "Bestellungen nach Land" (DE/AT/CH/LU, Balken + Prozent)
Wie an anderer Stelle im Projekt: es gibt noch keine echte, geräteüber-
greifende Bestell-Datenbank (Phase 1) — die Seite zeigt realistische
Beispieldaten in exakt der Struktur, die echte Bestellungen später haben
werden (Cloudflare Worker + D1), klar als solche gekennzeichnet.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Das Rund-Logo (schwarze Linien auf weißem Grund) wird per invert()+
mix-blend-mode:screen so eingefärbt, dass der weiße Kreis komplett
verschwindet und nur die Linienzeichnung als dezentes, leicht leuchtendes
Wasserzeichen übrig bleibt — kein Bildbearbeitungsprogramm nötig, rein CSS.
Riesig, zentriert, sehr langsam rotierend für einen dezenten Lebendig-Effekt.
Dazu ein wanderndes Glanzlicht auf der Zugangscode-Karte selbst, passend zum
Rest der Seite.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Die kleinen ✨-Sternchen oben rechts in den Kontobereich-Kacheln waren
bisher überall neutral-gelb, unabhängig von der Kistenfarbe. Jetzt bekommt
jedes Funkeln einen farbigen Schein passend zur eigenen Akzentfarbe der
Kiste (Lila/Teal/Pink/Grün/Gold).
Das Abo-Funkeln sticht zusätzlich klar heraus: eigener goldener Stern (🌟
statt ✨), größer, kräftiger und schneller leuchtend — soll dem Premium-
Charakter des Abos gerecht werden und auf den ersten Blick auffallen.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Ersetzt die (fehlerhaft auf die GANZE Domain wirkende) Cloudflare-Zero-
Trust-Access-Sperre durch eine eigene, schlanke Lösung nach dem bewährten
Vorbild von "Dogfather Universe": eine Pages-Functions-Middleware
(functions/_middleware.js) prüft bei jeder Anfrage ein HMAC-signiertes
Session-Cookie; ohne gültiges Cookie geht's zu public/gate.html (im Van's-
Design), wo ein Zugangscode eingegeben wird. Zwei getrennte Codes für qciga
und VanVan, 90 Tage gültig, danach neu eingeben. /admin/* ist komplett
ausgenommen — läuft weiter über das echte GitHub-OAuth-Login, das für
VanVan schon funktioniert.
Bonus: die drei separaten Vorschau-Seiten (demo-normal/demo-konto/demo-abo)
sind jetzt überflüssig und entfernt. Stattdessen gibt's ein schwebendes
Umschalter-Widget (Layout.astro), das NUR sichtbar ist, wenn das Gate-Cookie
vorhanden ist (also nur für uns beide) — auf jeder beliebigen Seite kann
per Knopfdruck zwischen "Normaler Besucher", "Angemeldete Kundin" und
"Abonnentin" gewechselt werden, ohne die Seite verlassen zu müssen.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Ergänzt /demo-abo/ (bereits vorhanden) um:
- /demo-normal/ — Shop wie ein nicht angemeldeter Besucher ihn sieht (räumt
ein evtl. simuliertes Konto im Browser vorher auf)
- /demo-konto/ — Kundenkonto einer angemeldeten Person OHNE Abo (Treuebonus
dadurch im gesperrten Zustand zu sehen)
Damit gibt es jetzt für jede Sicht einen eigenen Link. Beide noindex + aus
der Sitemap ausgeschlossen, wie /demo-abo/.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
"Mein Konto" und "Abmelden" starteten je nach Breite des Emojis (👤 vs 🚪)
an leicht unterschiedlichen Stellen. Jetzt echtes Flex-Layout mit fester
Icon-Spalte (1.2em, zentriert) — beide Labels stehen exakt untereinander.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Plan-Karten: eigenes Icon je Stufe (🌱/🌿/👑), Rabatt als farbiger Chip statt
reinem Fließtext, Prämien-Intervalle als eigene Chips (aus den admin-
konfigurierten Werten berechnet), Preis mit Farbverlauf, sanft pulsierender
Rahmen für die aktuell gebuchte Stufe.
Abo-Status: Tabelle durch ein Stat-Kachel-Raster ersetzt (Icon + Label + Wert
pro Kennzahl, Rabatt farblich hervorgehoben), echte Fortschrittsbalken statt
Text für den Weg zum nächsten Teddy (Prozent aus dem admin-konfigurierten
Intervall berechnet), "Bereits erhalten" als Badge-Chip, verfügbare Prämien
als eigene, leicht glühende Karten statt schlichter Buttons.
Benachrichtigungen: farbiger Icon-Kreis pro Ereignistyp (Erfolg/Prämie/
Warnung/Abbruch/Info) statt einheitlicher grauer Liste — auf einen Blick
erkennbar, worum es bei jedem Eintrag geht.
Alles in 4 Sprachen (DE/EN/CH/FR), neues i18n-Template aboRewardEveryLabel
für die Prämien-Intervall-Chips.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher musste man auf "Deutsch ▾" bzw. das Konto-Menü in der Kopfzeile klicken,
damit sich das Untermenü öffnet. Jetzt reicht auf dem Desktop einfaches
Drüberfahren mit der Maus (mit kurzer Schließverzögerung beim Verlassen,
damit der Wechsel vom Button zum Menü nicht sofort wieder zuklappt) — Klick
funktioniert als Fallback für Touch-Geräte/Tastatur weiterhin ganz normal.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Neue, nicht verlinkte Seite (noindex, aus der Sitemap ausgeschlossen), die
beim Aufruf ein Demo-Konto mit aktivem "Großes Abo" (14 bezahlte Monate,
verfügbare + bereits eingelöste Teddy-Prämien, mehrere Benachrichtigungen,
laufender Treuebonus-Fortschritt) ins localStorage DES AUFRUFENDEN BROWSERS
schreibt und direkt zum Abo-Tab im Kundenkonto weiterleitet — ändert nichts
an echten Kundendaten, jede Person sieht die Vorschau nur bei sich selbst.
Dafür neu: Layout.astro bekommt eine noindex-Prop, und die Kontoseite
unterstützt jetzt Deep-Links per URL-Hash (#abo, #treuebonus, …), damit die
Vorschau direkt im richtigen Tab landet.
Separat per `wrangler pages deploy --branch=vorschau-abo` auf eine eigene
Vorschau-URL deployed (vorschau-abo.vans-diy-bastelbedarf.pages.dev) —
komplett getrennt von der normalen Produktions-URL, wird nicht durch den
GitHub-Actions-Workflow (nur branch=main) überschrieben.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Erklärt jetzt direkt, was in dieser Liste erscheinen wird (Zahlungen, neue
Teddy-Prämien, Stufenwechsel), statt nur eine leere Aussage zu zeigen — in
allen 4 Sprachen.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der Treuebonus (10 Bestellungen → 20% Rabatt) sammelt jetzt nur noch, solange
ein aktives, bezahltes Abo besteht — ohne Abo bleibt der Fortschritt einfach
stehen, statt weiterzuzählen (account.ts: registriereAbgeschlosseneBestellung()).
Ebenso greift ein bereits freigeschalteter Rabatt im Warenkorb/Checkout nur,
solange das Abo aktiv ist (cart.ts: treuebonusDiscount()).
Im Kundenkonto wird die Treuebonus-Karte ohne aktives Abo nicht einfach
ausgeblendet, sondern zeigt bewusst einen einladenden gesperrten Zustand
("🔒 Nur mit aktivem Abo verfügbar" + Button "Zum Abo →") statt der üblichen
Fortschrittsanzeige — soll als klarer Anreiz fürs Abo wirken, nicht als totes
Feature. Dieselbe Sperre greift auch im Warenkorb: das Auswahl-Radio/Badge für
den Treuebonus-Artikel erscheint nur noch bei tatsächlich aktivem Abo, damit
nie ein Rabatt suggeriert wird, der beim Checkout dann doch nicht greift.
Alles in 4 Sprachen (DE/EN/CH/FR).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der "Mein Abo verwalten"-Button in der Kopfkarte fällt wieder weg — der
Zugriff aufs Abo läuft ab jetzt nur noch über die eigene "Mein Abo"-Nav-
Kachel. Stattdessen wandert "Meine Daten" aus der Schnellnavigation direkt
in die Kopfkarte: ein neuer, gleich premium gestylter Button (Teal/Lila statt
Gold, gleiches wanderndes Glanzlicht) unten rechts in der Karte, der zum
Profil-Bereich springt.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher waren nur Preis, Rabatt-% und ein paar Verhaltensregeln im CMS
editierbar — Namen, Vorteilstexte und die Teddy-Vergabe-Intervalle steckten
fest im Code. Jetzt ist pro Abo-Stufe (Klein/Mittel/Groß) direkt im
Adminbereich einstellbar:
- Name & Vorteilstext der Stufe, in allen 4 Sprachen einzeln
- Ob die Stufe aktuell überhaupt neu buchbar ist (bestehende Abonnent:innen
behalten ihre Vorteile trotzdem, im Kundenkonto wird die Stufe nur für neue
Buchungen ausgegraut mit "Derzeit nicht buchbar")
- Nach wie vielen Monaten es den kleinen/großen Teddy gibt (ersetzt die vorher
fest verankerten 6-/12-Monats-Abstände)
- Welches Produkt als "kleiner"/"großer" Teddy für die Prämien-Einlösung
verwendet wird (Produktauswahl statt festem Slug im Code)
Alle Berechnungen (Meilensteine, Fortschrittsanzeige) laufen jetzt komplett
über diese Admin-Werte statt über Konstanten im Code. Konto-Plan-Karten in
allen 4 Sprachen zeigen die admin-gepflegten Texte live an.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Drei Mitgliedschaftsstufen (Klein 4,99€/5%, Mittel 9,99€/10%, Groß 19,99€/20%)
mit automatischem Bestellrabatt und Teddy-Prämien nach Meilensteinen (12-Monats-
Rhythmus bzw. 6+12 bei Groß). Preise/Rabatte und alle Admin-Regeln (Kombinier-
barkeit mit anderen Rabatten, Fortsetzung bei Wiederanmeldung, Monate über
Stufen zusammenzählen, kostenloser Versand bei Prämie) sind über Decap CMS
einstellbar (src/content/abo-einstellungen.json).
Neuer "Mein Abo"-Bereich im Kundenkonto (6. Nav-Kachel) mit Plan-Vergleich,
Live-Status (Laufzeit, nächste Zahlung, Rabatt, Fortschritt bis zur nächsten
Prämie), Einlösen-Buttons für freigeschaltete Teddys, Kündigen/Wechseln sowie
einer übersetzten Benachrichtigungsliste. Dazu ein extra hervorgehobener
"Mein Abo verwalten"-Button neben Abmelden in der Kopfkarte.
Warenkorb/Checkout rechnen den Abo-Rabatt korrekt in die Summe ein und stellen
eingelöste Teddys als 0€-Gratisposition dar. Alles in 4 Sprachen (DE/EN/CH/FR).
Unterwegs zwei echte Bugs gefunden und behoben: addMonateISO() vermischte
lokale Zeit mit toISOString() (UTC) und verlor dadurch bei jeder Monats-
verlängerung reproduzierbar einen Tag; die Checkout-Positionsliste zeigte für
Gratis-Prämien fälschlich den vollen Preis statt 0€.
Wie beim Treuebonus gilt: Speicherung aktuell im localStorage des Geräts
(Phase 1) statt einer echten geräteübergreifenden Datenbank — folgt mit der
Zahlungsanbindung in Phase 2.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Neue eigene Kiste "Treuebonus" im Kundenkonto (5. Nav-Tab, grüner Akzent)
zeigt den Fortschritt ("X von 10 Bestellungen") mit Fortschrittsbalken und
Restanzahl-Hinweis, nach Freischaltung eine Erfolgsmeldung mit Link zum
Warenkorb. Es zählen ausschließlich erfolgreich abgeschickte, bezahlte
Bestellungen (in Phase 1: jede erfolgreich abgeschlossene Demo-Bestellung
im Checkout) — abgebrochene Bestellungen zählen nie mit.
Sobald der Bonus aktiv ist, erscheint im Warenkorb ein Hinweis-Banner und
bei jedem Artikel eine Auswahl ("Für 20% Treuebonus auswählen") — es kann
immer nur EIN Artikel gewählt werden (Radiobutton-Verhalten über alle
Positionen hinweg). Der Rabatt fließt automatisch in Warenkorb- und
Checkout-Summe ein (neue treuebonusDiscount()-Funktion in scripts/cart.ts,
in totalDiscount() eingerechnet). Nach erfolgreichem Bestellabschluss wird
die Belohnung als eingelöst markiert und der Fortschrittszähler beginnt
wieder bei 0 — beides dauerhaft im Konto (localStorage, Phase 1) gespeichert
und eindeutig diesem Kundenkonto zugeordnet.
Neue Funktionen in scripts/account.ts: registriereAbgeschlosseneBestellung(),
setTreuebonusArtikel(), treuebonusEinloesen(), treueFortschritt(). Beide
Zustandsübergänge (Fortschritt zählen vs. Belohnung einlösen) end-to-end
über den echten Checkout-Ablauf getestet und verifiziert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Neuer Button lädt die Rechnung als echte PDF-Datei herunter — komplett
clientseitig mit jsPDF + jspdf-autotable (beide MIT-lizenziert, per
dynamic import erst beim Klick nachgeladen, kein Einfluss auf die normale
Seitenladezeit). Zeigt exakt dieselben Daten wie der "Rechnung ansehen"-
Dialog (Rechnungsnummer/-datum, Verkäufer, Empfänger, Artikeltabelle,
Gesamtbetrag, §19-UStG-Hinweis), sauber formatiert mit Kopfzeile, zwei
Spalten für Verkäufer/Empfänger und einer echten Tabelle. Datei heißt
"Rechnung-<Bestellnummer>.pdf". Mit Node-Testskript verifiziert, dass die
PDF-Erzeugung fehlerfrei ein valides PDF mit korrekten Umlauten liefert.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Größeres Profilbild in der "Mein Konto"-Karte. Alle vier Navigations-
Knöpfe (Bestellungen/Offene Sendungen/Wunschliste/Meine Daten) haben jetzt
denselben besonderen Stil wie vorher nur "Meine Daten": wanderndes Verlaufs-
licht in der eigenen Akzentfarbe, pulsierender Glanzrand, funkelndes
Sternchen und Farbverlauf-Text — nur die Farbe unterscheidet sich pro
Knopf. Der "Meine Daten"-Inhaltsbereich (Profilkarte) bekommt dieselbe
"mega besondere" Behandlung wie die Begrüßungs-Karte (wandernder Verlaufs-
rand, Farbschein, Glanz-Sweep, Sternchen). Bestellkarten bekommen einen
passenden dezenten Glanz-Sweep und pulsierenden Schein in ihrer Status-
farbe für ein stimmigeres Gesamtbild.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Die Zahl im "Bestellungen"-Kasten zeigte bisher alle Bestellungen, obwohl
der Tab selbst nur die angekommenen anzeigt. Jetzt stimmen Zahl und Liste
überein. "Offene Sendungen" zählt entsprechend alles, was noch nicht
abgeschlossen ist (nicht nur "versendet"), passend zum Tab-Filter.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der bisherige "Rechnung (PDF)"-Knopf war ein toter Link (href="#"). Jetzt
öffnet "Rechnung ansehen" pro Bestellung ein natives Dialog-Fenster direkt
auf der Seite mit vollständiger Rechnung: Rechnungsnummer/-datum,
Verkäufer, Rechnungsempfänger (live mit dem aktuellen Kontonamen befüllt),
Artikeltabelle mit Einzel-/Gesamtpreisen und dem §19-UStG-Hinweis — kein
Herunterladen nötig, schließbar per Kreuz, Schließen-Knopf oder Klick auf
den abgedunkelten Hintergrund.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Wandernder Mehrfarb-Verlaufsrand, sanfter Farbschein im Hintergrund, ein
Glanz-Sweep, der regelmäßig durchläuft, ein pulsierender Leucht-Ring um
den Avatar und zwei funkelnde ✨-Sternchen — dieselbe Formsprache wie beim
"Meine Daten"-Knopf, nur größer und ruhiger für gute Lesbarkeit.
Respektiert prefers-reduced-motion.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher zeigte der Bestellungen-Tab ALLE Bestellungen (Überschneidung mit
"Offene Sendungen"). Jetzt ist es eine echte Trennung: "Bestellungen"
zeigt nur bereits angekommene/abgeschlossene, "Offene Sendungen" nur die
noch nicht angekommenen. Eigene Leermeldung, falls noch keine Bestellung
angekommen ist.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der echte Name war bisher versehentlich ebenfalls editierbar. Jetzt steht
er als reine Anzeige in derselben Tabelle wie E-Mail und Lieferadresse —
änderbar bleibt ausschließlich der optionale Benutzername (Spitzname).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Sanft wanderndes Mehrfarb-Verlaufslicht im Hintergrund, pulsierender
Glanzrand, funkelndes ✨-Sternchen und ein Farbverlauf-Text — hebt sich
jetzt deutlich von den anderen drei Knöpfen ab, ohne kitschig zu wirken.
Respektiert prefers-reduced-motion.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher war "Bestellungen" beim Öffnen der Seite automatisch aktiv. Jetzt
ist standardmäßig KEIN Knopf gedrückt — man muss selbst auswählen, was man
sehen möchte. Solange nichts angeklickt ist, steht direkt "Zuletzt
angesehen" da. "Meine Daten" ist jetzt ein vierter, gleichwertiger Tab-
Knopf (👤, goldener Akzent) statt permanent sichtbar — genau wie
Bestellungen/Wunschliste/Offene Sendungen erscheint das Profilformular
erst nach Klick.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Die Schnellnav-Leiste sprang bisher nur zum Abschnitt (der Rest blieb
sichtbar). Jetzt sind es echte Filter-Tabs: Klick auf "Bestellungen" /
"Wunschliste" / "Offene Sendungen" blendet alle anderen Bereiche komplett
aus und zeigt nur den ausgewählten. "Offene Sendungen" filtert zusätzlich
innerhalb der Bestellungen auf noch nicht abgeschlossene. Der aktive Tab
bleibt farbig hinterlegt und unterstrichen erkennbar. Start-Ansicht:
Bestellungen-Tab aktiv.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Die drei losen "Bestellungen/Wunschliste/Offene Sendungen"-Kästchen waren
nur Zahlen ohne Verbindung zu den Abschnitten weiter unten. Jetzt sind sie
eine zusammenhängende Leiste direkt über "Meine Bestellungen" — jedes
Segment ist ein echter Sprunglink zum passenden Abschnitt (📦 Bestellungen,
🩵 Wunschliste, 🚚 Offene Sendungen), mit eigener Akzentfarbe je Segment und
einem Hover-Unterstrich, der die Klickbarkeit deutlich macht.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher unterschied sich der Status nur durch eine kleine, ähnlich gefärbte
Pille — auf einen Blick kaum zu erkennen. Jetzt bekommt jede Bestellkarte
einen eigenen farbigen Rand plus dezenten Farbschein passend zum Status
(Blau = versendet/unterwegs, Grün = abgeschlossen/angekommen, Gold = in
Bearbeitung/Versand wird vorbereitet, Violett = bezahlt), zusätzlich ein
Icon direkt in der Status-Pille (🚚 unterwegs, ✅ angekommen, usw.) — genau
wie schon bei den Zahlungskarten im Checkout.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher gab es nur ein "Benutzername"-Feld, das überall (Begrüßung, Header,
Rezensionen) angezeigt wurde. Jetzt gibt es zwei getrennte Felder: einen
festen "Name" (Pflichtangabe, z.B. für Bestellungen) und einen optionalen
"Benutzername (Spitzname)" als Bonus, falls man lieber mit einem Spitznamen
statt dem echten Namen angezeigt werden möchte.
Überall, wo bisher nur der Benutzername angezeigt wurde (Header-Konto-Menü,
Begrüßung im Dashboard, Rezensions-Autorenname, "angemeldet als"-Hinweis),
gilt jetzt: Spitzname bevorzugt, sonst echter Name als Rückfalloption
(neue anzeigeName()-Hilfsfunktion in scripts/account.ts).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Jede Zahlungsart-Karte hat jetzt einen deutlich sichtbaren Farbschein in
der jeweiligen Markenfarbe (auch im Ruhezustand, nicht erst bei Hover),
einen feinen Farbstreifen am oberen Rand und einen dezenten Glanz-Sweep
beim Hover — wirkt hochwertiger/"geiler", bleibt aber gedeckt genug fürs
dunkle Gesamtdesign. Kreditkarte (Visa/Mastercard) bekommt einen eigenen
Gold-Akzent statt der bisherigen, kaum sichtbaren Farbe.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Nach Recherche zu den Markenrichtlinien von PayPal, Klarna, Visa und
Mastercard: Zahlungsoptionen im Checkout zeigen jetzt echte Markenlogos in
den offiziellen Farben (PayPal- und Klarna-Icon, Visa-Wortmarke auf Weiß,
Mastercard-Kreise in Rot/Orange unverändert nebeneinander) statt grober
Buchstaben-/Emoji-Platzhalter — genau die Verwendung, die die jeweiligen
Markenrichtlinien für die Kennzeichnung akzeptierter Zahlungsarten
vorsehen. Dieselbe PayPal-Grafik jetzt auch beim Social-Login auf der
Anmeldeseite statt eines schlichten "P".
Zusätzlich: Ein Vorschau-Link auf der Anmeldeseite meldet mit einem Demo-
Konto an und führt direkt zum Kundenbereich-Dashboard — bleibt dauerhaft
erreichbar, damit VanVan und wir jederzeit sehen können, wie der Bereich
für angemeldete Kund:innen aussieht, ohne das Formular jedes Mal
auszufüllen.
Der Phase-1-Demo-Hinweis auf Checkout- und Anmeldeseite steht jetzt am
Ende der Seite statt direkt unter der Überschrift, damit zuerst der
fertige, professionelle Eindruck zählt.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Nach Recherche zu üblichen Anmelde-Standards bei deutschen Online-Shops:
Ergänzt Social-Login-Buttons für Google, Apple und PayPal (PayPal explizit
wegen seiner Marktdominanz bei Zahlungen in DE/DACH), da Social Login
Registrierung/Login deutlich beschleunigt und laut Studien die Conversion
spürbar erhöht. Die Buttons sind noch nicht funktional (kein OAuth ohne
eigenes Backend) — ein Klick zeigt stattdessen ehrlich einen Phase-2-
Hinweis, statt eine Anmeldung vorzutäuschen.
Zusätzlich: Passwort-Sichtbarkeits-Toggle (Augen-Icon, eine der
wirkungsvollsten Login-UX-Verbesserungen laut UX-Recherche), "Angemeldet
bleiben"-Checkbox, sowie ein DSGVO-konformer Hinweis mit Link zur
Datenschutzerklärung unterhalb des Formulars. Gastbestellung ("Neu hier?")
war als gleichwertige Alternative schon vorhanden und bleibt bestehen —
Gastbestellung gilt laut EDPB-Empfehlung als Standard neben der freiwilligen
Registrierung.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Beim Einbau der Kundenbewertungen in den Shop-Filter (voriger Commit) landete
ein "import" mitten in einem define:vars-Skript, das aber gar keine Module
unterstützt. Dadurch brach das komplette Filter-Skript auf allen 4 Sprachen
mit einem SyntaxError ab, sobald es geladen wurde – Kategorie-Dropdown,
Mindestbewertung-Dropdown und Sortierung reagierten dadurch gar nicht mehr
auf Klicks. Die lokal gespeicherten Kundenbewertungen werden jetzt in einem
eigenen, echten Modul-Skript direkt danach eingerechnet.
Zusätzlich: horizontaler Scrollbalken im Dropdown-Menü entfernt (nur noch
vertikal scrollbar), wie gewünscht.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Bisher musste VanVan Bewertungen manuell im CMS eintragen. Jetzt können
angemeldete Kund:innen Rezensionen direkt auf der Produktseite abgeben
(inkl. Herzen-Sternebewertung und Text). Die Durchschnittsbewertung wird
automatisch berechnet und überall live eingebunden: Produktkarten
(shop-weit), Produktdetailseite, Shop-Filter/Sortierung nach Bewertung
und die Kundenstimmen-Sektion auf der Startseite.
Neu dazu: ein Kontobereich fürs Login (Demo-Login per E-Mail), Profilfoto-
Upload, wählbarer Benutzername, und ein Header-Kontomenü, das nur bei
Anmeldung erscheint. Jede Bestellung im Konto-Dashboard hat einen
"Rezension schreiben"-Link, der direkt zur Produktseite führt und dort
per Bestellnummer verknüpft wird; im Profil ist dann sofort sichtbar,
welche Bestellungen schon bewertet wurden.
Technisch als reines Frontend/localStorage-System umgesetzt (kein Backend
in dieser Phase), analog zum bestehenden Warenkorb-Muster. Admin-CMS-Feld
für manuelle Bewertungen entfernt, da Rezensionen jetzt ausschließlich von
Kund:innen kommen (auch aus rechtlichen Gründen: keine Fake-Bewertungen).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Im Filter "Mindestbewertung" wurden bisher schlichte 🩵-Emojis angezeigt. Grund:
das war ein natives <select>, und in der browsereigenen Auswahlliste lassen
sich weder Farbverlaeufe noch eigene Grafiken darstellen - der Browser rendert
dort nur das System-Emoji in seiner festen hellblauen Farbe.
Ersetzt durch dasselbe eigene Dropdown, das schon der Kategorie-Filter nutzt.
Dadurch erscheinen jetzt die echten HeartRating-Herzen mit dem Marken-Verlauf
von Lila (--c-purple-glow) nach Babyblau (--c-accent) - auch im geschlossenen
Knopf, sobald eine Bewertung gewaehlt ist. Der Verlauf bekam zusaetzlich einen
weichen Zwischenton, damit er im kleinen Herz-Format nicht hart umschlaegt,
sondern wirklich wie eine Mischung beider Farben wirkt.
Die Dropdown-Logik ist dabei fuer BEIDE Filter zu einem gemeinsamen Code
zusammengefasst worden (statt zweimal fast dasselbe): beide verhalten sich
identisch, oeffnen sich gegenseitig zu, schliessen bei Klick daneben und bei
Escape - nur noch eine Stelle zum Pflegen.
Im Browser funktional geprueft: 5 Optionen, oeffnet/schliesst korrekt, 10
Verlaufsherzen in der Liste, Auswahl setzt den Filterwert und uebernimmt die
Herzen in den Knopf, gegenseitiges Schliessen funktioniert. Gilt fuer alle 4
Sprachen.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
1. Neue Seite /konto/angemeldet/ (alle 4 Sprachen): zeigt, was Kund:innen nach
dem Anmelden sehen - Begruessung, Kennzahlen, Bestellhistorie mit farbigem
Bestellstatus, Sendungsverfolgung (echter DHL-Link), Rechnung/Nochmal-
bestellen, Wunschliste, "Zuletzt angesehen" und Profildaten. Klar als
Vorschau gekennzeichnet: es gibt noch kein echtes Login und keine Datenbank
(Phase 2), die Bestellungen sind Beispieldaten fuer die Gestaltung. Von der
Login-Seite aus verlinkt, damit die Ansicht ueberhaupt erreichbar ist.
2. "Ueber die Kreative": der erste Abschnitt ihrer Geschichte ("Meine Reise
begann mit einer einzigen Masche") steht jetzt direkt neben dem Foto statt
darunter. Foto bleibt beim Lesen sichtbar (sticky), die restlichen
Abschnitte folgen wie bisher darunter.
3. Kategorie-Seiten: der farbige Kreis um das Emoji bei "Hauptkategorie" ist
entfernt, das Emoji steht jetzt frei neben der Ueberschrift.
Dabei gefundener und behobener eigener Fehler: das noetige "align-items: start"
fuer das neue Nebeneinander-Layout hat im gestapelten Handy-Layout die
Grid-Zeile zu niedrig berechnet, wodurch das Foto 80px in den Text darunter
ragte (per Messung im Browser nachgewiesen, nicht nur per Screenshot geraten).
Jetzt sauber auf Bildschirme ab 901px begrenzt - Handy misst 24px Abstand.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Neue HeartRating-Komponente (Herzen statt Sterne, Lila-Babyblau-Verlauf wie
der Rest der Markenoptik) + komplettes Rezensions-System:
- Produktkarten: Bewertungszeile (Herzen + Anzahl) unter dem Titel, nur wenn
Bewertungen vorhanden sind.
- Produktseite: volle "Kundenrezensionen"-Sektion mit Durchschnitt und
einzelnen Rezensionen (Name, Herzen, Datum, Text) bzw. "Noch keine
Bewertungen"-Hinweis.
- Shop-Filter: neuer "Mindestbewertung"-Filter im Filter-Sidebar + neue
Sortierung "Beste Bewertung".
- Startseite: "Was unsere Kund:innen sagen"-Sektion mit Gesamtbewertung und
den 3 neuesten Rezensionen - erscheint automatisch, sobald die erste echte
Bewertung existiert.
- Adminbereich: neues Feld "Bewertungen" pro Produkt (Name/Herzen/Text/Datum),
mit deutlichem Hinweis, dass hier nur echte Kundenrueckmeldungen eingetragen
werden duerfen - erfundene Bewertungen sind in Deutschland/der EU gesetzlich
verboten (UWG). Deshalb bewusst OHNE Beispiel-Bewertungen im Code: alle
Bereiche starten leer und blenden sich automatisch ein, sobald VanVan die
erste echte Rezension eintraegt.
Mit temporaeren Testdaten end-to-end durchgetestet (Herzen-Darstellung,
Rezensions-Section, Filter, Startseiten-Sektion) und vor dem Commit wieder
aus den echten Produktdaten entfernt. Gilt fuer alle 4 Sprachen.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Die zwei ueberlappenden Kreise (Visa/Mastercard-Anmutung) beim
Kreditkarte-Zahlungsoption wirkten wie ein fremdes Marken-Logo statt einem
neutralen eigenen Icon. Ersetzt durch ein schlichtes SVG-Kartensymbol, im
gleichen Stil wie die anderen Zahlungsarten-Icons (PayPal/Klarna).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Zwei Fotos betroffen:
1. "Ueber die Kreative"-Seite: eine alte, spezifischere CSS-Regel
(.intro .portrait-frame.portrait img) hat lautlos die bereits einmal
gefixte 2:3-Bildkorrektur wieder auf 1:1 zurueckgesetzt (per Computed-
Style-Debug bestaetigt: ratio war 1/1 statt 2/3). Diese Regel stammte aus
einem laengst ersetzten Layout (Foto+Text nebeneinander), das nirgends
mehr benutzt wird, ausser eben ungewollt hier durch geteilte Klassennamen.
aspect-ratio aus dieser Regel entfernt, die 2/3-Regel greift jetzt wieder.
2. Startseite "Die Kreative"-Bereich (vanvan-portrait.png, 1122x1402 ≈ 4/5):
nutzte noch die allgemeine 1:1-Regel und schnitt das Foto ebenfalls
quadratisch zu. Eigenes Seitenverhaeltnis (4/5) ergaenzt, width/height
Attribute korrigiert (640x800 statt 640x640) fuer korrekte Bildproportion
schon vor dem CSS-Laden.
Per Screenshot auf Desktop und Mobil verifiziert: beide Fotos jetzt komplett
sichtbar, inkl. Oktopus- und Schildkroeten-Plushie.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Der native <select> mit optgroups zeigte Kuh/Hase/Wal/Oktopus/Schildkroete/
Pinguin zwar technisch an, aber in der schmucklosen Browser-eigenen Liste
kaum erkennbar (kein Kontrast, keine Struktur). Ersetzt durch ein eigenes,
zum Rest der Seite passendes Dropdown (Verlaufsrand-Look wie beim
Sprach-Umschalter): Hauptkategorien mit Icon als Gruppen-Header, Tier-
Unterkategorien darunter eingerueckt mit denselben freundlichen Namen wie auf
den Kategorie-Seiten ("Kuh „Frieda"", "Hase „HasiDog"" usw.) statt schlichtem
Kategorienamen. Filterlogik, URL-Preset (?kategorie=) und Barrierefreiheit
(role=listbox/option, aria-selected) unveraendert erhalten. Gilt fuer alle 4
Sprachen, gebaut und per Screenshot in offenem und geschlossenem Zustand
geprueft.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Beide Beschriftungen waren identisch schlichter grauer Kleinschrift-Text, kaum
von normalem Fliesstext zu unterscheiden. Jetzt: "Unterkategorien" bekommt ein
kleines Icon + zwei kurze Verlaufslinien als dezenten Trenner, "Hauptkategorie"
zusaetzlich einen Farbverlaufs-Icon-Kreis (Kategorie-Icon) und einen schmalen
Leucht-Trenner darunter, der die eigentliche Produktreihe einleitet - bewusst
mit den schon vorhandenen Marken-Verlaufsfarben statt neuer Effekte.
Co-Authored-By: Claude Sonnet 5 <[email protected]>