- Add price_min/price_max filters per keyword (stored in cents)
- Add allowed_postcodes filter per keyword (text[] array)
- Add mute hours per user with cross-midnight support
- Add digest mode with configurable interval and buffered summaries
- 10 new bot commands: /price_min, /price_max, /clear_price, /postcode,
/clear_postcode, /mute_hours, /mute_off, /digest_on, /digest_off, /status
- Updated keyword card display to show price range and postcodes
- New migrations: 05-keyword-filters.sql, 06-user-settings.sql
- httpx singleton: replace per-call AsyncClient with module-level singleton
using keepalive pool (configurable via env vars). Close client on shutdown.
- Scraper pagination: multi-page fetching (default 2 pages/60 ads, configurable
via SCRAPE_MAX_PAGES). Cursor-based early-stop to skip stale pages. Tracks
ads_cursor per keyword for cross-cycle deduplication.
- Notification retry queue: persistent notification_queue table with exponential
backoff (max 5 attempts → dead). Failed Telegram notifications are enqueued
instead of silently dropped. Queue processed at start of each scheduler cycle
(50 items max limit). /stats endpoint reports pending/dead counts.
- Reduce docker-compose from 6 services to 1 (worker only)
- Connect via supavisor pooled port (6543) on dedicated Supabase
- Add willhaben_tracker schema with search_path in asyncpg pool init
- Create consolidated migration SQL for Supabase SQL Editor
- Update .env.example with new connection pattern