Initial commit: webmail client (M0/M1)

Three-pane webmail client.
- Backend: FastAPI + async SQLAlchemy + arq worker (Postgres/Redis), IMAP/SMTP
  sync, threading, search, drafts/outbox with undo, attachments, 2FA.
- Frontend: React 18 + Vite + TypeScript + TanStack Query + Tailwind; three-pane
  UI with rich-text composer, light/dark themes, resizable panels.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 23:20:34 +02:00
co-authored by Claude Opus 4.8
commit a5ec0d21cb
174 changed files with 22239 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
"""arq worker package (SPEC §2 workers/)."""
+68
View File
@@ -0,0 +1,68 @@
"""arq worker entrypoint (SPEC §2 ``workers/worker.py``).
Run with: ``arq workers.worker.WorkerSettings`` (from ``backend/``).
"""
from __future__ import annotations
import logging
import uuid
from typing import Any
from app.config import get_settings
from app.outbox.jobs import send_job
from app.queue import redis_settings as arq_redis_settings
from app.sync.actions import (
delete_thread_job,
move_job,
move_thread_to_folder_job,
push_flags_job,
)
from app.sync.engine import bootstrap_and_backfill
logger = logging.getLogger(__name__)
async def sync_bootstrap_account(ctx: dict[str, Any], account_id: str) -> int:
"""Bootstrap + backfill an account (enqueued on account creation)."""
logger.info("sync.bootstrap_account start account=%s", account_id)
count = await bootstrap_and_backfill(uuid.UUID(account_id))
logger.info("sync.bootstrap_account done account=%s messages=%d", account_id, count)
return count
async def on_startup(ctx: dict[str, Any]) -> None:
logging.basicConfig(level=get_settings().log_level)
from app.sync.supervisor import start_supervisor
await start_supervisor(ctx)
logger.info("webmail worker started")
async def on_shutdown(ctx: dict[str, Any]) -> None:
from app.db import dispose_engine
from app.redis_client import close_redis
from app.sync.supervisor import stop_supervisor
await stop_supervisor(ctx)
await dispose_engine()
await close_redis()
logger.info("webmail worker stopped")
class WorkerSettings:
"""arq worker configuration."""
functions = [
sync_bootstrap_account,
push_flags_job,
move_job,
move_thread_to_folder_job,
delete_thread_job,
send_job,
]
on_startup = on_startup
on_shutdown = on_shutdown
max_jobs = 10 # global worker cap (SPEC §6.3)
job_timeout = 3600 # backfill of a large account can be long
redis_settings = arq_redis_settings()