fix: Crash-Robustheit + Performance in Backend und Frontend härten

Backend: recover() in allen langlebigen Goroutinen (neues internal/safego-
Paket), MIME-Multipart-Tiefenlimit gegen Stack-Overflow, IMAP-Zeilenlängen-
und FETCH-Result-Limits gegen OOM, MBOX-Buffer-Aliasing-Bug (Datenkorruption
beim Import), ungeprüfte Type Assertions abgesichert, Data Race im
API-Key-Rate-Limiter behoben, SMTP-Session-Panic führt jetzt zu 451-Retry
statt Prozessabsturz. Performance: O(n²)-String-Concat in Mailparser und
IMAP-Parser durch strings.Builder ersetzt.

Frontend: Error Boundaries für Root und Mail-Detailansicht ergänzt (gab es
vorher nicht), zahlreiche Guards gegen nil-Slices aus dem Backend-JSON die
sonst .map()/.length-Crashes/White-Screens auslösten, defekte JSON-Antworten
in api/core.ts abgefangen, zwei React-Key-Bugs bei löschbaren Listen
korrigiert.

Verifiziert auf 192.168.1.132: Build und Tests der geänderten Pakete
fehlerfrei, keine Regressionen gegenüber vorbestehendem Stand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j28kGcaJAhBnrYX34hGdt
This commit is contained in:
sysops
2026-08-05 13:39:00 +02:00
co-authored by Claude Sonnet 5
parent 0fa4fad49d
commit 798cb2817c
35 changed files with 502 additions and 112 deletions
+12 -3
View File
@@ -10,6 +10,7 @@ import (
"time"
"archivmail/internal/audit"
"archivmail/internal/safego"
imapv2 "github.com/emersion/go-imap/v2"
"github.com/emersion/go-imap/v2/imapclient"
@@ -107,7 +108,9 @@ func (s *Scheduler) TriggerSync(ctx context.Context, accountID int64) error {
s.running[accountID] = true
s.mu.Unlock()
go s.runSyncWithRetry(context.Background(), accountID)
safego.Go(s.logger, "imap manual sync", func() {
s.runSyncWithRetry(context.Background(), accountID)
})
return nil
}
@@ -121,7 +124,10 @@ func (s *Scheduler) loop(ctx context.Context) {
case <-ctx.Done():
return
case <-ticker.C:
s.checkAccounts(ctx)
// A panic in one tick must not stop the scheduler permanently.
safego.Run(s.logger, "imap scheduler tick", func() {
s.checkAccounts(ctx)
})
}
}
}
@@ -166,7 +172,10 @@ func (s *Scheduler) checkAccounts(ctx context.Context) {
s.logger.Info("imap scheduler: starting scheduled sync",
"account_id", acc.ID, "name", acc.Name)
go s.runSyncWithRetry(context.Background(), acc.ID)
accID := acc.ID
safego.Go(s.logger, "imap scheduled sync", func() {
s.runSyncWithRetry(context.Background(), accID)
})
}
}
}