2026-07-17 10:33:20 -04:00
2026-07-17 10:33:20 -04:00
2026-07-17 10:33:20 -04:00

Homefeed — frontend, real backend, and mock backend

frontend/        SvelteKit app — the actual site (homepage, category pages, article view, admin panel)
backend/         The real backend — Node.js/TypeScript, SQLite, RSS/API ingestion, Ollama-backed synthesis
mock-backend/    Tiny Express server serving dummy articles — useful for pure frontend UI work without Ollama running

Both backend/ and mock-backend/ implement the identical /api/feed, /api/article/:id, /api/tags, /api/events, /api/admin/* contract — the frontend doesn't know or care which one it's talking to. Switch between them by changing VITE_BACKEND_URL in frontend/.env.

Running the real backend

cd backend
cp .env.example .env   # set ADMIN_PASSWORD at minimum
npm install
npm run dev

See backend/README.md for what's fully implemented vs. stubbed (Telegram adapter, image-selection heuristic vs. vision model, etc.), and how it behaves when Ollama isn't reachable.

Running the mock backend instead (frontend-only work, no Ollama needed)

Two terminals:

# Terminal 1 — mock backend (http://localhost:4000)
cd mock-backend
npm install
npm start

# Terminal 2 — frontend (http://localhost:5173)
cd frontend
npm install
npm run dev

Open http://localhost:5173.

What's implemented

  • Homepage (/) — hero story, Local section, Business and Tech rails
  • Category pages (/category/local, /category/world, etc.) — full listing per category, local maps to the Philadelphia geo filter
  • Article page (/article/:id) — merge badge, hero image with single-source attribution, body, video slot, tag chips, thread continuation banners (both directions — "newer coverage" / "earlier coverage"), sources footer
  • Article cards — show source count (⇄ N sources), single-source attribution, or a video indicator, matching the design decided earlier
  • Light/dark theme toggle — slider in the masthead, top right, left of the settings cog. Dark is a genuine slate palette (not an inverted light theme). Persists via localStorage, respects system preference on first load, no flash-of-wrong-theme (set before hydration in app.html).
  • Admin panel (/admin/settings) — six tabs, all wired to the mock backend's /api/admin/* routes:
    • Merge — strictness slider, poll interval, hold-before-publish, follow-up thresholds, category priority (reorderable), tag dedup threshold, tag expiry
    • Sources — list, add, enable/disable, delete RSS/API/Telegram feeds
    • Models — AI service status, per-task model selection (embedding/image/synthesis), fetched from the mock's simulated Ollama catalog
    • Retention — published-article and raw-item age presets, storage cap with FIFO note and usage bar
    • Tracked events — list, create, toggle active/paused, delete
    • Connections — the asymmetric pair: frontend→backend URL (saved to this browser via localStorage, not a backend setting) and backend→AI-service host/port (a real backend setting, saved via /api/admin/settings)

Mock data

mock-backend/data.js has ~10 dummy articles covering: a 4-source merge with a follow-up (art-1art-2, same threadId), single-source articles across Business/Tech, and a Local section with a mix of merged, single-source, and video items — enough variety to sanity-check every card/badge state in the design.

Timestamps are generated relative to Date.now() (see hoursAgo() in data.js) rather than hardcoded, so "time ago" labels stay sensible no matter when you run this.

Connecting to the real backend later

The frontend never hardcodes localhost:4000 — see frontend/src/lib/config.ts. It reads VITE_BACKEND_URL (set in frontend/.env) or a value saved via setBackendUrl(). Pointing this project at the real backend instead of the mock is a one-line change, not a rewrite — swap the URL in .env and everything else keeps working, since both servers implement the same /api/feed, /api/article/:id, /api/tags, /api/events contract from homefeed-data-schema.md.

S
Description
No description provided
Readme 196 KiB
Languages
TypeScript 58.9%
Svelte 29.6%
JavaScript 10.3%
CSS 0.8%
HTML 0.4%