Public English tech-news digest: Python, Rust, Go, JS, Postgres, AWS, AI/ML. Server-rendered FastAPI + SQLite; worker fetches verified RSS/Atom/API endpoints, normalizes entries, ranks by freshness and trust, persists indefinitely. https://tilens.rdenadai.dev/
  • Python 83.7%
  • HTML 6.7%
  • CSS 5.1%
  • JavaScript 3.6%
  • Shell 0.8%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-02 23:53:34 +00:00
.forgejo/workflows ci(forgejo): build frontend assets before pytest 2026-08-26 18:24:49 -03:00
app feat(hn): raise top-stories fetch from 30 to 90 2026-09-02 17:26:46 -03:00
config feat: reader qol, footer links, 2000-cap, MIT News sources 2026-09-02 16:09:57 -03:00
deploy feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
docs feat: reader qol, footer links, 2000-cap, MIT News sources 2026-09-02 16:09:57 -03:00
scripts fix(brand+pw): warm-plate rounded-square logo + Python Weekly backfill 2026-08-31 18:49:57 -03:00
tests test(shell): pin stream calendar realignment to today's UTC date 2026-09-02 19:36:42 -03:00
.dockerignore chore: align build tooling, docker, scripts, and docs with backend/frontend layout 2026-08-17 19:27:18 -03:00
.env.example feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
.gitignore chore: align build tooling, docker, scripts, and docs with backend/frontend layout 2026-08-17 19:27:18 -03:00
docker-compose.yml feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
Dockerfile chore: align build tooling, docker, scripts, and docs with backend/frontend layout 2026-08-17 19:27:18 -03:00
package-lock.json release: v0.2.0 github opt-in, enrichment, rank badges, status quality, rss 2026-09-02 09:39:48 -03:00
package.json release: v0.2.0 github opt-in, enrichment, rank badges, status quality, rss 2026-09-02 09:39:48 -03:00
pyproject.toml release: v0.2.0 github opt-in, enrichment, rank badges, status quality, rss 2026-09-02 09:39:48 -03:00
README.md feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
uv.lock release: v0.2.0 github opt-in, enrichment, rank badges, status quality, rss 2026-09-02 09:39:48 -03:00

TILens

Public English technology-news aggregator covering Python, Rust, PostgreSQL, FastAPI, AWS, AI/ML, and adjacent topics. The server-rendered FastAPI site reads from a local SQLite database; a separate ingestion worker fetches verified RSS, Atom, and API endpoints, normalizes entries, ranks them by freshness and trust, and persists indefinitely.

Stack

  • Web: FastAPI + Jinja2, server-rendered with progressive enhancement. Reads SQLite with mode=ro and query_only=ON.
  • Worker: long-running process that owns migrations, scheduled fetches, normalization, and writes. Sole writer to the database.
  • Storage: SQLite WAL on a local volume. One database file, one worker, multiple read-only FastAPI workers.
  • Search: SQLite FTS5 with bounded literal-term queries.
  • Frontend assets: Tailwind CSS v4 and MathJax (compiled/copied, self-hosted).
  • Tests: pytest, Ruff, Playwright (visual capture).

Frontend policy

  • Light/dark themes with system default and cookie-backed override.
  • Pastel semantic palette for surfaces and topic identity.
  • Zero border radius on first-party UI.
  • Editorial layout (no card grids for the digest stream).
  • English-only interface.

Local development

Install runtime + dev dependencies:

uv sync --extra dev
npm install

Build frontend assets once, or watch CSS changes:

npm run build:assets # CSS + MathJax
npm run watch:css    # watch mode

Initialize the database and seed sources once:

mkdir -p data
uv run python scripts/audit_sources.py
uv run python -c "from app.backend.core.db import init_database; from pathlib import Path; init_database(Path('data/tilens.sqlite3'))"

Run the worker (separate terminal):

TILENS_DB_PATH=$(pwd)/data/tilens.sqlite3 \
  uv run python -m app.backend.services.worker_service

Run the web process:

TILENS_DB_PATH=$(pwd)/data/tilens.sqlite3 \
  uv run --extra dev uvicorn app.main:app --reload --port 8000

Open http://127.0.0.1:8000/.

Docker

Production image builds frontend assets and Python in one Dockerfile:

cp .env.example .env  # only required if you want to override defaults
docker compose up --build

The Compose stack runs web and worker against a shared tilens-data volume. Both services run as UID 10001 with a read-only root filesystem, dropped capabilities, and no-new-privileges. The worker exits nonzero if its supervisor task dies so Docker restarts it. A worker heartbeat probe (file mtime under 3 * TILENS_WORKER_INTERVAL_SEC + 120s) prevents acceptance while the supervisor is alive but the ingestion loop is hung.

The Compose file binds the web service to 127.0.0.1:8000 so it sits behind a reverse proxy. A reference Caddy configuration sits in deploy/Caddyfile. Configure the proxy, then set TILENS_COOKIE_SECURE=1 and re-deploy the web service for HTTPS-only cookies.

Tests

uv run --extra dev pytest
uv run --extra dev ruff check

Operations

See docs/operations.md for environment variables, backup procedure, worker lifecycle, single-writer guarantee, and public status policy.

Architecture

See docs/architecture.md for the data flow, schema, and security boundaries.

Source catalog

The set of trusted ingestion endpoints lives in config/sources.csv. Audit the catalog with:

uv run python scripts/audit_sources.py

The report is written to artifacts/source-audit/report.json. The artifacts/ directory is local generated output and is not committed.

Backups

Online SQLite backup via the backup API:

uv run python scripts/backup.py data/tilens.sqlite3 backups/snap.sqlite3