29-05-2026 Optimierungen Fixes am Code
This commit is contained in:
parent
e8c47b7553
commit
4bb9094207
31 changed files with 5141 additions and 76 deletions
305
docs/user-admin/user-zusammenhaenge.md
Normal file
305
docs/user-admin/user-zusammenhaenge.md
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
# User-Admin: Zusammenhänge und relevante Daten
|
||||
|
||||
Stand: 2026-05-21 (aktualisiert nach Phase 7)
|
||||
|
||||
Diese Notiz beschreibt den User als fachlichen Mittelpunkt für die weitere Konzeption des Admin-User-Bereichs. Grundlage sind die aktuellen Models und Migrationen im Laravel-Projekt.
|
||||
|
||||
> **Was sich seit dem ursprünglichen Stand (2026-05-05) geändert hat**:
|
||||
>
|
||||
> - Pressemitteilungen haben zusätzliche Felder: `subtitle`, `scheduled_at`,
|
||||
> `embargo_at`, `boilerplate_override`, `no_export` (Phase 7).
|
||||
> - Neue Tabelle `press_release_attachments` (Modell `PressReleaseAttachment`).
|
||||
> UI ist temporär deaktiviert (Security-Review), Tabelle und Service
|
||||
> bleiben aber erhalten.
|
||||
> - Neuer Service-Layer für PMs: `PressReleaseService` (Status-Übergänge,
|
||||
> Scheduling-Auflösung), `PressReleaseHtmlSanitizer` (HTMLPurifier-Wrapper),
|
||||
> `PressReleaseAttachmentStorage`.
|
||||
> - Neuer Console-Command `php artisan press-releases:publish-scheduled`
|
||||
> (Scheduler-Intervall 5 Min) veröffentlicht geplante PMs automatisch.
|
||||
> - Pivot `press_release_contact` bleibt n:m, der Customer-Flow speichert
|
||||
> aber nur einen Kontakt pro PM und das Feld ist nullable.
|
||||
|
||||
## Zentraler Ausgangspunkt
|
||||
|
||||
Ein `User` ist nicht nur ein Login-Konto, sondern bündelt im System mehrere fachliche Bereiche:
|
||||
|
||||
- Zugang und Status: Name, E-Mail, Verifikation, Passwort, 2FA, Aktiv/Inaktiv, Super-Admin-Flag, Rollen/Berechtigungen.
|
||||
- Portal- und Legacy-Zuordnung: `portal`, `registration_type`, `language`, `legacy_portal`, `legacy_id`.
|
||||
- CRM-Zuordnung: Firmen, Firmenrollen, Kontakte.
|
||||
- Content-Zuordnung: Pressemitteilungen, Bilder, Statusverlauf.
|
||||
- Abrechnung und Verträge: Rechnungsadresse, Zahlungsoptionen, Zahlungen, Rechnungen, Legacy-Rechnungen.
|
||||
- API und Sicherheit: Sanctum-Tokens, API-Nutzung, Magic-Links.
|
||||
- Kommunikation und Arbeitskomfort: Newsletter-Abos, Filter-Presets.
|
||||
|
||||
## Datenmodell im Überblick
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
users ||--o| profiles : "hat"
|
||||
users ||--o| billing_addresses : "hat"
|
||||
users ||--o{ companies : "owner_user_id"
|
||||
users }o--o{ companies : "company_user.role"
|
||||
users }o--o{ contacts : "contact_user"
|
||||
companies ||--o{ contacts : "hat"
|
||||
users ||--o{ press_releases : "autor"
|
||||
companies ||--o{ press_releases : "zugeordnet"
|
||||
contacts }o--o{ press_releases : "press_release_contact"
|
||||
press_releases ||--o{ press_release_images : "hat"
|
||||
press_releases ||--o{ press_release_status_logs : "hat"
|
||||
users ||--o{ press_release_status_logs : "changed_by_user_id"
|
||||
users ||--o{ user_payment_options : "hat"
|
||||
user_payment_options }o--o{ companies : "user_payment_option_company"
|
||||
user_payment_options ||--o{ user_payments : "hat"
|
||||
user_payments ||--o{ invoices : "erzeugt"
|
||||
users ||--o{ invoices : "hat"
|
||||
users ||--o{ legacy_invoices : "hat"
|
||||
users ||--o{ newsletter_subscriptions : "hat"
|
||||
users ||--o{ magic_links : "hat"
|
||||
users ||--o{ user_filter_presets : "hat"
|
||||
users ||--o{ api_usage_logs : "hat"
|
||||
```
|
||||
|
||||
## Direkte Relationen am User
|
||||
|
||||
`profile`
|
||||
|
||||
- Kardinalität: 1:0..1.
|
||||
- Tabelle: `profiles`, Foreign Key `user_id` ist eindeutig.
|
||||
- Inhalt: persönliche Profildaten, Anrede, Titel, Vor-/Nachname, Telefon, Adresse, Land, Geburtsdatum, Backlink, Statistik-/Footer-Code-Flags, Validierungs-/Vertragsdaten, Steuerdaten.
|
||||
- Relevanz im Admin: Datenqualität, Legacy-Profil, persönliche Stammdaten, Vertrag/Validierung.
|
||||
|
||||
`billingAddress`
|
||||
|
||||
- Kardinalität: 1:0..1.
|
||||
- Tabelle: `billing_addresses`, Foreign Key `user_id` ist eindeutig.
|
||||
- Inhalt: Rechnungsname, Adresse, PLZ, Ort, Land.
|
||||
- Relevanz im Admin: Rechnungsfähigkeit, fehlende Abrechnungsdaten, Kundendatenpflege.
|
||||
|
||||
`ownedCompanies`
|
||||
|
||||
- Kardinalität: 1:n.
|
||||
- Tabelle: `companies`, Foreign Key `owner_user_id`.
|
||||
- Bedeutung: Der User ist fachlicher Eigentümer einer Firma, auch ohne Pivot-Eintrag in `company_user`.
|
||||
- Relevanz im Admin: wichtig für Rechte im Customer-Profil und für klare Verantwortlichkeit.
|
||||
|
||||
`companies`
|
||||
|
||||
- Kardinalität: n:m.
|
||||
- Pivot: `company_user` mit `company_id`, `user_id`, `role`.
|
||||
- Rollen: `member`, `responsible`, `owner`.
|
||||
- Bedeutung: Ein User kann mehrere Firmen haben; eine Firma kann mehreren Usern zugeordnet sein.
|
||||
- Relevanz im Admin: Hauptstruktur für Kundenkonto, Berechtigungen in der Firmenpflege und spätere User-Detailansicht.
|
||||
|
||||
`contacts`
|
||||
|
||||
- Kardinalität: n:m.
|
||||
- Pivot: `contact_user` mit `contact_id`, `user_id`.
|
||||
- Zusätzlich gehört jeder Kontakt zwingend zu genau einer Firma über `contacts.company_id`.
|
||||
- Bedeutung: Kontakte können direkt Usern zugeordnet sein, fachlich sind sie aber an Firmen aufgehängt.
|
||||
- Relevanz im Admin: Ansprechpartner und Zuordnungsqualität.
|
||||
|
||||
`pressReleases`
|
||||
|
||||
- Kardinalität: 1:n.
|
||||
- Tabelle: `press_releases`, Foreign Key `user_id`.
|
||||
- Zusätzlich: optionale Firmenzuordnung über `company_id` und Pflichtkategorie über `category_id`.
|
||||
- Wichtig: Datenbankseitig ist `company_id` nullable, fachlich sollte eine Customer-PM einer Firma zugeordnet sein. Der Customer-Flow erzwingt aktuell eine eigene Firma und leitet daraus das Portal ab.
|
||||
- Relevanz im Admin: Content-Historie, Status, Veröffentlichungen, Qualität, Freigabeprozess.
|
||||
|
||||
`newsletterSubscriptions`
|
||||
|
||||
- Kardinalität: 1:n.
|
||||
- Tabelle: `newsletter_subscriptions`, Foreign Key `user_id`.
|
||||
- Inhalt: Portal, Name, E-Mail, IP, Bestätigung, Subscribe/Unsubscribe, Legacy-Zuordnung.
|
||||
- Relevanz im Admin: Kommunikationsstatus und Opt-in/Opt-out-Historie.
|
||||
|
||||
`billing / payments`
|
||||
|
||||
- `userPaymentOptions`: 1:n über `user_payment_options.user_id`.
|
||||
- `invoices`: 1:n über `invoices.user_id`.
|
||||
- `legacyInvoices`: 1:n über `legacy_invoices.user_id`.
|
||||
- Indirekt: `user_payment_options` hat n:m zu Firmen über `user_payment_option_company`; `user_payments` hängt an `user_payment_options`; `invoices` können zusätzlich an `user_payments` und `invoice_billing_addresses` hängen.
|
||||
- Relevanz im Admin: Vertrags-/Abo-Status, aktive API-Freischaltung, Rechnungen, Legacy-Archiv.
|
||||
|
||||
`tokens`
|
||||
|
||||
- Kommt über Laravel Sanctum `HasApiTokens`.
|
||||
- Tabelle: `personal_access_tokens` mit polymorphem `tokenable_type` / `tokenable_id`.
|
||||
- Im Customer-Bereich werden Tokens für API-Zugriffe verwaltet.
|
||||
- Relevanz im Admin: API-Zugang, genutzte Berechtigungen, letzter Zugriff.
|
||||
|
||||
`magicLinks`
|
||||
|
||||
- Kardinalität: 1:n.
|
||||
- Tabelle: `magic_links`, Foreign Key `user_id`.
|
||||
- Inhalt: Token-Hash, Zweck, Payload, Ablauf, Verbrauch, IPs.
|
||||
- Relevanz im Admin: Auth-/Support-Kontext, Magic-Login-Historie.
|
||||
|
||||
`filterPresets`
|
||||
|
||||
- Kardinalität: 1:n.
|
||||
- Tabelle: `user_filter_presets`, Foreign Key `user_id`.
|
||||
- Inhalt: Seite, Name, Default-Flag, letzte Nutzung, Filter-JSON.
|
||||
- Relevanz im Admin: eher Arbeitskomfort/Personalisierung, nicht Kern-Kundendaten.
|
||||
|
||||
`apiUsageLogs`
|
||||
|
||||
- Kardinalität: faktisch 1:n über `api_usage_logs.user_id`, aber aktuell keine Relation im `User`-Model.
|
||||
- Inhalt: Token, Methode, Pfad, Route, Status, IP, User-Agent, Dauer, Zeitpunkt.
|
||||
- Relevanz im Admin: API-Aktivität, Support und Missbrauchsanalyse.
|
||||
|
||||
`roles` und `permissions`
|
||||
|
||||
- Kommen über Spatie `HasRoles`.
|
||||
- Tabellen u. a. `roles`, `permissions`, `model_has_roles`, `model_has_permissions`, `role_has_permissions`.
|
||||
- Relevanz im Admin: Trennung zwischen Admin, Editor, Customer, Super-Admin und feineren Berechtigungen wie `press-releases:publish` oder `users:manage`.
|
||||
|
||||
## Firmen, Kontakte und Pressemitteilungen
|
||||
|
||||
Die fachliche CRM-/Content-Struktur läuft im Kern so:
|
||||
|
||||
- User hat mehrere Firmen über `company_user`.
|
||||
- User kann zusätzlich direkter Eigentümer einer Firma über `companies.owner_user_id` sein.
|
||||
- Firma hat mehrere Kontakte über `contacts.company_id`.
|
||||
- Firma hat mehrere Pressemitteilungen über `press_releases.company_id`.
|
||||
- Pressemitteilung hat genau einen Autor/User über `press_releases.user_id`.
|
||||
- Pressemitteilung kann mehrere Kontakte über `press_release_contact` referenzieren.
|
||||
- Kontakt kann mehreren Usern direkt zugeordnet sein über `contact_user`, bleibt aber immer an genau eine Firma gebunden.
|
||||
|
||||
Daraus ergibt sich für den User-Admin eine wichtige Sicht:
|
||||
|
||||
- User-Zentrum: Wer ist der Account?
|
||||
- Firmen-Zentrum: Welche Firmen gehören dazu, in welcher Rolle?
|
||||
- Kontakt-Zentrum: Welche Ansprechpartner hängen an diesen Firmen und/oder am User?
|
||||
- Content-Zentrum: Welche Pressemitteilungen wurden vom User erstellt und welcher Firma sind sie zugeordnet?
|
||||
- Abrechnungs-Zentrum: Welche Zahloptionen, Rechnungen und Legacy-Rechnungen hängen am User und ggf. an Firmen?
|
||||
|
||||
## Pressemitteilungen im Detail
|
||||
|
||||
Eine Pressemitteilung (`press_releases`) enthält:
|
||||
|
||||
- Identifikation: `id`, `uuid`, `slug`, `legacy_portal`, `legacy_id`.
|
||||
- Zuordnung: `portal`, `language`, `user_id`, `company_id`, `category_id`.
|
||||
- Inhalt: `title`, `subtitle`, `text`, `backlink_url`, `keywords`, `boilerplate_override`.
|
||||
- Status/Publikation: `status`, `published_at`, `scheduled_at`, `embargo_at`, `no_export`, `hits`, `teaser_begin`, `teaser_end`.
|
||||
- Medien: Bilder über `press_release_images`, Anhänge über `press_release_attachments` (UI deaktiviert).
|
||||
- Kontakte: Pivot `press_release_contact`.
|
||||
- Verlauf: Statuslogs über `press_release_status_logs`, inklusive `changed_by_user_id`, Statuswechsel, Grund und Quelle.
|
||||
|
||||
Service-Layer rund um PMs:
|
||||
|
||||
- `App\Services\PressRelease\PressReleaseService` — kapselt die Übergänge `submitForReview`, `publish`, `reject`, `archive`, `deleteFromAdmin` sowie das Auflösen von `scheduled_at`/`embargo_at` für die echte Veröffentlichung.
|
||||
- `App\Services\PressRelease\PressReleaseHtmlSanitizer` — Wrapper um `mews/purifier` mit definierter Tag-/Attribut-Whitelist.
|
||||
- `App\Services\PressRelease\PressReleaseAttachmentStorage` — kapselt Datei-Operationen auf dem `public`-Disk (UI aktuell deaktiviert).
|
||||
- `App\Console\Commands\PublishScheduledPressReleases` — wird per Scheduler (alle 5 Min) ausgeführt und veröffentlicht freigegebene PMs zum geplanten Zeitpunkt, respektiert Embargo.
|
||||
|
||||
Fachliche Konsequenz:
|
||||
|
||||
- Für Kunden sollte `company_id` praktisch Pflicht sein, obwohl die DB es nullable erlaubt.
|
||||
- Für Admins kann `company_id = null` als Migrations-/Altfall auftauchen und sollte im User-Admin sichtbar markiert werden.
|
||||
- `portal` sollte mit der Firma konsistent sein. Im Customer-Flow wird das Portal aus der Firma abgeleitet; im Admin-Bereich sollte eine bewusste Korrektur möglich sein.
|
||||
|
||||
## User-relevante Tabellen
|
||||
|
||||
Kernkonto:
|
||||
|
||||
- `users`
|
||||
- `profiles`
|
||||
- `billing_addresses`
|
||||
- `sessions`
|
||||
- `password_reset_tokens`
|
||||
- `personal_access_tokens`
|
||||
- `magic_links`
|
||||
- Spatie Permission-Tabellen
|
||||
|
||||
CRM:
|
||||
|
||||
- `companies`
|
||||
- `company_user`
|
||||
- `contacts`
|
||||
- `contact_user`
|
||||
|
||||
Content:
|
||||
|
||||
- `press_releases`
|
||||
- `press_release_images`
|
||||
- `press_release_attachments` (UI temporaer deaktiviert)
|
||||
- `press_release_contact`
|
||||
- `press_release_status_logs`
|
||||
- `categories`
|
||||
- `category_translations`
|
||||
|
||||
Billing:
|
||||
|
||||
- `billing_addresses`
|
||||
- `user_payment_options`
|
||||
- `user_payment_option_company`
|
||||
- `user_payments`
|
||||
- `payment_options`
|
||||
- `payment_option_translations`
|
||||
- `invoices`
|
||||
- `invoice_billing_addresses`
|
||||
- `legacy_invoices`
|
||||
|
||||
Kommunikation/API/Arbeitskomfort:
|
||||
|
||||
- `newsletter_subscriptions`
|
||||
- `api_usage_logs`
|
||||
- `user_filter_presets`
|
||||
|
||||
## Relevante Inhalte für den Admin-User-Bereich
|
||||
|
||||
Für eine optimierte Admin-User-Ansicht sollten diese Blöcke geplant werden:
|
||||
|
||||
- Account: Status, Portal, Sprache, Registrierungstyp, Rollen, Berechtigungen, Super-Admin, letzte Aktivität, letzte IP, E-Mail-Verifikation, 2FA-Status.
|
||||
- Datenqualität: Profil vorhanden, Rechnungsadresse vorhanden, Firma vorhanden, Kontakte vorhanden, veröffentlichte PMs vorhanden, Legacy-Zuordnung vorhanden.
|
||||
- Firmen: Firmenliste mit Rolle, Eigentümerstatus, Portal, Aktivstatus, Logo, Footer-Code-Flag, Kontakt-/PM-Anzahl.
|
||||
- Kontakte: Kontakte je Firma plus direkte User-Kontakte aus `contact_user`.
|
||||
- Pressemitteilungen: Gesamtzahl, Statusverteilung, letzte PMs, veröffentlichte PMs, PMs ohne Firma, PMs mit Portalabweichung.
|
||||
- Abrechnung: Rechnungsadresse, aktive Zahlungsoptionen, verknüpfte Firmen zu Zahlungsoptionen, Zahlungen, Rechnungen, Legacy-Rechnungen.
|
||||
- API: Token-Anzahl, Berechtigungen, letzte Nutzung, API-Usage-Logs.
|
||||
- Support/Admin-Aktionen: User bearbeiten, Rollen/Berechtigungen ändern, Impersonation, Magic-Link-Kontext, ggf. Account deaktivieren.
|
||||
|
||||
## Offene Punkte für die weitere Konzeption
|
||||
|
||||
- `User` hat keine direkte `apiUsageLogs()`-Relation, obwohl `api_usage_logs.user_id` existiert. Für Admin-Detailansichten wäre eine Relation sinnvoll.
|
||||
- `press_releases.company_id` ist nullable. Fachlich sollte geklärt werden, ob das nur Legacy-/Admin-Fälle erlaubt oder langfristig verboten werden soll.
|
||||
- `contacts` gehören immer zu einer Firma, können aber zusätzlich direkt Usern zugeordnet werden. Für die Oberfläche muss klar sein, ob "User-Kontakte" nur direkte Pivot-Kontakte meint oder alle Kontakte seiner Firmen.
|
||||
- Eine Firma kann über `owner_user_id` und zusätzlich über `company_user.role = owner` eine Eigentümerinformation haben. Das sollte im Admin eindeutig dargestellt und ggf. harmonisiert werden.
|
||||
- Billing hängt primär am User, Zahlungsoptionen können aber über Pivot auch Firmen betreffen. Für den Admin sollte klar werden, ob Rechnungen immer User-Rechnungen sind oder später firmenscharf betrachtet werden sollen.
|
||||
- Portal-Scope ist auf Firmen, Kontakte, Pressemitteilungen und Newsletter aktiv. Admin-Auswertungen nutzen teils `withoutGlobalScopes()`. In der User-Admin-Konzeption muss entschieden werden, wann portalübergreifend gesucht und angezeigt wird.
|
||||
|
||||
## Quellen im Code
|
||||
|
||||
Modelle:
|
||||
|
||||
- `app/Models/User.php`
|
||||
- `app/Models/Company.php`
|
||||
- `app/Models/Contact.php`
|
||||
- `app/Models/PressRelease.php`
|
||||
- `app/Models/PressReleaseImage.php`
|
||||
- `app/Models/PressReleaseAttachment.php`
|
||||
- `app/Models/PressReleaseStatusLog.php`
|
||||
- `app/Models/Profile.php`
|
||||
- `app/Models/BillingAddress.php`
|
||||
- `app/Models/Invoice.php`
|
||||
- `app/Models/LegacyInvoice.php`
|
||||
- `app/Models/UserPaymentOption.php`
|
||||
- `app/Models/UserPayment.php`
|
||||
- `app/Models/NewsletterSubscription.php`
|
||||
- `app/Models/MagicLink.php`
|
||||
- `app/Models/UserFilterPreset.php`
|
||||
- `app/Models/ApiUsageLog.php`
|
||||
|
||||
Services / Commands:
|
||||
|
||||
- `app/Services/PressRelease/PressReleaseService.php`
|
||||
- `app/Services/PressRelease/PressReleaseHtmlSanitizer.php`
|
||||
- `app/Services/PressRelease/PressReleaseAttachmentStorage.php`
|
||||
- `app/Services/Image/ImageService.php`
|
||||
- `app/Console/Commands/PublishScheduledPressReleases.php`
|
||||
- `routes/console.php` (Scheduler-Eintraege)
|
||||
|
||||
Migrationen:
|
||||
|
||||
- `database/migrations/*`
|
||||
Loading…
Add table
Add a link
Reference in a new issue