# Phase 2 — User Experience & Advanced Filtering ## Scope This phase introduces **user-facing features** that significantly improve the experience of keyword tracking. Currently, every matching ad triggers an instant notification regardless of price, location, or time of day — leading to noise for popular keywords. After this phase: - Users can configure price ranges and postcodes per keyword - Notifications respect mute hours (no alerts at 3 AM) - Users opt into digest mode (bundled summaries instead of individual pings) ## Architecture ``` ┌──────────────────────────────────────────────┐ │ User Interaction Layer │ │ │ │ Telegram Bot Commands: │ │ /set_price_min <€> │ │ /set_price_max <€> │ │ /set_postcode │ │ /mute_hours - │ │ /digest on|off │ │ │ └──────────┬───────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────┐ │ Database Schema (extended) │ │ │ │ keywords table: │ │ + price_min int │ │ + price_max int │ │ + allowed_postcodes text[] │ │ │ │ user_settings table (new): │ │ telegram_id text PK │ │ mute_start time │ │ mute_end time │ │ digest_mode bool DEFAULT false │ │ digest_interval int DEFAULT 60 │ └──────────┬───────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────┐ │ Notification Pipeline (modified) │ │ │ │ For each new ad: │ │ ├─ filter by price_min/max? → skip │ │ ├─ filter by allowed_postcodes? → skip │ │ ├─ user in mute hours? │ │ │ digest_on → buffer to digest_table │ │ │ digest_off→ skip notification │ │ └─ normal → send now │ │ │ │ Digest scheduler (separate task): │ │ every digest_interval: │ │ collect buffered notifications per user │ │ format as summary message │ │ send single message │ │ clear buffer │ └──────────────────────────────────────────────┘ ``` ## Tasks | Task | File | Description | |------|------|-------------| | Price range filters per keyword | [task-price-filters.md](./task-price-filters.md) | Add `price_min` and `price_max` columns to the keywords table; filter ads during processing based on these thresholds. Bot commands to set/unset. | | Location / postcode filters per keyword | [task-postcode-filters.md](./task-postcode-filters.md) | Add `allowed_postcodes` text[] column to keywords; only notify if an ad's location matches any allowed postcode. | | Mute hours per user | [task-mute-hours.md](./task-mute-hours.md) | Create `user_settings` table with configurable mute window (start/end time in UTC); suppress notifications during this window. | | Digest / summary notifications | [task-digest-notifications.md](./task-digest-notifications.md) | Buffer notifications for users with digest mode enabled; send a bundled summary at configured intervals instead of individual alerts. | ## General Acceptance Criteria - [ ] Users can set price min/max on any keyword and only receive notifications within that range - [ ] Postcode filtering works — ads outside allowed postcodes are silently skipped (not counted as new) - [ ] Mute hours suppress all notifications to a user during the configured window, regardless of keyword - [ ] Digest mode buffers individual alerts and sends one summary message at the configured interval - [ ] All filters combine correctly: an ad is only notified if it passes price + postcode checks AND the user is not muted (or digest mode active) - [ ] The bot provides clear feedback when a filter setting is changed ("Keyword X: price range set to €100–€500") - [ ] Admin can view all keyword filters and user settings via `/keywords` command output