Wire up Ticketmaster, SeatGeek, Telegram, scoring, Playwright stubs. Deduplicate events with fuzzy venue/name matching. Retry calendar updates on transient failures. Backlog tasks marked complete. Made-with: Cursor
97 lines
4.3 KiB
Markdown
97 lines
4.3 KiB
Markdown
# Architecture
|
|
|
|
## High-level flow
|
|
|
|
```
|
|
┌──────────────┐ ┌──────────────┐
|
|
│ Ticketmaster │ │ SeatGeek │
|
|
│ Provider │ │ Provider │
|
|
└──────┬───────┘ └──────┬───────┘
|
|
│ │
|
|
└────────┬───────────┘
|
|
▼
|
|
┌───────────────┐
|
|
│ Normalize & │
|
|
│ Deduplicate │
|
|
└───────┬───────┘
|
|
▼
|
|
┌───────────────┐
|
|
│ Impact Score │
|
|
└───────┬───────┘
|
|
▼
|
|
┌───────────────┐
|
|
│ Filter by │
|
|
│ date window │
|
|
└───────┬───────┘
|
|
│
|
|
┌───────┴───────┐
|
|
▼ ▼
|
|
┌──────────────┐ ┌──────────────┐
|
|
│ Telegram │ │ Airbnb │
|
|
│ Alert │ │ Calendar │
|
|
│ (primary) │ │ (optional) │
|
|
└──────────────┘ └──────────────┘
|
|
```
|
|
|
|
## Module map
|
|
|
|
```
|
|
src/
|
|
├── main.py # CLI entrypoint, orchestration
|
|
├── config.py # Pydantic settings from env vars
|
|
├── models.py # NormalizedEvent dataclass
|
|
├── log.py # Structured logging configuration
|
|
├── dedup.py # Deduplication across providers
|
|
├── providers/
|
|
│ ├── base.py # EventProvider abstract base class
|
|
│ ├── ticketmaster.py # Ticketmaster Discovery API
|
|
│ └── seatgeek.py # SeatGeek API
|
|
├── scoring/
|
|
│ └── impact.py # Rule-based impact scoring
|
|
├── notifications/
|
|
│ └── telegram.py # Telegram bot message sender
|
|
└── airbnb/
|
|
├── auth.py # Playwright storage state management
|
|
└── calendar.py # Calendar navigation and price updates
|
|
```
|
|
|
|
## Key design decisions
|
|
|
|
### 1. Provider abstraction
|
|
|
|
All event providers implement `EventProvider.fetch() -> list[NormalizedEvent]`. This makes it trivial to add new sources (Eventbrite, PredictHQ, scraping) without touching the orchestration layer.
|
|
|
|
### 2. Normalized event model
|
|
|
|
A single `NormalizedEvent` dataclass acts as the shared contract between providers, deduplication, scoring, and output formatting. Fields: name, date, venue, source, url, raw metadata.
|
|
|
|
### 3. Airbnb automation is isolated and optional
|
|
|
|
The `src/airbnb/` module is completely decoupled from event ingestion. If Playwright breaks (selectors change, login expires), the system degrades gracefully to Telegram-only alerts. The main runner catches all Airbnb errors and logs them without crashing.
|
|
|
|
### 4. Storage state for auth
|
|
|
|
Airbnb authentication uses Playwright's `storage_state` API. A one-time manual login script saves cookies/localStorage to `state.json`. Subsequent headless runs load this state. No passwords are stored in code or env vars.
|
|
|
|
### 5. Configuration via environment
|
|
|
|
All secrets and tunables live in env vars (loaded from `.env` in local dev). No config files to manage, easy to override in Docker/cron.
|
|
|
|
### 6. No database
|
|
|
|
For weekly runs processing dozens of events, in-memory processing is sufficient. If persistence becomes necessary (e.g., tracking price change history), a simple JSON file or SQLite would be the first step.
|
|
|
|
## Error handling strategy
|
|
|
|
- Each provider's `fetch()` is wrapped in try/except; one failing source does not block others.
|
|
- Telegram send failures are logged but do not block Airbnb updates.
|
|
- Airbnb automation failures are logged and reported via Telegram if possible.
|
|
- The main runner returns a nonzero exit code if all providers fail.
|
|
|
|
## Future extension points
|
|
|
|
- New providers: subclass `EventProvider`
|
|
- New notification channels: add modules under `notifications/`
|
|
- Smarter scoring: replace `scoring/impact.py` internals
|
|
- Multi-listing: extend config and loop in `main.py`
|