# Projekt-Audit: Kritische Stellen & Verbesserungsvorschlaege Erstellt: 2026-03-12 > Hinweis: Einige Stellen (auskommentierter Code, Debug-Statements) sind bewusst so, > da der Code an vielen Stellen noch in Entwicklung ist. Diese Datei dokumentiert > trotzdem alle Fundstellen, damit sie spaeter gezielt aufgeraeumt werden koennen. --- ## 1. Sicherheit ### 1.1 APP_KEY als Passwort (KRITISCH) — BEHOBEN 2026-03-12 **Problem:** Der Laravel APP_KEY wurde als Default-Passwort fuer neue User gesetzt und mit loose comparison (`==`) statt `Hash::check()` verglichen. **Fix:** - `app/Repositories/UserRepository.php` — `Hash::make(config('app.key'))` statt `env('APP_KEY')` - `app/User.php isPasswort()` — `Hash::check(config('app.key'), $this->password)` statt `==` - `app/Repositories/CustomerRepository.php:22` — war bereits auskommentiert, kein Handlungsbedarf > ACHTUNG: Bestehende User mit dem alten Klartext-APP_KEY als Passwort muessen > einmalig migriert werden (z.B. per Artisan-Command), da `Hash::check()` gegen > den alten Klartext-Wert nicht mehr matcht. Alternativ: Beim naechsten Login > pruefen und automatisch re-hashen. --- ### 1.2 Unauthentifizierter Cron-Endpoint **Problem:** `/cron/jobs/action/{action}/{key}` in `routes/web.php` ist ein GET-Endpoint ohne Auth-Middleware. Cron-Jobs koennen von aussen getriggert werden, wenn die URL bekannt ist. **Vorschlag:** - Signed-URL Middleware (`signed`) oder ein geheimer Token-Vergleich in Middleware - Alternativ: Cron-Jobs ausschliesslich ueber `php artisan schedule:run` ausfuehren und den HTTP-Endpoint entfernen --- ### 1.3 env() ausserhalb von Config-Dateien — TEILWEISE BEHOBEN 2026-03-12 **Problem:** `env()` funktioniert nicht wenn `config:cache` aktiv ist. **Fix (im Rahmen von 1.1):** - `app/User.php` und `app/Repositories/UserRepository.php` — `env('APP_KEY')` durch `config('app.key')` ersetzt. - `app/Repositories/CustomerRepository.php:22` — war bereits auskommentiert. **Pruefen:** Ob weitere `env()` Aufrufe ausserhalb von `config/` existieren. --- ### 1.4 Datei-Upload: Client-Extension vertraut **Problem:** `getClientOriginalExtension()` nutzt die vom Browser gelieferte Dateiendung. Ein manipulierter Upload koennte eine unerwartete Extension erhalten. **Dateien:** - `app/Repositories/FileRepository.php:56` - `app/Repositories/ImportRepository.php` (gleicher Ansatz) **Vorschlag:** `$file->extension()` verwenden (leitet Extension aus MIME-Type ab) oder zusaetzlich gegen eine Whitelist validieren. --- ### 1.5 PayPal-Fehler an User exponiert **Problem:** `abort(403, 'PayPal Type: '.$order['type'])` gibt interne PayPal-Fehlertypen direkt an den User weiter. **Datei:** `app/Http/Controllers/Pay/PayPalController.php:65` **Vorschlag:** Fehler intern loggen, dem User eine generische Fehlermeldung zeigen. --- ## 2. Routing-Probleme ### 2.1 Doppelte Route-Namen — BEHOBEN 2026-03-12 **Fix in `routes/web.php`:** | Alt (doppelt) | Neu (eindeutig) | Route | |---------------------|------------------------------|------------------------------------------| | `home` (GET `/`) | `landing` | Oeffentliche Startseite | | `home` (GET `/home`)| `home` (unveraendert) | Auth-geschuetztes Dashboard | | `user_sales` (Z.204)| `user_sales_orders` | User-Bestellungen (orders-Methode) | | `user_sales_detail` (Z.205)| `user_sales_order_detail` | User-Bestellungsdetail (orderDetail) | | `user_sales` (Z.248)| `user_sales` (unveraendert) | Shop-Verkaeufe (index-Methode) | | `user_sales_detail` (Z.249)| `user_sales_detail` (unveraendert) | Shop-Verkaufsdetail (detail) | Die umbenannten Routen (`user_sales_orders`, `user_sales_order_detail`) wurden in keinen Views/Controllern referenziert, daher waren keine weiteren Anpassungen noetig. --- ### 2.2 GET-Routen fuer Loeschaktionen **Problem:** Loeschaktionen wie `admin_product_delete`, `admin_product_image_delete`, `admin_lead_delete_file` sind als GET definiert. GET-Requests sollten keine Daten aendern (Browser-Prefetch, Crawler, CSRF-Risiko). **Vorschlag:** Auf DELETE-Method umstellen mit `@method('DELETE')` in Blade-Forms. --- ### 2.3 GET-Route mutiert Daten **Problem:** `SalesController::detail()` setzt `shipped = 1` bei einem GET-Request. **Datei:** `app/Http/Controllers/SalesController.php` (detail-Methode) **Vorschlag:** Versand-Status per separatem POST/PATCH-Endpoint setzen. --- ## 3. Bugs / Korrektheitsprobleme ### 3.1 Stornierungs-Mail sendet Rechnungs-Mail **Problem:** `createCancellation()` ruft `Invoice::sendInvoiceMail()` auf statt eine dedizierte Stornierungs-Mail. Kunden erhalten bei Stornierung die Rechnungs-Mail. **Datei:** `app/Repositories/InvoiceRepository.php:279` **Vorschlag:** Eigene `sendCancellationMail()` Methode erstellen und hier aufrufen. --- ### 3.2 Schedule: payments:reminders ohne Frequenz **Problem:** Der Command `payments:reminders` hat keine Schedule-Frequenz (`->daily()` etc.) konfiguriert. Ohne Frequenz laeuft er ggf. jede Minute. **Datei:** `app/Console/Kernel.php:37-43` **Vorschlag:** Gewuenschte Frequenz setzen, z.B. `->dailyAt('08:00')`. --- ### 3.3 helpers.php: Doppelte Funktion **Problem:** `make_old_url()` ist zweimal definiert (Zeile 3-9 und 11-16). Die zweite Definition wird durch `function_exists`-Guard ignoriert. **Datei:** `app/helpers.php` **Vorschlag:** Doppelte Definition entfernen. --- ## 4. Performance ### 4.1 N+1 Query-Probleme Mehrere Controller laden Beziehungen in Schleifen ohne Eager Loading: | Datei | Stelle | Problem | |-------|--------|---------| | `app/Http/Controllers/SalesController.php` | datatable() | `$order->member->getFullName()` pro DataTable-Zeile | | `app/Repositories/InvoiceRepository.php` | prepairForDelivery() | `Attribute::find()` in dreifach verschachtelter Schleife | | `app/Http/Controllers/SyS/AdminToolsController.php` | _dbOrderPaymentFor() | `ShoppingUser::all()` dann `->shopping_order` pro Eintrag | | `app/Http/Controllers/User/PaymentController.php` | index() | `user_margins`/`user_credits` in DataTable-Callback | **Vorschlag:** `with()` / `load()` fuer Eager Loading nutzen. Bei DataTables die Relationships im Query vorladen. --- ### 4.2 AdminToolsController: Ganze Tabellen laden **Problem:** `ShoppingUser::all()` laedt die komplette Tabelle ohne Pagination. **Datei:** `app/Http/Controllers/SyS/AdminToolsController.php:97` **Vorschlag:** Chunking (`chunk()`) oder Query mit Filtern nutzen. --- ## 5. Code-Qualitaet (bei Gelegenheit) ### 5.1 Keine FormRequest-Klassen Das Projekt hat keinen einzigen FormRequest. Alle 25+ Controller nutzen inline `Validator::make()`. Bei neuen Features sollten FormRequests genutzt werden. Bestehende nach und nach migrieren. ### 5.2 Fehlende Return-Type-Deklarationen Projekt-weit fehlen Return-Types auf Methoden (Controller, Models, Services, Repositories). Bei jeder Aenderung an einer Datei sollten Return-Types ergaenzt werden. ### 5.3 Model-Relationships ohne Return-Type-Hints Alle Relationship-Methoden in `app/User.php` und `app/Models/*.php` haben keine Return-Type-Hints (`BelongsTo`, `HasMany`, etc.). ### 5.4 `$dates` deprecated (10+ Models) `protected $dates = ['deleted_at']` ist seit Laravel 10 deprecated. Sollte durch `casts()` Methode ersetzt werden: ```php protected function casts(): array { return ['deleted_at' => 'datetime']; } ``` Betroffene Models: `ShoppingOrder`, `UserAccount`, `ShoppingOrderItem`, `UserShop`, `PromotionUser`, `Product`, `ShoppingUser`, `ShoppingOrderMargin`, `PromotionAdmin`, `UserMessage`. ### 5.5 PayPal: Fehlendes Error-Handling `PayPalController::paymentSuccess()` und `payment()` haben kein try/catch. Netzwerkfehler oder unerwartete PayPal-Antworten fuehren zu unbehandelten 500-Fehlern. **Datei:** `app/Http/Controllers/Pay/PayPalController.php` ### 5.6 Invoice Service: Nur statische Methoden `app/Services/Invoice.php` ist komplett statisch — nicht testbar und nicht per Dependency Injection nutzbar. Bei Ueberarbeitung auf Instanz-Methoden umstellen. ### 5.7 Typo: prepairForDelivery `app/Repositories/InvoiceRepository.php:156` — Methode heisst `prepairForDelivery` statt `prepareForDelivery`. --- ## Zusammenfassung nach Prioritaet | Prio | # | Thema | Aufwand | |------|---|-------|---------| | ~~KRITISCH~~ | ~~1.1~~ | ~~APP_KEY als Passwort~~ | ~~BEHOBEN~~ | | KRITISCH | 1.2 | Cron-Endpoint ohne Auth | Klein | | ~~HOCH~~ | ~~1.3~~ | ~~env() ausserhalb Config~~ | ~~BEHOBEN~~ | | ~~HOCH~~ | ~~2.1~~ | ~~Doppelte Route-Namen~~ | ~~BEHOBEN~~ | | HOCH | 3.1 | Falsche Mail bei Stornierung | Klein | | HOCH | 3.2 | Schedule ohne Frequenz | Klein | | MITTEL | 1.4 | File-Upload Extension | Klein | | MITTEL | 1.5 | PayPal-Fehler exponiert | Klein | | MITTEL | 2.2 | GET fuer Loeschaktionen | Mittel | | MITTEL | 2.3 | GET mutiert Daten | Klein | | MITTEL | 3.3 | Doppelte Funktion helpers.php | Klein | | MITTEL | 4.1 | N+1 Queries | Mittel | | MITTEL | 4.2 | Ganze Tabellen laden | Klein | | NIEDRIG | 5.1-5.7 | Code-Qualitaet | Fortlaufend |