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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Entwicklungsplan: Release-Fertigstellung Pressekonto
|
||||
# Entwicklungsplan: Release-Fertigstellung Pressekonto
|
||||
|
||||
> Konsolidiert aus vier Analysen vom **03.07.2026** (dev-Doku-Abgleich, Web-Frontend-Bestandsaufnahme, Backend-Baustellen, Deploy-Readiness).
|
||||
> Reihenfolge nach **Risiko/Nutzen**: erst Korrektheit & kaputte Pfade, dann Release-Entscheidungen (Billing), dann Frontend-Fertigstellung, dann Aufräumen, dann Deploy/QA.
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
---
|
||||
|
||||
## Stand & Wiedereinstieg (zuletzt: 03.07.2026)
|
||||
## Stand & Wiedereinstieg (zuletzt: 09.07.2026)
|
||||
|
||||
**Phase R0 komplett; R1 bis auf [EXTERN] fertig; R2.1 erledigt.** Erledigt: R0.1–R0.5 (Variant-Routen raus, gdpr_consent_at in allen drei Registrierungspfaden, Newsletter-Binding config-aware + fail-fast, Seeder produktionssicher inkl. PlanSeeder + Dev-User-Guard, Fehlerseiten 403/404/419/500/503 self-contained) · R1.1 (Gate safe-by-default `true`, Legacy-/Grandfathered-Pfade per Test festgeschrieben, Scope-Logik war korrekt) · R1.3 (Quota-Reset als finales Tarif-Modell-Verhalten dokumentiert).
|
||||
Offen in R1 (alle [EXTERN]): R1.2 Stripe-Live-Sync, R1.4 Preisfreigabe, R1.5 Refund-Entscheidung.
|
||||
|
|
@ -22,11 +22,15 @@ R2.2+R2.3 erledigt: Hub-Landing komplett ueberarbeitet (datengetriebenes Tarif-G
|
|||
**06.07. — Spoke-Frontend-Audit umgesetzt (Fake raus, Newsletter zurueckgebaut, Boersendaten echt, EN-Lokalisierung):** Ergebnis des businessportal24-Frontend-Audits vollstaendig abgearbeitet: (a) **Fake-Inhalte entfernt** — Fake-Anzeigen (`focus-ad`, `feed-ad`, Inline-Ad + Studie-Box in release-detail) geloescht; alle Mock-/Fallback-Daten raus (focus-hero, feed, most-read, active-newsrooms, industry-spotlight, industry-index rendern jetzt nur noch mit echten Daten oder gar nicht); Legacy-Mock-Komponenten geloescht (`featured-releases`, `press-releases-grid`, `highlight-card`, `press-release-card`); tote Links/Buttons ersetzt oder entfernt (Newsroom-Link, Richtlinien-Link, Print statt Permalink, „Newsroom folgen" raus, RSS-Erwaehnung raus, ⌘K funktional). (b) **Newsletter zurueckgebaut** — `newsletter-strip` aus allen Spoke-Seiten + Newsletter-Box aus release-detail entfernt (Feature nachgelagert, s. unten; Backend/DOI-Hinweis in R6.1 bleibt). (c) **Boersendaten echt** — neuer `MarketDataService` (Yahoo-Finance-Quotes, `config/market.php`, Cache) + Artisan-Command `market:refresh` alle 15 Min. im Scheduler; `live-ticker` konsumiert nur noch echte Daten und blendet sich ohne Daten aus. (d) **EN-Lokalisierung** — alle UI-Texte der Kern-Seiten (Header/Footer, Home-Sektionen, release-detail, kategorie, suche, newsrooms, newsroom, Pagination) in `lang/de/web.php` + `lang/en/web.php` ausgelagert; `Carbon::setLocale('de')`-Hardcodes auf `app()->getLocale()` umgestellt. **Langform-Seiten (veroeffentlichen, faq, hilfe, api) bleiben vorerst deutsch** — hreflang="en" dort entfernt; EN-Uebersetzung nachgelagert.
|
||||
**06.07. — Zwei Legacy-Befunde des Users gefixt:** (1) **Buchungs-Gate-Bug:** `grandfatheredNow` verlangte ein gesetztes `grandfathered_until` — das ist aber das explizite Legacy-Vertragsende und im Import-Regelfall NULL; dadurch hatte praktisch kein Bestandskunde eine aktive Zahlungsoption („Buchung erforderlich"). Jetzt deckelt `grandfathered_until` nur, wenn gesetzt; sonst zaehlt die laufende, vom MAN-Lauf fortgerollte Periode (`current_period_end`). Lokal: 15/22 Vereinbarungen wieder aktiv, Limits/unbegrenztes Kontingent greifen. (2) **Legacy-API-Uebernahme (User-Entscheidung, ersetzt „OUT" aus der Scope-Doku):** `legacy:import-api-keys` uebernimmt die api_keys der Altportale als Sanctum-Tokens mit identischem Secret (nur berechtigte Nutzer; Dry-Run lokal: 406 Keys); die Auth-Middleware uebersetzt X-ApiKey/api_key fuer gueltige Keys in Bearer (unbekannte weiter 410+Hinweis); die dokumentierten /service/…-Pfade sind Aliasse auf die v1-Controller (nicht uebernommene Alt-Endpoints antworten 410 mit Hinweis). Go-Live-Kette: Import laeuft NACH dem Grandfathering (WS-7 ergaenzt). Ausserdem R6.1-Vorpruefung: /thumbnails-Redirect nachgeruestet (fehlte trotz „ANGEPASST"-Vermerk), QA-Checkliste `dev/release/qa-checkliste.md` erstellt.
|
||||
**06.07. — Bestandskunden end-to-end verifiziert + Adress-Luecke geschlossen (Suite: 993 gruen):** Nach dem Buchungs-Gate-Fix zeigte sich die naechste Luecke der Kette: Der MAN-Rechnungslauf ueberspringt Vereinbarungen ohne Rechnungsadresse — und der Grandfather-Import nahm Adressen nie mit, weil die Altportale sie nur als Freitext-Blob fuehren. Neu: `legacy:import-billing-addresses` (LegacyAddressParser strukturiert die Blobs best-effort, raet nie; Report der manuell nachzupflegenden Faelle; nie ueberschreibend; CY in config/countries.php ergaenzt). Lokal: 11/21 Bestandskunden mit Adresse, MAN-Lauf rechnet ab (Zypern-Rechnungen exakt wie Legacy-Brutto, kein Preissprung), 9 manuell zu klaeren (7 leere Alt-Adressen). API-Key-Import echt gelaufen (406 Tokens), connektar-Key end-to-end gegen /service und /api/v1 verifiziert (200). **Git-Hygiene vorgezogen:** Users Frontend-Umbau committet (eigener Commit), Produktiv-SQL-Dumps enttrackt + .gitignore (User-Entscheidung: ohne History-Bereinigung, Repo bleibt privat; Dumps liegen weiter lokal fuer R6.3).
|
||||
**07.07. — QA-Abschnitt A abgenommen + Billing/USt-Haerten + Tarifwechsel/Downgrades:** QA-Checkliste Abschnitt A (Login & Konto) komplett manuell abgenommen; dabei 3 2FA-Befunde gefixt: 2FA-Einrichtung verlangt jetzt Code-Bestaetigung (vorher keine Login-Challenge), Recovery-Codes nur noch einmalig sichtbar, falscher Challenge-Code crasht nicht mehr (fehlende Route `two-factor.login`); E-Mail-Wechsel jetzt als Pending-Flow mit Bestaetigungslink an die neue Adresse. **Stripe-USt vervollstaendigt:** `automatic_tax` in der Checkout-Session aktiviert (USt fehlte vorher in der Session), STR-Rechnungsspiegelung liest USt aus `total_taxes` (Stripe-API liefert kein `tax`-Feld), Profil-Rechnungsadresse als Stripe-Rechnungsempfaenger (Wallet-Daten ueberschreiben sie nicht mehr); Rechnungsseite listet neue STR/MAN-Rechnungen (STR verlinkt ins Stripe-Portal), Archiv-Filter entfernt, Altsystem-Archiv nur noch fuer Bestandskunden. **Tarifwechsel im Buchungs-Modal:** Abo-Swap mit anteiliger Verrechnung; Downgrades ohne Gutschrift erst zum Periodenende, Kontingent-Sperre beim Wechsel. **UX-Runde:** Volltext-Suchindex (+ Fix doppelte Alpine-Instanz), PM-Vorschau im echten Portal-Design mit Portal-Switch, Ablehnungsbegruendung direkt im Editor, Einreichen-Modal-Panelstruktur + fixierter Kontingent-Badge, Add-ons-Modal statt Toast bei fehlendem Guthaben, Depublikations-Sektion ans PM-Seitenende + Direktlinks je Portal, `single_purchases`-ENUM um `depublication` erweitert, abgebrochener Depublikations-Checkout blockiert nicht mehr.
|
||||
**08.07. — Agentur-Attribution + Depublikations-Kauf + eVatR-USt-ID-Pruefung:** Agentur-Attribution neu geloest — Uebermittler kommt aus neuem Profilfeld `users.agency_name` statt eigener Agentur-Firma; PM-Detailseite zeigt Urheber/Uebermittler-Zeile; `legacy:migrate-agency-names` uebertraegt die Alt-Agenturnamen; `companies:retire-agency-type` schafft den Firmen-Typ „Agentur" ab; Firmen-Typ-Auswahl aus der Profil-UI entfernt (Plan abgehakt, Abnahme 08.07. dokumentiert). **Depublikation end-to-end:** Kauf wird als eingeloest markiert, erzeugt Rechnung + Bestaetigungs-Mail; Buchungsseiten-Verlauf zeigt den Kauftyp, Erfolgsmeldungen gruen. **USt-ID-Pruefung (neu):** vor jeder Buchung per eVatR (EU-VIES) gegengeprueft, Stripe-Tax-IDs abgeglichen; eigene USt-IdNr. aus `BILLING_OWN_VAT_ID`. Deploy-Runbook §3a ergaenzt: FULLTEXT-Migrations-Wartungsfenster fuer `press_releases` (bei importiertem Bestand faellt jede Spaltenaenderung auf ALGORITHM=COPY = Stunden; Ablauf Indizes droppen -> migrieren -> nacheinander neu bauen = ~6 Min).
|
||||
**09.07. — KI-Kennzeichnung (Art. 50 KI-VO) + PM-Editor-UX + Tages-Fixes (Suite: 1142 gruen):** KI-Kennzeichnung als **Pflicht-Deklaration fuer Text und Bilder** umgesetzt (Enums `AiTextDeclaration`/`AiImageDeclaration`, Model `PressReleaseAiDeclaration` + Migrations, Concern `InteractsWithAiDeclaration`, `AiDeclarationRequiredException`, oeffentliches Label `portal/ai-public-label`, Test `PressReleaseAiDeclarationTest`) — EU-KI-VO Art. 50 Transparenzpflicht. PM-Editor-UX: Kategorie in die Schreibflaeche, Bild-Upload als Modal-Flow. **Tages-Fixes:** OpenAPI-Route `/docs/api/v1` auf `public/api/v1.yml` umgebogen (der `docs/`-Ordner ist ein nicht mitgekommener Mount; Route lief sonst 500) + 404-Guard; `depublish`-Credits `25 -> 35` (Entscheidung O6) in config bestaetigt und die zwei stehen gebliebenen Preis-Tests nachgezogen. Suite wieder komplett gruen (1142).
|
||||
**Noch uncommittet im Arbeitsbaum (WIP, jeweils mit Tests) — vor R6.5 in fokussierte Commits zerlegen:** Kontakt-Nachrichten-Feature (`ContactMessage`-Model/Enums/Factory/Migration + Admin-Queue-Livewire, `ContactMessagesAdminTest`), Validierungs-Feedback (`PressReleaseValidationFeedbackTest` + `pr-error-summary`), Page-Data-Cache (`PageDataCacheTest`), Company-Portal-Restriction (`CompanyPortalRestrictionTest`), Lang-Auslagerungen (`lang/{de,en}/auth|passwords|validation|static`), `contact-launcher`/`legal-language-notice`-Komponenten. Ausserdem ist der komplette `docs/`-Ordner im Arbeitsbaum geloescht (Mount nicht mitgekommen) — **bewusst ignoriert (User 09.07.)**, die einzige code-relevante Datei `docs/api/v1.yml` liegt jetzt als `public/api/v1.yml` vor.
|
||||
**Wiedereinstieg / naechste Schritte:**
|
||||
1. ~~Klaerungsliste Rechtstexte~~ **erledigt 06.07.**; ~~R3.1-Restbacklog~~ **erledigt 06.07.** (siehe oben).
|
||||
2. **[EXTERN]:** Postfach `info@pressekonto.com` anlegen (Haupt-Rechts-Mail, 06.07.); CONTACT_EMAIL_*-Support-Postfaecher je Brand; REPORT_EMAIL_* optional · R1.2 Stripe-Live · R1.4 Preisfreigabe · R5.4 Favicons · anwaltliche Freigabe AGB v0.6/Datenschutz v0.3. (~~Depublikations-Preis~~ entschieden: 35 EUR netto.)
|
||||
3. **Phase-2-Rest (bewusst nach Launch):** T11-Ausbau DSA-Queue (Basis existiert) · englische Rechtstexte (O-C, nach Sprachvarianten-Entscheidung) · oeffentliche Versionshistorie der Rechtstexte (O-D) · Ablehnungs-Mails mit Kategorie-Link (rejection_categories im Reject-Flow verdrahten).
|
||||
4. **Dann:** R6.1 manuelle QA-Durchgaenge (User, per qa-checkliste.md), R6.3 Staging-Rehearsal [EXTERN], R6.4 Go-Live-Kette, R6.5 Git-Hygiene-Rest: Branch (~142 Commits vor main) pushen + mergen + Release-Tag, sobald freigegeben; optional vorher die drei user_filter_presets-Migrations zusammenfuehren. (~~SQL-Dump-Entscheidung~~ erledigt 06.07.: enttrackt + ignoriert.)
|
||||
4. **Dann:** R6.1 manuelle QA-Durchgaenge (User, per qa-checkliste.md), R6.3 Staging-Rehearsal [EXTERN], R6.4 Go-Live-Kette, R6.5 Git-Hygiene-Rest: Branch (~180 Commits vor main, Stand 09.07.) pushen + mergen + Release-Tag, sobald freigegeben — **vorher den uncommitteten WIP (s. Stand-Block oben) in fokussierte Commits zerlegen**; optional die drei user_filter_presets-Migrations zusammenfuehren. (~~SQL-Dump-Entscheidung~~ erledigt 06.07.: enttrackt + ignoriert.)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -113,7 +117,7 @@ R2.2+R2.3 erledigt: Hub-Landing komplett ueberarbeitet (datengetriebenes Tarif-G
|
|||
|
||||
- [x] **R5.1 `.env.example` vervollständigen** — Erledigt 03.07.: alle projektspezifischen Keys ergänzt und dokumentiert (Multi-Domain `APP_PORTAL_*`/`APP_PRESSEECHO_*`/`APP_BUSINESSPORTAL_*`/`APP_PROTOCOL`, `SANCTUM_STATEFUL_DOMAINS`, Legacy-DBs, Stripe/Cashier/Billing inkl. `STRIPE_PRICE_SINGLE_PM` + `BILLING_OWN_VAT_ID`, KI `OPENAI_*`/`CLASSIFICATION_*`/`CONTENT_SCORE_*`, `NEWSLETTER_SYNC_*`, `VITE_DEV_SERVER_URL`, `SESSION_SECURE_COOKIE`-Prod-Hinweis). Werte selbst (Live-Keys, Adressen) bleiben [EXTERN].
|
||||
- [x] **R5.2 Deploy-Runbook schreiben** — Erledigt 03.07.: `dev/release/deploy-runbook.md` — Server-Voraussetzungen, Prod-`.env`-Solltabelle, Build-/Release-Schritte (composer, `npm run build`, storage:link, migrate --force, Stammdaten-Seeder, Caches, queue:restart), Queue-Worker (Queue `classification`, systemd-Beispiel), Cron/Scheduler (5 Tasks mit Ausfall-Folgen), Stripe-Webhook, Erst-Einrichtung (Legacy-Import-Reihenfolge), Smoke-Test-Checkliste, Rollback. Enthält den robots.txt-Deploy-Hinweis aus R2.4.
|
||||
- [ ] **R5.3 Monitoring/Alerting entscheiden** — kein Sentry o. ä. installiert; Scheduler-/Queue-Failure-Alerting fehlt. Minimalvorschlag: `schedule`-`onFailure`-Mail + Log-Rotation; optional Sentry. **[EXTERN: Entscheidung]**
|
||||
- [x] **R5.3 Monitoring/Alerting** — Umgesetzt 09.07. (Entscheidung: Mail-Alerts + Log-Rotation, ohne neues Dependency): zentraler `OperationalAlert`-Helper (immer `Log::critical`, zusätzlich Best-Effort-Mail an `MONITORING_ALERT_EMAIL`, Fallback `LEGAL_CONTACT_EMAIL`, feature-flagged via `MONITORING_ALERTS_ENABLED`); alle 6 Scheduler-Tasks mit `->onFailure()` verdrahtet, Queue-`failing`-Listener in `AppServiceProvider`; `.env.example`/Runbook: `LOG_STACK=daily` als Prod-Sollwert (Rotation 14 Tage). Tests: `OperationalAlertTest`. **Bewusst offen (nachgelagert):** echtes APM/Sentry (neues Dependency + DSN [EXTERN]) — der Log-+Mail-Weg deckt Ausfall-Erkennung fürs Release ab.
|
||||
- [ ] **R5.4 Favicons je Domain** — `domains:generate-favicons` erzeugt bewusst leere Platzhalter-Dateien; echte Favicons für pressekonto/presseecho/businessportal24 deployen. **[EXTERN: Assets]**
|
||||
|
||||
---
|
||||
|
|
@ -124,7 +128,7 @@ R2.2+R2.3 erledigt: Hub-Landing komplett ueberarbeitet (datengetriebenes Tarif-G
|
|||
- [x] **R6.2 Security-Review** — Audit + Härtung erledigt 03.07. **Solide befunden:** CSRF (Stripe-Webhook via Signatur, keine Ausnahmen), Magic-Link-Krypto (64-Zeichen-Token, sha256-gehasht, atomare Einmalverwendung), HTMLPurifier-Sanitizing der PM-Texte, Raw-Queries durchgängig mit Bindings, IDOR-Schutz doppelt (Scope + Policy), BasicAuth timing-sicher, Session host-only korrekt fürs Hub-and-Spoke-Setup. **Gefixt:** Security-Header-Middleware (app-seitig), Logo-Upload im Company-Create über ImageService (vorher SVG/XSS möglich), Rate-Limits für Passwort-Reset/Registrierung/Consume-Routen, `EnsureUserIsCustomer` als persistente Livewire-Middleware. Tests: `SecurityHardeningTest`. **Offen/bewusst:** CSP separat einführen (Livewire/Alpine-Inline-Strategie nötig); Token-Abilities werden auf API-Routen nicht feingranular geprüft (ein Scope für alles — ok, solange keine eingeschränkten Tokens ausgegeben werden); Draft-PM-Anhänge nur per URL-Obscurity (dokumentierter MVP-Tradeoff); HSTS am Proxy setzen; **[USER-ENTSCHEIDUNG] Legacy-SQL-Dumps (`dev/migration 2026/sql/*.sql`, Produktivdaten!) sind im Git getrackt — enttracken + ggf. History bereinigen.**
|
||||
- [ ] **R6.3 Staging-Import-Rehearsal** — Datenimport gegen produktiven Legacy-Snapshot auf Staging (mehrfach als der offene Vollständigkeitsnachweis referenziert, P6.10/P11.3). Achtung: `mysql_businessportal`-Verbindung lokal ist nur ein ~April-Snapshot — fürs Rehearsal echten aktuellen Dump ziehen. **[EXTERN: Server/Snapshot]**
|
||||
- [ ] **R6.4 Go-Live-Kette** — Go-Live-Mailing (Passwort-Reset) + API-Kunden-Mailing: Code fertig, **finale Texte + Freigabeliste [EXTERN]**; DNS-Cutover `pressekonto.de`; Legacy-System read-only während Final-Import; alte Symfony-Server abschalten. *(= P11.x)*
|
||||
- [ ] **R6.5 Git-Hygiene** — Branch `fix/zeitzone-europe-berlin` (73 Commits vor `main`) pushen und nach `main` mergen; danach Release-Tag. Die drei `user_filter_presets`-Migrations zusammenführen (rev-5, „Hygiene vor Go-Live") optional davor.
|
||||
- [ ] **R6.5 Git-Hygiene** — Branch `fix/zeitzone-europe-berlin` (**~180 Commits vor `main`**, Stand 09.07.) pushen und nach `main` mergen; danach Release-Tag. **Vorher:** den uncommitteten Arbeitsbaum-WIP (Kontakt-Nachrichten, Validierungs-Feedback, Page-Cache, Company-Portal-Restriction, Lang-Auslagerungen; s. Stand-Block) in fokussierte Commits zerlegen. Die drei `user_filter_presets`-Migrations zusammenführen (rev-5, „Hygiene vor Go-Live") optional davor.
|
||||
- [x] **R6.6 Doku-Sync** — Erledigt 03.07.: `12-NAECHSTE-SCHRITTE.md` + `08-PROGRESS.md` tragen deutliche Verweis-Banner auf den aktiven Release-Plan (Phase 8/Stripe als erledigt markiert, Test-Stand korrigiert).
|
||||
|
||||
---
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue