Agentur-Attribution: Plan abgehakt, Abnahme-Status 08.07. dokumentiert

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-08 09:51:56 +00:00
parent 3ff95bc93a
commit d57f6b5c66

View file

@ -0,0 +1,142 @@
# Entwicklungsplan: Agentur-Attribution → User-Profil (Umbau)
> Erstellt **07.07.2026** nach User-Entscheidung. Ziel: Der Firmen-Typ „Agentur"
> verschwindet aus dem Firmen-Modell. Firmen sind ausschließlich die Newsrooms,
> unter denen PMs veröffentlicht werden. Die Übermittler-Angabe („übermittelt
> von …") wird eine **Profil-Eigenschaft des einliefernden Accounts**.
> Geplanter Umfang: **1 Arbeitstag**.
> **Status 08.07.2026: A1–A5 UMGESETZT, Abnahme erfüllt.** Beide
> Daten-Commands sind lokal scharf gelaufen (Reports unter
> `storage/app/private/migration/`): 4.482 User mit `agency_name`
> (93 Mehrfach-Fälle exakt verglichen — der Plan zählte 77 normalisiert —,
> 10 Owner-lose nur reportet), 2.607 Agentur-Firmen umtypisiert,
> 2.149 soft-gelöscht, 1 geschützter Fall (Zahlungsoptions-/Mitglieds-
> Verknüpfung). Beispiel-PM zeigt die Attributions-Zeile aus dem
> Profilfeld. Deploy-Runbook (Erst-Einrichtung, Schritt 2) ergänzt.
> Offen: nur A6 (nachgelagert).
---
## Ausgangslage (Stand 07.07.2026)
**Bereits umgesetzt (07.07.):** Die Legacy-Attributions-Zeile („Original-Inhalt
von {Firma} und übermittelt von {Agentur}") ist auf der öffentlichen
Detailseite wieder da — aktuell noch über die Legacy-Datenstruktur:
- `PressRelease::submittingAgency()` — hasOne auf `companies`
(`owner_user_id = user_id` der PM, `type = agency`, ohne PortalScope)
- Rendering in `resources/views/web/release-detail.blade.php` (unter dem
Pressekontakt-Block), Übersetzungen `web.detail.attribution*` (de/en)
- Eager Loading in `ReleaseDetailPageData` + `PressReleasePreviewController`
- 3 Tests in `tests/Feature/Web/ReleaseDetailTest.php` (Verteiler, gleichnamig,
ohne Agentur)
**Datenlage (lokal geprüft 07.07.):**
| Fakt | Wert |
|---|---|
| Agentur-Firmen (`companies.type = agency`, aktiv) | 4.756 |
| … davon selbst Newsroom (PMs mit `company_id` = Agentur) | 2.598 (7.963 PMs) |
| … mit Pressekontakten | 27 |
| … ohne Owner (`owner_user_id IS NULL`) | 10 |
| User mit Agentur-Firma | 4.482 |
| User mit **mehreren** verschieden benannten Agentur-Firmen | 77 |
| connektar: User 14016 (`info@connektar.de`) | Agentur-Firmen 18811 (pe) + 49196 (bp24), 20.830 PMs |
**Kernproblem des Ist-Zustands:** Die Agentur ist eine Pseudo-Firma — im
Kunden-Panel nicht von echten Firmen unterscheidbar, die Zuordnung
(owner_user_id → user_id der PM) versteht niemand, und mehrere Agentur-Firmen
pro Account sind mehrdeutig.
---
## Arbeitsregeln
- Test-First bei Verhaltensänderungen; Tests gezielt:
`php artisan test --compact --filter=<Name>` (wir sind im Sail-Container).
- Nach PHP-Änderungen: `vendor/bin/pint --dirty --format agent`.
- Jeder Schritt = eigener, fokussierter Commit.
- Daten-Kommandos immer mit `--dry-run` zuerst; nie überschreibend.
- Web-Frontend-Views gehören dem User → Änderungen dort separat committen.
---
## A1 — Profilfeld `users.agency_name` (~30 min)
- [x] Migration: `agency_name` (string 190, nullable) auf `users`.
- [x] `User`: fillable ergänzen; `UserFactory`-State `withAgency()`.
- [x] Kein eigenes Agentur-Logo/Website fürs Erste (bewusst schlank —
erweiterbar, wenn gebraucht).
## A2 — Daten-Übernahme Agentur-Firmen → Profil (~1–1,5 h)
- [x] Artisan-Command `legacy:migrate-agency-names` (`--dry-run`, Report nach
`storage/app/private/migration/`):
- Je User mit Agentur-Firma(en): Namen nach `users.agency_name` übernehmen.
- **Regel Mehrfach-Fälle (77 User):** zuletzt aktualisierter Datensatz
(`updated_at` max) gewinnt; alle Varianten in den Report.
- Nie überschreiben, wenn `agency_name` bereits gesetzt.
- Die 10 Owner-losen Agentur-Firmen nur reporten (manuelle Sichtung).
- [x] Test mit Factories (Einzel-Fall, Mehrfach-Fall, bereits gesetzt).
- [x] **Go-Live-Hinweis:** Command in die WS-7-/Deploy-Checkliste aufnehmen
(läuft NACH dem Firmen-/User-Import).
## A3 — Attribution auf Profilfeld umstellen (~1 h)
- [x] `release-detail.blade.php`: `$agencyName = $release->user?->agency_name`
statt `submittingAgency` (Vergleichs-/Fallback-Logik bleibt identisch:
Name ≠ Firma → „Original-Inhalt von … und übermittelt von …";
Name = Firma → „Inhalt übermittelt von …"; leer → „Original-Inhalt von …").
- [x] Eager Loading umstellen: `user:id,agency_name` statt `submittingAgency`
(`ReleaseDetailPageData`, `PressReleasePreviewController`).
- [x] `PressRelease::submittingAgency()` entfernen.
- [x] Tests in `ReleaseDetailTest` auf `agency_name` umschreiben; Suite-Ausschnitt
grün (`ReleaseDetail`, `PressReleasePreview`).
## A4 — Firmen bereinigen: Typ „Agentur" abschaffen (~1,5 h)
- [x] Artisan-Command `companies:retire-agency-type` (`--dry-run`, Report):
- Agentur-Firmen **mit** PMs oder Kontakten → `type = company` umtypen
(bleiben Newsrooms; 2.598 + 27, Überschneidung möglich).
- Agentur-Firmen **ohne** PMs und Kontakte → Soft-Delete (~2.100).
Vorher prüfen: keine `company_user`-Mitgliedschaften Dritter, keine
`user_payment_option_company`-Verknüpfung — sonst nur umtypen.
- [x] Test mit Factories (umtypen, löschen, geschützter Fall).
- [x] Command ebenfalls in die Deploy-Checkliste (nach A2!).
## A5 — UI anpassen (~1,5 h)
- [x] **Kunden-Panel Profil** (`livewire/customer/profile.blade.php`):
neuer Abschnitt „Agentur-Angaben" mit Feld „Agentur-/Verteilername"
und Erklärtext: *„Falls Sie Pressemitteilungen im Auftrag Dritter
einreichen, erscheint diese Angabe öffentlich als Übermittler unter
Ihren Mitteilungen."* Validierung: nullable, max 190.
- [x] **Firma anlegen** (`customer/press-kits/create.blade.php`): Typ-Feld
entfernen, fest `type = company`.
- [x] **Firmen-Übersicht** (`customer/press-kits/index.blade.php`):
Typ-Label aus der Meta-Zeile entfernen (nach A4 gibt es nur noch einen Typ).
- [x] **Admin** (`admin/companies/create|edit.blade.php`): Typ-Auswahl
entfernen; `admin/users/*`: Feld `agency_name` anzeigen/editierbar machen.
- [x] Tests: Profil speichert `agency_name`; Firma-Anlegen ohne Typ-Feld.
## A6 — Nachgelagert (NICHT morgen)
- `companies.type`-Spalte + `CompanyType`-Enum komplett entfernen
(erst wenn A4 produktiv gelaufen und verifiziert ist).
- Optional: Agentur-Logo/-Website im Profil, falls die Attributions-Zeile
verlinkt werden soll.
- Admin-Auswertung „PMs je Übermittler" (Tracking-Wunsch aus dem Konzept,
Abschnitt Distribution-Partner).
---
## Abnahme (Ende des Tages)
- [x] Beispiel-PM `fuehrende-laufblogger-…` zeigt weiterhin
„Original-Inhalt von Trailbloggercamp und übermittelt von
connektar.de Presseverteiler" — jetzt aus `users.agency_name`.
- [x] Kunden-Panel: Agentur-Name im Profil sichtbar/änderbar; Firmenliste
ohne Agentur-Einträge bzw. ohne Typ-Label.
- [x] Beide Daten-Commands mit Report gelaufen (lokal), Deploy-Checkliste ergänzt.
- [x] Testsuite grün, Pint sauber, Commits je Schritt.