Upload-Job bleibt bei einem Panic im Verarbeitungspfad nicht mehr auf "running" hängen, sondern zeigt "error" mit generischer Meldung (Panic- Rohwert nur im Server-Log, ErrMsg geht ans Frontend und könnte sonst Mail-Inhalt-Fragmente transportieren). Zusätzlich fail-closed nil-Guards an allen 13 GetByUsername-Aufrufstellen in internal/api/, die das Ergebnis bisher ungeprüft dereferenzierten. Verifiziert auf 192.168.1.132: Build und go vet fehlerfrei für die geänderten Dateien. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019j28kGcaJAhBnrYX34hGdt
3.7 KiB
id, title, status, created
| id | title | status | created |
|---|---|---|---|
| PROJ-73 | Restliche Crash-Härtung (Upload-Job-Status bei Panic, fehlende nil-Checks) | In Review | 2026-08-05 |
Problem
Nach der großen Crash-Robustheit-Härtung (Commit 798cb28) sind zwei kleinere
Lücken bewusst offen geblieben:
runUploadJob(internal/api/upload.go) läuft jetzt zwar dankinternal/safegonicht mehr prozessfatal bei einem Panic, der Job-Status bleibt aber dauerhaft auf"running"hängen — der Nutzer bekommt nie eine Fehlermeldung im Upload-UI, der Job wirkt wie ein hängender Prozess.internal/api/ocr_handlers.go:66(s.users.GetByUsername(...)) und analoge Stellen dereferenzieren das Ergebnis ohne explizitenu == nil- Check. Aktuell liefert kein Store(nil, nil), daher kein akuter Bug — aber ungeschützt gegen künftige Store-Implementierungen oder Refactorings.
Lösung (Vorschlag)
- In
runUploadJob:defereinbauen, der beirecover() != nilden Job-Status auf"error"setzt (inkl. Fehlermeldung), statt nur zu loggen. - Alle
GetByUsername-Aufrufstellen (grepGetByUsernameüberinternal/api/) aufif u == nil { ... }-Guard nach demerr == nil- Check prüfen und ergänzen wo fehlend.
Implementation Notes
1. Upload-Job-Status bei Panic — internal/api/upload.go:148-162
runUploadJob bekommt direkt nach ctx := context.Background() ein
defer func(){ if rec := recover(); rec != nil { ... } }():
- setzt unter
job.muStatus = "error"undErrMsg, - gibt den Panic anschließend per
panic(rec)weiter, damitsafego.Runihn wie bisher mit Task-Namen loggt (Prozess bleibt stabil).
Bewusste Abweichung vom Spec-Vorschlag: die ErrMsg enthält nicht den
Panic-Wert, sondern den generischen Text „Import wegen eines internen Fehlers
abgebrochen". Ein Panic-Wert kann Fragmente von Mail-Inhalten transportieren
und ErrMsg wird über /upload/progress/{jobID} ans Frontend ausgeliefert
(DSGVO). Die Details stehen im Server-Log.
Feldnamen sind konsistent zum bestehenden Muster (Status "running"/"done"/
"error", ErrMsg mit JSON-Tag error_msg), snapshot() liefert sie bereits
unverändert ans Frontend — keine API-Änderung nötig.
2. nil-Guards nach GetByUsername — alle 13 Aufrufstellen in
internal/api/, jeweils nur die vorhandene if err != nil-Bedingung erweitert
(kein neuer Fehlerpfad, damit Statuscodes/Logging unverändert bleiben):
| Datei:Zeile | neue Bedingung |
|---|---|
restore_handlers.go:43, :140 |
err != nil || user == nil (500) |
search_handlers.go:429, :497 |
err != nil || u == nil || !mailBelongsToUser(...) (403) |
export.go:373 |
err != nil || u == nil || !mailBelongsToUser(...) (403) |
export.go:472 |
err != nil || u == nil (500) |
smtpout_handlers.go:103 |
err != nil || u == nil || u.Email == "" (400) |
ocr_handlers.go:66 |
err != nil || u == nil || !mailBelongsToUser(...) (403) |
auth_handlers.go:106 |
err != nil || user == nil (500) |
profile_handlers.go:36, :113, :183 |
err != nil || user == nil (500) |
ediscovery.go:134 |
err != nil || u == nil (500) |
Alle Pfade, die eine Zugriffsprüfung machen (Search/Export/OCR), fallen bei
u == nil auf „access denied" zurück, nicht auf „erlaubt" — fail-closed.
Lokal kein go build möglich (kein Go-Toolchain), nur statische Prüfung.
Acceptance Criteria
- Upload-Job zeigt nach einem simulierten Panic im Verarbeitungspfad
Status
"error"mit Fehlermeldung statt dauerhaft"running". - Alle
GetByUsername-Stellen ininternal/api/haben einen expliziten nil-Guard. go build ./... && go vet ./...auf 132 fehlerfrei für geänderte Dateien.