docs/EINRICHTUNG.md walks from nothing to a running shop: tools and access, generating database/session/admin values, the Entra ID app registration used for both sign-in and mail (redirect URI, client secret, SMTP.SendAsApp with admin consent, enterprise app object id), unlocking the shared mailbox in Exchange Online, Stripe keys and webhook events, optional services, a complete secret/config map table, rollout, verification, maintenance (secret expiry) and troubleshooting keyed to the messages of the admin email test. Linked from README and k8s/README. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
22 KiB
Wabenhain einrichten — von null bis live
Diese Anleitung führt durch alles, was außerhalb des Codes eingerichtet werden muss, damit der Shop in Kubernetes vollständig läuft: Geheimnisse (Secrets), Microsoft-Anmeldung, Mailversand über Microsoft 365, Stripe und die optionalen Dienste. Sie setzt nichts voraus, was nicht hier steht.
Zeitbedarf: etwa 2 Stunden für Pflicht und Mailversand, plus Wartezeiten bei Microsoft (bis zu 30 Minuten) und Stripe.
Reihenfolge:
- Werkzeuge und Zugänge bereitlegen
- Grundwerte erzeugen (Datenbank, Sitzungen, Admin)
- Microsoft Entra ID: App-Registrierung (Anmeldung und Mailversand)
- Microsoft 365: Absender-Postfach freischalten
- Stripe
- Optionale Dienste
- Secret und ConfigMap ausfüllen
- Ausrollen
- Prüfen
- Wartung: was abläuft und was zu tun ist
- Fehlerbehebung
Sicherheitsregel für das ganze Dokument: Echte Werte gehören ausschließlich in
k8s/02-secret.yaml(per.gitignoreausgeschlossen) bzw. direkt ins Cluster. Nie committen, nie in Chats, Tickets oder Screenshots kopieren. Die ConfigMap (k8s/01-configmap.yaml) ist unverschlüsselt und im Cluster für jeden mit Lesezugriff im Klartext sichtbar — dort steht nichts Geheimes.
1. Werkzeuge und Zugänge
Auf deinem Rechner:
| Werkzeug | Wofür | Prüfen mit |
|---|---|---|
kubectl mit Zugriff auf das Cluster |
Secrets und Manifeste anwenden | kubectl get nodes |
openssl |
Zufallswerte erzeugen | openssl version |
| Node.js | Datenbank-Passwort URL-kodieren | node --version |
PowerShell mit Modul ExchangeOnlineManagement |
Postfach für den Mailversand freischalten | Get-Module -ListAvailable ExchangeOnlineManagement |
Modul einmalig installieren (PowerShell):
Install-Module ExchangeOnlineManagement -Scope CurrentUser
Zugänge, die du brauchst:
| Zugang | Rolle | Wofür |
|---|---|---|
| Microsoft Entra Admin Center (entra.microsoft.com) | Anwendungsadministrator oder Globaler Administrator | App-Registrierung, Administratorzustimmung |
| Microsoft 365 Admin Center (admin.microsoft.com) | Exchange-Administrator | Freigegebenes Postfach anlegen und freischalten |
| Stripe-Dashboard (dashboard.stripe.com) | Administrator | API-Schlüssel, Webhook |
Gitea (git.encry.de) |
Schreibrecht am Repository | Image-Build (siehe k8s/README.md) |
2. Grundwerte erzeugen
Diese Werte denkst du dir nicht aus, sondern lässt sie erzeugen. Notiere sie vorübergehend in einem Passwort-Manager, nicht in einer Textdatei.
Datenbank-Passwort (DB_PASSWORD und DATABASE_URL)
openssl rand -base64 32 | tr -d '=+/' | head -c 32
Das Passwort steht an zwei Stellen im Secret:
DB_PASSWORD: roh, genau wie erzeugt.DATABASE_URL: URL-kodiert. Sonderzeichen würden sonst als Trennzeichen der URL gelesen.Ergebnis einsetzen:node -e "console.log(encodeURIComponent('HIER-DAS-PASSWORT'))"postgresql://wabenhain:<KODIERTES-PASSWORT>@wabenhain-postgres:5432/wabenhain?schema=public
Bei MySQL statt Postgres: mysql://wabenhain:<KODIERTES-PASSWORT>@wabenhain-mysql:3306/wabenhain und in der ConfigMap DATABASE_PROVIDER: "mysql".
Sitzungsschlüssel (SESSION_SECRET)
openssl rand -base64 32
Signiert alle Login-Cookies. Wird er bekannt, lassen sich Sitzungen fälschen — auch die eines Admins. Ihn zu ändern meldet alle nur ab.
Erstes Admin-Konto (ADMIN_EMAIL, ADMIN_PASSWORD)
ADMIN_EMAIL: eine echte, nicht erratbare Adresse, z. B.[email protected]— nichtadmin@…oderinfo@…. Sonst könnte jemand diese Adresse vorher als Kundenkonto registrieren. An diese Adresse gehen außerdem die Benachrichtigungen über eingegangene Widerrufe.ADMIN_PASSWORD:openssl rand -base64 24 | tr -d '=+/' | head -c 28
Das Konto wird beim ersten Start angelegt. Beim ersten Login verlangt der Admin-Bereich die Einrichtung der Zwei-Faktor-Authentifizierung (Authenticator-App bereithalten).
3. Microsoft Entra ID: App-Registrierung
Eine App-Registrierung erledigt zwei Aufgaben:
- „Mit Microsoft anmelden“ (Single Sign-on im Kundenkonto)
- Mailversand über Microsoft 365 per OAuth 2.0 — ohne Passwort
Eine zweite Unternehmensanwendung ist nicht nötig.
3.1 App registrieren
- Entra Admin Center → Identität → Anwendungen → App-Registrierungen → Neue Registrierung.
- Name: z. B.
Wabenhain Shop. - Unterstützte Kontotypen: „Nur Konten in diesem Organisationsverzeichnis“ (Single Tenant).
- Umleitungs-URI: Plattform Web, Adresse
https://wabenhain.com/api/auth/entra/callback— zeichengenau, mithttps, ohne Schrägstrich am Ende. - Registrieren.
Auf der Seite Übersicht notieren:
| Angezeigt als | Gehört in |
|---|---|
| Anwendungs-ID (Client-ID) | ENTRA_CLIENT_ID |
| Verzeichnis-ID (Mandanten-ID) | ENTRA_TENANT_ID |
ENTRA_REDIRECT_URI ist die Adresse aus Schritt 4: https://wabenhain.com/api/auth/entra/callback.
3.2 Geheimen Clientschlüssel anlegen
- In der App → Zertifikate & Geheimnisse → Geheime Clientschlüssel → Neuer geheimer Clientschlüssel.
- Beschreibung z. B.
Shop 2026, Ablauf 24 Monate (Maximum). - Sofort die Spalte „Wert“ kopieren →
ENTRA_CLIENT_SECRET.
⚠ Nicht die „Geheimnis-ID“ kopieren — das ist der häufigste Fehler (Microsoft meldet dann
AADSTS7000215). Der Wert wird nur dieses eine Mal angezeigt; ist er weg, einen neuen Schlüssel anlegen.Ablaufdatum sofort in den Kalender eintragen, mit Erinnerung vier Wochen vorher. Läuft der Schlüssel ab, fallen Microsoft-Anmeldung und Mailversand gleichzeitig aus (siehe Wartung).
3.3 API-Berechtigungen
In der App → API-Berechtigungen. Es braucht zwei Arten:
| Berechtigung | API | Typ | Wofür |
|---|---|---|---|
openid, email, profile, User.Read |
Microsoft Graph | Delegiert | Anmeldung („Mit Microsoft anmelden“) |
SMTP.SendAsApp |
Office 365 Exchange Online | Anwendung | Mailversand |
User.Read ist meist schon vorhanden. Die übrigen hinzufügen:
Für die Anmeldung (falls noch nicht vorhanden):
- Berechtigung hinzufügen → Microsoft Graph → Delegierte Berechtigungen.
openid,email,profileanhaken → Berechtigungen hinzufügen.
Für den Mailversand:
- Berechtigung hinzufügen → Reiter „Von meiner Organisation verwendete APIs“.
- Nach Office 365 Exchange Online suchen und auswählen. (Die Berechtigung liegt nicht unter Microsoft Graph.)
- Anwendungsberechtigungen (nicht „Delegierte“) →
SMTP.SendAsAppanhaken → Berechtigungen hinzufügen.
Danach: „Administratorzustimmung für <Organisation> erteilen“ klicken und bestätigen. In der Liste muss bei jeder Berechtigung ein grünes „Erteilt für …“ stehen.
Was
SMTP.SendAsApperlaubt: Die App darf per SMTP senden — aber nur mit Postfächern, die ihr in Exchange ausdrücklich freigegeben werden (Abschnitt 4). Ohne diese Freigabe kann sie nichts senden.
3.4 Objekt-ID der Unternehmensanwendung notieren
- Entra → Identität → Anwendungen → Unternehmensanwendungen.
- Filter „Anwendungstyp“ auf Alle Anwendungen stellen, nach
Wabenhain Shopsuchen, öffnen. - Auf der Übersicht die Objekt-ID kopieren.
⚠ Das ist eine andere Objekt-ID als die auf der Seite der App-Registrierung. Für Exchange zählt nur die der Unternehmensanwendung.
4. Microsoft 365: Absender-Postfach freischalten
Alle Shop-Mails (Bestellbestätigung, Versandmeldung, Passwort-Reset, Widerrufsbestätigung …) gehen von einem Postfach aus, z. B. [email protected].
Empfohlen: ein freigegebenes Postfach (Shared Mailbox). Es braucht keine Lizenz und hat kein Passwort, mit dem sich jemand anmelden könnte. Die App sendet ohne Anmeldung einer Person.
4.1 Freigegebenes Postfach anlegen (falls noch nicht vorhanden)
- Microsoft 365 Admin Center → Teams und Gruppen → Freigegebene Postfächer → Freigegebenes Postfach hinzufügen.
- Name
Wabenhain, E-Mail[email protected]→ Änderungen speichern. - Optional: Mitglieder hinzufügen, die Antworten der Kundschaft lesen sollen.
4.2 App für genau dieses Postfach freischalten
In PowerShell (als Exchange-Administrator). Platzhalter ersetzen:
<CLIENT-ID>=ENTRA_CLIENT_IDaus 3.1<OBJEKT-ID>= Objekt-ID der Unternehmensanwendung aus 3.4
Connect-ExchangeOnline
# 1. App in Exchange bekannt machen
New-ServicePrincipal -AppId <CLIENT-ID> -ObjectId <OBJEKT-ID> -DisplayName "Wabenhain Shop"
# 2. Zugriff NUR auf das Absender-Postfach
Add-MailboxPermission -Identity "[email protected]" -User <OBJEKT-ID> -AccessRights FullAccess
# 3. Authentifiziertes SMTP für dieses Postfach erlauben (auch OAuth läuft darüber)
Set-CASMailbox -Identity "[email protected]" -SmtpClientAuthenticationDisabled $false
Empfohlene Absicherung: Authentifiziertes SMTP für alle anderen Postfächer abschalten. Die Einstellung am Absender-Postfach aus Schritt 3 hat Vorrang, der Shop sendet weiter.
Set-TransportConfig -SmtpClientAuthenticationDisabled $true
4.3 Kontrolle
Get-ServicePrincipal | Where-Object DisplayName -eq "Wabenhain Shop"
Get-MailboxPermission -Identity "[email protected]" | Where-Object { $_.User -like "*Wabenhain*" }
Get-CASMailbox -Identity "[email protected]" | Format-List SmtpClientAuthenticationDisabled # muss False sein
Disconnect-ExchangeOnline -Confirm:$false
Änderungen in Exchange brauchen bis zu 30 Minuten, bis sie greifen.
Ergebnis für die Konfiguration:
| Wert | Wo | Inhalt |
|---|---|---|
SMTP_USER |
Secret | [email protected] |
SMTP_FROM |
ConfigMap | Wabenhain <[email protected]> — dieselbe Adresse wie SMTP_USER |
Server (smtp.office365.com), Port (587, STARTTLS) und Anmeldeverfahren (OAuth 2.0) sind fest im Code — dafür gibt es keine Einstellungen. Ein SMTP-Passwort gibt es nicht.
5. Stripe
Im Stripe-Dashboard, Live-Modus (Schalter oben rechts, nicht „Testmodus“).
5.1 API-Schlüssel
Entwickler → API-Schlüssel:
| Angezeigt als | Gehört in | Wo |
|---|---|---|
Veröffentlichbarer Schlüssel (pk_live_…) |
STRIPE_PUBLISHABLE_KEY |
ConfigMap (nicht geheim) |
Geheimer Schlüssel (sk_live_…) |
STRIPE_SECRET_KEY |
Secret |
Sicherer als der volle geheime Schlüssel ist ein eingeschränkter Schlüssel (rk_live_…) mit Schreibrecht auf Checkout Sessions, Refunds und Leserecht auf Charges/Payment Intents.
Beide Schlüssel müssen aus demselben Modus stammen. Mit
sk_testsehen Bestellungen erfolgreich aus, ohne dass Geld fließt.
5.2 Webhook
Entwickler → Webhooks → Endpunkt hinzufügen:
- URL:
https://wabenhain.com/api/checkout/webhook - Ereignisse:
checkout.session.completedcheckout.session.async_payment_succeededcheckout.session.async_payment_failedcheckout.session.expiredcharge.refundedcharge.dispute.created
Nach dem Anlegen Signaturgeheimnis anzeigen (whsec_…) → STRIPE_WEBHOOK_SECRET im Secret.
Ohne Webhook-Secret wird keine Zahlung bestätigt: Bestellungen bleiben auf „Neu“, es gibt weder Rechnung noch Bestätigungsmail.
5.3 Zahlungsarten
Einstellungen → Zahlungsmethoden: gewünschte Arten aktivieren (Karte, SEPA-Lastschrift, PayPal, Klarna, Apple Pay, Google Pay). Der Shop zeigt automatisch an, was dort aktiv ist. Für Apple Pay die Domain wabenhain.com unter Apple Pay registrieren.
6. Optionale Dienste
Alle folgenden Werte dürfen leer bleiben. Die Funktion ruht dann, der Shop läuft weiter. Ausführliche Anleitungen stehen in .env.example im jeweiligen Abschnitt.
| Dienst | Werte | Ohne sie | Einrichtung |
|---|---|---|---|
| Cloudflare Turnstile (CAPTCHA) — dringend empfohlen | TURNSTILE_SECRET_KEY (Secret), NEXT_PUBLIC_TURNSTILE_SITE_KEY (ConfigMap) |
Keine Bot-Abwehr an Formularen | dash.cloudflare.com → Turnstile → Widget für wabenhain.com anlegen. Beide setzen oder beide leer. |
| Google-Rezensionen | GOOGLE_PLACES_API_KEY (Secret), GOOGLE_PLACE_ID (ConfigMap) |
Statische Beispiel-Stimmen | Google Cloud: „Places API (New)“ aktivieren, Abrechnung an, API-Schlüssel ohne Referrer-Beschränkung |
| DHL (Versandmarken, Packstation, Sendungsverfolgung) | DHL_API_KEY, DHL_API_SECRET, DHL_GKP_USERNAME, DHL_GKP_PASSWORD, DHL_ACCOUNT_NUMBER, DHL_TRACKING_API_KEY (Secret), DHL_ENVIRONMENT (ConfigMap) |
Kein Etikettendruck, keine Packstation im Checkout | developer.dhl.com, Geschäftskundenvertrag — Schritt für Schritt in .env.example |
| ApiCore-Synchronisierung | APICORE_SYNC_EMAIL, APICORE_SYNC_PASSWORD (Secret), APICORE_API_URL (ConfigMap) |
Sync-Knopf meldet Konfigurationsfehler | Eigenes, MFA-freies Service-Konto mit nur lesenden Rechten, siehe .env.example |
7. Secret und ConfigMap ausfüllen
7.1 Secret (k8s/02-secret.yaml)
cp k8s/02-secret.example.yaml k8s/02-secret.yaml
k8s/02-secret.yaml öffnen und jeden Wert aus der Tabelle eintragen. Werte in doppelten Anführungszeichen lassen (stringData — Kubernetes kodiert selbst, kein base64 von Hand).
| Schlüssel | Pflicht | Inhalt | Quelle |
|---|---|---|---|
DATABASE_URL |
ja | Verbindungs-URL mit URL-kodiertem Passwort | Abschnitt 2 |
DB_PASSWORD |
ja | Datenbank-Passwort roh | Abschnitt 2 |
SESSION_SECRET |
ja | ≥ 32 zufällige Zeichen | Abschnitt 2 |
ADMIN_EMAIL |
ja | nicht erratbare Admin-Adresse | Abschnitt 2 |
ADMIN_PASSWORD |
ja | ≥ 12 Zeichen, zufällig | Abschnitt 2 |
STRIPE_SECRET_KEY |
ja | sk_live_… bzw. rk_live_… |
5.1 |
STRIPE_WEBHOOK_SECRET |
ja | whsec_… |
5.2 |
SMTP_USER |
ja | [email protected] |
4 |
ENTRA_TENANT_ID |
ja* | Verzeichnis-ID | 3.1 |
ENTRA_CLIENT_ID |
ja* | Anwendungs-ID | 3.1 |
ENTRA_CLIENT_SECRET |
ja* | Wert des Clientschlüssels | 3.2 |
ENTRA_REDIRECT_URI |
ja* | https://wabenhain.com/api/auth/entra/callback |
3.1 |
TURNSTILE_SECRET_KEY |
empfohlen | Turnstile-Secret | 6 |
GOOGLE_PLACES_API_KEY |
nein | Google-API-Schlüssel | 6 |
APICORE_SYNC_EMAIL, APICORE_SYNC_PASSWORD |
nein | Service-Konto | 6 |
DHL_* (6 Werte) |
nein | DHL-Zugangsdaten | 6 |
* Ohne die ENTRA_*-Werte gibt es weder „Mit Microsoft anmelden“ noch Mailversand — keine Bestellbestätigungen, keine Passwort-Resets. Für den Live-Betrieb daher Pflicht.
Nicht mehr verwendet (aus älteren Secrets entfernen): SMTP_HOST, SMTP_PORT, SMTP_PASSWORD, SMTP_OAUTH_TENANT_ID, SMTP_OAUTH_CLIENT_ID, SMTP_OAUTH_CLIENT_SECRET.
7.2 ConfigMap (k8s/01-configmap.yaml)
Nur diese Werte anpassen, der Rest sind sinnvolle Vorgaben:
| Schlüssel | Inhalt |
|---|---|
NEXT_PUBLIC_SITE_URL |
https://wabenhain.com — muss zu host in k8s/06-ingress.yaml passen |
SMTP_FROM |
Wabenhain <[email protected]> — dieselbe Adresse wie SMTP_USER |
DATABASE_PROVIDER |
postgresql (oder mysql, passend zu DATABASE_URL) |
STRIPE_PUBLISHABLE_KEY |
pk_live_… |
NEXT_PUBLIC_TURNSTILE_SITE_KEY |
Turnstile-Site-Key (empfohlen) |
VAT_RATE_PERCENT* |
Umsatzsteuersätze prüfen (Honig 7 %, Kerzen 19 %, Propolis je nach Einordnung) |
DHL_ENVIRONMENT |
sandbox, bis DHL getestet ist, dann production |
GOOGLE_PLACE_ID, APICORE_API_URL |
nur bei Nutzung |
8. Ausrollen
Erstmalig, in dieser Reihenfolge (Details und Hintergründe: k8s/README.md):
kubectl apply -f k8s/00-namespace.yaml
kubectl apply -f k8s/01-configmap.yaml
kubectl apply -f k8s/02-secret.yaml
# Nur EINE Datenbank, passend zu DATABASE_PROVIDER:
kubectl apply -f k8s/03-postgres.yaml
kubectl wait --for=condition=ready pod -l app=wabenhain-postgres -n wabenhain --timeout=120s
kubectl apply -f k8s/04-uploads-pvc.yaml
kubectl apply -f k8s/05-app-deployment.yaml
kubectl apply -f k8s/06-ingress.yaml
kubectl apply -f k8s/07-backup-cronjob.yaml
kubectl rollout status deployment/wabenhain-app -n wabenhain
Datenbank-Migrationen und das Anlegen des Admin-Kontos laufen beim Start des Pods automatisch.
Später einen Wert ändern: Datei anpassen, erneut anwenden und den Pod neu starten — die App liest Secrets und ConfigMap nur beim Start:
kubectl apply -f k8s/02-secret.yaml # bzw. 01-configmap.yaml
kubectl rollout restart deployment/wabenhain-app -n wabenhain
Einzelnen Wert ohne Datei ändern bzw. entfernen:
kubectl -n wabenhain patch secret wabenhain-secrets --type=merge -p '{"stringData":{"SMTP_USER":"[email protected]"}}'
kubectl -n wabenhain patch secret wabenhain-secrets --type=json -p '[{"op":"remove","path":"/data/SMTP_PASSWORD"}]'
Wer
k8s/02-secret.yamllokal pflegt, trägt jede Änderung auch dort ein — sonst setzt das nächstekubectl applyden alten Stand zurück.
9. Prüfen
Der Reihe nach:
- Vollständigkeit der Konfiguration im laufenden Pod:
Jeder fehlende Pflichtwert erscheint als Blocker mit Begründung.
kubectl -n wabenhain exec deploy/wabenhain-app -- node_modules/.bin/tsx scripts/preflight.ts - Shop erreichbar:
https://wabenhain.comöffnen. - Admin-Login:
https://wabenhain.com/kontomitADMIN_EMAIL/ADMIN_PASSWORDanmelden → Zwei-Faktor-Authentifizierung einrichten → Admin-Bereich öffnet sich. - Mailversand: Admin → E-Mail-Test → „Test-Mail senden“. Erfolg: grüne Meldung und eine Mail an die Admin-Adresse. Fehler: die Seite zeigt die Meldung von Microsoft und was zu tun ist (siehe Fehlerbehebung).
- Microsoft-Anmeldung: abmelden, auf
/konto„Mit Microsoft anmelden“ wählen. - Firmendaten: Admin → Inhalte → Firmendaten — Name, Anschrift und eine gültige E-Mail-Adresse eintragen. Sie erscheinen im Impressum und in der Widerrufsbelehrung.
- Bezahlung: eine kleine echte Bestellung aufgeben, bezahlen, im Admin prüfen: Status „Bezahlt“, Rechnung vorhanden, Bestätigungsmail angekommen. Danach im Admin erstatten.
- Widerruf: im Footer „Vertrag widerrufen“ testen → Eingangsbestätigung kommt an, Eintrag erscheint unter Admin → Widerrufe.
10. Wartung
| Was | Läuft ab / ändert sich | Folge, wenn verpasst | Was tun |
|---|---|---|---|
Entra-Clientschlüssel (ENTRA_CLIENT_SECRET) |
nach höchstens 24 Monaten | Microsoft-Anmeldung und Mailversand fallen gleichzeitig aus | Vier Wochen vorher neuen Schlüssel anlegen (3.2), Secret ersetzen, Pod neu starten, E-Mail-Test, danach alten Schlüssel in Entra löschen |
| Stripe-Schlüssel | bei Verdacht auf Abfluss | Fremde könnten Erstattungen auslösen | Im Stripe-Dashboard „Schlüssel rollen“, Secret ersetzen, Pod neu starten |
SESSION_SECRET |
bei Verdacht auf Abfluss | Sitzungen fälschbar | Neuen Wert erzeugen, ersetzen, neu starten (meldet alle ab) |
| DHL-/Google-/Turnstile-Schlüssel | je nach Anbieter | Funktion ruht | Beim Anbieter erneuern, Secret ersetzen |
| Postfach-Freigabe | bei Umbenennung oder neuem Absender-Postfach | Mailversand scheitert („Exchange lässt die App nicht …“) | Abschnitt 4.2 für das neue Postfach wiederholen, SMTP_USER und SMTP_FROM anpassen |
Nach jeder Änderung an Secret oder ConfigMap: kubectl rollout restart deployment/wabenhain-app -n wabenhain und kurz Admin → E-Mail-Test.
11. Fehlerbehebung
Mailversand (Anzeige in Admin → E-Mail-Test)
| Meldung / Ursache | Lösung |
|---|---|
| „nicht vollständig eingerichtet“ + Liste fehlender Werte | Genannte Werte ins Secret, Pod neu starten |
AADSTS7000215 — Client-Secret falsch |
In ENTRA_CLIENT_SECRET steht die Geheimnis-ID statt des Werts → neuen Schlüssel anlegen (3.2) |
AADSTS7000222 — Client-Secret abgelaufen |
Neuen Schlüssel anlegen (3.2), ersetzen, neu starten |
AADSTS700016 — App nicht gefunden |
ENTRA_CLIENT_ID und ENTRA_TENANT_ID gehören nicht zusammen |
AADSTS90002 / 900023 — Tenant ungültig |
ENTRA_TENANT_ID prüfen (Verzeichnis-ID) |
„Exchange lässt die App nicht mit dem Postfach senden“ (535 5.7.3) |
(1) SMTP.SendAsApp erteilt? (3.3) (2) New-ServicePrincipal mit der Objekt-ID der Unternehmensanwendung? (3.4/4.2) (3) Add-MailboxPermission für genau SMTP_USER? (4) 30 Minuten gewartet? |
„Authentifiziertes SMTP ausgeschaltet“ (SmtpClientAuthentication is disabled) |
Set-CASMailbox -Identity "[email protected]" -SmtpClientAuthenticationDisabled $false |
| „SendAsDenied“ | SMTP_FROM ist nicht die Adresse aus SMTP_USER → angleichen |
| „nicht erreichbar“ (Netzwerk) | Cluster muss ausgehend smtp.office365.com:587 und login.microsoftonline.com:443 erreichen (Firewall, NetworkPolicy) |
Ausführliche Fehler stehen außerdem im Pod-Log:
kubectl logs deploy/wabenhain-app -n wabenhain | grep "\[mail\]"
Microsoft-Anmeldung
| Symptom | Lösung |
|---|---|
| Knopf „Mit Microsoft anmelden“ fehlt | Einer der vier ENTRA_*-Werte fehlt |
Microsoft meldet „redirect_uri mismatch“ (AADSTS50011) |
ENTRA_REDIRECT_URI und die Umleitungs-URI in der App-Registrierung (3.1) müssen zeichengenau gleich sein |
Sonstiges
| Symptom | Lösung |
|---|---|
| Pod startet nicht, Log nennt Datenbankfehler | DATABASE_URL: Passwort URL-kodiert? Host passend zum Datenbank-Manifest? |
| Bestellungen bleiben auf „Neu“ | Stripe-Webhook (5.2): URL, Ereignisse und STRIPE_WEBHOOK_SECRET prüfen; im Stripe-Dashboard unter Webhooks die Zustellversuche ansehen |
| Bilder weg nach Neustart | k8s/README.md, Abschnitt „Bilder/Videos verschwinden nach jedem Redeploy“ |