Commit graph

198 commits

Author SHA1 Message Date
b4b2e013d6 recht: Meldeverfahren v2 Phasen 1-4 — Re-Sync-Sperre, Anonymisierung, Magic-Link-Intake, Self-Service-Korrektur
Phase 1: sync_locked_at auf press_releases (Importer überspringt gesperrte
PMs auch bei --force), LegalRequest um Verifikation/Ausführung erweitert,
verschlüsselte Vorher-Snapshots mit Löschfrist (snapshots:purge, täglich).

Phase 2: AnonymizationService (Unicode-Wortgrenzen-Schwärzung, Pflicht-Diff,
transaktionale Ausführung mit Snapshot, Kontakt-Detach, Bild-Löschung,
Sitemap-Invalidierung, Verlauf ohne Klartext-Altwerte); Admin-Queue kann
DSGVO-Anfragen anonymisieren oder depublizieren, inkl. Snapshot-Restore.

Phase 3: Deflektions-Trichter „PM melden/ändern" (melden/pm) mit Kosten-
Tabelle vorab; Magic-Link geht nur an die hinterlegte Pressekontaktadresse
(neuer purpose press_release_report), atomare Verifikation, Anliegen-Auswahl
erzeugt verifizierte Queue-Anfragen; toter-Kanal-Fallback; Owner-Einstieg.

Phase 4: Panel-Abschnitt „Änderung & Korrektur" — Levenshtein-Gate (5 %,
Mini-Edit-Ausnahme ≤ 2 Zeichen) stuft klein/groß ein; kleine Korrektur
kostenlos sofort live (Snapshot, Sperre, Verlauf, Re-Score), größere als
Change-Anfrage (Interim bis 10-€-Checkout, Phase 7).

Entwicklungsplan mit Entscheidungen E1-E8 und offenen Punkten in
docs/Decision-Update; 41 Pest-Tests (tests/Feature/Legal) grün.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 15:56:34 +00:00
58c0cc3f23 admin: Newsletter mit Abmelde-Liste, Follow-up-Filtern und gedrosseltem Versand
- Unterseite /admin/newsletter/abmeldungen listet Newsletter-Opt-outs mit
  Zeitpunkt, Suche und Link zur User-Detailseite
- Kampagnen-Filter: Empfänger einer früheren Kampagne ausschließen
  (Abgleich per User-ID und E-Mail-Snapshot) für Follow-up-Mailings
- Login-Filter kann Monats-Scheiben (von–bis) abgrenzen, um große
  Listen Monat für Monat abzuarbeiten
- Versand läuft in Wellen (Standard 50 Mails / 15 Min, per .env
  justierbar) gegen SMTP-Limits und Blocklisten; Hinweis im Senden-Modal
- web: Firmen-Website im Newsroom & Co. als absolute URL verlinkt
  (Company::websiteUrl), statt relativ auf /newsroom/www.example.de
- kunde: API-Doku-Button öffnet die /de/api-Seite; OpenAPI-Spezifikation
  als eigener, benannter Download (pressekonto-api-v1.yml)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 12:38:47 +00:00
9b73972d33 kunde: PM-Liste zeigt Firmen-Kontext unter der Headline und Bild-Thumbnails
Der aktive Firmen-Kontext (Firmen-Umschalter) steht jetzt prominent
unter der Überschrift — Firmenname oder „Alle Firmen" — statt als
kleiner Hinweistext. Neue Spalte „Bild" zwischen Status und Titel mit
dem Titelbild (thumb-Variante, is_preview zuerst), dem gewählten
Platzhalter bei bildlosen PMs oder einem generischen Icon-Fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 14:31:44 +00:00
921c533fdb admin: Benutzer-Übersicht verlinkt die Detailseite zusätzlich zur Schnellansicht
Neuer Button in der Aktionsspalte und im Detail-Modal führt zu
admin/users/{id}; bestehende Aktions-Buttons bekommen Tooltips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 13:34:02 +00:00
37e543e69a admin: Credits und freie PMs ohne Zahlung gutschreiben
Neues Panel "Guthaben & Kontingent" auf der Benutzer-Detailseite
(users:manage): Credits gehen als Grant-Buchung ins Wallet-Ledger,
freie Pressemitteilungen als bezahlte 0-€-Einzelkäufe, die das
Buchungs-Gate erfüllen und beim Veröffentlichen regulär eingelöst
werden — Stripe bleibt unberührt. Jede Gutschrift landet mit Vergeber
und Grund als neuer Typ "Gutschrift" im Aktivitäts-Verlauf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 13:06:01 +00:00
ab0030d71e web: Mail-Abmeldungen landen im Aktivitäts-Verlauf
Neuer ActivityType "Mail-Abmeldung": Der Unsubscribe-Controller
protokolliert Abbestellen (Link-Klick und RFC-8058-One-Click) sowie
das Wieder-Aktivieren — nur bei echter Zustandsänderung, wiederholte
Klicks erzeugen keine Doppel-Einträge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:26:49 +00:00
215cbcbdbf admin: internes Newsletter-Modul mit Filtern, Protokoll und Abmeldung
Neues Modul unter Admin ▸ Newsletter (nur users:manage): Kampagnen mit
Betreff + leicht formatiertem Text (Purifier-Profil newsletter: fett/
kursiv, Listen, Links) im zentralen Mail-Layout. Empfänger-Filter auf
der User-Datenbank: Portal, Legacy-Vertrag (Bestandsschutz), Login
innerhalb/außerhalb X Monaten, Sortierung nach Login/Erstellung — mit
Live-Zähler und Vorschau im Editor.

