Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m25s
Mail now uses the same Entra ID app registration as "Sign in with Microsoft" (ENTRA_TENANT_ID, ENTRA_CLIENT_ID, ENTRA_CLIENT_SECRET), so only one enterprise application is needed. The app additionally gets the SMTP.SendAsApp permission; Exchange still limits it to the mailbox granted via Add-MailboxPermission. Password (basic auth) sending is removed entirely: SMTP_HOST, SMTP_PORT, SMTP_PASSWORD and the separate SMTP_OAUTH_* settings are gone. The transport is fixed to smtp.office365.com:587 with required STARTTLS. SMTP_USER (sending mailbox) and SMTP_FROM remain. - lib/entra.ts exposes readEntraAppCredentials(), shared by SSO and mail - diagnosis drops basic-auth-only causes; hints name the ENTRA_* values and warn that an expired secret breaks sign-in and mail together - admin e-mail test, .env.example, docker-compose, k8s manifests, preflight and README updated Verified against Entra ID with fake values: token error classified, client secret never exposed, missing ENTRA_CLIENT_SECRET reported. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
135 lines
6.6 KiB
YAML
135 lines
6.6 KiB
YAML
# 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 <[email protected]>"
|
|
|
|
# ---------------------------------------------------------------------
|
|
# 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"
|
|
|
|
# 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"
|
|
|
|
# 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: ""
|