Commit Graph
59 Commits
Author SHA1 Message Date
Nick SzaunigandClaude Opus 5.5 f29dbcf392 fix(deps): High-Advisories schliessen
pnpm audit --prod meldete 5 high:
- next 16.3.6 -> 16.3.8, eslint-config-next mitgezogen
- sharp 0.35.5 direkt und per Override (next pinnt sonst 0.35.4)
- source-map-js >= 1.2.2 (transitiv ueber next)
- mysql2 >= 3.23.1 und deepmerge-ts >= 8.0.0 (prisma-CLI, gleiche
  Untergrenzen wie im Wabenhain-Repo)

Lokal geprueft: lint, typecheck, 132 Tests, next build gruen; audit sauber.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-14 09:02:55 +02:00
Nick SzaunigandClaude Opus 5.5 5a88f3dcd6 fix: Client-IP haerten (CF-Connecting-IP, X-Real-IP, Admin-Session)
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 8m8s
- 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]>
2026-10-12 11:26:56 +02:00
Nick SzaunigandClaude Opus 5.5 34ccbc3b9a fix: SMTP-Fehler nur bei Empfaengerablehnung endgueltig
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]>
2026-10-12 11:20:34 +02:00
Nick SzaunigandClaude Opus 5.5 e6fa383934 fix(security): eigene Rate-Limits zaehlen IPv6 je /64-Netz
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 7m24s
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]>
2026-10-12 10:06:28 +02:00
Nick SzaunigandClaude Opus 5.5 f75a5f7769 fix(security): Client-IP nicht aus X-Real-IP, better-auth nur mit Server-Wert
Docker-Images bauen und veroeffentlichen / build-and-push (push) Canceled after 0s
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]>
2026-10-12 09:49:58 +02:00
Nick SzaunigandClaude Opus 5.5 c3fdfbdc77 fix(worker): endgueltig abgelehnte Mails nicht wiederholen, Adressen nicht loggen
Docker-Images bauen und veroeffentlichen / build-and-push (push) Canceled after 0s
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]>
2026-10-12 09:24:28 +02:00
Nick SzaunigandClaude Opus 5.5 f2b548cb98 chore(k8s): Images auf CI-Build pinnen statt :latest
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 5m51s
App, Migration und Worker zeigen auf sha-<commit> mit
imagePullPolicy IfNotPresent. Damit gibt es ein Rollback per
rollout undo, und ein Neustart zieht nicht mehr ungeprueft das
neueste Image (oder scheitert, wenn Gitea gerade nicht laeuft).
README beschreibt das Ausrollen mit kubectl set image.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-12 05:27:47 +02:00
Nick SzaunigandClaude Opus 5.5 b725aa230c feat(k8s): taegliche pg_dump-Sicherung der Datenbank
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 7m39s
CronJob artista-db-backup schreibt per pg_dump auf die Storage Box
(StorageClass smb-backup, SMB 3.1.1 mit seal). 14 Tage taeglich,
8 Wochen sonntags.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-12 02:04:24 +02:00
Nick SzaunigandClaude Opus 5.5 d3a7f8b824 chore(k8s): CPU- und Speicher-Reservierung entfernen
Docker-Images bauen und veroeffentlichen / build-and-push (push) Canceled after 1m17s
Requests stehen explizit auf 0 statt zu fehlen, weil Kubernetes einen
fehlenden Request auf das Limit setzt und dann noch mehr reserviert.
Die Limits bleiben als Obergrenze.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 04:08:14 +02:00
Nick SzaunigandClaude Opus 5.5 98d1f7686c chore: postgres auf 18.6-alpine aktualisieren
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 6m47s
18.1 war fünf Minor-Releases alt. Minor-Updates sind binärkompatibel,
das Datenverzeichnis bleibt unverändert.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-10 02:02:55 +02:00
Nick SzaunigandClaude Opus 5.5 a47e91e9d5 feat: Telefonnummer im Kontaktformular ist Pflicht
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m50s
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]>
2026-10-07 00:56:30 +02:00
Nick SzaunigandClaude Opus 5.5 20adfaa97e feat: Gutschein-Detailseite zeigt, ob der Code gerade einlösbar ist und warum nicht
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m54s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 23:26:14 +02:00
Nick SzaunigandClaude Opus 5.5 7a3e37f96f feat: Buchungsdialog zeigt Preis erst unter der gewählten Zahlungsweise
Keine Vorauswahl mehr. Unter der gewählten Option stehen Preisaufstellung und Raten mit Fälligkeit; Weiter erst nach Auswahl.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 23:26:14 +02:00
Nick SzaunigandClaude Opus 5.5 5c2878875b feat: Buchung sofort möglich, sobald alle Freigaben erteilt sind
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m54s
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]>
2026-10-06 23:07:39 +02:00
Nick SzaunigandClaude Opus 5.5 a76a9cf616 fix: Teambilder in gerader Reihe, Tagesablauf-Karte auf dem Smartphone mittig
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 23:07:38 +02:00
Nick SzaunigandClaude Opus 5.5 2be1de6a63 fix: Intro-Video passt sich dem Format an, keine schwarzen Balken bei Hochformat
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 23:00:24 +02:00
Nick SzaunigandClaude Opus 5.5 7745d5862d feat: Kontaktformular für ein Erstgespräch
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 4m31s
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]>
2026-10-06 11:37:27 +02:00
Nick SzaunigandClaude Opus 5.5 d45700a9ef perf: Medien aufbereiten (pnpm media:optimize) und länger cachen
Ursachen der langen Ladezeiten: Reel-Video 1,6 GB in 4K mit Index am Dateiende, Headerbild 15 MB, Vorschaubild 1,3 MB im Original. Neues Skript erzeugt Web-Fassungen (<name>.web.mp4, 1080p, faststart; verkleinerte Bilder), die Seite bevorzugt sie automatisch. Mediendateien mit ?v= werden ein Jahr (immutable) gecacht, optimierte Bilder 30 Tage.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 07:17:31 +02:00
Nick SzaunigandClaude Opus 5.5 1ca09cbaef feat: Logo deutlich größer und auf jedem Untergrund sichtbar
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]>
2026-10-06 07:15:09 +02:00
Nick SzaunigandClaude Opus 5.5 33f5096bf1 feat: Video unter dem Headerbild aus dem Medienverzeichnis (intro.mp4)
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]>
2026-10-06 07:09:46 +02:00
Nick SzaunigandClaude Opus 5.5 51b6d79bbf fix: Tagesablauf – Zurück-Knopf funktioniert, Karten nicht mehr abgeschnitten
Positionen kommen aus getBoundingClientRect statt offsetLeft (bezog sich auf <body> und verfehlte den Einrastpunkt: Weiter sprang zwei Tage, Zurück hing am Ende). Weiter ist am Ende deaktiviert, Pfeile stehen über den Karten, ab md passen die Karten vollständig in den Inhaltsbereich.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 06:55:08 +02:00
Nick SzaunigandClaude Opus 5.5 df105aafca fix: Stefan Höchtl aus dem Team entfernt, Tennisplatz statt Küche bei der Ausstattung
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-06 06:51:24 +02:00
Nick SzaunigandClaude Opus 5.5 a28d18c3e6 fix: Worker übersteht Stripe-Fehler einzelner Buchungen, Rechnungsentwürfe beim Beenden löschen
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]>
2026-10-06 06:34:20 +02:00
Nick SzaunigandClaude Opus 5.5 1ce7947d93 fix: Stripe-Ratenplan bei Prüfung anhalten, doppelte Pläne verhindern
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]>
2026-10-06 06:28:41 +02:00
Nick SzaunigandClaude Opus 5.5 c1ad9ad2ca feat: Folgeraten über Stripe Billing einziehen
Statt eigener Off-Session-Einzüge durch den Worker legt die Anwendung nach
bezahlter erster Rate einen Stripe Subscription Schedule an. Stripe übernimmt
Einzug, Wiederholungen (Smart Retries), 3-D-Secure-Links und Mahnungen.

