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 84.5%
  • HTML 6.4%
  • CSS 4.9%
  • JavaScript 3.4%
  • Shell 0.7%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Rodolfo De Nadai 84c38a8883
All checks were successful
CI / test (push) Successful in 3m47s
Merge pull request 'Improvements v0.3.0' (#15) from improvements-v0.3.0 into main
Reviewed-on: #15
2026-09-18 22:06:37 +00:00
.forgejo/workflows ci(forgejo): build frontend assets before pytest 2026-08-26 18:24:49 -03:00
app fix(worker): preserve auto-blocked status across sync_catalog 2026-09-18 14:27:48 -03:00
config test(worker): end-to-end WAF coverage for new allowlist + source catalog cleanup 2026-09-17 21:52:18 -03:00
deploy feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
docs feat(worker): auto-block sources past failure threshold with 24h probe 2026-09-17 12:23:11 -03:00
scripts fix(brand+pw): warm-plate rounded-square logo + Python Weekly backfill 2026-08-31 18:49:57 -03:00
tests test: fix stream calendar fallback test to match actual code behavior 2026-09-18 19:02:11 -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(worker): auto-block sources past failure threshold with 24h probe 2026-09-17 12:23:11 -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 chore(release): bump version to 0.3.0 2026-09-17 12:24:17 -03:00
package.json chore(release): bump version to 0.3.0 2026-09-17 12:24:17 -03:00
pyproject.toml chore(release): bump version to 0.3.0 2026-09-17 12:24:17 -03:00
README.md feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
uv.lock test(worker): end-to-end WAF coverage for new allowlist + source catalog cleanup 2026-09-17 21:52:18 -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