Release-Doku: Stand 09.07. nachgezogen; Runbook FULLTEXT-Fenster + Monitoring
Stand-Block 07.-09.07. (Billing/USt, Tarifwechsel, Agentur-Attribution, KI-Kennzeichnung, Tages-Fixes), R5.3 abgehakt, Commit-Zahlen aktualisiert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1ad2e544a9
commit
ef5de54300
2 changed files with 64 additions and 6 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Deploy-Runbook — Pressekonto (Laravel-System)
|
||||
|
||||
**Stand:** 03.07.2026 · **Gilt für:** das neue Laravel-System (Hub pressekonto + Spokes presseecho/businessportal24).
|
||||
**Stand:** 09.07.2026 · **Gilt für:** das neue Laravel-System (Hub pressekonto + Spokes presseecho/businessportal24).
|
||||
`FTP-LIVE-DEPLOY.md` betrifft nur das Alt-Symfony-System und ist für dieses System **nicht** anwendbar.
|
||||
|
||||
> Referenz-Plan: `dev/release/entwicklungsplan-release.md` (R5.2). Externe Voraussetzungen
|
||||
|
|
@ -34,6 +34,8 @@ Basis: `.env.example` kopieren und anpassen. Abweichend von den Dev-Defaults zwi
|
|||
| `DB_CONNECTION` + `DB_*` | MySQL-Zugangsdaten |
|
||||
| `MAIL_MAILER` + `MAIL_*` | echter Mailer — **Default `log` versendet nichts!** |
|
||||
| `MAIL_FROM_ADDRESS` | echte Absenderadresse |
|
||||
| `LOG_STACK` | `daily` (der Default `single` wächst unbegrenzt; `daily` rotiert mit `LOG_DAILY_DAYS`, Default 14) |
|
||||
| `MONITORING_ALERT_EMAIL` | Ops-Postfach für Betriebs-Alerts (R5.3); leer = Fallback auf `LEGAL_CONTACT_EMAIL` |
|
||||
| `SESSION_SECURE_COOKIE` | `true` |
|
||||
| `BASIC_AUTH_ENABLED` | Staging: `true` + User/Passwort · Live: `false` |
|
||||
| `BILLING_ENFORCE_BOOKING` | `true` (Default) |
|
||||
|
|
@ -77,6 +79,50 @@ php artisan event:cache
|
|||
php artisan queue:restart
|
||||
```
|
||||
|
||||
### 3a. Achtung: Migrationen auf `press_releases` (FULLTEXT erzwingt Tabellen-Kopie)
|
||||
|
||||
`press_releases` trägt zwei FULLTEXT-Indizes (`press_releases_admin_search_fulltext`
|
||||
auf title+keywords, `press_releases_web_search_fulltext` auf title+subtitle+text+keywords).
|
||||
Deshalb lehnt MySQL für **jede Spaltenänderung** ALGORITHM=INSTANT **und** INPLACE ab
|
||||
("InnoDB presently supports one FULLTEXT index creation at a time") und fällt auf
|
||||
ALGORITHM=COPY zurück — bei importiertem Bestand (~175k Zeilen, schwere Textspalten)
|
||||
lief das auf Dev mit ~30 Zeilen/s, also **1,5 h+ pro ALTER** (beobachtet 08./09.07.2026
|
||||
bei der KI-Kennzeichnungs-Migration). Nach dem Legacy-Import gilt das auf Prod genauso.
|
||||
|
||||
Bewährter Ablauf für solche Migrationen (Dev-erprobt, gesamt ~6 Min statt Stunden):
|
||||
|
||||
```sql
|
||||
-- 1) FULLTEXT-Indizes droppen (Suche ist solange offline!)
|
||||
ALTER TABLE press_releases DROP INDEX press_releases_admin_search_fulltext;
|
||||
ALTER TABLE press_releases DROP INDEX press_releases_web_search_fulltext;
|
||||
|
||||
-- 2) Migration laufen lassen: php artisan migrate --force
|
||||
-- (Spalten-ALTER geht jetzt per INPLACE in ~40 s; INSTANT bleibt wegen
|
||||
-- der versteckten FTS_DOC_ID-Spalte auch ohne Indizes gesperrt)
|
||||
|
||||
-- 3) Indizes NACHEINANDER neu aufbauen (InnoDB baut nur einen FULLTEXT gleichzeitig;
|
||||
-- Dev-Zeiten: admin ~40 s, web ~4,5 Min)
|
||||
ALTER TABLE press_releases ADD FULLTEXT press_releases_admin_search_fulltext (title, keywords);
|
||||
ALTER TABLE press_releases ADD FULLTEXT press_releases_web_search_fulltext (title, subtitle, text, keywords);
|
||||
```
|
||||
|
||||
Dazu beachten:
|
||||
|
||||
- **Wartungsfenster einplanen**: zwischen Schritt 1 und 3 liefern Admin- und Web-Suche
|
||||
Fehler/keine Treffer. Alternativ die volle COPY-Dauer akzeptieren (Suche bleibt online,
|
||||
Schreibzugriffe auf PMs sind währenddessen aber gesperrt).
|
||||
- **DB-Backup vorher** (gilt ohnehin, siehe Abschnitt 9).
|
||||
- Solche Migrationen **wiederaufnehmbar** schreiben (`Schema::hasColumn`-Guards, kein
|
||||
`->after()`), Vorlage: `2026_07_08_172023_add_ai_declaration_to_press_releases.php`.
|
||||
Hintergrund: Laravel legt pro Spalte ein eigenes ALTER ab — bricht der Prozess
|
||||
mittendrin ab, ist die Migration halb angewandt und ohne Guards nicht wiederholbar.
|
||||
- Einen laufenden COPY-ALTER **nicht clientseitig killen**: der Server-Thread läuft als
|
||||
Zombie weiter und Laravel reiht das Statement nach `KILL <id>` per Lost-Connection-Retry
|
||||
erneut ein — es stauen sich doppelte ALTERs am Metadata-Lock. Falls doch nötig:
|
||||
in MySQL `SHOW PROCESSLIST` prüfen und **alle** betroffenen Threads killen.
|
||||
- Beim allerersten Go-Live ist das unkritisch: `php artisan migrate` läuft dort **vor**
|
||||
dem Legacy-Import auf leeren Tabellen (Reihenfolge aus Abschnitt 7 einhalten).
|
||||
|
||||
## 4. Queue-Worker (Pflicht)
|
||||
|
||||
Die KI-Jobs (`ClassifyPressRelease`, `ScorePressRelease`) laufen auf der
|
||||
|
|
@ -117,6 +163,14 @@ Aktive Tasks (`php artisan schedule:list`):
|
|||
| täglich 04:30 | `billing:generate-manual-invoices` | manuelle Rechnungen fehlen |
|
||||
| So 04:00 | `press-releases:purge-drafts --days=180` | Alt-Entwürfe bleiben liegen |
|
||||
| monatl. 1. 00:05 | `press-releases:reset-monthly-quota` | **Kontingente werden nie zurückgesetzt** |
|
||||
| alle 15 Min | `market:refresh` | Börsendaten im Ticker veralten |
|
||||
|
||||
**Monitoring (R5.3):** Jeder Scheduler-Task hat ein `->onFailure()`, der
|
||||
Queue-Worker einen `Queue::failing()`-Listener. Fehlschläge werden als
|
||||
`critical` ins Tageslog geschrieben **und** an `MONITORING_ALERT_EMAIL`
|
||||
gemailt (Fallback `LEGAL_CONTACT_EMAIL`; abschaltbar über
|
||||
`MONITORING_ALERTS_ENABLED=false`). Die Mail ist Best-Effort — der Log-Eintrag
|
||||
ist die verlässliche Spur, daher `LOG_STACK=daily` setzen.
|
||||
|
||||
## 6. Stripe-Webhook
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue