docs: Konfigurationsvorlagen vollstaendig und uebernahmefaehig machen
01-configmap.yaml und 02-secret.example.yaml sind jetzt so geschrieben, dass sie sich als Produktivkonfiguration uebernehmen lassen: in drei Abschnitte gegliedert (ANPASSEN / Vorgaben / optional), jeder Wert mit der Angabe, was ohne ihn nicht funktioniert. Anzupassen sind genau zwei Werte in der ConfigMap und die mit "CHANGE-ME" markierten im Secret; alles Uebrige traegt eine brauchbare Vorgabe oder darf leer bleiben. Beide Dateien decken zusammen jede Umgebungsvariable ab, die die Anwendung liest, und jeder Schluessel steht in genau einer der beiden. Bisher war das Handarbeit und driftete: GOOGLE_PLACES_API_KEY lag in der unverschluesselten ConfigMap, APICORE_API_URL unnoetig im Secret. Neu ist deshalb src/lib/k8s-manifest-env.test.ts. Der Test liest die process.env-Zugriffe unter src/ und die Schluessel der beiden Manifeste und prueft vier Zusagen: keine gelesene Variable fehlt, kein Schluessel steht doppelt (sonst entschiede allein die Reihenfolge der envFrom-Eintraege, welcher Wert gewinnt), kein Schluessel ist tot, und die committete Secret-Vorlage enthaelt keine ausgefuellten Werte. Beim ersten Lauf hat der Test zwei Dinge gefunden. ADMIN_EMAIL und ADMIN_PASSWORD liest nicht die App, sondern prisma/seed.ts — das ist legitim und steht jetzt begruendet in einer Ausnahmeliste, zusammen mit DB_PASSWORD fuer das Datenbank-StatefulSet. STRIPE_PUBLISHABLE_KEY dagegen wird von keiner einzigen Code-Stelle gelesen: der Checkout laeuft vollstaendig serverseitig ueber eine Stripe-Checkout-Session. Der Schluessel ist aus Secret-Vorlage, .env.example, docker-compose.yml und README entfernt, mit Hinweis, wofuer man ihn braeuchte. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
990a16e654
commit
479ace1b88
6 files changed
+323
-87
No files matched your search
+106
-48
@@ -1,19 +1,17 @@
|
||||
# Vorlage OHNE echte Geheimnisse — analog zu .env.example. Kopieren nach
|
||||
# 02-secret.yaml (per .gitignore ausgeschlossen, NIE committen), Werte
|
||||
# ausfuellen, dann "kubectl apply -f k8s/02-secret.yaml".
|
||||
# Geheime Konfiguration. Vorlage OHNE echte Werte — kopieren nach
|
||||
# 02-secret.yaml (per .gitignore ausgeschlossen, NIE committen), ausfuellen,
|
||||
# dann "kubectl apply -f k8s/02-secret.yaml".
|
||||
#
|
||||
# Alternative ohne Datei mit Klartext-Secrets auf der Platte:
|
||||
# kubectl create secret generic wabenhain-secrets -n wabenhain \
|
||||
# --from-literal=DATABASE_URL='postgresql://wabenhain:CHANGE-ME@wabenhain-postgres:5432/wabenhain?schema=public' \
|
||||
# --from-literal=DB_PASSWORD='CHANGE-ME' \
|
||||
# --from-literal=SESSION_SECRET="$(openssl rand -base64 32)" \
|
||||
# --from-literal=ADMIN_EMAIL='[email protected]' \
|
||||
# --from-literal=ADMIN_PASSWORD="$(openssl rand -base64 24 | tr -d '=+/' | head -c 28)" \
|
||||
# --from-literal=STRIPE_SECRET_KEY='' \
|
||||
# --from-literal=STRIPE_PUBLISHABLE_KEY='' \
|
||||
# --from-literal=STRIPE_WEBHOOK_SECRET='' \
|
||||
# --from-literal=SMTP_HOST='' --from-literal=SMTP_USER='' --from-literal=SMTP_PASSWORD='' \
|
||||
# --from-literal=TURNSTILE_SECRET_KEY=''
|
||||
# ANPASSEN: jeder Wert, der "CHANGE-ME" enthaelt. Die leeren Werte ("")
|
||||
# gehoeren zu optionalen Funktionen und koennen leer bleiben — die App faellt
|
||||
# dann nachvollziehbar zurueck (siehe Kommentar an der jeweiligen Stelle) und
|
||||
# stuerzt nicht ab. Nichts hier darf FEHLEN: ein fehlender und ein leerer
|
||||
# Schluessel sind fuer die App zwar dasselbe, aber ein vollstaendiges Secret
|
||||
# macht sofort sichtbar, welche Funktionen es ueberhaupt gibt.
|
||||
#
|
||||
# Gegenprobe nach dem Ausrollen: "pnpm preflight" meldet jeden Wert, der fuer
|
||||
# den Live-Betrieb fehlt, als Blocker — mit Begruendung, was ohne ihn kaputt
|
||||
# geht.
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -21,55 +19,115 @@ metadata:
|
||||
namespace: wabenhain
|
||||
type: Opaque
|
||||
stringData:
|
||||
# ---------------------------------------------------------------------
|
||||
# PFLICHT — ohne diese Werte ist kein Live-Betrieb moeglich
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# Host "wabenhain-postgres" bzw. "wabenhain-mysql" passend zum Service aus
|
||||
# 03-postgres.yaml/03-mysql.yaml waehlen; Port 5432 (Postgres) bzw. 3306
|
||||
# (MySQL). Muss zu DATABASE_PROVIDER in 01-configmap.yaml passen.
|
||||
# WICHTIG: das Passwort hier MUSS URL-encodiert sein (Sonderzeichen wie
|
||||
# @ : / % # ? & sonst ungueltig bzw. falsch geparst) — DB_PASSWORD unten
|
||||
# bleibt dagegen roh/unencodiert. Encodieren z.B. mit:
|
||||
#
|
||||
# WICHTIG: das Passwort MUSS hier URL-encodiert sein — Sonderzeichen wie
|
||||
# @ : / % # ? & werden sonst als Trennzeichen der URL gelesen, und die
|
||||
# Verbindung schlaegt mit einer irrefuehrenden Meldung fehl. DB_PASSWORD
|
||||
# weiter unten bleibt dagegen roh. Encodieren mit:
|
||||
# node -e "console.log(encodeURIComponent('DEIN-PASSWORT'))"
|
||||
DATABASE_URL: "postgresql://wabenhain:CHANGE-ME@wabenhain-postgres:5432/wabenhain?schema=public"
|
||||
# Dasselbe Passwort wie oben in DATABASE_URL — wird vom Postgres-/MySQL-
|
||||
# StatefulSet (je nachdem, welches du anwendest) zum Anlegen des
|
||||
# Datenbank-Nutzers verwendet.
|
||||
|
||||
# Dasselbe Passwort wie in DATABASE_URL, aber UNENCODIERT. Das
|
||||
# Datenbank-StatefulSet legt damit den Datenbanknutzer an (03-postgres.yaml
|
||||
# bzw. 03-mysql.yaml), und die Sicherung in 07-backup-cronjob.yaml meldet
|
||||
# sich damit an. Die App selbst liest diesen Wert nicht — sie kennt nur
|
||||
# DATABASE_URL.
|
||||
DB_PASSWORD: "CHANGE-ME"
|
||||
# Mindestens 32 Zeichen, z.B.: openssl rand -base64 32
|
||||
SESSION_SECRET: "CHANGE-ME-min-32-zeichen-zufaelliger-string"
|
||||
# Unvorhersehbar waehlen (nicht "admin@..."), siehe README "Admin-Zugang" —
|
||||
# sonst koennte sich jemand die erwartete Adresse vorregistrieren.
|
||||
ADMIN_EMAIL: "[email protected]"
|
||||
|
||||
# Signiert die Login-Cookies. Mindestens 32 Zeichen, unvorhersehbar.
|
||||
# Erzeugen mit: openssl rand -base64 32
|
||||
# Wird dieser Wert bekannt, ist jede Sitzung faelschbar, auch die eines
|
||||
# Admins. Ihn zu aendern meldet alle Kundinnen und Kunden ab, mehr nicht.
|
||||
SESSION_SECRET: "CHANGE-ME-mindestens-32-zeichen-zufaellig"
|
||||
|
||||
# Erstes Admin-Konto, angelegt beim Start durch "prisma db seed".
|
||||
# Unvorhersehbare Adresse waehlen, NICHT "admin@..." oder "info@...":
|
||||
# sonst kann sich jemand die erwartete Adresse vorher selbst registrieren
|
||||
# und das Konto belegen (siehe README "Admin-Zugang").
|
||||
ADMIN_EMAIL: "[email protected]"
|
||||
|
||||
# Mindestens 12 Zeichen. Dieses Konto darf Rueckerstattungen ausloesen und
|
||||
# alle Kundendaten einsehen. Erzeugen mit:
|
||||
# openssl rand -base64 24 | tr -d '=+/' | head -c 28
|
||||
ADMIN_PASSWORD: "CHANGE-ME"
|
||||
STRIPE_SECRET_KEY: ""
|
||||
STRIPE_PUBLISHABLE_KEY: ""
|
||||
STRIPE_WEBHOOK_SECRET: ""
|
||||
SMTP_HOST: ""
|
||||
SMTP_USER: ""
|
||||
SMTP_PASSWORD: ""
|
||||
|
||||
# Stripe im LIVE-Modus (sk_live_...). Mit einem sk_test-Schluessel sehen
|
||||
# Bestellungen erfolgreich aus, ohne dass Geld fliesst.
|
||||
STRIPE_SECRET_KEY: "CHANGE-ME"
|
||||
|
||||
# Ohne Webhook-Secret wird keine Zahlung bestaetigt: Bestellungen bleiben
|
||||
# auf "NEU" stehen, es gibt keine Rechnung und keine Bestaetigungsmail.
|
||||
# Stammt aus dem Webhook-Endpunkt im Stripe-Dashboard, der auf
|
||||
# https://wabenhain.com/api/checkout/webhook zeigt (whsec_...).
|
||||
STRIPE_WEBHOOK_SECRET: "CHANGE-ME"
|
||||
|
||||
# Ohne SMTP werden E-Mails nur ins Server-Log geschrieben (src/lib/mail.ts):
|
||||
# keine Bestellbestaetigung, keine Versandmeldung, keine
|
||||
# Passwort-Zuruecksetzung. Funktioniert mit jedem SMTP-Anbieter; Port und
|
||||
# Absenderadresse stehen als SMTP_PORT/SMTP_FROM in 01-configmap.yaml.
|
||||
SMTP_HOST: "CHANGE-ME"
|
||||
SMTP_USER: "CHANGE-ME"
|
||||
SMTP_PASSWORD: "CHANGE-ME"
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# EMPFOHLEN — der Shop laeuft auch ohne, aber ungeschuetzt
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# Cloudflare Turnstile (CAPTCHA) fuer Registrierung, Newsletter und
|
||||
# Firmenanfrage. Leer = kein CAPTCHA; die Formulare bleiben nutzbar, aber
|
||||
# bei einem oeffentlichen Shop sammeln sich darueber schnell Bot-Eintraege.
|
||||
# Der oeffentliche Gegenpart NEXT_PUBLIC_TURNSTILE_SITE_KEY steht in
|
||||
# 01-configmap.yaml — beide setzen oder beide leer lassen.
|
||||
TURNSTILE_SECRET_KEY: ""
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# OPTIONAL — leer lassen, solange die Funktion nicht genutzt wird
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
# Google-Places-API fuer echte Google-Rezensionen auf der Startseite.
|
||||
# Leer = die Startseite zeigt die statischen Beispiel-Stimmen.
|
||||
#
|
||||
# Der Schluessel gehoert hierher und NICHT in 01-configmap.yaml: er ist
|
||||
# abrechenbar, und eine ConfigMap ist unverschluesselt und in der
|
||||
# Cluster-Oberflaeche im Klartext lesbar. Die zugehoerige GOOGLE_PLACE_ID
|
||||
# ist dagegen oeffentlich und steht dort.
|
||||
GOOGLE_PLACES_API_KEY: ""
|
||||
|
||||
# Zugangsdaten des ApiCore-Sync-Kontos (Admin -> Ernten bzw. Produkte ->
|
||||
# "ApiCore-Synchronisierung"). Leer = der Sync-Knopf meldet einen
|
||||
# Konfigurationsfehler, statt still nichts zu tun.
|
||||
#
|
||||
# ApiCore kennt keinen API-Key-Mechanismus, nur E-Mail/Passwort-Login —
|
||||
# deshalb hier ein eigenes, MFA-FREIES Service-Konto eintragen, nicht einen
|
||||
# echten Admin-Zugang. Noetige Leserechte: harvests:read, products:read,
|
||||
# extractions:read, bottling:read und optional apiaries:read. Die Adresse
|
||||
# APICORE_API_URL ist nicht geheim und steht in 01-configmap.yaml.
|
||||
APICORE_SYNC_EMAIL: ""
|
||||
APICORE_SYNC_PASSWORD: ""
|
||||
|
||||
# DHL-Versandmarken (Admin -> Bestellung -> "DHL-Versandmarke"), siehe
|
||||
# .env.example fuer die vollstaendige Einrichtungsanleitung. Leer lassen,
|
||||
# bis vorhanden — der Button zeigt dann "noch nicht konfiguriert" statt
|
||||
# zu crashen.
|
||||
# .env.example fuer die vollstaendige Einrichtung. Leer = der Knopf meldet
|
||||
# "noch nicht konfiguriert", der Rest des Shops ist unberuehrt. Ob Sandbox
|
||||
# oder Echtbetrieb, steuert DHL_ENVIRONMENT in 01-configmap.yaml.
|
||||
DHL_API_KEY: ""
|
||||
DHL_API_SECRET: ""
|
||||
DHL_GKP_USERNAME: ""
|
||||
DHL_GKP_PASSWORD: ""
|
||||
DHL_ACCOUNT_NUMBER: ""
|
||||
|
||||
# Entra-ID-SSO ("Mit Microsoft anmelden"), siehe .env.example fuer die
|
||||
# Einrichtung in Azure. ENTRA_REDIRECT_URI muss auf die echte, oeffentliche
|
||||
# Domain zeigen: https://wabenhain.com/api/auth/entra/callback
|
||||
# Einrichtung in Azure. Leer = der Anmeldeknopf erscheint gar nicht erst.
|
||||
# ENTRA_REDIRECT_URI muss exakt der in Azure hinterlegten Adresse
|
||||
# entsprechen und auf die echte Domain zeigen:
|
||||
# https://wabenhain.com/api/auth/entra/callback
|
||||
ENTRA_TENANT_ID: ""
|
||||
ENTRA_CLIENT_ID: ""
|
||||
ENTRA_CLIENT_SECRET: ""
|
||||
ENTRA_REDIRECT_URI: ""
|
||||
# Abrechenbarer Zugangsschluessel fuer die Google-Places-API (echte
|
||||
# Google-Rezensionen auf der Startseite). Gehoert hierher und NICHT in
|
||||
# 01-configmap.yaml: eine ConfigMap ist unverschluesselt und in der
|
||||
# Cluster-Oberflaeche im Klartext lesbar. Die zugehoerige, oeffentliche
|
||||
# GOOGLE_PLACE_ID steht dort.
|
||||
GOOGLE_PLACES_API_KEY: ""
|
||||
# Zugangsdaten des ApiCore-Sync-Kontos (Admin -> Ernten bzw. Produkte ->
|
||||
# "ApiCore-Synchronisierung"), siehe .env.example. Die zugehoerige Adresse
|
||||
# APICORE_API_URL ist nicht geheim und steht in 01-configmap.yaml.
|
||||
APICORE_SYNC_EMAIL: ""
|
||||
APICORE_SYNC_PASSWORD: ""
|
||||
Reference in new issue
Block a user