Files
archivmail/features/PROJ-73-restliche-crash-haertung.md
T
sysopsandClaude Sonnet 5 88cdc3eb3e fix(PROJ-73): Upload-Job-Status bei Panic + nil-Guards nach GetByUsername
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
2026-08-05 13:50:36 +02:00

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:

  1. runUploadJob (internal/api/upload.go) läuft jetzt zwar dank internal/safego nicht 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.
  2. internal/api/ocr_handlers.go:66 (s.users.GetByUsername(...)) und analoge Stellen dereferenzieren das Ergebnis ohne expliziten u == 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)

  1. In runUploadJob: defer einbauen, der bei recover() != nil den Job-Status auf "error" setzt (inkl. Fehlermeldung), statt nur zu loggen.
  2. Alle GetByUsername-Aufrufstellen (grep GetByUsername über internal/api/) auf if u == nil { ... }-Guard nach dem err == nil- Check prüfen und ergänzen wo fehlend.

Implementation Notes

1. Upload-Job-Status bei Panicinternal/api/upload.go:148-162

runUploadJob bekommt direkt nach ctx := context.Background() ein defer func(){ if rec := recover(); rec != nil { ... } }():

  • setzt unter job.mu Status = "error" und ErrMsg,
  • gibt den Panic anschließend per panic(rec) weiter, damit safego.Run ihn 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 in internal/api/ haben einen expliziten nil-Guard.
  • go build ./... && go vet ./... auf 132 fehlerfrei für geänderte Dateien.