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 82.2%
  • HTML 7.3%
  • CSS 5.7%
  • JavaScript 4.2%
  • Shell 0.4%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Rodolfo De Nadai 82c225b08c
All checks were successful
CI / test (push) Successful in 3m27s
Merge pull request 'Improvements v0.0.9' (#11) from improvements/v0.0.9 into main
Reviewed-on: #11
2026-08-30 01:10:46 +00:00
.forgejo/workflows ci(forgejo): build frontend assets before pytest 2026-08-26 18:24:49 -03:00
app test(ingest): cover newsletter article adapter failure paths 2026-08-29 20:10:02 -03:00
config feat(ingest): v0.0.9 newsletter article adapters 2026-08-29 20:00:12 -03:00
deploy feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
docs feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
scripts feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
tests test(ingest): cover newsletter article adapter failure paths 2026-08-29 20:10:02 -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 feat(ingest): v0.0.9 expand digest and add personal/AI sources 2026-08-28 14:18:33 -03:00
package.json feat(ingest): v0.0.9 expand digest and add personal/AI sources 2026-08-28 14:18:33 -03:00
pyproject.toml feat(ingest): v0.0.9 expand digest and add personal/AI sources 2026-08-28 14:18:33 -03:00
README.md feat(release): improvements v0.0.5 2026-08-20 11:31:52 -03:00
uv.lock feat(ingest): v0.0.9 expand digest and add personal/AI sources 2026-08-28 14:18:33 -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