Implements the approved design proposal across every screen.
- Layout: feeds · list · reader panes on desktop (≥1280px), list + reader
with the feeds in a drawer on tablets, one column with a bottom tab bar
(À lire, Focus, Favoris, Flux) on phones.
- List: dense rows with an unread dot, feed initial and square thumbnail
instead of large cards; touch swipe reveals the action (→ lu, ← favori).
The magazine grid stays available as a view toggle.
- Reader: inline pane on desktop, full screen on phones with a bottom
action bar (favori, partager, original, Suivant); collapsible "Résumé IA"
block; "Aa" settings become a bottom sheet on phones.
- Search: the existing /articles/search endpoint gets a UI — ⌘K / "/"
palette on desktop, full screen on phones, with recent searches.
- Mobile "Mes flux" screen: views, subscriptions with errors, theme,
OPML import/export, logout.
- Focus mode: progress bar, counter and labelled buttons.
- Tokens: new paper / deep-forest palette (all text ≥4.5:1), Newsreader +
Inter replace Playfair + Lora (two families instead of four), shared
Icon and FeedAvatar components.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UPyU2LbJ2rTrsgZqQKhH3j
Replaces the Go server with a Rust one (axum, tokio, sqlx, feed-rs,
ammonia, reqwest) serving the same REST/WebSocket API, so the React
frontend is unchanged.
- Same database: migrations keep the schema_migrations table and file
names, Argon2id hashes and hashed session tokens created by the Go
server keep working (users stay logged in), and feed item GUIDs are
computed the same way, so existing articles are not re-ingested.
- Same security model: SSRF-safe fetching (public addresses only,
checked at resolution time and on every redirect), HTML sanitization,
CSP and security headers, same-origin guard, WebSocket origin check,
per-IP / per-user rate limits, trusted-proxy aware client IPs.
- Fix: articles whose publication date lies in the future (ingested
before the clamp existed) pinned the top of the list. The maintenance
job now pulls such dates back at startup and daily.
- Relative links and images in feed content are resolved against the
article URL instead of being dropped.
- Deploy: static musl binary in an Alpine image; the Unraid compose file
uses pull_policy: always so the new image is applied on the next
`docker compose up -d`. CI runs fmt, clippy and tests (including a
PostgreSQL integration test) before building the image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fc1UFpB4V1MGWLxHAu3BMK
- Dockerfile: Go 1.26, npm ci, go mod verify, non-root user, alpine 3.22.
- Compose: Postgres no longer published on the host, password and new
security settings read from .env, GOMEMLIMIT.
- README: document new environment variables and reading shortcuts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>