Versand friert die Empfängerliste als Protokoll ein (newsletter_
campaign_recipients) und stellt pro Empfänger einen Queue-Job ein;
der Opt-out wird im Worker erneut geprüft. Jede Mail trägt den
signierten One-Click-Abmelde-Link (neuer EmailNotificationType::
Newsletter, bestehende Unsubscribe-Infrastruktur inkl. RFC 8058);
die Abmeldung greift sofort für alle künftigen Auswahlen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 09:26:57 +00:00
d411e6ce7f admin: Verlauf protokolliert jede versendete E-Mail
Neuer Listener RecordMailActivity am MessageSent-Event erfasst zentral
alle Versandwege (Mailables, Notifications, Fortify, Queue-Mails beim
realen Versand im Worker). Neuer ActivityType "E-Mail" mit Empfänger,
Betreff und Mailable-Klasse in den Metadaten; bekannte Empfänger werden
mit ihrem User verknüpft.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 09:13:43 +00:00
e3ce626b73 admin: PM-Detailseite verlinkt Firma, Autor und Firmen-Benutzer
Firma und Autor sind im Header und Status-Grid klickbar
(admin/companies/{id} bzw. admin/users/{id}). Das Kontakte-Panel heißt
jetzt "Firma & Pressekontakte" und zeigt die Firmendaten (Adresse,
E-Mail, Telefon, Website) über den Pressekontakten. Neu: "Benutzer mit
Zugriff (über Firma)" listet alle Firmen-Mitglieder mit Rolle und
Autor-Markierung — mehrere User hängen nur über die Firma an einer PM,
Magic-Links sind reine Login-Tokens.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 08:48:22 +00:00
58c773b153 web: Domain-spezifische Favicons und App-Icons für alle drei Marken (R5.4)
Eigene Icon-Sets unter public/icons/{pressekonto,presseecho,businessportal24}
(SVG-Favicon + Touch-/App-Icons); ThemeHelper mappt das aktive Theme auf den
Icon-Ordner (Portal/Admin nutzt den pressekonto-Satz), alle Layout-Heads
binden Favicon + apple-touch-icon domain-abhängig ein.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 07:50:21 +00:00
3d10cbf709 web: Startseiten-Feed cachen + Index gegen Filesort der Feed-Query
Der Livewire-Feed lief auf jeder Startseiten-Impression ungecacht; seine
ORDER-BY-published_at-Query kann wegen portal IN (…) keinen bestehenden
Index zur Sortierung nutzen und filesortete ~10-20k Zeilen (live gemessen
2,3 s pro Aufruf — die Startseite blieb dadurch trotz Seitendaten-Cache
bei 6-9 s TTFB). Zwei Maßnahmen:

- Neuer Index (language, status, deleted_at, published_at): Backward
  Index Scan statt Filesort, Query 2 ms statt 2,3 s — greift auch für
  ungecachte Livewire-Interaktionen (Zeitraum-Filter, tiefe Seiten).
- Feed-Seiten 1-3 laufen über WebPageCache (SWR wie die übrigen
  Seitendaten); gecacht werden nur items + total, der Paginator wird pro
  Request neu gebaut (keine Host-URLs des Cache-Erzeugers im Cache).
  Unbekannte timeframe-Werte aus der URL fallen auf 'all' zurück und
  erreichen weder Query noch Cache-Key. Der doppelte Gesamt-COUNT pro
  Request entfällt; der 'Mehr laden'-Zähler nutzt jetzt den gefilterten
  Total des Paginators.