- Gateway: Zeitplan anlegen/beenden, Rechnungen lesen; chargeOffSession entfällt
- Webhook: invoice.paid, invoice.payment_failed, invoice.payment_action_required
- Worker: fehlende Zeitpläne anlegen, überfällige Raten abgleichen,
  Zeitpläne stornierter Buchungen beenden
- Storno beendet den Zeitplan und storniert offene Rechnungen
- "Rate bezahlen" führt auf Stripes Rechnungsseite
- Migration: Booking.stripeScheduleId, Installment.stripeInvoiceId

Zeitplan-Form mit Stripe-Testuhr gegen die Test-API geprüft.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-05 23:52:43 +02:00
Nick SzaunigandClaude Opus 5.5 bcf0f5c937 fix: Medien unabhaengig von Gross- und Kleinschreibung finden
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m53s
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]>
2026-10-02 06:37:00 +02:00
Nick SzaunigandClaude Opus 5.5 a37f12a60f fix: Logo deutlich groesser, Video im eigenen Seitenverhaeltnis
- Logo ueber dem Headerbild bis 112 px hoch, nach dem Scrollen 64 px,
  im Fussbereich 80 px; Kopfzeile waechst mit
- Videos aus dem Medienverzeichnis direkt mit Steuerleiste, quer oder
  hoch, erstes Bild als Vorschau; ein einzelnes Video breit und mittig
