WS-7: Live-Deployment-Checkliste + WS-6/WS-7 als erledigt dokumentiert

Kompakte Go-Live-Checkliste (Live-.env, Migrationen, einmalige Setups,
Stripe-Webhook, Cache-Warmup, Scheduler/Worker, Post-Deploy-Kontrollen).
WS-6 (Auth/Verifizierung/Google) und WS-7 im Detailplan als erledigt
markiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-17 13:32:35 +00:00
parent 253141c6dc
commit a2ff47e44e
2 changed files with 184 additions and 11 deletions

View file

@ -103,18 +103,20 @@ Alle hinter WS-2 **oder** regulärem Login.
- **Tests:** `HasActiveBookingTest`, `PressReleaseSubmitApiTest` (402/422), `DashboardTest` (Banner an/aus + grandfathered-Ausnahme), `LegacyBundleTest` (grandfathered zählt portalübergreifend).
- **Aufwand:** erledigt. **Abhängigkeit:** WS-4 (erledigt).
### WS-6 — Login/Registrierung: Flow + E-Mail-Verifizierung + Google-Login (Merkliste 7 + Zweig 3)
**Scope nach Entscheidung 2 & 3:**
- **E-Mail-Verifizierung aktivieren:** Fortify `emailVerification()` bzw. Volt-Flow scharf schalten. Bei Registrierung: User wird angelegt, aber **erst nach Bestätigung** `customer`-Rolle + `is_active=true` (heute fehlt beides in `CreateNewUser`/Register-Volt). Bis dahin kein Zugriff auf geschützte Bereiche.
- **Ausnahme-Kanäle:** Magic-Link & Google-Login gelten als verifiziert (keine zusätzliche E-Mail-Verifizierung) → dort direkt `is_active=true` + Rolle.
- **Google-Login:** Laravel Socialite installieren, `config/services.php` + Redirect/Callback-Controller, Provider-Verknüpfung (`provider`/`provider_id`-Spalten an `users`), Rollen-/`is_active`-Logik.
- **Flow-Audit:** Login, Passwort-Reset, Verify-Email, 2FA, Magic-Link-Login durchtesten und korrigieren.
- **Tests:** Registrierung→Verifizierung→Aktivierung; unverifizierter User blockiert; Socialite gemockt; Account-Verknüpfung; Magic-Link/Google ohne E-Mail-Verifizierung aktiv.
- **Aufwand:** ~23 Tage.
### WS-6 — Login/Registrierung: Flow + E-Mail-Verifizierung + Google-Login (Merkliste 7 + Zweig 3) — ✅ erledigt 17.06.2026
**Scope nach Entscheidung 2 & 3 — vollständig umgesetzt (Audit 17.06., 65 Auth-Tests grün):**
- **E-Mail-Verifizierung scharf:** `User implements MustVerifyEmail`; `verified`-Middleware greift real auf den Panel-Routen (`routes/admin.php`, `routes/customer.php`). Eigener Volt-Flow statt Fortify-Built-in (`Features::emailVerification()` bewusst aus, wie `registration()`/`resetPasswords()`): Notice-Volt + `VerifyEmailController` + Resend-Route. Lockout der Bestands-User durch Backfill-Migration verhindert.
- **Rolle + Aktivierung erst nach Bestätigung:** `CreateNewUser` legt inaktiv & rollenlos an; `App\Listeners\ActivateUserAfterVerification` (auf `Verified`-Event) setzt `is_active=true` + `customer`.
- **Ausnahme-Kanäle:** Magic-Link & Google gelten als verifiziert → `SocialAuthService`/Magic-Link setzen `email_verified_at` + Rolle direkt.
- **Google-Login:** `laravel/socialite ^5.27`, `config/services.php`, `GoogleController` (redirect/callback), `oauth_provider`/`oauth_provider_id`-Migration, De-Dup über E-Mail.
- **Flow-Audit:** Login (2FA-Bypass behoben), Passwort-Reset, Verify-Email, 2FA-Challenge, Magic-Link alle als Volt-Komponenten, gehärtet (Security-Review 16.06.).
- **Tests:** `tests/Feature/Auth/` (10 Dateien): Registrierung→Verifizierung→Aktivierung, unverifiziert blockiert, Socialite gemockt, Account-Verknüpfung, Magic-Link/Google ohne E-Mail-Schritt.
- **Operativ offen → WS-7:** Google-Keys + Redirect-URI in der Prod-`.env`.
- **Doku:** [Sicherheit & Deployment-Hinweise (Auth, Rollen, Verifizierung).md](Sicherheit%20&%20Deployment-Hinweise%20(Auth,%20Rollen,%20Verifizierung).md).
### WS-7 — Live-Deployment-Checkliste (Merkliste 4)
- Kompakte Liste nötiger Commands & Live-Settings: `migrate`, `enforce_booking=true`, Stripe-Live-Keys, `BILLING_OWN_VAT_ID`, Asset-Build, Scheduler/Worker, Favicons, Domain-Config, Socialite-Keys damit nicht aus langen Dokumenten gesucht werden muss.
- **Aufwand:** ~½ Tag (reine Doku).
### WS-7 — Live-Deployment-Checkliste (Merkliste 4) — ✅ erledigt 17.06.2026
- Kompakte, abarbeitbare Go-Live-Checkliste erstellt: [Live-Deployment-Checkliste (WS-7).md](Live-Deployment-Checkliste%20(WS-7).md). Deckt ab: Live-`.env` (Domains, MySQL + Legacy-DBs, Session/Cookies, `BILLING_ENFORCE_BOOKING=true`, `BILLING_OWN_VAT_ID`, Stripe-Live-Keys, Google-/OpenAI-Keys, echter Mailer), Code/Assets-Build, Migrationen (Reihenfolge), einmalige Setups (`billing:sync-stripe-plans`, `legacy:grandfather-subscriptions` für `net_cents`, `domains:generate-favicons`), Stripe-Webhook, Cache-Warmup, Scheduler-Cron + Queue-Worker, Post-Deploy-Kontrollen.
- **Aufwand:** erledigt (reine Doku).
### WS-8 — Code-Optimierung (Zweig 4)
- Nach Abschluss der Features: gezielte Optimierung (N+1 in Listen, doppelte Query-Logik, Service-Extraktion). Bewusst zuletzt, wenn der Funktionsumfang steht.