Lokal mit Live-Datenbestand: Startseite kalt 875 ms (vorher 2,5 s),
warm 11 ms (vorher 72 ms).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 14:53:09 +00:00
07d89a0e6a web: Preise-Seite zeigt unter Weitere Leistungen nur noch Depublizieren
Inhaltliche Korrektur (8 Credits) und Update/Ergänzung (4 Credits)
existieren als buchbare Leistungen noch nicht — sie folgen erst mit dem
Bookings-/Magic-Link-Rework und fliegen bis dahin von der Preisliste.

Depublizieren wird als Direktkauf in Euro abgerechnet (Stripe-Checkout
über billing.depublication_price_cents), nicht in Credits: Die Seite
zeigt jetzt 35 € aus derselben Preisquelle wie der Kauf-Flow statt der
falschen 35 Credits. Ohne konfigurierten Preis verschwindet der Block
komplett (wie das Angebot auf der PM-Detailseite).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 11:34:22 +00:00
2ea64ad222 web: Strukturierte Daten (JSON-LD) und SEO-Metas fürs öffentliche Frontend
Ergänzt die bislang fehlenden strukturierten Daten auf den Presse-Seiten:

- PM-Detailseite: NewsArticle + BreadcrumbList als JSON-LD sowie
  article:published_time/-section/-tag-Metas und og:image:alt — nur auf
  der öffentlichen Seite, die noindex-Vorschau bleibt ohne Markup.
- Kategorie-Seiten: BreadcrumbList plus hreflang de/en über die
  lokalisierten Slugs (CategoryPageData liefert dafür neu
  categoryAlternateSlugs, mit View-Fallback für gecachte Alt-Daten).
- Newsroom: Organization-Markup (Logo, Website als sameAs, Boilerplate).
- Portal-Homepages: WebSite mit SearchAction (Sitelinks-Searchbox) und
  Organization.
- Layout: og:locale und twitter:image ergänzt; neue Sections meta_extra
  und structured_data.

Neue Komponente x-web.structured-data rendert JSON-LD mit JSON_HEX_TAG,
damit "</script>" in Titeln/Teasern das Script-Tag nicht aufbrechen kann.
JSON-LD-URLs werden wie der Canonical aus der Portal-Basis gebaut
(unabhängig von forceRootUrl), damit Host und Canonical übereinstimmen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 10:27:45 +00:00
dec524989b web: Responsive-/Mobile-Fixes fürs öffentliche Frontend
Behebt strukturelle Mobile-Bugs (320/390px) über presseecho,
businessportal24 und den pressekonto-Hub hinweg:

- Focus-/Kategorie-/Newsroom-Hero: Text im Flow (min-h + flex) statt
  fester Höhe, responsive Typo — Overlay überläuft nicht mehr nach oben.
- Quality-Summary: Grid stackt auf Mobile (behebt Seiten-Overflow).
- Hub: Utility-Bar mit Wrap, Header mit Mobile-Burger, Footer stackt,
  Architektur-Diagramm als gestapelte Mobile-Variante.
- Sticky-Header (Portal): fehlende .header-sticky-CSS ergänzt und Script
  mit Platzhalter, damit der Header beim Scrollen sichtbar bleibt.
- Header-Overflow bei 320px entschärft (Portal + Hub); Hub-Hero-H1
  verkleinert, damit die Wortmarke "businessportal24" umbricht.
- Mobile-Nav um Preise/FAQ/API ergänzt; Industry-Index-Dichte,
  Touch-Targets und Preise-Einzel-PM-Block für kleine Screens verbessert.
- Homepages/Shared: px-8 → px-4 sm:px-6 lg:px-8.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-16 09:33:49 +00:00
3e855375b1 web: Kategorie-Badge im Feed bricht auf Mobile sauber um
Lange Kategorienamen liefen auf schmalen Viewports aus dem Layout —
Badge darf jetzt umbrechen und ist mobil auf 8rem begrenzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:07:05 +00:00
a3671bab90 emails: Portal-Wortmarken im Mail-Header ergänzen
Rechts neben der pressekonto-Wortmarke erscheinen jetzt presseecho
und businessportal24 — Empfänger ordnen System-Mails damit sofort
den Portalen zu. Hellere Markenfarben auf Hub-Blau für Lesbarkeit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:06:59 +00:00
3a11963990 admin: Aktivitäts-Verlauf unter Reports ▸ Verlauf
Chronologisches Protokoll der Systemereignisse als neue Admin-Seite
(/admin/reports/activity) mit Filter nach Ereignistyp, Zeitraum und
Suche. Erfasst ab jetzt fortlaufend:

- Registrierungen inkl. Weg (Formular, Google, Magic-Link)
- Anmeldungen inkl. Weg (Passwort, Google, Magic-Link, Impersonation)
- PM-Statuswechsel mit Ergebnis/Begründung (zentral im Status-Log-Hook;
  KI-/Scheduler-Wechsel erscheinen als „System")
- Zahlungseingänge (Rechnungsspiegelung) und Credit-Aufladungen
- Formular-Eingänge: Kontakt, Rechtsanfrage, Widerruf, Kündigung,
  Newsletter-Anmeldung (Observer auf den Modellen)

Schreiben ist Best-Effort über den ActivityLog-Service — ein
fehlgeschlagener Verlaufseintrag bricht nie den fachlichen Ablauf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 16:00:58 +00:00
e32431e948 billing: Zahlungsbestätigung per Mail nach jeder Buchung
Sobald eine bezahlte Stripe-Rechnung in den STR-Kreis gespiegelt
wird, erhält der Kunde eine Bestätigungsmail mit Rechnungsnummer
und Beträgen — deckt Tarif (inkl. Verlängerung), Einzel-PM und
Credits ab. Transaktionsmail ohne Opt-out; durch die idempotente
Spiegelung genau eine Mail pro Beleg, Gutschriften bleiben stumm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 14:36:37 +00:00
0b01929f80 profil: Speichern-Buttons für Persönliche Daten und Konto & Sicherheit
Die beiden oberen Panels auf /admin/me/profile hatten als einzige
keine eigene Speichern-Zeile — Sprach- und Kontaktdaten-Änderungen
ließen sich nur über die Buttons weiter unten sichern. Footer wie in
den übrigen Panels ergänzt, per flex/mt-auto bündig am Panel-Ende.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 13:12:05 +00:00
ce59cbbf4a auth: Selbst-Registrierungen nicht mehr als Legacy-Bestand einstufen
Die Register-Komponente setzte kein registration_type, wodurch der
DB-Default existing_legacy griff und jeder Neukunde im Admin als
Legacy-Bestand erschien. Jetzt wird explizit Company gesetzt —
konsistent mit dem CustomerAccountProvisioner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 13:11:53 +00:00
700f5e6131 dashboard/errors: Onboarding-Card „Erste Schritte" & Hub-Styling der Fehlerseiten
Neue aufklappbare "Erste Schritte"-Card als erste Card im Kunden-Dashboard,
die neue Nutzer durch Profil, Rechnungsadresse, Firma und erste PM führt und
sich ausblendet, sobald alle Schritte erledigt sind. Zusätzlich die
gemeinsame Fehlerseiten-Vorlage (404/403/419/500/503) an das Hub-Design
angepasst (Palette, Gold-Akzent, Hub-Blau-Button), weiterhin self-contained
ohne Vite-Assets.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-15 13:07:36 +00:00
830aca5149 admin: Betriebsüberwachung im Backend (Queue-Worker & Deployment-Checks)
Neue Reports-Seite (settings:manage) zeigt den Queue-Zustand (ältester
wartender Job, Worker aktiv/gestoppt, fehlgeschlagene Jobs) und
Deployment-Checks als Ampel: Permissions ausgerollt, APP_DEBUG,
Session-Secure-Cookie, ausstehende Medien-Privatisierung. Damit ist die
für Magic-Link-Login und fristrelevante Mails kritische Queue-Abhängigkeit
aus dem Admin sichtbar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:49:57 +00:00
8f517e993d security: Stored-XSS über page_url im Kontaktformular schließen (H3)
page_url aus dem anonymen Kontaktformular wird auf url:http,https
validiert; das Admin-Backend rendert nur http(s)-Links klickbar, sonst
als Text. Verhindert javascript:-URIs, die beim Admin-Klick im
Admin-Kontext liefen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:49:05 +00:00
77f8f9cb35 security: Rechteausweitung schließen & Admin-Panel feingranular gaten (K1, H1, H2, M8)
- users:manage/roles:manage auf allen User-/Rollen-Masken erzwungen;
  is_super_admin aus $fillable entfernt und nur per autorisiertem
  forceFill setzbar; zentraler Gate::before-Super-Admin-Kurzschluss (K1/M8).
- Nicht-Super-Admins können Super-Admin-Konten nicht mehr bearbeiten (Fix#2);
  Impersonation mit Rangprüfung, keine Token-Erstellung während Impersonation (H1).
- Destruktive/verwaltende Admin-Aktionen (CRM/Billing/Compliance/Struktur)
  hängen an neuen admin-only Permissions; Editor behält reine Content-Rechte (H2).
- Kanonischer Permission-Katalog (App\Authorization\Permission) als Single
  Source of Truth für Seeder und Monitoring.

Deployment: `php artisan db:seed --class=RolesAndPermissionsSeeder` auf allen
Umgebungen ausführen (neue Permissions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:48:50 +00:00
6250b0bab4 media: PM-Medien privat ausliefern + Vorschau-Signatur (M4, M5, Fix#4/#5)
- Neue PM-Bilder/Anhänge liegen auf der privaten local-Disk; Auslieferung
  über kontrollierte Media-Routen mit gemeinsamer Zugriffslogik
  (AuthorizesPressReleaseMediaAccess). Öffentliche Medien werden aus den
  geladenen Modellen ermittelt (weniger Queries) und länger gecacht.
- Anonyme Token-Vorschau lädt Bilder über temporär signierte URLs (Fix#5).
- API-Resource baut Variant-URLs über die Media-Route statt /storage
  (Fix#4). Storage-Schicht prüft zusätzlich den serverseitigen MIME-Type (M5).
- press-releases:privatize-media migriert Bestandsmedien.

Deployment: einmalig `php artisan press-releases:privatize-media` ausführen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:48:06 +00:00
6e84266f90 press-releases: Publish-Rechte, Quota-Races & Slug vereinheitlichen
- Publish/Reject/Archive und changeStatus erzwingen konsistent
  press-releases:publish; changeStatus schloss die Lücke, über die das
  Status-Modal die Prüfung umging (Fix#1/H2).
- publish()/changeStatusFromAdmin sperren PM- und User-Zeile
  transaktional; QuotaExceededException wird in Admin-Publish und im
  Auto-Publish-Job abgefangen (Warnung statt 500 / bleibt in Review, Fix#3/M2).
- Slug-Erzeugung nur noch über HasUniqueSlug (generateUniqueSlug +
  saveWithUniqueSlugRetry), redundanter Controller-Helper entfernt (M3).
- API-/Legacy-Text wird vor der Persistenz sanitisiert (M6);
  Scheduler/Legacy-Tracking ignorieren soft-gelöschte PMs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:47:51 +00:00
aae456954a billing: Nebenläufigkeit & Idempotenz härten (H4, Stripe, Boost-Slots)
- CreditTopup-Gutschrift, MAN-Rechnung, Proof-PDF und Stripe-Webhook-
  Spiegelung sperren die betroffene Zeile innerhalb der Transaktion und
  prüfen die Idempotenz erst danach (verhindert Doppelgutschrift bei
  at-least-once-Webhooks, H4).
- Gemeinsamer LocksModelForUpdate-Trait für die häufige Lock-by-Key-Form
  (CreditTopup, ManualInvoice).
- Unique-Index auf invoices.stripe_invoice_id; Boost-Inventar über
  boost_slot_locks serialisiert, verwaiste Kategorie-Locks werden beim
  Löschen der Rubrik entfernt.

Deployment: vor migrate prüfen, ob invoices.stripe_invoice_id bereits
Duplikate enthält (die Unique-Migration bricht sonst bewusst ab).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 13:47:21 +00:00
6f96e4a4cc PM-Detailseite: Inhaltspruefung (Gruen/Gelb/Rot) + Qualitaets-Score sichtbar
- Neue Kachel "Inhaltspruefung" in Status & Verlauf (Badge je Ergebnis,
  "Ausstehend" ohne Pruefung); bei Gelb neutraler Hinweis, dass die
  Boost-Platzierung gruen gepruefte Meldungen voraussetzt
- Content-Score-Panel des Editors in gemeinsame Komponente
  x-content-score-panel extrahiert und auf der Detailseite wiederverwendet
  (Score/100, Stufe, Abstand zur naechsten Schwelle)
- PressReleaseClassification::badgeClass() (ok/warn/err)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 14:59:33 +00:00
4f2be1e0a8 PM-Uebersicht: Rubrik unter Portal, Boost-moeglich-Hinweis, gruener Haken
- Rubrik (lokalisiert) direkt unter den Portal-Pills; Kategorie wird in
  accessiblePageFor() eager geladen (kein N+1)
- Status-Spalte: laeuft kein Boost, wirbt eine veroeffentlichte gruene PM
  mit "Boost moeglich ->" (Link zur PM-Seite mit den Add-ons)
- Gruen geprueft: kleiner gruener Haken neben dem Titel (Tooltip
  "Inhaltspruefung: Gruen")

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 13:23:07 +00:00
0cddf5fbdc Add-on-Panel zeigt freie Boost-Plaetze je Stufe
slotAvailability() liefert zusaetzlich free/limit (knappste Ausgabe, ohne
den eigenen gehaltenen Slot); solange buchbar, steht unter den Kauf-Buttons
"Noch X von Y Plaetzen frei." — bei laufendem Boost weiterhin nur der
Verlaengerungs-Hinweis.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 13:12:05 +00:00
6796fa472e Preise-Seite: zwei Boost-Stufen inkl. Slot-Hinweis in der Leistungsnote
Oeffentliche Preisliste rendert beide Staffeln (Startseiten-Boost 12/20/35,
Kategorie-Boost 6/10/18); die Boost-Note der Leistungsbeschreibung nennt
jetzt beide Stufen und die begrenzten Plaetze je Seite (de/en). Muss mit in
die anwaltliche Freigabe des Rechtstexte-Pakets [EXTERN].

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 12:28:03 +00:00
0474d22347 Boost-Slot-Grenzen (5/3) + Kategorie-Boost zum halben Satz
Entscheidung 13.07.: verkauft wird nur, was sichtbar ist — max. 5
gleichzeitige Boosts je Startseite, 3 je Branchenseite (= die sichtbaren
Plaetze; Hero-Slider damit vertagt). Neue Stufe Kategorie-Boost (nur
Branchenseite, 6/10/18 Credits = 50 % aufgerundet); der Startseiten-Boost
(12/20/35) erscheint weiter auf Start- UND Branchenseite.

- boosts.placement (home/category, Bestand = home) + BoostPlacement-Enum;
  Preise/Slots in config/credits.php (boost_category, boost_slots)
- BoostService::slotAvailability() je Ausgabe (Portal x Sprache, Kategorie
  zusaetzlich je Rubrik); ausgebucht -> soldOut-Exception mit fruehestem
  freien Termin; Verlaengerungen halten ihren Slot, Stufen verlaengern
  unabhaengig; Kategorie-Boost invalidiert nur Kategorie-Caches
- Startseite zeigt nur Home-Boosts; Branchenseite: Kategorie-Boosts mit
  Vorrang (ihre 3 Slots sind die Garantie), Home-Boosts fuellen den Rest
- Add-on-Panel der PM-Seite: zwei Boost-Angebote, bei vollem Inventar
  "Derzeit ausgebucht — frei ab" statt Kauf-Buttons (serverseitig gegated);
  Buchungsseiten-Preisliste um die Kategorie-Staffel ergaenzt

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 12:28:03 +00:00
cc61bf21d9 Add-on-Modal: Pflicht-Schalter + Verlaengerungs-Hinweis bei laufendem Boost
Kauf-Button bleibt deaktiviert, bis der Bestaetigungs-Schalter aktiv ist
(serverseitig abgesichert). Laeuft bereits ein Boost, warnt das Modal,
dass die Buchung die Laufzeit verlaengert, mit altem und neuem Enddatum.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:17:32 +00:00
d5b806443e E-Mail-Praeferenzen: Opt-out je Mail-Typ + One-Click-Unsubscribe ohne Login
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 17:15:05 +00:00
47c1cac5f5 PM-Liste: Hinweis auf laufende Boost-Platzierung unter dem Status
Badge "Boost bis TT.MM.JJJJ" in der Status-Spalte; Boost-Enden der
Seite in einer Query aggregiert statt isBoosted() je Zeile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:11:38 +00:00
df6b24518c Web: Boost-Platzierung auf Start- und Branchenseite ausspielen
Geboostete PMs besetzen Lead- und Top-Slots vor der Chronologie
(HomePageData/CategoryPageData ueber boosted()-Scope) und tragen das
Badge "Top-Platzierung". Abgelaufene Boosts wirken nicht.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:05:10 +00:00
0665553c88 Werbeplaetze reaktiviert: Eigenwerbe-Slots oeffnen das Kontakt-Widget
Die im Spoke-Frontend-Audit entfernten Anzeige-Flaechen (focus-ad,
feed-ad, Inline-Ad) kehren als dezente Eigenwerbung zurueck:

- neue Komponente x-web.ad-slot im frueheren "ANZEIGE"-Stil mit Hinweis
  "Hier koennte Ihre Werbung stehen" (DE/EN)
- eingebaut an den drei frueheren Stellen: Hero-Sidebar der Startseiten,
  Feed nach der dritten Meldung, PM-Detailseite nach der
  Unternehmensbeschreibung (nicht in der privaten Vorschau)
- Klick oeffnet das schwebende Kontakt-Widget mit vorgewaehltem neuen
  Thema "Werbung buchen" (ContactMessageTopic::Advertising); Anfragen
  landen wie gewohnt in der Admin-Queue "Kontakt"

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 16:53:02 +00:00
0cda19458d KI-Kennzeichnung: 2 Optionen im Submit-Modal + Labels auf Detailseite
Submit-Modal auf zwei Auswahloptionen reduziert (kein Label vs.
"Ganz oder ueberwiegend mit generativer KI erstellt"); alle vier
Enum-Werte bleiben fuer API/Bestand gueltig und mappen per formOption()
auf die zwei Gruppen. Oeffentliche Detailseite rendert jetzt Text-Label
("KI-generiert: Nach Angaben ...") und Bild-Badge (KI-generiert/
KI-bearbeitet, abgedunkelter Hintergrund) — fehlte dort bisher komplett.
Bildnachweis-Vorschlag ohne "Foto:"-Praefix (stand sonst doppelt).
Einreich-Toast + FAQ: automatische Pruefung in Minuten statt 24 h.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 16:51:23 +00:00
93d7f6d480 Add-ons: Kaufbestaetigung vor Credit-Abbuchung + deutlichere Buttons
Boost-Laufzeiten und Nachweis oeffnen jetzt ein Bestaetigungs-Modal mit
Preis, Guthaben und Restsaldo; erst "Kostenpflichtig buchen" bucht ab.
Boost-Buttons primary mit explizitem Kauf-Label.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:44:05 +00:00
b26dc9057c Admin-PM-Liste: KI-Pruefungs-Modal + geschaerfte KI-Prompts
- Spalten umsortiert (Aktionen, Datum, KI-Pruefung zuerst); Pruefen-Button
  nur noch Icon, oeffnet Detail-Modal mit Klassifikation, Begruendung,
  Content-Score inkl. Faktor-Breakdown und Re-Check (wire:poll bis Queue durch)
- Content-Score: Bild-Punkte (10) systemseitig statt KI (nur ein Upload-Bild
  moeglich), Quellen 10->5, Pressestil 20->25; Breakdown wandert ins Audit-Log
- Klassifikations-Prompt prueft gegen aktive Ablehnungskategorien (K1-K6,
  rejection_categories): klarer Verstoss => direkt rot mit Kategorie-Code

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 16:37:47 +00:00
6a45ebf607 Legacy-API-Paritaet S1+S2: connektar-Flow verhaltensgleich + KI-Schalter
Eigene Compat-Controller (Api/Legacy) fuer die 5 real genutzten
/service-Endpoints (Prod-Log-Beleg): Company-/Kontakt-Create (liefen
410!), PM-Create, Bild-Upload, published-only-GET — verschachtelte
Alt-Params, 201+Location+{}, Alt-Fehlerformat, Hit-Zaehlung,
Legacy-Land-Mapping.

- Anlegen = Einreichen (Alt-Verhalten); Sofort-Publish via neuer
  Permission api:immediate-publication (WS-7: connektar zuweisen)
- Admin-Schalter 'KI-Pruefung Legacy-API' (app_settings-Tabelle,
  Toggle auf /admin/press-releases): an = review + KI-Routing
- Admin-PM-Liste: KI-Spalte (Ampel-Badge) + manueller Pruef-Button
  ohne Routing fuer ungepruefte PMs
- Mails bei API-Einlieferern an Pressekontakt, sonst Firmen-Mail,
  Fallback Einlieferer (User-Entscheidung 10.07.)
- Tests: LegacyServiceParityTest (connektar-Flow end-to-end);
  Suite 1182 gruen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 14:09:40 +00:00
b18598584c Web-Frontend: /api-Doku mit KI-Deklarationsfeldern (curl-Beispiele + Hinweis)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:44:20 +00:00
3843e534da Web-Frontend: Kartenkomponenten auf PressRelease-Helper umgestellt (R4.3)
@php-Bloecke von feed-item, feed-top-item, focus-side-item, focus-hero,
kategorie, newsroom, release-detail, veroeffentlichen nutzen die neuen
Model-Helper — gerendertes Markup unveraendert (Web-Suite 215 gruen).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 11:57:26 +00:00
0603fe5368 R2.5: legal-request-Hinweistexte final (Wortlaut aus Meldeverfahren v0.1)
- Meldung/DSGVO/Persoenlichkeitsrecht auf die am 06.07. freigegebenen
  /melden-Texte gezogen: kostenlose manuelle Pruefung, unverzuegliche
  Eingangsbestaetigung mit Vorgangsnummer (sofern E-Mail), Entscheidung
  mit Begruendung; DSGVO ohne pauschale 30-Tage-Zusage, stattdessen
  Bestaetigungslink/Nachweis wie im Meldeverfahren
- ENTWURF-TODO entfernt, Querverweis auf /melden ergaenzt
- Render-Test erweitert (Vorgangsnummer, kostenlos, melden-Link)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:11:28 +00:00
34f0e0f134 Web-Frontend: Aufrufe-Anzeige + Share-Tracking auf der PM-Detailseite
- Meta-Zeile zeigt Aufrufe (hits inkl. aktuellem Aufruf) in beiden
  Hero-Varianten; in der Vorschau ausgeblendet
- Teilen-Buttons melden den Kanal an release.share (fetch keepalive,
  CSRF-Meta); Link-kopieren trackt nur bei erfolgreichem Copy

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:56:55 +00:00
8f5970436b PM-Tracking: Ereignis-Log fuer Aufrufe + Shares (press_release_events)
- press_release_events (type view/share, channel, ohne Personenbezug):
  Model/Enums/Factory, Cascade-Delete an der PM
- Detailaufruf loggt View-Event zusaetzlich zum Legacy-hits-Zaehler
  (bleibt bewusst einfacher Page-Request-Zaehler, User-Vorgabe 10.07.)
- POST press-release/{slug}/share (throttle 30/min, nur archiv-sichtbare
  PMs des Portals) loggt Teilen-Klicks je Kanal (LinkedIn/X/E-Mail/Copy)
- Kundenpanel-PM-Seite: neue Kachel Geteilt mit Kanal-Aufschluesselung
- lang: web.detail.views (de/en)
- Tests: Web/PressReleaseTrackingTest (7)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:56:42 +00:00
d1939f6f2a Web-Frontend: Umbau Spokes/Hub, Kontakt-Widget (contact-launcher)
Startseiten/Feeds/Kategorie/Rechtsseiten ueberarbeitet, Kontakt-Modal durch
schwebendes contact-launcher-Widget ersetzt, legal-language-notice ergaenzt;
Platzhalter-SVGs + Theme-CSS angepasst.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:45:58 +00:00
fd8e050cb7 Backend-WIP: Kontakt-Queue, Page-Cache, Validierungs-Feedback, i18n
Gebuendelt, da ueber gemeinsame lang-/Service-Dateien verschraenkt:
- Kontakt-Nachrichten: contact_messages-Tabelle + Model/Enums/Factory,
  Admin-Queue (livewire/admin/contact-messages), ContactController
  persistiert das Anliegen zusaetzlich zur Brand-Mail
- Page-Data-Cache (Services/Web/*PageData) + web-archive-Indizes auf
  press_releases
- Validierungs-Feedback + Company-Portal-Restriction (Feature-Tests)
- i18n-Auslagerung lang/de|en (auth, passwords, validation, static)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:38:11 +00:00
6984846233 Monitoring (R5.3): Betriebs-Alerts fuer Scheduler-/Queue-Ausfaelle
OperationalAlert loggt critical + Best-Effort-Mail an MONITORING_ALERT_EMAIL
(Fallback LEGAL_CONTACT_EMAIL, feature-flagged). Alle 6 Scheduler-Tasks mit
onFailure, Queue::failing-Listener; .env.example: LOG_STACK=daily als Prod-Soll.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:34:40 +00:00
ac870a4076 Buchungsseite: Buchungs- und Verlaengerungsdatum des Abos aus Stripe
Cashier spiegelt die Periode nicht lokal; neuer SubscriptionPeriodResolver
holt start_date + current_period_end (Item-Ebene) gecacht, Fallback null.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:34:28 +00:00