§ Overview
A self-hosted personal AI news digest delivered via Telegram. Polls a curated set of RSS feeds, uses Claude (Haiku 4.5) to score each article against the user’s interests, and ships a focused 5–7 item daily summary at 7 AM local time. Single-user-first, hexagonal architecture in ~3.5k LoC.
§ Key features
- 01RSS polling with race-safe three-outcome upsert (insert / source-appended / duplicate) in a single SQL statement
- 02LLM scoring against a versioned interests profile — updating interests re-grades only stale rows
- 03Structured Claude outputs validated with Pydantic schemas at the API boundary
- 04DB-driven scheduler reconciled every 60s — add / pause / remove sources from Telegram with no restart
- 05Two-process deploy (scheduler + bot worker) sharing one Postgres, both built from one Dockerfile
- 06Telegram-only interface by design — no web dashboard, no public ports, no domain, no TLS
- 07~71% test coverage against a real Postgres test database (no SQLAlchemy mocking)
§ Challenges & solutions
Designing for one specific user under a fixed monthly cost ceiling forced every architectural decision: no multi-tenancy, no web dashboard, no embedding-based dedup in v1. The hexagonal layout (domain Protocols separate from Postgres adapters) keeps the LLM and Telegram concerns swappable behind one file each, so a future move to a local model or a different chat platform stays contained. The scoring loop also needed a versioned interests field so updating interests via Telegram re-grades only stale rows rather than the whole table.
