feat: Phase 2 — user experience & advanced filtering

- 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
This commit is contained in:
2026-07-10 21:19:34 +02:00
parent 3e7e5d0b32
commit 5d792e8ae7
5 changed files with 574 additions and 4 deletions
@@ -0,0 +1,9 @@
-- Phase 2: Price and postcode filters per keyword
ALTER TABLE keywords
ADD COLUMN IF NOT EXISTS price_min int,
ADD COLUMN IF NOT EXISTS price_max int,
ADD COLUMN IF NOT EXISTS allowed_postcodes text[];
COMMENT ON COLUMN keywords.price_min IS 'Minimum price in cents (e.g. 5000 = €50). NULL = no limit.';
COMMENT ON COLUMN keywords.price_max IS 'Maximum price in cents (e.g. 500000 = €5000). NULL = no limit.';
COMMENT ON COLUMN keywords.allowed_postcodes IS 'Austrian postcodes (4-digit strings). Only ads matching these are notified.';
@@ -0,0 +1,31 @@
-- Phase 2: User settings (mute hours + digest mode) and digest buffer
CREATE TABLE IF NOT EXISTS user_settings (
telegram_id text PRIMARY KEY,
mute_start time,
mute_end time,
digest_mode bool NOT NULL DEFAULT false,
digest_interval int NOT NULL DEFAULT 60,
last_digest_flush timestamptz,
CONSTRAINT chk_mute_hours CHECK (
mute_start IS NULL AND mute_end IS NULL
OR mute_start IS NOT NULL AND mute_end IS NOT NULL
)
);
COMMENT ON TABLE user_settings IS 'User-specific settings for notification behavior';
CREATE TABLE IF NOT EXISTS digest_buffer (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
telegram_id text NOT NULL,
ad_id uuid REFERENCES ads(id) ON DELETE CASCADE,
keyword text NOT NULL,
title text NOT NULL,
price int, -- in cents
url text,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_digest_buffer
ON digest_buffer(telegram_id, created_at DESC);
COMMENT ON TABLE digest_buffer IS 'Buffer for digest-mode notifications, flushed at intervals';