Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m34s
Echter Datei-Upload statt CSS-Platzhaltergrafiken, gespeichert unter UPLOAD_DIR (Laufzeit-Verzeichnis, weiss nichts von seiner tatsaechlichen Speicher-Anbindung — in Produktion ein von der Betreiberin selbst per Kubernetes eingebundenes Volume, z.B. SMB; lokal ein simples ./uploads). - lib/uploads.ts: Kernlogik. Bildformat wird ausschliesslich aus den tatsaechlichen Bilddaten erkannt (Magic-Bytes via sharp), nie aus Client-Dateiname/MIME-Type. Zufaellige, nicht erratbare Dateinamen (Path-Traversal-/Overwrite-Schutz). Re-Encoding validiert Pixel-Daten vollstaendig und entfernt eingebettete Metadaten (EXIF/ICC/XMP) als Nebeneffekt. Content-Type beim Ausliefern kommt ausschliesslich aus einer festen Endung->MIME-Zuordnung, nie aus Dateiinhalt/-namen. - app/api/admin/upload/route.ts: Admin-only Upload-Endpunkt (CSRF- + Auth- + Rate-Limit-Pruefung, max. 8 MB, JPEG/PNG/WebP/AVIF). - app/uploads/[...path]/route.ts: liefert hochgeladene Bilder aus (public/ wird zur Build-Zeit fest ins Image gebacken, kann also keine zur Laufzeit hinzugefuegten Dateien bedienen) — mit Path-Traversal-Schutz und nosniff-Header. - content-registry.ts: neuer "image"-Feldtyp fuer Hero-/Startseite- Grafiken, admin/inhalte hat dafuer ein Upload-Widget. - Produkt-/Ernten-Admin-Formulare: Mehrfach-Bild-Upload fuer Product.images/Harvest.images (beide Felder existierten im Schema, hatten aber bislang keine Admin-Oberflaeche). Oeffentliche Seiten (Shop, Ernten, Chargen-QR-Seite) zeigen jetzt echte Fotos statt Platzhalter, sobald vorhanden. - Kubernetes: nur ein einfacher volumeMount in 05-app-deployment.yaml (Platzhalter-emptyDir, klar als CHANGE-ME markiert) — die eigentliche Volume-Quelle (SMB o.ae.) bindet die Betreiberin selbst ein, wie gewuenscht keine SMB/CSI-spezifischen Manifeste hinzugefuegt. Verifiziert: tsc --noEmit clean, 139/139 Tests gruen (21 neu), pnpm build clean. Upload-/Serving-Pipeline live gegen einen laufenden Server getestet (Auth-/CSRF-Gates, Path-Traversal-Ablehnung, Format-Ablehnung) — ein vollstaendiger authentifizierter Upload end-to-end (braucht echten Admin-Login inkl. 2FA) wurde nicht live durchgespielt, nur per Code-Review verifiziert. Co-Authored-By: Claude Sonnet 5 <[email protected]>
31 lines
1.4 KiB
YAML
31 lines
1.4 KiB
YAML
# Nicht-geheime Konfiguration. Geheimnisse (Passwoerter, API-Keys) gehoeren
|
|
# in 02-secret.yaml (aus 02-secret.example.yaml kopiert), NIE hierher.
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: wabenhain-config
|
|
namespace: wabenhain
|
|
data:
|
|
# "postgresql" oder "mysql" — muss zum Service passen, den du unter
|
|
# 03-postgres.yaml/03-mysql.yaml tatsaechlich ausrollst, UND zum
|
|
# DATABASE_URL-Host in 02-secret.yaml. Ein einzelnes Image traegt beide
|
|
# Prisma-Client-Varianten, siehe src/lib/prisma.ts.
|
|
DATABASE_PROVIDER: "postgresql"
|
|
NODE_ENV: "production"
|
|
# Oeffentliche URL des Shops (fuer absolute Links in E-Mails/Sitemaps/CSP).
|
|
NEXT_PUBLIC_SITE_URL: "https://shop.example.com"
|
|
SMTP_PORT: "587"
|
|
SMTP_FROM: "Wabenhain <[email protected]>"
|
|
# Optional, siehe README-Abschnitte "Google-Rezensionen"/"CAPTCHA" — leer
|
|
# lassen, wenn nicht genutzt, die App faellt automatisch zurueck.
|
|
GOOGLE_PLACES_API_KEY: ""
|
|
GOOGLE_PLACE_ID: ""
|
|
NEXT_PUBLIC_TURNSTILE_SITE_KEY: ""
|
|
# "sandbox" bis DHL-Versandmarken getestet sind, danach "production".
|
|
DHL_ENVIRONMENT: "sandbox"
|
|
# Verzeichnis fuer hochgeladene Bilder (Inhalte-/Produkt-/Erntenfotos,
|
|
# siehe app/api/admin/upload/route.ts) — MUSS exakt dem mountPath des
|
|
# "uploads"-Volumes in 05-app-deployment.yaml entsprechen. Die App selbst
|
|
# weiss nicht, was fuer ein Volume dort gemountet ist; siehe .env.example.
|
|
UPLOAD_DIR: "/app/uploads"
|