Doku: Phase 3 im Entwicklungsplan abgeschlossen markiert (3.1-3.3 nachgezogen)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0d0edf1a6c
commit
6961cac4da
1 changed files with 3 additions and 3 deletions
|
|
@ -57,9 +57,9 @@ Keine Fachlogik-Änderung. Reduziert erreichbare Demo-Komponenten und Altlasten.
|
|||
|
||||
## Phase 3 — Backend-Querschnittslogik zentralisieren (Paket D + Domain)
|
||||
|
||||
- [ ] **3.1 `Company::scopeAccessibleBy()` / `CompanyPolicy`** — identische `owner_user_id == me OR whereHas('users', me)`-Closure in 4 Controllern + Überlappung mit `User::accessibleCompanyIds()` und `CustomerCompanyContext::accessibleCompanyQuery()`. Policy wird in `ContactAccessService:229` bereits referenziert. → konsequent über Gate/Policy.
|
||||
- [ ] **3.2 API-PressRelease-Zugriff + Eager-Loads zentralisieren** — `findOwnedPressRelease` doppelt (PressRelease/Image-Controller); Relation-Liste (`company:…`, `category.translations`, `images`) mehrfach. → expliziter Scope (`ownedByApiUser`) + `withApiResourceRelations()`. Unique-Slug-Reimplementierung (`PressReleaseController:201-220`) durch bestehendes `HasUniqueSlug` ersetzen.
|
||||
- [ ] **3.3 `DomainContext`-Service** — Host→Config-Auflösung 4× (`ThemeServiceProvider::boot`, `ThemeMiddleware`, `SetDomainUrl`, `SetCurrentPortal`). **Vorher prüfen, ob `SetDomainUrl` toter Code ist** (scheint nicht in `bootstrap/app.php` registriert). `CurrentPortalContext` mutable static → request-scoped Binding.
|
||||
- [x] **3.1 `Company::scopeAccessibleBy()`** — `owner_user_id == me OR whereHas('users', me)` als Scope (Single Source of Truth); `CompanyController` (2×) und `CustomerCompanyContext::accessibleCompanyQuery()` nutzen ihn. Test: `CompanySearchByTermTest` (accessibleBy).
|
||||
- [x] **3.2 API-PressRelease-Zugriff + Eager-Loads zentralisieren** — `PressRelease::scopeOwnedByApiUser()` (bewusst enger als `accessibleBy`: nur Autorschaft) für `findOwnedPressRelease` in PressRelease- und Image-Controller; `apiResourceRelations()` bündelt die 5× wiederholte Relation-Liste. Test: `PressReleaseAccessScopeTest`. **Bewusst nicht ersetzt:** Unique-Slug-Reimplementierung — der API-Fallback (`Str::random(8)`) divergiert vom Trait-`slugFallback()`.
|
||||
- [x] **3.3 `DomainContext` / toter Code** — **Fund:** `SetDomainUrl` war nirgends registriert (toter Code) → gelöscht; die Host→Config-Auflösung läuft real nur noch zentral über `DomainAssetContext::resolve()` (`ThemeServiceProvider`/`SetCurrentPortal`), keine 4-fache Dopplung mehr. **Bewusst nicht angefasst:** `CurrentPortalContext` mutable static → request-scoped Binding (test-gekoppelt, separater Schritt).
|
||||
- [x] **3.4 Performance** — `LogApiUsage` ist jetzt terminable (INSERT nach gesendeter Antwort, kein Queue-Worker nötig; Startzeit über Request-Attribut). Offene Single-Purchase über `User::openSinglePurchaseCount()` per-Request memoisiert (vorher 3× Count + 1× exists pro Status-Widget-Render → jetzt 1× Count), genutzt von Quota-Total/-Remaining, `hasActiveBooking` und `CustomerStatusSummary`. `CustomerCompanyContext::selectedCompany()` nutzt eine einzige `first()`-Query statt exists()+first() (Verwerfen bei Nichterreichbarkeit bleibt). `LegacySubscriptionService::cancelBundleFor` ist ein einziges Bulk-Update (UserPaymentOption ohne Observer → sicher).
|
||||
- [x] **3.5 Kleinere Zentralisierungen** — `VatResolver::normalizeCountryCode()`/`isEuCountry()` als SSOT, genutzt von `resolve()`, `VatIdValidationService` und `StripeCheckoutService` (3×). `User::findByEmail()` bündelt die `LOWER(email)`-Lookups (ContactAccessService 2×, SocialAuthService 1×); bleibt bewusst case-insensitiv, weil E-Mails nicht normalisiert gespeichert werden — der indexfreundliche Direktvergleich braucht erst eine Schreib-Normalisierung (offen). Währung über `config('billing.default_currency')` ('EUR'; für Stripe-Calls `strtolower(...)`), ersetzt 8 verstreute `'EUR'`/`'eur'`-Literale und vereinheitlicht nebenbei die uneinheitliche `SinglePurchase.currency`. Neuer `CustomerAccountProvisioner::provisionVerifiedCustomer()` ist die gemeinsame Provisioning-Methode für ContactAccessService und SocialAuthService (verifiziert + aktiv + customer-Rolle). Tests: `UserFindByEmailTest`, erweiterte `VatResolverTest`.
|
||||
- [x] **3.6 Auth-Gates** — `Gate::define('access-admin'|'access-customer')` als SSOT (AppServiceProvider), nutzbar via `@can`/Policies. `EnsureUserIsAdmin`/`EnsureUserIsCustomer` prüfen jetzt über diese Gates (`Gate::denies(...)`). Der Impersonation-Redirect ist in die eigene Middleware `BlockAdminDuringImpersonation` ausgelagert (Sitzungs-Bedingung statt Rollenfrage), sie läuft vor der Zugriffsprüfung und ist zusätzlich als persistente Livewire-Middleware registriert. Tests: `Auth/AccessGatesTest`, bestehende `UserImpersonationTest` (Redirect bleibt grün).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue