尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
AI-powered news aggregation and summarization platform with a newspaper-inspired editorial UI. Fetches RSS feeds, summarizes them using LLM APIs, and presents everything in a clean, multi-column layout with real-time widgets.查看完整 README ↗AI-powered news aggregation and summarization platform with a newspaper-inspired editorial UI. Fetches RSS feeds, summarizes them using LLM APIs, and presents everything in a clean, multi-column layout with real-time widgets.
JOB_PROFILEBased on the "Mental Antibody" implementation spec and the "Engineering Cognitive Resilience" research paper. 57 features across 5 tabs:
Overview — Dashboard stats, quick actions, recent activity
Training
useOptimistic for instant feedbackAnalysis
Reflection
Reference
Bias Radar — 5-tab slide-over panel used across the app (from article views and homepage): technique picker, compare, decode, steelman, timeline, diet report, gut check
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Tailwind CSS 4, Vite, ShadCN UI, Recharts |
| Backend | Express 5, better-sqlite3 (WAL mode), rss-parser |
| AI | Groq (openai/gpt-oss-20b), OpenRouter (minimax/minimax-m2.7) |
| APIs | TMDB, CoinGecko, Open-Meteo, Frankfurter, Hacker News, PBS |
# Clone the repository
git clone https://github.com/elodlukacs/news-digest.git
cd news-digest
# Install server dependencies
cd server
npm install
cp .env.example .env
# Edit .env with your API keys (see Configuration below)
# Install client dependencies
cd ../client
npm install
Edit server/.env with your API keys:
# Required — at least one LLM provider
GROQ_API_KEY= # https://console.groq.com
OPENROUTER_API_KEY= # https://openrouter.ai
# Optional
TELEGRAM_BOT_TOKEN= # BotFather on Telegram
TELEGRAM_CHAT_ID= # Your chat ID
TMDB_API_KEY= # https://www.themoviedb.org/settings/api
DB_PATH= # SQLite path (default: ./newsreader.db)
PORT= # Server port (default: 3001)
# Access control — see "Securing a deployed backend" below
API_TOKEN= # Bearer token required on every endpoint except /api/health
ALLOWED_ORIGINS= # Comma-separated browser origins allowed to call the API
# Timeouts
LLM_TIMEOUT_MS= # Per-LLM-request timeout (default 90000)
RSS_TIMEOUT_MS= # Per-feed fetch timeout (default 15000)
Client (build-time only):
VITE_API_URL — backend URL for a split deployment (e.g. https://api.example.com/api). Omit only if the frontend host proxies /api to the backend.VITE_API_TOKEN — must match the server's API_TOKEN when auth is enabled.Running locally needs nothing: with API_TOKEN empty the API is open, and CORS
allows localhost only. As soon as the backend is reachable from anywhere
else, set both variables. Without a token, anyone who can reach the host can
delete categories, rewrite the system prompts that produce every summary, and
spend your LLM credits.
# server/.env
API_TOKEN=<a long random string>
ALLOWED_ORIGINS=https://your-frontend.example
# client build environment
VITE_API_TOKEN=<the same string>
GET /api/health stays unauthenticated so container health checks work. The API
also rate-limits: 300 requests/min per IP overall, 20/min on the LLM-backed
routes.
Prompts you edit in the /prompts UI survive restarts. On boot the server
re-seeds the prompts defined in server/db.js, but only for rows still
byte-identical to what it last wrote (tracked via prompts.source_hash).
Anything you have changed is left alone and listed in the startup log. To
deliberately adopt the code versions, run once with PROMPT_SEED_FORCE=1.
# Terminal 1 — Backend (port 3001)
cd server
node index.js
# Terminal 2 — Frontend (port 5173)
cd client
npm run dev
Open http://localhost:5173 in your browser.
# Type-check
cd client && npx tsc --noEmit
# Lint
cd client && npm run lint
# Production build
cd client && npm run build # outputs to client/dist/
+ button in the navigation bar (e.g., "World News", "Technology")JOB_PROFILE)news-reader/
├── client/ # React frontend
│ ├── src/
│ │ ├── components/ # UI components
│ │ │ ├── ui/ # ShadCN UI primitives
│ │ │ └── *.tsx # Page-level components
│ │ ├── features/
│ │ │ └── mindgames/ # Cognitive Resilience Dashboard (9 sub-modules)
│ │ │ ├── common/ # Shared: FeaturePanelHeader, TabHeader
│ │ │ ├── dashboard/ # CognitiveDashboard, CognitiveTabNav
│ │ │ ├── overview/ # OverviewTab (stats, quick actions)
│ │ │ ├── training/ # InoculationPanel, PatternTests
│ │ │ ├── analysis/ # ForensicPanel, StudyStressTester, CompareCoverage, NewsSpectrum
│ │ │ ├── reflection/ # ScientistPanel, BridgePanel, JournalTrends, InformationDiet, StressDiagnostic
│ │ │ ├── reference/ # PromptLibrary, NarrativeMapPanel, DisinfoMap
│ │ │ ├── quiz/ # DailyQuiz
│ │ │ └── bias-radar/ # BiasRadarPanel, TechniquePicker, TechniqueCard
│ │ ├── hooks/ # useApi, useTheme, useWidgets, useMediaQuery, usePullToRefresh
│ │ ├── types/ # TypeScript interfaces
│ │ ├── utils/ # Date formatting utilities
│ │ ├── config.ts # API_BASE configuration
│ │ └── index.css # Theme definitions (4 themes via CSS custom properties)
│ ├── vite.config.ts
│ └── components.json # ShadCN UI config
├── server/
│ ├── index.js # Express entry point
│ ├── db.js # SQLite setup (WAL mode, auto-creates tables)
│ ├── routes/ # API route handlers
│ │ ├── categories.js # CRUD for feed categories
│ │ ├── feeds.js # Feed management
│ │ ├── summaries.js # Summary generation + history
│ │ ├── chat.js # AI chat about summaries
│ │ ├── briefing.js # Morning briefing generation
│ │ ├── jobs.js # Job board (12 sources + AI filter)
│ │ ├── stats.js # LLM usage + trending
│ │ ├── widgets.js # Weather, crypto, rates, HN, releases
│ │ ├── homepage.js # Newspaper grid homepage
│ │ ├── settings.js # User preferences (theme, etc.)
│ │ ├── telegram.js # Send-to-Telegram
│ │ ├── discovery.js # RSS feed auto-discovery
│ │ ├── narrative.js # Narrative map
│ │ ├── prompts.js # Prompt library
│ │ ├── disinfo.js # Disinfo map
│ │ ├── cognitive.js # Stress diagnostic
│ │ ├── forensics.js # Fallacy detection
│ │ ├── inoculation.js # Inoculation game
│ │ ├── scientist.js # ADEPT debate + journal
│ │ ├── bridge.js # SOS audit
│ │ ├── compare.js # Coverage comparison
│ │ ├── spectrum.js # News spectrum
│ │ └── bias-radar/ # Bias radar (decode, related, timeline, daily-quiz, steelman, missing-story)
│ ├── lib/ # Shared utilities
│ │ ├── llm.js # LLM provider fallback (Groq → OpenRouter)
│ │ ├── rss.js # RSS parsing
│ │ ├── telegram.js # Telegram bot integration
│ │ └── fetchWithTimeout.js # HTTP with timeout
│ ├── jobs/ # Job aggregator
│ │ ├── sources.js # 11 aggregator fetchers + ALL_SOURCES registry
│ │ ├── sources-ats.js # Direct Greenhouse/Lever/Ashby/Workable boards
│ │ ├── profile.js # JOB_PROFILE — configurable role/seniority/region
│ │ ├── ai-filter.js # AI relevance filtering (reads JOB_PROFILE)
│ │ └── common.js # Shared job utilities
│ └── middleware/ # Express middleware
├── AGENTS.md # Agent instructions & architecture reference
└── vercel.json # Vercel deployment config
Both halves deploy independently. Whichever host you use, set API_TOKEN +
ALLOWED_ORIGINS on the server and VITE_API_TOKEN on the client — see
Securing a deployed backend.
.github/workflows/deploy-*.yml uses)Both client/Dockerfile and server/Dockerfile build standalone images; the
workflows SSH to the host and run ~/newsreader/deploy-frontend.sh /
deploy-backend.sh there.
DB_PATH=/data/newsreader.db
(already the image default). Health check hits /api/health.client/nginx.conf proxies /api/ to http://newsreader-api:3001,
so put both containers on the same Docker network and the default
VITE_API_URL=/api works with no build arg. If your backend container has a
different name, change the set $api_upstream line in client/nginx.conf.cd client && npm install && npm run buildclient/distVITE_API_URL to your backend URL, including the /api suffixvercel.json excludes api/ from the SPA rewrite. Without that exclusion the
rewrite matched /api/* too and every API call came back as 200 OK with an
HTML body — which surfaced as "Invalid response from server" rather than a
network error. The client now detects HTML responses on API requests and reports
the misconfiguration explicitly.
servernode index.jsPORT (most hosts provide it)/data), set DB_PATH=/data/newsreader.dbThe process handles SIGTERM/SIGINT by checkpointing the SQLite WAL and
closing the DB, so restarts don't leave an unflushed WAL behind.
MIT