- Navigations-Chrome (CategoryNavigation), Suche- und Newsroom-Seitendaten
300s gecacht; gemeinsamer WebPageCache-Helper (eine TTL/Key-Konvention).
- Cache-Poisoning über ?page= geschlossen (Key an Paginator ausgerichtet,
kein withQueryString im Cache); Newsrooms cachet nur den ungefilterten
Fall und die ersten Seiten (kein unbegrenzter Key-Raum).
- Detailseiten schreiben Hits/View-Events deferred nach der Response
(M12); OpenAI-/Markt-/USt-ID-Aufrufe mit Connect-Timeouts und
begrenzten Retries; Admin-Memo-Caches konsistent invalidiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Magic-Link-Login übergibt bei aktiviertem 2FA an die 2FA-Challenge,
statt sie zu umgehen (M1).
- Bestätigungs-/Benachrichtigungs-Mails (Kontakt, Recht, Kündigung,
Widerruf, Magic-Link) laufen als ShouldQueue+afterCommit über die Queue,
damit die Response nicht am SMTP-Roundtrip hängt.
Hinweis: Der Queue-Worker muss im Betrieb laufen und überwacht werden, da
fristrelevante Bestätigungen darüber zugestellt werden (siehe
Betriebsüberwachung).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
Statt bis zu 300 s Cache-TTL zu warten, verwirft der BoostService nach
der Buchung die Home-/Kategorie-Caches der betroffenen Ausgaben (inkl.
Eltern-Rubrik) — die bezahlte Platzierung ist direkt sichtbar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
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>
- 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>
A3 des Umbaus Agentur-Attribution → User-Profil: Eager Loading der
Detailseite/Vorschau lädt user:id,agency_name; die Legacy-Relation
PressRelease::submittingAgency() (Pseudo-Firma type=agency via
owner_user_id) entfällt. Tests decken Verteiler-Fall, Namensgleichheit
und PM ohne Übermittler ab.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Archiv-Suche lief auf grossen Datenbestaenden langsam und war im Browser
komplett tot: app.js startete ein eigenes Alpine, Livewire injizierte
zusaetzlich seins - der DOM-Morph brach mit "Alpine.transaction is not a
function" ab (keine Rubrik klickbar, Suchbegriff nicht aenderbar).
- app.js buendelt jetzt Livewire + Alpine aus livewire.esm,
@livewireScriptConfig im Web-Layout stoppt die Auto-Injektion
- MySQL-Volltext-Index (Boolean-Mode, +wort*) statt LIKE ueber alles;
LIKE-Fallback fuer SQLite-Tests und kurze Tokens
- Firmen-/Rubrik-Treffer als ID-Listen statt orWhereHas (OR + EXISTS
hebelte den Volltext-Index aus)
Co-authored-by: Cursor <cursoragent@cursor.com>
Frontend-Umbau (Kevin, 06.07.2026), Ergebnis des businessportal24-Audits:
- Fake-Anzeigen und Mock-/Fallback-Daten entfernt (focus-ad, feed-ad,
highlight-card, press-release-card, featured-releases, press-releases-grid);
Sektionen rendern nur noch mit echten Daten oder gar nicht
- Newsletter-Strip und Newsletter-Box zurueckgebaut (Feature nachgelagert,
vor Reaktivierung DOI-Flow noetig)
- Echte Boersendaten: MarketDataService (Yahoo-Finance-Quotes, config/market.php,
Cache) + market:refresh alle 15 Min. im Scheduler; live-ticker blendet sich
ohne Daten aus
- EN-Lokalisierung der Kern-Seiten via lang/de/web.php + lang/en/web.php;
Carbon-Locale folgt app()->getLocale()
- Web-Tests auf den neuen Frontend-Stand nachgezogen (Suite: 993 gruen)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Scope-Doku fuehrte den /thumbnails-Redirect als "ANGEPASST", im Code
existierte er nicht — alte Symfony-Bild-URLs (/thumbnails/..., /uploads/
...) liefen ins 404. Neuer LegacyMediaRedirectController mappt den
Original-Dateinamen (bleibt beim Medien-Import erhalten) auf die neue
Storage-URL fuer PM-Bilder und Firmenlogos; unbekannte Dateien bleiben
404. Gefunden bei der R6.1-Vorpruefung.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Default 3500 Cent in config/billing.php (per Env ueberschreibbar,
0 deaktiviert) — Checkout und /melden-Preisanzeige (Doppelausweis
35,00 netto / 41,65 brutto) sind damit ohne weiteren Env-Handgriff
aktiv. O6 aus der Entscheidungsliste geschlossen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zwei eigenstaendige Formulare unter /melden/rechtswidrig (DSA Art. 16:
URL, Name, E-Mail, Begruendung, Wahrheitsversicherung) und
/melden/kontaktdaten (DSGVO-Antrag) auf allen drei Domains. Gemeldete
URLs werden automatisch der passenden veroeffentlichten PM zugeordnet;
ohne Treffer bleibt die URL im payload. Jede Meldung erhaelt eine
Vorgangsnummer (M-{id}, analog K-{id} der Kuendigung), die meldende
Person unverzueglich eine Eingangsbestaetigung (DSA Art. 16 Abs. 4) und
das Melde-Postfach einen internen Hinweis — auch im bestehenden
Per-PM-Flow. Admin-Queue zeigt Vorgangsnummer, Name und gemeldete URL;
/melden verlinkt die neuen Formulare als ersten Weg.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Unter dem Artikelinhalt steht jetzt eine eigene Zeile mit "Inhalt melden"
und "Eigene Daten entfernen" (inkl. Kostenlos-Hinweis) — bisher waren die
Wege nur in der Sidebar-Box "Weiterfuehrend" auffindbar. Erfuellt die
DSA-Anforderung eines leicht zugaenglichen Meldewegs direkt am Inhalt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/richtlinien rendert jetzt alle aktiven Kategorien aus der neuen
rejection_categories-Tabelle (stabiler code als Anker, public_label/desc,
optionale Beispiele) statt der statischen K1-K6-Liste. Kategorien werden
nie geloescht, nur deaktiviert; neue Kategorien erscheinen ohne
Textaenderung und ohne neue AGB-Version (AGB par. 7 Abs. 3 verweist nicht
abschliessend). Seeder legt K1-K6 idempotent an; Versionszeile der Seite
kommt aus legal_documents. Go-Live-Checkliste um beide Seeder ergaenzt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Selbst gehostetes Umami (sys.adametz.media) je Brand: Website-IDs aus
dev/release/umami.md in config/domains.php, Snippet via x-web.umami im
web-master-Layout auf allen oeffentlichen Seiten der drei Domains.
UMAMI_ENABLED=false haelt es aus, bis die Webseiten live gehen
(User-Vorgabe 06.07.; Go-Live-Checkliste WS-7 ergaenzt). Damit stimmt
Datenschutz Abschnitt 5 mit dem Code ueberein. User bestaetigt ausserdem:
Log-/Backup-Fristen und Stripe-Entitaet passen wie eingetragen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User-Entscheidung 06.07.: info@pressekonto.com ist die Haupt-E-Mail fuer
alle rechtlichen Anliegen. Zentral in config/legal.php (LEGAL_CONTACT_EMAIL),
verwendet von Impressum, AGB, Datenschutz, /melden und /richtlinien auf
allen drei Domains. Support-Kontakt bleibt je Brand (CONTACT_EMAIL_*),
REPORT_EMAIL_* ist nur noch optionales separates DSA-Postfach. Nebenbei
den verunglueckten Enterprise-Hinweis auf der Buchungsseite repariert
(E-Mail war ohne Trennung angeklebt).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- GET kontakt/ueber-uns -> 301 auf die Ausgaben-Startseite;
kontakt.store-POST bleibt fuer das Hub-Kontakt-Modal
- Legacy-Aliases (contact/kontakt/ueber-uns) buendeln auf die Startseite
- Spoke-Footer: Kontakt als mailto (Betreiber-Fallback bis R2.1),
Ueber-uns-Link raus, Selfservice-Kuendigungslink ergaenzt
- Sitemap-Konstanten bereinigt, Tests angepasst
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
team/partner/karriere/presse (erfundene Personen, Fake-Partner,
Bewerben-Buttons ohne Ziel) samt Routen entfernt (User-Entscheidung
03.07.: lieber weniger Seiten, aber ehrlich). Altes Scaffold
(livewire web.burger-menu/header/footer) wurde nur von diesen Seiten
genutzt und ist mit raus. Legacy-.html-Links: team/partner/karriere
-> 301 Startseite; presse/* behaelt die bestehende 301-Regel auf /faq.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Oeffentliche Bestaetigungsseite /de/kuendigung ohne Login: Art der
Kuendigung (Grund nur bei ausserordentlich), Zuordnungsdaten,
Beendigungszeitpunkt; Honeypot + Rate-Limit wie beim Widerruf.
Sofortige automatische Zugangsbestaetigung per E-Mail (Par. 312k
Abs. 4 BGB) + Betreiber-Mail. Kuendigungen laufen in der
Recht-&-Compliance-Queue unter den Widerrufen auf (K-Vorgaenge,
eigener Filter, Erledigt/Wieder-oeffnen, vierte KPI-Karte).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
x-web.static-page ist jetzt host-aware: Auf der pressekonto-Domain laden
Utility-Bar + Hub-Header/-Footer (inkl. Kontakt- und Widerrufs-Modal,
damit die Footer-Buttons ueberall funktionieren) statt des
Spoke-Geruests; Breadcrumb fuehrt zur Hub-Landing. Hub-Anker-Navigation
(#tarife/#funktion/#familie/#faq) absolut auf die Landing, damit sie
auch von Unterseiten aus funktioniert. Spokes unveraendert (Test).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
POST /widerruf (host-agnostisch, throttled, Honeypot, eigener
withdrawal-Error-Bag): persistiert nur Zuordnungsdaten (Name, E-Mail,
optionale Bestellnummer - KEIN Grund, darf nicht verlangt werden) und
versendet sofort die gesetzlich vorgeschriebene automatische
Eingangsbestaetigung mit Zeitstempel an den Verbraucher plus eine
interne Benachrichtigung an die Brand-Kontaktadresse des Hosts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der WebPortalContext kennt nur die beiden Spokes - Anfragen von
pressekonto.test waeren sonst bei businessportal24 gelandet.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Liefert Plan::active(), Einzel-PM-Preis und stuendlich gecachte echte
Zahlen (Archiv-Mitteilungen gesamt/je Portal, aktive Newsrooms,
Branchen) an web.pressekonto. Tests: Katalog-Preise statt Fake-Liste,
keine toten Links/erfundenen Referenzen, Rechtsseiten auf der
Hub-Domain erreichbar. (Gehoert zum Web-Commit der Hub-Ueberarbeitung.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/variant-1 + /variant-2 referenzierten nicht existierende Views
web.businessportal24-variant-float-glow/-glass-gradient; Fragmente der
alten Frontend-Version, nirgends verlinkt. Regressionstest ersetzt den
Stub in DevExampleRoutesTest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vier komponierbare Scopes auf PressRelease:
- published() Status freigegeben + published_at gesetzt (ohne Zeitschranke,
damit Statistik-Fenster frei einschraenken koennen)
- visibleInArchive() published() + published_at <= jetzt (oeffentlich sichtbar)
- forPortalValues() whereIn portal
- forLanguage() where language
~19 duplizierte Query-Bloecke in routes/web.php (Home, Kategorie, Detail,
Veroeffentlichen, Suche, Newsrooms, Newsroom-Detail, Legacy-Redirect) nutzen
jetzt diese Scopes. Jedes withoutGlobalScope(PortalScope) bleibt an seiner
Stelle erhalten; die Klausel-Reihenfolge ist fuers Ergebnis irrelevant (reine
AND-Verknuepfung), daher verhaltensgleich.
Test: Web/PublishedReleaseScopeTest; die 89 bestehenden Web/-Tests bleiben gruen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ergänzt web-master.blade.php um <link rel="canonical">, OpenGraph- und
Twitter-Card-Tags. Self-Canonical-Default wird portal-getrennt aus der
Portal-URL ($domainUrl) + Request-Pfad gebaut – bewusst nicht aus
url()->current(), da URL::forceRootUrl sonst alle Portale fälschlich auf
pressekonto.test kanonisieren würde. Seiten können canonical/meta_description/
og_type/og_image per @section überschreiben; release-detail als article
ausgezeichnet. Erfüllt die Canonical-Hygiene aus dem Duplicate-Content-Update §5.
Tests: tests/Feature/Web/CanonicalMetaTest.php (inkl. Cross-Portal-Negativtest).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Umbenennung presseportale → pressekonto in Domains, Themes und Dokumentation.
Design-Tokens, Portal-Shell, Customer-Dashboard, Auth- und Admin-PM-Views.
Artisan-Befehl migrate:legacy-media mit Tests und Hub-Flux-Entwicklungsdocs.
Co-authored-by: Cursor <cursoragent@cursor.com>