diff --git a/dev/optimize/entwicklungsplan.md b/dev/optimize/entwicklungsplan.md index a40be7ff..b56e126a 100644 --- a/dev/optimize/entwicklungsplan.md +++ b/dev/optimize/entwicklungsplan.md @@ -7,16 +7,15 @@ ## Stand & Wiedereinstieg (zuletzt: 02.07.2026) -**Fertig:** Phasen **0–4** vollständig · **5.1** · **5.2 Teil 1** (Form-Rules-Concern) · **5.3 Teil 1+2** (`Contact::displayName()`, `Category::localizedName()`) + `portalBadgeColor()`-Toter-Code entfernt · **5.4 vollständig** (page-header 33 Seiten, empty-state 5 States, table-pagination 13 Wrapper) · **5.5 Teil-erledigt** (``, ``). +**Fertig:** Phasen **0–4** vollständig · **5.1** · **5.2 Teil 1** (Form-Rules-Concern + `User::syncCompaniesWithRoles()`) · **5.3 Teil 1+2** (`Contact::displayName()`, `Category::localizedName()`) + `portalBadgeColor()`-Toter-Code entfernt · **5.4 vollständig** (page-header 33 Seiten, empty-state 5 States, table-pagination 13 Wrapper) · **5.5 vollständig** (``, ``, `` über login/register/reset/confirm — **funktional gegengetestet 02.07.2026**). Zusätzlich Backfill-Command `users:backfill-portal-role` + Import-Nachlauf (rollenlose aktive Nutzer). Zusätzlich **Perf-Fix** auf `/admin/me/press-releases`: `User::accessibleCompanyIds()` hydratisierte ~107k Company-Models (jetzt `toBase()`-pluck + memoisiert), `accessibleBy()` nutzt company_id-Subquery, Status-Counts via UNION statt OR-GROUP-BY; neue `PressRelease::accessibleStatusCountsFor()`. Und Fix: fehlendes `.search-wrap`-CSS (Suchfeld /admin/me/firmen). Pint sauber, betroffene Test-Filter grün. **Hier geht es weiter** — der Rest ist teils UI-Extraktion (visuelle/funktionale QA nötig), teils backend-testbar. Empfehlung weiterhin: **eine Component/ein Schritt pro Commit**, im Browser gegenchecken (`vendor/bin/sail npm run dev`). -1. **5.5 Rest** (braucht **funktionale Auth-QA**): `` — 7 Felder über login/register/reset/confirm divergieren (Label-Zeile mit „vergessen?"-Link, `:placeholder`-Bindung, current-/new-password, Alpine-`showPassword` auf Form-Ebene). Rate-Limit-Trait bleibt zurückgestellt (login vs. magic-link divergieren zu stark). -2. **5.2 Rest**: gemeinsamer `UserUpsertService`/`SaveUserAction` (Achtung: Anlegen vs. Bearbeiten divergieren stark — Bearbeiten trägt zusätzlich Profil/Kontakte/Passwort/2FA; nur den wirklich gemeinsamen Persistenz-Kern ziehen) + Blade-Feld-Components (`billing-fields`, `company-link-picker`, `role-checkboxes`, `contact-fields`). -3. **5.3 Rest**: `PressReleaseStatus`-Badge-Methode + ``/``/`` (die Status-Badge-Call-Sites nutzen divergente Farb-Vokabulare — vor Zentralisierung klären). -4. **Phase 6** (Web-Frontend) — separat, dem User gehörend, vor jedem Löschen bestätigen lassen. +1. **5.3 Rest**: `PressReleaseStatus`-Badge-Methode + ``/``/`` (die Status-Badge-Call-Sites nutzen divergente Farb-Vokabulare — vor Zentralisierung klären). Letzter sinnvoller Schliff von Phase 5. +2. **5.2 Rest**: Blade-Feld-Components (`billing-fields`, `company-link-picker`, `role-checkboxes`, `contact-fields`) in den User-Formularen. Der gemeinsame `UserUpsertService` wurde als Over-Engineering verworfen — nur der wirklich geteilte Kern (`syncCompaniesWithRoles`) wurde gezogen. Rate-Limit-Trait bleibt zurückgestellt (login vs. magic-link divergieren zu stark). +3. **Phase 6** (Web-Frontend) — separat, dem User gehörend, vor jedem Löschen bestätigen lassen. **Wichtig beim Wiedereinstieg:** `resources/views/components/layouts/app/sidebar.blade.php` gehört dem User und bleibt aus allen Commits ausgeschlossen (`git reset -q -- …` vor jedem `git add`). `resources/views/web/**` und `components/web/**` erst in Phase 6. @@ -104,7 +103,7 @@ Keine Fachlogik-Änderung. Reduziert erreichbare Demo-Komponenten und Altlasten. - [~] **5.2 User create/edit entdoppeln** — **Teil 1 erledigt:** `ProvidesUserFormRules`-Concern bündelt die zwischen Anlegen/Bearbeiten identischen Validierungsblöcke (`userIdentityRules(?int $ignore)`, `userRolesAndCompaniesRules()`, `userBillingRules()`); die nur im Bearbeiten genutzten Profil-/Kontakt-Regeln bleiben dort inline. Beide Formulare nutzen die Spreads, 31 User-Tests grün. **Offen (bewusst, mit User abzustimmen):** gemeinsamer `UserUpsertService`/`SaveUserAction` für die ~175-Zeilen-`save()` (Anlegen/Bearbeiten divergieren stark — Bearbeiten trägt zusätzlich Profil, Kontakte, Passwort, 2FA), sowie die Blade-Feld-Components (`billing-fields`, `company-link-picker`, `role-checkboxes`, `contact-fields`) — Markup-Extraktion braucht visuelle QA (analog zur zurückgestellten 2.8). - [~] **5.3 Formatierungs-Components/Enum** — **Erledigt (Model-Methoden, getestet):** `Contact::displayName()` (6 Relation-Stellen ersetzt; `ContactDisplayNameTest`) und `Category::localizedName()` (4 Stellen; `CategoryLocalizedNameTest`). **Geklärt & erledigt:** Die `portalBadgeColor()`-Helfer in `companies/index`, `companies/show`, `contacts/index` waren toter Code (kein Aufruf) und wurden entfernt — eine `Portal::badgeColor()`-Zentralisierung ist damit gegenstandslos. **Offen (UI-/Blade-lastig, mit User abzustimmen):** `PressReleaseStatus`-Badge-Methode sowie die Blade-Components ``, ``, ``, `` (Markup-Extraktion braucht visuelle QA). - [x] **5.4 Seiten-Struktur-Components** — **erledigt.** `` (Props size sm/md/lg + descriptionWidth, Slots :meta/:actions) über **33 Seiten** ausgerollt; `` (Icon-Slot, variant warm/err, Default-Slot für Onboarding) über **5 States**; `` (:paginator) über **13 Wrapper**. **Bewusst nicht gebaut:** `` (nur triviales `
`, keine wiederholte Innenstruktur → Over-Engineering) und `` (existiert nirgends — keine `flux:combobox`). **Bewusst bespoke:** companies/show + press-releases/show (Sonder-Header mit Logo/Untertitel). -- [~] **5.5 Flash/Auth-Components** — **Erledigt:** `` (6 Flash-Blöcke: categories/create+edit, footer-codes/index, presets/index) und `` (login, forgot-password, register, magic-link). **Bewusst bespoke:** companies/show (icon-loses Flash-Design + info-Variante), verify-email/settings-profile (eigene Status-Logik). **Offen (bewusst zurückgestellt, braucht funktionale Auth-QA):** `` — 7 Felder über login/register/reset/confirm divergieren (Label-Zeile mit „Passwort vergessen?"-Link vs. schlicht, statische vs. `:placeholder`-Bindung, current-/new-password, Alpine-`showPassword`-State auf Form-Ebene); Extraktion verlagert Alpine-State in die Component und muss die Login-/Registrier-/Reset-Flows funktional (nicht nur optisch) verifizieren. `ensureNotRateLimited()/throttleKey()`-Trait bleibt zurückgestellt (login: 1 Key/5 Versuche/Lockout-Event/clear-on-success vs. magic-link: 2 Keys/3+15 Versuche/Stunden-Decay/kein Event — zu wenig gemeinsame Fläche). ``/``/`` optional, geringer Hebel. +- [~] **5.5 Flash/Auth-Components** — **Erledigt:** `` (6 Flash-Blöcke: categories/create+edit, footer-codes/index, presets/index) und `` (login, forgot-password, register, magic-link). **Bewusst bespoke:** companies/show (icon-loses Flash-Design + info-Variante), verify-email/settings-profile (eigene Status-Logik). **Erledigt (funktional gegengetestet 02.07.2026):** `` über login/register/reset/confirm — Alpine-`show`-State in die Component verlagert, `:placeholder`-Prop, optionaler `labelAction`-Slot für den „Passwort vergessen?"-Link, `show-error`-Schalter für Bestätigungsfelder. Login/Register/Reset/Confirm im Browser durchgetestet (Show/Hide-Toggle + Placeholder + Fehler). `ensureNotRateLimited()/throttleKey()`-Trait bleibt zurückgestellt (login: 1 Key/5 Versuche/Lockout-Event/clear-on-success vs. magic-link: 2 Keys/3+15 Versuche/Stunden-Decay/kein Event — zu wenig gemeinsame Fläche). ``/``/`` optional, geringer Hebel. ---