- Wrap all build_* route calls in asyncio.to_thread() so SQLite queries
run in a thread pool instead of blocking the event loop. Fixes tab
switch freezes and SSE stream stalls.
- Add 60s TTL caches to alerts, sessions, presence, and cross-node
endpoints (previously uncached, queried on every request).
- Scope alerts queries (top targets, devices, reason breakdown, heatmap)
to last 7 days instead of all-time full table scans.
- Add composite indexes: (bssid, received_at) on beacon_events and
deauth_events, (src_mac, received_at) on probe_events.
- Add background pruning task: runs every 6 hours, deletes events older
than HOT_DAYS from all tables, followed by WAL checkpoint.
- Document the full diagnosis and fixes in README.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>