- Abschnitt heisst "Stimmen": Models erzaehlen, wie sie ARTISTA erleben

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 06:30:08 +02:00
Nick SzaunigandClaude Opus 5.5 84c8f2f32b feat: Tagesablauf laut Wochenplan, Termin 03. bis 09. Mai 2027
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m51s
- Alle sieben Tage aus dem Wochenplan-PDF mit Uhrzeit, Coach und
  Foto-Kennzeichnung im Karussell
- Migration: Camp-Termin 03.05. bis 09.05.2027 (ersetzt 08. bis 15.05.)
- Leistungen laut PDF: 20 Workshops und Shootings, sechs Naechte,
  Bustransfer ab und bis Florenz, Fruehstueck, Snacks und Abendessen
- FAQ Anreise mit Transferzeiten
- Hinweise "Programmentwurf" und "Laut Beschreibung der Unterkunft" entfernt

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 05:49:33 +02:00
Nick SzaunigandClaude Opus 5.5 3f5a2554ee chore: Design-Pruefung, Scroll-Hinweis nicht als Bounce-Easing werten
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m41s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-01 23:54:28 +02:00
Nick SzaunigandClaude Opus 5.5 5c4b8be7ff test: Widerrufsbelehrung als Voraussetzung fuer den Live-Verkauf
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-01 23:53:40 +02:00
Nick SzaunigandClaude Opus 5.5 7203cd1e6e feat: Onepage nach Filmcamp-Gliederung umgebaut
- 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]>
2026-10-01 23:53:18 +02:00
Nick SzaunigandClaude Opus 5.5 3cba3e2341 docs: Testlauf nach Team- und Unterkunftsumbau
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m42s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-01 18:39:42 +02:00
Nick SzaunigandClaude Opus 5.5 efd047b993 feat: Social-Vorschau mit Luftbild der Villa
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-01 18:31:04 +02:00
Nick SzaunigandClaude Opus 5.5 804bb832ea feat: Team, Villa-Bilder und bestaetigte Camp-Eckdaten
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m49s
- 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]>
2026-10-01 07:39:27 +02:00
Nick SzaunigandClaude Opus 5.5 28663cda7a fix(k8s): ACME-HTTP01-Challenge im eigenen Ingress (edit-in-place)
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m53s
cert-manager legte die Challenge in einem separaten Ingress ohne TLS an.
Die HTTP->HTTPS-Umleitung schickte die Pruefung auf HTTPS, wo nur die App
antwortete ("expected <token> but got <!doctype html>"), das Zertifikat
wurde nie ausgestellt und Traefik zeigte sein Default-Zertifikat.
Mit http01-edit-in-place landet der Challenge-Pfad im App-Ingress und
gilt damit auch unter HTTPS.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-29 06:18:39 +02:00
Nick SzaunigandClaude Opus 5.5 6a9c6c8e50 docs: Gestaltung um Rezensionen, Platzhalter-Tafeln und Formregeln ergaenzt
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 3m7s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 17:46:47 +02:00
Nick SzaunigandClaude Opus 5.5 2ef92db9ed style: Hero, Leistungen und Abschnittsrhythmus ueberarbeitet
- Hero: Schlagzeile zweizeilig direkt unter dem Masthead, Buchung im
  ersten Bildschirm; Termin, Ort und Preis als Cover-Line-Leiste
