# willhaben-tracker Telegram bot that monitors classified ads on [willhaben.at](https://www.willhaben.at) and notifies you about new listings matching your keywords, plus price drops on tracked ads. Notifications include photos when available. ## Prerequisites - Docker - Docker Compose (v2.x) ## Quick Start ```bash cp .env.example .env # Edit .env with your bot token and database credentials docker compose up -d --build ``` ## Deploy on Tizona (NAS) Copy-paste these commands from your local machine: ```bash # 1. Clone repo on tizona (run as root via SSH) ssh tizona "mkdir -p /mnt/user/appdata && rm -rf /mnt/user/appdata/willhaben-tracker" ssh tizona "git clone https://git.lago.dev/Lago/willhaben-tracker.git /mnt/user/appdata/willhaben-tracker" # 2. Copy .env (must exist locally) scp .env tizona:/mnt/user/appdata/willhaben-tracker/.env # 3. Start stack on tizona ssh tizona "cd /mnt/user/appdata/willhaben-tracker && docker compose up -d --build" # 4. Verify everything is running ssh tizona "cd /mnt/user/appdata/willhaben-tracker && docker compose ps" ``` ### Update (pull + rebuild) ```bash ssh tizona "cd /mnt/user/appdata/willhaben-tracker && \ git pull origin main && \ docker compose build worker --no-cache && \ docker compose up -d" ``` ### Full reset (wipe data, keep schema) ```bash ssh tizona "cd /mnt/user/appdata/willhaben-tracker && \ docker compose down && \ rm -rf data/db && mkdir -p data/db && \ docker compose up -d --build" ``` ### Backup & Restore ```bash # Dump database ssh tizona "docker compose exec db pg_dump -U postgres postgres" > backup_$(date +%F).sql # Restore cat backup_2024-01-01.sql | ssh tizona "cd /mnt/user/appdata/willhaben-tracker && docker compose exec -T db psql -U postgres postgres" ``` ### Troubleshooting | Problem | Fix | |---------|-----| | `role "supabase_admin" does not exist` in Studio | Full reset (wipes data, re-runs init scripts) | | Migrations didn't run on new tables | `data/db/` had stale data — delete it and restart | | Worker crashes with `UndefinedTableError` | Docker image was built before migration commit — force rebuild: `docker compose build worker --no-cache && docker compose up -d` | | Studio shows "unhealthy" but APIs work | Cosmetic health check issue — ignore unless you can't browse tables | ## Configuration Edit `.env` before first startup. All values are read by the worker and database services. | Variable | Description | Default | |---------------------------|----------------------------------------------------|--------------------------------| | `TELEGRAM_BOT_TOKEN` | Token from @BotFather | (required) | | `POSTGRES_USER` | PostgreSQL username | `postgres` | | `POSTGRES_PASSWORD` | PostgreSQL password | (required) | | `POSTGRES_DB` | Database name | `postgres` | | `JWT_SECRET` | PostgREST JWT signing key | auto-generated default | | `DEFAULT_INTERVAL_MINUTES`| Default scrape interval per keyword | `5` | ## Architecture | Service | Image | Port | Purpose | |----------|------------------------------------|-------|----------------------------------| | db | postgres:15-alpine | 55632 | PostgreSQL database | | rest | postgrest/postgrest:v12.2.0 | — | REST API over the database | | kong | kong:2.8.1 | 55621 | Reverse proxy / gateway | | studio | supabase/studio | 55630 | Supabase Studio admin UI | | meta | supabase/postgres-meta:v0.84.2 | — | Database metadata service | | worker | (built from ./worker) | — | Scraper + Telegram bot | ## Telegram Bot UI All users must be whitelisted before use. The bot uses **inline keyboards** (buttons) instead of text commands for a clean experience. Times are shown in **Vienna timezone**. ### Commands (global menu, appears when you type `/`) | Command | Access | Description | |---------|--------|-------------| | `/start` | Anyone | Open main menu | | `/admin` | Admin only | Open admin panel | ### Main Menu (`/start`) Tap one of the buttons: - **➕ Add Keyword** → Bot asks for keyword text → Shows confirmation with Yes/No - **📋 My Keywords** → Sends a formatted card per keyword with status, interval (Vienna tz), last scrape, subscriber count. Each card has action buttons: - `⏸ Stop` / `▶ Start` — Toggle active state - `✏️ Edit` — Submenu to change name or interval - Change Name: type new name → confirm Yes/No → in-place update - Change Interval: preset buttons (1m, 3m, 5m, 10m, 30m, 60m) or ⌨️ Custom - `🗑 Remove` — Confirm Yes/No → deletes subscription - **📊 Stats** — Keywords count, ads indexed, notifications sent ### Admin Panel (`/admin`) - **➕ Add User** — Enter Telegram ID → adds user - **👥 List Users** — Shows all users with status icons and admin badges - **🗑 Remove User** — Enter Telegram ID → removes user ## Default Admin On first boot, Telegram ID `298181113` is seeded as an admin user. Add additional admins via the `/admin` panel.