View file

@ -0,0 +1,171 @@
**Version:** Juni 2026 · **Datum:** 17.06.2026 · **Status:** Go-Live-Referenz (WS-7)
**Scope:** Eine kompakte, abarbeitbare Liste aller Commands & Live-Settings für den Go-Live damit nichts in langen Dokumenten gesucht werden muss. Die Begründungen stehen in [Sicherheit & Deployment-Hinweise (Auth, Rollen, Verifizierung)](Sicherheit%20&%20Deployment-Hinweise%20(Auth,%20Rollen,%20Verifizierung).md) und im [Detailplan Launch-Slice](Detailplan%20Umsetzung%20Launch-Slice%20(Magic-Link,%20Compliance,%20Bestandsschutz,%20Auth).md); hier nur das Was/Womit.
> **Reihenfolge zählt:** erst Code & Assets, dann Migrationen (vor echtem Traffic auf geschützte Routen), dann einmalige Setups, zuletzt Caches + Worker/Scheduler. Befehle laufen auf dem Live-Host via Sail bzw. dem dortigen PHP Platzhalter `php artisan …` ggf. durch `vendor/bin/sail artisan …` ersetzen.
---
## 0. Vor dem Deploy besorgen (externe Keys/Settings)
- [ ] **Stripe Live-Keys**: `STRIPE_KEY`, `STRIPE_SECRET` (Live-Modus), Webhook-Signing-Secret (`STRIPE_WEBHOOK_SECRET`, erst nach Schritt 4 final).
- [ ] **Google Cloud OAuth**: Client-ID/Secret; Redirect-URI in der Google Console **exakt** = `https://pressekonto.com/auth/google/callback` (Portal-Host!).
- [ ] **OpenAI**: `OPENAI_API_KEY` für KI-Klassifikation/Content-Score.
- [ ] **Mail-Provider** (echter Versand statt `log`): Zugangsdaten/Domain (SPF/DKIM gesetzt).
- [ ] **DNS/SSL**: alle Domains zeigen auf den Host, gültige Zertifikate (Portal + presseecho + businessportal24).
- [ ] **Domain final bestätigen:** Standing-Wert ist `pressekonto.com` (so in `.env.example`). ⚠️ `CLAUDE.md` nennt `pressekonto.de` vor Go-Live verbindlich klären und überall konsistent setzen.
---
## 1. Live-`.env` — kritische Settings
```env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://pressekonto.com
APP_PROTOCOL=https
# Domains (ThemeServiceProvider matcht hierüber)
APP_PORTAL_NAME=pressekonto.com
APP_PORTAL_URL=https://pressekonto.com
APP_PRESSEECHO_NAME=presseecho.de
APP_PRESSEECHO_URL=https://presseecho.de
APP_BUSINESSPORTAL_NAME=businessportal24.de
APP_BUSINESSPORTAL_URL=https://businessportal24.de
# Datenbank (Prod = MySQL) Haupt-DB + zwei Legacy-Quellen für den Import
DB_CONNECTION=mysql
DB_HOST=… DB_DATABASE=… DB_USERNAME=… DB_PASSWORD=…
DB_DATABASE_PRESSEECHO=… DB_HOST_PRESSEECHO=… DB_USERNAME_PRESSEECHO=… DB_PASSWORD_PRESSEECHO=…
DB_DATABASE_BUSINESSPORTAL=… DB_HOST_BUSINESSPORTAL=… DB_USERNAME_BUSINESSPORTAL=… DB_PASSWORD_BUSINESSPORTAL=…
# Session/Cookies über die Live-Domain absichern
SESSION_DRIVER=database
SESSION_DOMAIN=.pressekonto.com
SESSION_SECURE_COOKIE=true
SANCTUM_STATEFUL_DOMAINS=pressekonto.com
# Queue & Cache (DB-getrieben, kein Redis-Zwang)
QUEUE_CONNECTION=database
CACHE_STORE=database
# Mail echter Versand statt log!
MAIL_MAILER=smtp
MAIL_HOST=… MAIL_PORT=… MAIL_USERNAME=… MAIL_PASSWORD=… MAIL_SCHEME=…
MAIL_FROM_ADDRESS="…@pressekonto.com"
MAIL_FROM_NAME="Pressekonto"
# Abo-/Bestandsschutz-Gate SCHARF (WS-5)
BILLING_ENFORCE_BOOKING=true
BILLING_OWN_VAT_ID=DE… # Pflicht für eVatR-Prüfung ausländischer USt-IDs
BILLING_VAT_RATE=0.19
# Stripe (Live)
STRIPE_KEY=pk_live_…
STRIPE_SECRET=sk_live_…
STRIPE_WEBHOOK_SECRET=whsec_… # aus Schritt 4
STRIPE_PRICE_SINGLE_PM=price_… # aus billing:sync-stripe-plans (Schritt 3)
# Google-Login
GOOGLE_CLIENT_ID=…
GOOGLE_CLIENT_SECRET=…
GOOGLE_REDIRECT_URI=https://pressekonto.com/auth/google/callback
# KI-Klassifikation / Content-Score
OPENAI_API_KEY=…
```
> Nach jeder `.env`-Änderung im laufenden Betrieb: `php artisan config:cache` erneuern (Schritt 5).
---
## 2. Code & Assets
```bash
composer install --no-dev --optimize-autoloader # zieht u.a. laravel/socialite
npm ci
npm run build # baut Portal- UND Web-Assets (public/build/portal + /web)
php artisan storage:link
```
---
## 3. Migrationen + einmalige Setups
```bash
php artisan migrate --force
```
Diese Phase-Migrationen MÜSSEN durchlaufen (Details im Sicherheits-Doc §7):
1. `backfill_email_verified_at_for_existing_users` — verhindert Lockout aller Bestands-User.
2. `downgrade_legacy_editor_users_to_customer` — schließt die Admin-Überberechtigung.
3. `add_oauth_provider_columns_to_users` — Google-Verknüpfung.
4. `create_legal_requests_table` — Compliance-Queue (WS-3).
Einmalige Setups (idempotent, in dieser Reihenfolge):
```bash
# Stripe: Tarife als Netto-Produkte/Preise anlegen → liefert STRIPE_PRICE_SINGLE_PM
php artisan billing:sync-stripe-plans
# Bestandsschutz aus dem Rechnungsarchiv neu nach user_payment_options migrieren.
# WICHTIG: auf Prod erneut laufen lassen, damit net_cents befüllt ist (vorher nur Dry-Run prüfen).
php artisan legacy:grandfather-subscriptions --dry-run
php artisan legacy:grandfather-subscriptions
# Favicons für alle Domains generieren
php artisan domains:generate-favicons
```
---
## 4. Stripe-Webhook
```bash
php artisan cashier:webhook # registriert den Webhook-Endpoint bei Stripe
```
Danach das im Stripe-Dashboard angezeigte **Signing-Secret** als `STRIPE_WEBHOOK_SECRET` in die `.env` eintragen und `config:cache` erneuern.
---
## 5. Caches scharf stellen
```bash
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan icons:cache
```
(oder gebündelt `php artisan optimize`). Bei jeder späteren `.env`-/Code-Änderung erneut ausführen.
---
## 6. Scheduler & Queue-Worker (Dauerbetrieb)
**Cron** (einmal pro Minute, treibt alle geplanten Tasks):
```cron
* * * * * cd /pfad/zur/app && php artisan schedule:run >> /dev/null 2>&1
```
Aktive geplante Tasks: `magic-links:purge` (täglich 03:00), `press-releases:purge-drafts` (So 04:00), `press-releases:publish-scheduled` (alle 5 min), `billing:generate-manual-invoices` (täglich 04:30), `press-releases:reset-monthly-quota` (Monats-1. 00:05).
**Queue-Worker** (Pflicht sonst bleiben KI-Klassifikation & Content-Score liegen):
```bash
php artisan queue:work --queue=default --tries=3 --max-time=3600
```
Verarbeitet die `ShouldQueue`-Jobs `ClassifyPressRelease` & `ScorePressRelease` (DB-Queue). Über Supervisor/systemd persistent halten. Manueller Einmal-Lauf als Fallback: `php artisan classification:work`.
---
## 7. Nach dem Deploy prüfen
- [ ] **Keine Lockouts:** Stichprobe aktiver Legacy-User → Login + Panel erreichbar.
- [ ] **`editor`-Rolle bereinigt:** `Role::findByName('editor')->users()->whereNotNull('legacy_portal')->count()` == 0.
- [ ] **Admins legitim:** Die 4 verbliebenen Legacy-Admins (Alt-Gruppe 1) sind echtes Personal.
- [ ] **Bestandsschutz korrekt:** `user_payment_options` (grandfathered) hat befülltes `net_cents`; Bestandskunden sehen den Buchungs-Hinweis NICHT (WS-5).
- [ ] **Gate scharf:** Einreichen ohne Buchung → 402; Bestandskunde/Abo → durchgelassen.
- [ ] **Auth-Kanäle:** Registrierung→Verifizierungsmail→Aktivierung; Magic-Link-Login; Google-Round-Trip (live mit echter https-Domain).
- [ ] **Stripe:** Test-Checkout + Webhook-Event kommt an (Cashier verarbeitet).
- [ ] **KI-Queue:** eine PM einreichen → Worker klassifiziert (kein Stau in `jobs`/`failed_jobs`).
- [ ] **Mail:** echte Zustellung (nicht `log`), Absender/Domain stimmen.