- Leistungen: Inklusivleistungen in Bodoni ohne Linie unter jeder Zeile,
  Beispielablauf ruhiger, Hinweis unter statt neben der Ueberschrift
- Unterkunft ohne Split-Header, Ueber ARTISTA kompakter
- FAQ-Symbol gezeichnet statt Textzeichen, groesserer Abschnittsabstand
- Header auf Mobil ohne doppeltes "Modelcamp 2027"

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 17:46:30 +02:00
Nick SzaunigandClaude Opus 5.5 00c7118c10 style: Platzhalter als typografische Tafeln statt Verlaufsflaechen
Beige Verlaeufe mit Bogen- und Silhouettenformen wirkten wie generische
Fuellbilder. Jetzt: ruhiger Palettenton, feine Papierstruktur,
Passepartout und ein angeschnittener Bodoni-Buchstabe aus "ARTISTA"
(Cover: Jahreszahl), skaliert ueber Container-Einheiten. Eindeutig kein
Foto, in Produktion ohne Label. Galerie etwas flacher.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 17:46:29 +02:00
Nick SzaunigandClaude Opus 5.5 f74a08fa68 feat: Google-Rezensionen als eigener Abschnitt auf der Onepage
- 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]>
2026-09-28 17:46:19 +02:00
Nick SzaunigandClaude Opus 5.5 b4eafbe433 feat: Google-Rezensionen ueber Places API (New) abrufen
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]>
2026-09-28 17:30:30 +02:00
Nick SzaunigandClaude Opus 5.5 66247cfbf9 fix(security): NetworkPolicy vor der App wieder aktiv (Traefik in kube-system)
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m53s
Traefik laeuft im Cluster in kube-system ohne Host-Netzwerk (geprueft).
Die App ist damit nur noch fuer Traefik-Pods aus kube-system erreichbar
(Namespace + Label), was die Umgehung der Login-/2FA-Rate-Limits per
gefaelschtem X-Real-Ip aus anderen Pods verhindert.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 11:34:36 +02:00
Nick SzaunigandClaude Opus 5.5 67cdddc33f docs: Betriebsdoku auf neue k8s-Dateinamen und Pod-Security-Stufe
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m57s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 11:26:29 +02:00
Nick SzaunigandClaude Opus 5.5 a0ba921d19 refactor(k8s): Aufbau wie Wabenhain/ApiCore, Zertifikat funktionsfaehig
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 3m2s
- Dateinamen nach Wabenhain-Schema (01-configmap, 02-secret,
  03-storage, 04-postgres, 05-app-deployment, 06-ingress,
  07-worker-cronjob, 08-networkpolicy); Secret-Vorlage als
  02-secret.yaml.example, echte 02-secret.yaml gitignored.
- Namespace: Pod Security "baseline" erzwungen, "restricted" als warn/audit.
  "restricted" kann den HTTP-01-Solver-Pod von cert-manager abweisen und
  damit die Zertifikatsausstellung blockieren.
- NetworkPolicy nur noch fuer PostgreSQL; keine Policy vor der App (wie
  Wabenhain/ApiCore), da sie bei Traefik im Host-Netzwerk die Seite sperrt.
- README: kompletter Neuaufbau inkl. Freigabe der Retain-PVs nach
  "kubectl delete namespace", Zertifikats-Diagnose.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 11:26:13 +02:00
