Files
box-box/documentations/refactor/27-phase-19b-paddock-briefing-rss.md

111 lines
4.4 KiB
Markdown

# Phase 19B Paddock Briefing RSS Backend Spike
## Goal
Prototype the backend foundation for a future fan-facing Paddock Briefing module
without scraping article pages or touching Race Hub UI. The spike keeps news as a
local-first cache: feeds can be fetched and normalized by backend code, stored in
SQLite, and read through a small API shape.
## Source Evaluation
Recommended first-party or publisher-owned feeds:
- FIA official RSS, `https://www.fia.com/rss/news`: keep as the official source
for federation announcements and regulatory context.
- BBC Sport F1, `https://feeds.bbci.co.uk/sport/formula1`: strong free headline
source for UK-centered coverage.
- Autosport F1, `https://www.autosport.com/rss/f1/news/`: useful motorsport
specialist feed; retain summaries only when provided by the feed.
- RaceFans F1, `https://www.racefans.net/category/f1-news/feed/`: useful
independent specialist feed with a clean WordPress RSS surface.
- Guardian Formula One,
`https://www.theguardian.com/sport/formulaone/rss`: broad editorial coverage
and stable RSS conventions.
Optional sources to evaluate before shipping:
- RACER F1, `https://racer.com/f1/feed`: reasonable supplemental specialist
feed.
- Formula 1 YouTube Atom,
`https://www.youtube.com/feeds/videos.xml?channel_id=UCB_qr75-ydFVKSF9Dmo6izg`:
video-only briefing cards, separate from article news.
- Motorsport.com F1, `https://www.motorsport.com/rss/f1/news/`: not included in
the default prototype list until terms and caching expectations are reviewed.
Avoid Formula1.com scraping or hidden endpoints, X/Twitter scraping, Reddit as a
primary news source, and feed aggregator products such as RSS.app or Feedspot.
## Legal And Product Caveats
Only fetch publisher-provided RSS/Atom XML. Do not fetch article bodies, bypass
paywalls, scrape Open Graph metadata, or store full article content. The product
surface should show source, title, canonical URL, publish time, category, and a
short feed-provided summary/snippet when available. Each card should link users
to the publisher site for the article.
Before enabling a source by default, review the publisher feed terms, robots/TOS
language around caching, and whether feed summaries are intended for display.
Keep TTLs conservative and make source attribution visible in the UI.
## Implemented Proof
This spike adds:
- `internal/news`: a standard-library RSS/Atom parser and polite fetch helper
with a 10-second default timeout and a box-box User-Agent.
- URL-based deduplication with UTM parameter stripping.
- `news_sources` and `news_items` tables in SQLite migration `003_news.sql`.
- Store/query methods for upserting cached feed metadata/items and listing
newest cached items.
- `GET /api/v1/news`, with optional `limit` and `source` query params.
- Unit tests using local XML fixtures only.
The endpoint is intentionally read-only against the local SQLite cache. It does
not fetch feeds during web requests, avoiding unexpected network work in the
product UI path. A later ingestion command can call `internal/news.Fetch`, upsert
sources/items, and mark `fetched_at`/`expires_at` according to a TTL policy.
## API Shape
`GET /api/v1/news?limit=25&source=racefans-f1`
Response:
```json
[
{
"source": "racefans-f1",
"title": "Example headline",
"url": "https://publisher.example/story",
"published_at": "2026-05-25T14:00:00Z",
"summary": "Feed-provided snippet",
"category": "news",
"fetched_at": "2026-05-25T14:10:00Z"
}
]
```
Default limit is 25; maximum accepted limit is 100.
## Follow-Up Frontend Plan
Add a Paddock Briefing surface outside Race Hub while Race Hub redesign work is
active. Recommended first UI slice:
- Query `/api/v1/news?limit=12`.
- Group by recency with source badges and external-link treatment.
- Show snippets only when present, with clear publisher attribution.
- Add source filters after the cache refresh command exists.
- Treat video feed items as a separate rail or filter, not mixed into hard-news
headlines by default.
## Open Questions
- Should news refresh live behind an explicit CLI command, opportunistic startup
refresh, or a manual button in an admin/data-health screen?
- What default TTL should each source use? A 15-30 minute TTL is reasonable for
race weekends; longer may be enough outside live sessions.
- Should the cache keep historical briefing items indefinitely, or prune after a
rolling window such as 30-90 days?