- CF-Connecting-IP gilt nur noch als oeffentliche Unicast-Adresse
(nicht 0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12,
192.168/16, 240/4, Broadcast, ::, ::1, fc00::/7, fe80::/10,
::ffff:privat); sonst gilt die Gegenstelle.
- X-Real-IP ohne X-Forwarded-For nur noch ausserhalb von Produktion;
in Produktion ergibt das "unknown".
- Neuer Helfer headersWithClientIp, von withClientIp und der
Admin-Session-Pruefung genutzt: ein vom Client gesendeter
x-artista-client-ip-Wert wird nie geglaubt.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Bisher setzte jeder SMTP-5xx die Mail sofort auf FAILED, auch Anmelde-
und Richtlinienfehler (EAUTH, EMESSAGE, 552). Ein kaputtes SMTP-Secret
haette alle Buchungs- und Zahlungsmails verworfen, ohne Rueckweg
(dedupeKey verhindert erneutes Einreihen).
Endgueltig ist jetzt nur EENVELOPE mit 550, 551, 553, 556 oder 5xx mit
Status 5.1.x. Alles andere bleibt PENDING und wird bis
MAX_EMAIL_ATTEMPTS wiederholt.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
consumeRateLimit bekommt IPv6-Adressen als /64-Praefix (rateLimitSubject):
ein Anschluss hat meist ein ganzes /64 und koennte sonst durch Adresswechsel
jedes Limit umgehen. better-auth bekommt weiter die einzelne Adresse und
normalisiert sie selbst auf /64 (ipv6Subnet, Standard 64).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Traefik vertraut seit 2026-10-12 den weitergeleiteten Headern aus
Cloudflare-Netzen. Wer eine eigene Cloudflare-Zone auf den Server zeigen
laesst, konnte damit X-Real-IP und den ersten X-Forwarded-For-Eintrag
faelschen und die Rate-Limits (Buchung, Kontakt, Login, 2FA) umgehen.
- clientIp: Gegenstelle ist der letzte X-Forwarded-For-Eintrag (von Traefik
angehaengt); CF-Connecting-IP nur, wenn sie eine Cloudflare-Edge ist.
- better-auth liest nur noch x-artista-client-ip, den der Auth-Endpunkt
per withClientIp setzt (ein mitgeschickter Wert wird ersetzt).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Eine Mail an eine Adresse ohne Mailserver (SMTP 556, nullMX) wurde bis zu
8-mal erneut versendet und liess jeden Worker-Lauf mit Exit-Code 1 enden;
das SMTP-Fehlerlog enthielt dabei die Empfaengeradresse.
- SMTP-Antworten 5xx markieren die Mail sofort als FAILED, 4xx und
Verbindungsfehler bleiben wiederholbar.
- Adressen werden aus Log und lastError entfernt.
- Worker-CronJob: backoffLimit 0 (kein zweiter Pod je Fehlschlag) und
ttlSecondsAfterFinished 1 Tag, damit Fehler-Pods nicht stehen bleiben.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Gleiche Prüfung wie bei der Buchung: mindestens 6 Zeichen, nur Ziffern, Leerzeichen und + ( ) / -.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Vor dem 01.11.2026 gilt dann der Early-Bird-Preis. Fehlt eine Freigabe, bleibt die Vorschau.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Neuer Abschnitt nach den Fragen, im Menü als Erstgespräch. Anfrage geht als E-Mail an die Veranstalter-Adresse (Admin) bzw. ADMIN_NOTIFY_EMAIL, sofort zugestellt, sonst über den Worker wiederholt. Gleicher Schutz wie die Buchung: nur JSON von der eigenen Seite, Rate Limit (5/h je IP), Prüfung auf dem Server, Honeypot gegen Bots, doppeltes Absenden ergibt eine Mail. Keine automatische Mail an die angegebene Adresse (sonst Missbrauch für Spam an Dritte).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Das hochgeladene logo.png ist die helle Fassung und war auf der hellen Kopfzeile und im Fuß bis auf das goldene A unsichtbar. Die Seite misst jetzt die Helligkeit (sharp) und ordnet die Datei selbst zu; fehlt eine passende Fassung, wird per CSS abgedunkelt bzw. aufgehellt. Über dem Foto bis 176 px hoch mit weichem Schatten, nach dem Scrollen 80 px. Raster-Logos laufen über die Bildoptimierung (Original 5378 px, 313 KB).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Startet nur nach Klick; mit Vorschaubild (intro.jpg) lädt vorab nichts vom Video. Vorschaubilder von Intro und Reels laufen über die Bildoptimierung statt im Original, Videos bevorzugen eine Web-Fassung <name>.web.mp4.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Befunde aus dem Sicherheits-Review:
- Anhalten, Beenden und Abgleich der Ratenpläne fangen Fehler je Buchung ab.
Ein Stripe-Fehler bei einer Buchung bricht nicht mehr den ganzen
Worker-Lauf ab (E-Mails, Reservierungen liefen sonst nicht weiter).
Teilfehler setzen den Exit-Code 1, damit der CronJob-Lauf sichtbar
fehlschlägt.
- Beim Beenden eines Plans werden neben offenen Rechnungen auch Entwürfe
gelöscht. Laut Stripe-Testuhr bleibt ein Entwurf nach dem Beenden zwar
liegen und wird nicht eingezogen; das Löschen schließt das aus.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Befunde aus dem Sicherheits-Review des vorherigen Commits:
- Gerät eine Buchung in "Prüfung nötig" (Rückbuchung, Doppelzahlung ...),
wird der Stripe-Plan beendet und offene Rechnungen storniert. Nach
Bestätigung legt der Worker einen neuen Plan für die offenen Raten an.
Vorher zog Stripe auch bei Buchungen in Prüfung weiter ein.
- Vor dem Anlegen wird bei Stripe nach einem laufenden Plan der Buchung
gesucht; der Idempotenzschlüssel enthält Generation und Start. Verhindert
einen zweiten Plan nach verlorener ID und die Rückgabe des alten,
beendeten Plans nach einer Prüfung.
- Start bei bereits verstrichener Fälligkeit deterministisch am nächsten
9-Uhr-Termin, letzte Rate bleibt am Stichtag.
- Rückbuchungs-Event meldet die betroffene Buchung zurück.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Im Container (Linux) wurde z. B. reels/Reel-1.JPG nicht als Vorschaubild
erkannt, weil nur exakt reel-1.jpg gesucht wurde. Die Suche vergleicht
Dateinamen jetzt ohne Ruecksicht auf die Schreibweise und liefert den
echten Dateinamen aus. Gilt fuer Logo, Headerbild, Portraets und Videos.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- Figtree als einzige Schrift, Logo mittig in fester Kopfzeile
- Headerbild ueber volle Breite und Hoehe, ohne Preis, mit Terminleiste
- "Was dich erwartet" stellt die Villa mit animierter Bilderfolge vor,
darunter Tagesablauf als Karussell (Programm folgt als PDF)
- Preis: regulaerer Preis durchgestrichen, kein Verkaufsstartdatum,
Ueberschrift "Jetzt Platz sichern mit Early Bird"
- Team als "Mit dabei", danach drei Reels im Hochformat
- Logo, Headerbild, Portraets und Reels ueber feste Dateinamen im
Medienverzeichnis (docs/MEDIEN.md), ohne Neustart austauschbar
- Widerrufsbelehrung im Admin pflegbar, Seite /widerruf, Live-Verkauf
ohne Freigabe gesperrt
- Anreise: Abholung am Bahnhof Firenze Santa Maria Novella
- Booking-Link entfernt, Gedankenstriche aus Kundentexten entfernt
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- Team-Abschnitt mit neun Personen, Eric Heitz als Head of Modelcamp,
Portraets im Rundbogen mit Initialen-Platzhaltern bis Fotos vorliegen
- Unterkunftsbilder der Villa La Chiesina lokal in public/images/unterkunft
(vom Auftraggeber freigegeben), Hero-Leitbild, Ausstattung, Booking-Link
- Migration: Termin 08.05.-15.05.2027, Ort Arcidosso (Toskana), eigenes
Bett im geteilten Zimmer, 13 Plaetze; Admin-Werte bleiben erhalten
- Reveal: kein Hydration-Fehler mehr bei reduzierter Bewegung
- Doku zu offenen Punkten aktualisiert
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- ReviewsSection (Server Component) mit Durchschnitt, zugaenglichen
Sternen, Initialen statt Profilbildern, relativer Zeit, Links zur
Rezension und zum Maps-Eintrag sowie Hinweis "Rezensionen von Google"
- lange Texte optisch gekuerzt, "Weiterlesen" mit aria-expanded
- ohne Daten ausgeblendet; in Entwicklung/Staging ein Einrichtungshinweis
- Laden parallel zu loadPublicPage, Fehler blenden nur den Abschnitt aus
- Links aus der API-Antwort nur zu HTTPS-Google-Hosts (safeGoogleUrl)
- Linkstile und Browser-Oberflaechen (Scrollbar, Caret, Unterstreichung)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Muster wie Wabenhain (Feldmaske, 1 h Cache, 5 s Timeout, Schluessel im
Header). Ohne Konfiguration oder bei Fehler null, keine Ersatz-Stimmen.
Keine Profilbilder (kein IP-Transfer der Besucherinnen an Google),
Quellenlinks nur als https. Neue Variablen GOOGLE_PLACES_API_KEY und
GOOGLE_PLACE_ID in .env.example und Secret-Vorlage.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
next build versuchte /admin statisch zu rendern. currentAdmin() rief dabei
getAuth() vor headers() auf und scheiterte ohne BETTER_AUTH_SECRET im
Build-Container. Jetzt werden zuerst die Request-Header gelesen, wodurch
alle Admin-Routen dynamisch sind und Auth erst zur Laufzeit geladen wird.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>