Nick SzaunigandClaude Opus 5.5 d813d56514 fix(security): NetworkPolicy der App an Namespace und Label binden
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m52s
Nur Label-Abgleich ueber alle Namespaces liess jeden Pod mit Label
app.kubernetes.io/name=traefik zu. Jetzt muss zusaetzlich der Namespace
traefik oder kube-system sein (Namespace-Namen sind nicht faelschbar).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 11:02:22 +02:00
Nick SzaunigandClaude Opus 5.5 9c7d2d02a2 docs(k8s): Deployment Schritt fuer Schritt wie bei Wabenhain
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m53s
Voraussetzungen pruefen (Traefik, cert-manager, csi-driver-smb),
Einzel-Applies in Reihenfolge mit kubectl wait auf Postgres,
Fehlersuche fuer Migration, App und Zertifikat.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 06:33:47 +02:00
Nick SzaunigandClaude Opus 5.5 cddc36bee8 feat(k8s): Ingress, Zertifikat und Netzwerk nach Muster Wabenhain/ApiCore
- Ingress: HTTP->HTTPS-Middleware redirect-to-https wieder am Ingress
  (wie Wabenhain), Service-Port als Nummer, cert-manager letsencrypt-prod.
- NetworkPolicy: Traefik ueber das Pod-Label (traefik/rke2-traefik) in
  jedem Namespace erkannt statt fester Namespace "traefik" - verhindert,
  dass die Seite unerreichbar wird, wenn Traefik z. B. in kube-system laeuft.
- README: Voraussetzungen pruefen und Deployment Schritt fuer Schritt
  (kubectl wait auf Postgres) wie bei Wabenhain.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 06:33:22 +02:00
Nick SzaunigandClaude Opus 5.5 b9d6f089c9 fix(docker): Prisma-Schema-Engine und OpenSSL im Tools-Image
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 4m31s
Der Migrations-initContainer scheiterte: "pnpm install --ignore-scripts"
ueberspringt das postinstall von @prisma/engines, das die Schema-Engine
fuer "prisma migrate deploy" herunterlaedt. Der Builder holt das jetzt mit
"pnpm rebuild @prisma/engines prisma" nach. Zusaetzlich openssl in der
Basisstufe, weil die Engine unter Alpine libssl braucht.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 02:28:51 +02:00
Nick SzaunigandClaude Opus 5.5 32a5b8eb9d fix(security): Haertung der minimalen k8s-Manifeste wiederhergestellt
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m24s
Befunde des Commit-Security-Reviews: automountServiceAccountToken: false
fuer Postgres, App und Worker; Speicherlimits fuer Migrations-initContainer
und Worker; Laufzeitgrenze (activeDeadlineSeconds) fuer den Worker;
Groessenlimits fuer die emptyDir-Volumes.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 01:15:55 +02:00
Nick SzaunigandClaude Opus 5.5 91791b791f refactor(k8s): minimale, flache Manifeste zum Kopieren
Kustomize-Struktur (base/overlays) entfernt. Stattdessen nummerierte
Einzeldateien, ausrollbar mit "kubectl apply -f k8s/":
00-namespace, 01-config, 02-storage (SMB-PVs/PVCs Postgres + Medien),
03-postgres (StatefulSet + Service), 04-app (Deployment mit
Migrations-initContainer + Service), 05-ingress, 06-worker,
07-networkpolicy. Secrets als secrets.yaml.example (echte secrets.yaml
ist gitignored). Images mit Tag latest aus der Gitea-Pipeline.
Kurzanleitung in k8s/README.md, Betriebsdoku angepasst.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 01:12:26 +02:00
Nick SzaunigandClaude Opus 5.5 c84eb1e740 refactor(k8s): schlanker Umfang, Postgres und Medien auf SMB
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m17s
Auf Wunsch des Betreibers auf das Noetige reduziert: StatefulSet
PostgreSQL, Services, Ingress, App-Deployment, zwei SMB-PersistentVolumes
(Postgres-Daten, Medien). Beibehalten nach Absprache: Worker-CronJob
(Folgeraten, Reservierungsfreigabe, Mail-Wiederholung), ConfigMap und die
NetworkPolicies (Sicherheitsbefund Rate-Limit-Umgehung).

- Migration als initContainer im App-Deployment statt eigenem Job
- Entfernt: Backup-CronJob/-Volume (NAS sichert die Freigabe),
  Migrations-CronJob, PodDisruptionBudget, HTTP-Redirect-Ingress und
  Middleware, Namespace-Objekt (einmalig von Hand anzulegen)
