# Nicht-geheime Konfiguration. Geheimnisse (Passwoerter, API-Schluessel) # gehoeren in 02-secret.yaml, NIE hierher: eine ConfigMap ist unverschluesselt # und in der Cluster-Oberflaeche im Klartext lesbar. # # ANPASSEN vor dem ersten Ausrollen: NEXT_PUBLIC_SITE_URL und SMTP_FROM. Alle # uebrigen Werte sind sinnvolle Vorgaben und koennen so bleiben; die leeren # ("") gehoeren zu optionalen Funktionen, die dann einfach ruhen. # # Zusammen mit 02-secret.yaml deckt diese Datei JEDE Umgebungsvariable ab, die # die Anwendung liest. Die Vollstaendigkeit wird automatisch geprueft, siehe # src/lib/k8s-manifest-env.test.ts — kommt im Code eine neue Variable dazu, # faellt das beim naechsten "pnpm test" auf, nicht erst im Betrieb. apiVersion: v1 kind: ConfigMap metadata: name: wabenhain-config namespace: wabenhain data: # --------------------------------------------------------------------- # ANPASSEN # --------------------------------------------------------------------- # Oeffentliche Adresse des Shops. Einzige Quelle fuer Sitemap, # Canonical-Tags, JSON-LD und JEDEN Link in JEDER E-Mail (src/lib/url.ts). # Muss zum "host" in 06-ingress.yaml passen — mit https, ohne # abschliessenden Schraegstrich. NEXT_PUBLIC_SITE_URL: "https://wabenhain.com" # Absenderadresse aller Transaktions-E-Mails. Sollte auf einer eigenen # Domain liegen, sonst landen die Mails regelmaessig im Spam-Ordner. # Muss die Adresse des Postfachs aus SMTP_USER (Secret) sein — der Versand # laeuft ueber Microsoft 365 mit OAuth 2.0, siehe README "E-Mail-Versand". SMTP_FROM: "Wabenhain " # --------------------------------------------------------------------- # VORGABEN — koennen so bleiben # --------------------------------------------------------------------- NODE_ENV: "production" # "postgresql" oder "mysql" — muss zu dem Datenbank-Manifest passen, das du # tatsaechlich ausrollst (03-postgres.yaml bzw. 03-mysql.yaml), UND zum # Schema in DATABASE_URL im Secret. Ein einzelnes Image traegt beide # Prisma-Client-Varianten, siehe src/lib/prisma.ts. DATABASE_PROVIDER: "postgresql" # Gleichzeitig offene Datenbankverbindungen JE INSTANZ. Leer = 20. # # Beim Hochskalieren mitdenken: der Wert multipliziert sich mit "replicas" # in 05-app-deployment.yaml. Drei Instanzen mit je 20 belegen 60 der # voreingestellt 100 Verbindungen von PostgreSQL — daneben brauchen der # Aufraeum-CronJob, die Sicherung und gelegentlich eine Konsole noch # welche. Entweder diesen Wert senken oder max_connections anheben. DATABASE_POOL_SIZE: "20" # Verzeichnis fuer hochgeladene Bilder und Videos. MUSS exakt dem mountPath # des "uploads"-Volumes in 05-app-deployment.yaml entsprechen — die App # weiss nicht, was dort gemountet ist, sie schreibt nur in diesen Pfad. # Fehlt der Wert, schreibt die App nach "./uploads" relativ zum # Arbeitsverzeichnis: das trifft im Image zufaellig denselben Ort, ist aber # nirgends zugesichert. Deshalb hier ausdruecklich setzen. UPLOAD_DIR: "/app/uploads" # Ablage der Rechnungs-PDFs, nach Jahr und Kunde sortiert: # /app/invoices/2026/mustermann-erika/RE-2026-A3F9C1B2.pdf # Muss zum mountPath des "invoices"-Volumes in 05-app-deployment.yaml # passen. BEWUSST ein anderes Verzeichnis als UPLOAD_DIR: auf die Uploads # zeigt eine oeffentliche Route, auf dieses Verzeichnis keine. Siehe # src/lib/invoice-storage.ts und 04-uploads-pvc.yaml. INVOICE_DIR: "/app/invoices" # Urkunden-PDFs der Bienenpatenschaft (src/lib/sponsorship/storage.ts): # /app/invoices/urkunden/2026/WH-P-2026-00042/r1.pdf # Unterordner des Rechnungs-Volumes: ebenso privat (keine oeffentliche Route # zeigt dorthin), ebenso taeglich gesichert (07-backup-cronjob.yaml sichert # das ganze Volume), und kein zweites ReadWriteOnce-Volume am App-Pod. Die # Pfade der Rechnungen beginnen mit dem Jahr, "urkunden" kollidiert nicht. CERTIFICATE_DIR: "/app/invoices/urkunden" # Hintergrundaufgaben im App-Prozess (src/lib/background-jobs.ts): Urkunden # nachholen, Abo-Lieferungen anlegen, Verzug nach Rueckbuchung beenden. # Laufen im App-Pod, weil nur er das Volume mit CERTIFICATE_DIR einhaengt. # "off" nur fuer zusaetzliche Instanzen, die keine Aufgaben uebernehmen sollen. BACKGROUND_JOBS: "on" # Stripe-Kundenportal fuer "Zahlungsart aendern" im Abo (bpc_..., kein # Geheimnis). Legt scripts/stripe-setup.ts --apply an und gibt die ID aus. # Leer lassen ist der Normalfall: dann sucht die App die Konfiguration ueber # ihre Metadaten (wabenhain=abo-zahlungsart). Gibt es keine, bietet das Konto # "Zahlungsart aendern" nicht an — die Standardkonfiguration von Stripe wird # bewusst nie benutzt, weil sie Kuendigung oder Tarifwechsel erlauben koennte. STRIPE_PORTAL_CONFIGURATION_ID: "" # Umsatzsteuersatz in GANZEN Prozent, der auf der Rechnung ausgewiesen wird. # 7 = ermaessigter Satz (Honig als Lebensmittel, Anlage 2 zum UStG) # 19 = voller Satz # 0 = Kleinunternehmerregelung; die Rechnung traegt dann statt der # Steuerzeilen den Pflichthinweis nach § 19 UStG # # Die Shop-Preise sind BRUTTOPREISE (§ 1 PAngV). Die Steuer wird daraus # herausgerechnet, nicht aufgeschlagen — der Endpreis bleibt also genau der, # den die Kundschaft im Warenkorb gesehen hat. # # Der Satz wird bei jeder Rechnung FESTGESCHRIEBEN. Eine Aenderung hier gilt # nur fuer kuenftige Rechnungen; bereits ausgestellte behalten ihren Satz. VAT_RATE_PERCENT: "7" # Satz je Kategorie. Der Steuersatz haengt an der Art der Ware: Honig ist # ein Lebensmittel und ermaessigt besteuert, eine Bienenwachskerze nicht. # Fehlt hier ein Wert, gilt VAT_RATE_PERCENT von oben. # # PROPOLIS bitte pruefen: als Lebensmittel waeren 7% richtig, als # Nahrungsergaenzungs- oder Kosmetikprodukt 19%. Voreingestellt ist der # volle Satz, weil er im Zweifel der sicherere ist. VAT_RATE_PERCENT_HONIG: "7" VAT_RATE_PERCENT_KERZEN: "19" VAT_RATE_PERCENT_PROPOLIS: "19" # Weitere Bienenprodukte (Kategorie SONSTIGES, z. B. Salben, Wachstuecher). VAT_RATE_PERCENT_SONSTIGES: "19" # Bienenpatenschaft (Urkunde, Namensgebung, Abo-Monatsbeitrag ohne # Honiganteil): Leistung zum Regelsatz. Vor der Veroeffentlichung mit der # Steuerberatung bestaetigen (Spec, "Geschaeftliche Konfiguration"). VAT_RATE_PERCENT_PATENSCHAFT: "19" # Threads fuer das Umrechnen hochgeladener Videos (Admin -> Inhalte -> # Hero-Video). NICHT ohne Not erhoehen: ffmpeg teilt sich das Speicherlimit # dieses Pods mit dem Node-Prozess, und jeder zusaetzliche Thread haelt # eigene Bildpuffer — bei 4K-Material rund 12 MB je Bild. Zu viele Threads # bringen den Pod beim Video-Upload um. Siehe src/lib/video-transcode.ts. VIDEO_TRANSCODE_THREADS: "2" # "sandbox", bis die DHL-Versandmarken getestet sind, danach "production". # Wirkt nur, wenn die DHL-Zugangsdaten im Secret gesetzt sind. DHL_ENVIRONMENT: "sandbox" # Oeffentlicher Stripe-Schluessel (pk_live_...) fuer das eingebettete # Zahlungsformular. Nicht geheim — er steht ohnehin im HTML der Kasse. # Muss zum STRIPE_SECRET_KEY im Secret passen (beide live). Leer = der # Checkout nimmt keine Bestellungen an. STRIPE_PUBLISHABLE_KEY: "" # --------------------------------------------------------------------- # OPTIONAL — leer lassen, solange die Funktion nicht genutzt wird # --------------------------------------------------------------------- # Oeffentlicher Teil von Cloudflare Turnstile (CAPTCHA). Der geheime # Gegenpart TURNSTILE_SECRET_KEY steht im Secret — beide setzen oder beide # leer lassen. Leer = kein CAPTCHA-Widget, die Formulare bleiben nutzbar. NEXT_PUBLIC_TURNSTILE_SITE_KEY: "" # Google-Eintrag, aus dem die echten Rezensionen auf der Startseite kommen. # Die Place-ID ist oeffentlich (sie steckt in jeder Google-Maps-Adresse des # Eintrags) und darf deshalb hier stehen; der abrechenbare # GOOGLE_PLACES_API_KEY liegt im Secret. Leer = statische Beispiel-Stimmen. GOOGLE_PLACE_ID: "" # Adresse der ApiCore-API fuer den Stammdaten-Sync (Ernten, Produkte, # Chargen — siehe src/lib/apicore-client.ts), mit dem globalen Praefix # "api", z.B. "https://apicore.example.org/api". Nur die Adresse; die # Zugangsdaten des Sync-Kontos liegen im Secret. Leer = der Sync-Knopf im # Admin meldet einen Konfigurationsfehler. APICORE_API_URL: ""