feat: Phase 3 — web dashboard, testing, and CI/CD
CI / lint-and-test (push) Has been cancelled

- Remove multi-marketplace from Phase 3
- Add FastAPI web UI on port 8766 with basic auth
- Add 6 Jinja2 templates (dashboard, keywords, users, ads, stats)
- Add pytest test suite (45 tests, 49% coverage)
- Add GitHub Actions CI/CD workflow
- Update docker-compose.yml to expose web UI port
- Update Dockerfile to include tests
This commit is contained in:
2026-07-10 22:28:18 +02:00
parent 0c20799f9a
commit 8151c530da
26 changed files with 1506 additions and 388 deletions
+28 -23
View File
@@ -1,12 +1,12 @@
# Phase 3 — Scalability & Advanced Features
# Phase 3 — Web Dashboard & Testing
## Scope
This phase introduces **structural improvements** that make the project maintainable, extensible, and testable. Currently, the entire system is a single async Python process with no tests and no CI/CD pipeline. After this phase:
This phase introduces **observability and reliability** improvements. Currently, the entire system is a single async Python process with no tests, no CI/CD pipeline, and no way to monitor what's happening without SSH-ing into the server. After this phase:
- A **Web Dashboard** provides real-time visibility into keywords, ads, users, and stats
- Automated tests provide confidence for every change (≥80% coverage)
- CI/CD pipeline runs on every push to validate code quality
- Multi-marketplace architecture enables adding new sources without modifying core logic
## Architecture
@@ -21,18 +21,17 @@ This phase introduces **structural improvements** that make the project maintain
│ │ │ ├── db.py (asyncpg pool mgmt) │
│ │ │ ├── bot.py (Telegram handlers) │
│ │ │ ├── notifier.py (message sending) │
│ │ │ ├── scraper.py (base scraper class) │
│ │ │ ├── scrapers/
│ │ │ │ ├── __init__.py │
│ │ │ │ ├── willhaben.py (willhaben-specific) │
│ │ │ │ └── base.py (abstract base class) │
│ │ │ ├── scraper.py (willhaben scraper)
│ │ │ ├── web.py (FastAPI dashboard)
│ │ │ ├── health.py (healthcheck endpoint) │
│ │ │ ── migrate.py (migration runner) │
│ │ │ ── migrate.py (migration runner) │
│ │ │ └── templates/ (Jinja2 HTML templates) │
│ │ ├── tests/ │
│ │ │ ├── conftest.py │
│ │ │ ├── test_scraper.py │
│ │ │ ├── test_notifier.py │
│ │ │ ── ...
│ │ │ ── test_filters.py
│ │ │ └── test_web.py │
│ │ ├── Dockerfile │
│ │ └── requirements.txt │
│ ├── .github/ │
@@ -42,17 +41,17 @@ This phase introduces **structural improvements** that make the project maintain
│ └── docker-compose.yml │
└──────────────────────────────────────────────────────┘
Multi-marketplace abstraction:
Web Dashboard (FastAPI, port 8766):
ScraperBase (abstract):
- async fetch_ads(keyword) → list[dict]
- async parse_response(html/json) → list[dict]
- normalize_ad(raw) → dict with standard keys
WillhabenScraper(ScraperBase):
- implements willhaben-specific URL, headers, parsing
GET / → Dashboard (keywords overview, stats summary)
GET /keywords → Keywords list with status, filters, subscribers
GET /keywords/<id> → Keyword detail (recent ads, price history, scrape logs)
GET /users → Users list with settings
GET /ads → Recent ads with search/filter
GET /stats → JSON stats (extends existing /stats endpoint)
Future: KleinAnzeigenScraper, MobileScraper, ...
Auth: Basic Auth via WEB_UI_USERNAME / WEB_UI_PASSWORD env vars
Templates: Jinja2 with inline CSS (zero external dependencies)
CI/CD Pipeline (.github/workflows/ci.yml):
@@ -71,6 +70,8 @@ Tests Structure:
- test_scraper_pagination() — verify pagination logic with mock responses
- test_price_filters() — verify filter functions
- test_notification_retry() — verify retry queue behavior
- test_mute_digest() — verify mute hours and digest buffering
- test_web_endpoints() — verify web UI routes
Integration tests:
- Test against real willhaben API (rate-limited, cached)
@@ -81,13 +82,17 @@ Tests Structure:
| Task | File | Description |
|------|------|-------------|
| Multi-marketplace abstraction layer | [task-multi-marketplace.md](./task-multi-marketplace.md) | Refactor `scraper.py` into a base class + per-marketplace implementations. Introduces a standard ad schema and factory for registering new sources. |
| Web Dashboard (FastAPI + Jinja2) | [task-web-ui.md](./task-web-ui.md) | Add a read-only web dashboard for monitoring keywords, ads, users, and stats. Runs on port 8766 with basic auth. |
| Test suite with pytest (≥80% coverage) | [task-testing-pytest.md](./task-testing-pytest.md) | Add comprehensive unit tests covering scraper parsing, notification logic, price/postcode filters, retry queue, and scheduler flow. Configure coverage thresholds. |
## General Acceptance Criteria
- [ ] Web Dashboard is accessible at `http://<host>:8766` with basic auth
- [ ] Dashboard shows keywords with status, filters, subscribers, and last scrape time
- [ ] Dashboard shows recent ads with price, location, and keyword
- [ ] Dashboard shows users with mute/digest settings
- [ ] Dashboard shows stats (ads indexed, notifications sent, queue status)
- [ ] CI pipeline runs on every push to `main` and feature branches — fails if lint or coverage checks are not met
- [ ] Code coverage is ≥80% across all source files in `worker/src/`
- [ ] Multi-marketplace abstraction works — adding a new marketplace requires only creating one file under `scrapers/` with no changes to core logic
- [ ] All existing functionality (willhaben scraping, notifications) continues to work after refactoring
- [ ] The `/health` endpoint exposes test results or coverage stats (optional enhancement)
- [ ] All existing functionality (willhaben scraping, Telegram notifications, health server) continues to work
- [ ] Health server still works on port 8765 (no regression)