safe move + sqlite WAL + log indexes + backup with logs

- 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>
This commit is contained in:
2026-05-18 19:54:32 +02:00
parent 66b32ded36
commit 7e7ec67e58
9 changed files with 331 additions and 27 deletions
+7 -3
View File
@@ -1,7 +1,7 @@
import enum
from datetime import datetime
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, Integer, String, func
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, Index, Integer, String, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
@@ -129,7 +129,7 @@ class FilterLog(Base):
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
account_id: Mapped[int | None] = mapped_column(Integer, nullable=True)
account_name: Mapped[str] = mapped_column(String(100), default="")
level: Mapped[LogLevel] = mapped_column(Enum(LogLevel), default=LogLevel.INFO)
level: Mapped[LogLevel] = mapped_column(Enum(LogLevel), default=LogLevel.INFO, index=True)
message: Mapped[str] = mapped_column(String(1000))
rule_name: Mapped[str | None] = mapped_column(String(200), nullable=True)
action_type: Mapped[str | None] = mapped_column(String(50), nullable=True)
@@ -138,7 +138,11 @@ class FilterLog(Base):
mail_from: Mapped[str | None] = mapped_column(String(255), nullable=True)
folder: Mapped[str | None] = mapped_column(String(255), nullable=True)
details: Mapped[str | None] = mapped_column(String(2000), nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), index=True)
__table_args__ = (
Index("ix_filter_logs_account_created", "account_id", "created_at"),
)
class ProcessedMail(Base):