gruene-seele/dev/docs/project-audit.md

8.9 KiB

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.phpHash::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.phpenv('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:

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