- PostgreSQL auf SMB als bewusste, dokumentierte Ausnahme mit
  hard, cache=strict, SMB 3.1.1 + seal, uid 70 / 0700

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 20:36:30 +02:00
Nick SzaunigandClaude Opus 5.5 974c403a8b docs: SMB-Verschluesselung und Rechte der Volumes beschrieben
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m39s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 20:14:58 +02:00
Nick SzaunigandClaude Opus 5.5 7a60af9cd4 fix(security): SMB-Volumes verschluesselt und minimal berechtigt
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m40s
Befunde des Commit-Security-Reviews behoben:
- Klartextuebertragung: vers=3.1.1 mit "seal" (SMB3-Verschluesselung)
  fuer Medien- und Backup-Volume.
- Rueckschritt Zugriffskontrolle: Backup-PV/PVC wieder ReadWriteOnce statt
  ReadWriteMany (nur der Backup-Job haengt es ein).
- Zu weite Rechte: Medien-Volume nur lesbar (dir_mode 0550, file_mode
  0440); geschrieben wird ausschliesslich ueber das NAS.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 20:14:44 +02:00
Nick SzaunigandClaude Opus 5.5 a7c11ccbd0 docs: Einrichtung der SMB-Volumes im Betriebshandbuch
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 1m50s
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 20:11:20 +02:00
Nick SzaunigandClaude Opus 5.5 24939b58d5 feat: SMB-PersistentVolumes fuer Medien und Datenbank-Sicherungen
Statische PVs ueber csi-driver-smb (smb.csi.k8s.io), fest an die PVCs
artista-modelcamp-media (App liest, uid 1001) und
artista-modelcamp-db-backup (pg_dump-Job, uid 70, 0700/0600) gebunden,
reclaimPolicy Retain. Zugang ueber Secret artista-modelcamp-smb.
Das PostgreSQL-Datenverzeichnis bleibt bewusst auf Blockspeicher
(SMB erfuellt dessen Sperr- und fsync-Anforderungen nicht, Briefing §13);
die Datenbank landet ueber die taeglichen Dumps trotzdem auf dem NAS.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 20:11:04 +02:00
Nick SzaunigandClaude Opus 5.5 95e3733ab8 refactor: Kubernetes-Ressourcen und Images heissen artista-modelcamp
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m19s
Alle Ressourcen tragen den Praefix artista-modelcamp- im Namespace
artista; Images <owner>/artista-modelcamp und
<owner>/artista-modelcamp-tools. DATABASE_URL-Host, Backup-Host,
Traefik-Middleware-Referenz und Betriebsdoku entsprechend angepasst.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 14:38:37 +02:00
Nick SzaunigandClaude Opus 5.5 f9349144ea refactor: Kubernetes-Ressourcen und Images heissen artista-filmcamp
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 4m39s
Alle Ressourcen tragen den Praefix artista-filmcamp- (Deployment,
Service, StatefulSet, CronJobs, PVCs, ConfigMap, Secret, Ingress,
NetworkPolicies, Middleware) und liegen im Namespace artista. Die Images
heissen wieder <owner>/artista-filmcamp und <owner>/artista-filmcamp-tools,
passend zum Repo. DATABASE_URL-Host, Backup-Host und Betriebsdoku
entsprechend angepasst.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 14:15:12 +02:00
Nick SzaunigandClaude Opus 5.5 c18c628131 fix: Image-Namen auf artista-modelcamp statt Repo-Namen "Filmcamp"
Die Pipeline leitete den Image-Namen vom Repo "Artista-Filmcamp" ab. Das
Produkt ist das ARTISTA MODELCAMP 2027: Images heissen jetzt fest
<owner>/artista-modelcamp und <owner>/artista-modelcamp-tools, passend zu
Overlay und Betriebsdoku.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 13:26:29 +02:00
Nick SzaunigandClaude Opus 5.5 771eeee887 fix: Admin-Routen nicht vorab rendern (Docker-Build ohne Secrets)
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 4m25s
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]>
2026-09-27 12:42:25 +02:00
Nick Szaunig 59bb5a38a3 first commit
Docker-Images bauen und veroeffentlichen / build-and-push (push) Failing after 1m32s
2026-09-27 06:06:56 +02:00