Kategorie-Pflichtfeld direkt unter die Firma statt in die Sidebar.
Titelbild-Upload öffnet ein Modal: erst Bild wählen, dann erscheinen
die gestrafften Schritte (Herkunft & Bildnachweis mit Vorschlag aus
dem Urheber, Personen & Rechte, Bestätigung), Optionales eingeklappt.
Bildrechte-Checkbox im Einreichen-Modal nur noch mit eigenem Titelbild.
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>
Den in allen vier PM-Editoren identischen, rein praesentationalen
Pre-Submit-Checklisten-Block (~34 Zeilen je Datei) in eine
Blade-Component ausgelagert, die $this->presubmitChecks als Prop nimmt.
Render-Test ergaenzt.
Bewusst konservativ: Nur dieser wire:model-freie, presentational Block
wurde extrahiert. Die interaktiven Markup-Panels (Tag-Input, Publish-
Schedule, Kontakt-/Firmen-Select) bleiben in den Editoren, da ihre
wire:model-/Alpine-Bindungen ohne visuelle QA nicht risikofrei in
Components zu ueberfuehren sind und die Tests gerendertes Markup nur
begrenzt abdecken.
Tests: volle Suite gruen (800 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Erkenntnis: Die Admin-Inline-Query (Contact::withoutGlobalScopes()->where
->orderBy) ist exakt der Contact::forCompany()-Scope -> alle vier
Kontakt-Helfer waren funktional identisch. companyContacts/companyContact/
defaultContactIdFor in neuen Concern InteractsWithPressReleaseContacts
(ueber forCompany) ausgelagert. tagSuggestionsFor() (4x identisch) in
InteractsWithPressReleaseTags verschoben. Ungenutzte Collection-Importe
in den Customer-Editoren entfernt; selectedCompany() bleibt je Kontext
(Admin: withoutGlobalScopes find; Customer: CustomerCompanyContext).
Tests: volle Suite gruen (794 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
presubmitChecks() der vier Editoren in ProvidesPressReleasePresubmitChecks
zentralisiert (war 4x dupliziert mit Drift). Kanonische Version uebernimmt
die bessere Customer-Variante: Firmenname statt leerer Hinweis in der
company-Zeile. Dafuer erhalten die Admin-Editoren ein selectedCompany()
(Company::withoutGlobalScopes find), das auch in with() genutzt wird;
Customer behaelt seine user-gescopte Aufloesung via CustomerCompanyContext.
Tests: volle Suite gruen (794 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Die ~95% identischen Validierungsregeln (Inhaltsfelder, publishMode,
terminabhängiger Scheduling-Block mit zeitzonenbewusster Closure, Embargo)
in baseFormRules() zentralisiert. Die vier Editor-formRules() ergänzen nur
noch die abweichenden Schlüssel (portal nur Admin, companyId mit/ohne
exists). Ungenutzten Rule-Import in customer/edit entfernt.
Tests: volle Suite gruen (794 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Die in allen vier PM-Editoren wortgleiche Scheduling-Maschinerie
(updatedPublishMode/ScheduledDate/ScheduledTime, updated, syncScheduledAt,
resolveScheduledAt, validateScheduledAtWhenReady, notifyValidationError)
in einen gemeinsamen Concern ausgelagert (spiegelt InteractsWith-
PressReleaseTags). ~85 Zeilen je Datei entfernt.
Tests: volle Suite gruen (794 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Themen-Tag-Verwaltung (addTag/removeTag/tagsArray) war in create- und
edit-Editor byte-identisch dupliziert -> Trait
App\Livewire\Concerns\InteractsWithPressReleaseTags.
- Kontaktauswahl je Firma (withoutGlobalScopes + where + Sortierung) aus
create/edit/dashboard in Contact::scopeForCompany() zentralisiert.
- Rechnungsadress-Pflichtfelder als BillingAddress::REQUIRED_FIELDS; isComplete()
und neues completenessPercent() teilen die Liste, Dashboard nutzt es statt
eigener Feldliste.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Beim Speichern/Veroeffentlichen waren Termine 2 Stunden versetzt: die
App-Zeitzone stand auf UTC, Termine wurden nach UTC umgerechnet, aber
published_at roh angezeigt.
- config/app.php: timezone UTC -> Europe/Berlin
- PressRelease: DISPLAY_TIMEZONE + setTimezone-Umrechnung entfernt
- Admin-/Customer-Formulare: scheduledAtUtc() -> resolveScheduledAt(),
parst direkt in App-Zeitzone; Edit-Hydration ohne setTimezone
- ProofPdfRenderer + Boost-Anzeige: setTimezone entfernt
- Tests an verschiebungsfreies Verhalten angepasst
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bug: Im Submit-Modal navigierte 'Buchung auswaehlen' per wire:navigate direkt
zur Buchungsseite, OHNE vorher zu speichern -> im Erstellen ging die ganze PM
verloren, im Bearbeiten die ungespeicherten Aenderungen.
- Submit-Modal: neuer Prop booking-action; ist er gesetzt, speichert der Button
ueber eine Livewire-Aktion zuerst und navigiert erst danach
('Speichern & Buchung auswaehlen'). Fallback-href nur dort, wo bereits
gespeichert ist (Detailansicht).
- create/edit: Persistenz in persistDraft()/persistEdit() extrahiert;
saveDraftAndChooseBooking() speichert den Entwurf bzw. die Aenderungen und
leitet erst dann zur Buchung (Edit reklassifiziert bei Inhaltsaenderung).
- Beide Submit-Modals mit booking-action verdrahtet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9A — Gelb geht direkt live (Entscheidung 12.06.2026):
- routeByClassification(): Gelb durchlaeuft denselben Auto-Publish-Pfad
wie Gruen (autoPublishApproved); nur Rot wird abgelehnt
- Scheduler publiziert faellige gelbe + gruene PMs; unklassifizierte
bleiben als Fallback in der manuellen Queue
9B — Slot-Verbrauch bei Veroeffentlichung (Decision-Update 3.2):
- Increment aus submitForReview() entfernt; publish() und
changeStatusFromAdmin() zaehlen idempotent beim ersten
published-Uebergang (Pruefung ueber Status-Logs); Rot kostet nichts
- Submit-Guard: Einreichen erfordert freien Slot
(QuotaExceededException, API 422)
9C — Submit-Gate vorbereitet (Decision-Update 5.1):
- User::hasActiveBooking()-Stub hinter config/billing.php
(enforce_booking, Default aus); Tarif-Modul ersetzt nur den Rumpf
- Einreichungs-Modal zeigt ohne Buchung einen Buchungs-Hinweis;
Server-Guard (BookingRequiredException), API antwortet 402
- Fix: Customer-Create legte PMs bei "Zur Pruefung senden" direkt mit
Status review an (vorbei an Blacklist/Quota/KI/Status-Log) — laeuft
jetzt immer ueber submitForReview()
Suite: 451 passed, 4 skipped (9 neue Tests). Pint clean.
Plan: docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md (Block 2 nach Review-Stopp).
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>