- fix: "Log leeren" without account filter used a plain DELETE over
millions of rows. That held the sqlite write lock long enough that
the scheduler's own log writes started failing with
"database is locked", and the request itself eventually 500'd back
as HTML "Internal Server Error" — which the frontend then tried to
JSON.parse, producing the popup the user reported. Now uses
DROP+CREATE for full clears (near-instant) and wal_checkpoint to
reclaim space; per-account clear still uses a normal DELETE.
- Raise sqlite busy_timeout from 10s to 60s so a legitimately slow
writer no longer starves smaller ones.
- retry-failed: single bulk DELETE with mail_uid IN (...) per account
instead of one query per uid.
- Both endpoints now return proper HTTPException(500, ...) with detail
instead of letting the exception bubble as plain text.
- Frontend: parseResponse() reads text first, then tries JSON. Both
clearLogs() and retryFailed() surface the actual server message
instead of crashing on non-JSON responses.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- fix: imap folder names with spaces (RFC3501 quoting in move/create/select)
- fix: move only deletes source after COPY + Message-ID verification in target
- fix: backup endpoint hung on sqlite write locks — enable WAL + busy_timeout
- perf: indexes on filter_logs(created_at, level, account_id+created_at) for
fast log queries on millions of rows
- feat: optional "logs mit sichern" checkbox in backup export, restore on import
- UI: backup download uses fetch+blob with error display instead of location.href
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>