FocusFetch is a full-stack content discovery app for technical and professional reading. It lets a user enter one or more keywords, pull matching posts from multiple sources, rank the results, and refine future ordering through lightweight interaction feedback.
The current MVP combines a Next.js frontend with a Flask backend and supports Reddit, Stack Overflow, and Medium out of the box.
- Searches across multiple content sources from one query flow
- Scores results with lexical relevance, freshness, and source preference signals
- Stores interaction history in MongoDB when available, with a local JSON fallback for simpler setup
- Proxies frontend API calls through Next.js route handlers for cleaner browser-to-backend communication
- Frontend: Next.js 14, React 18, TypeScript, Tailwind CSS
- Backend: Flask, scikit-learn, requests, BeautifulSoup
- Persistence: MongoDB or local JSON storage fallback
- Deployment helpers: Docker and Docker Compose
.
|-- backend/ Flask API, ranking logic, source adapters, tests
|-- frontend/ Next.js UI and server-side proxy routes
|-- docker/ Dockerfiles and docker-compose setup
|-- README.md
|-- .gitignore
|-- .dockerignore
- The user enters keywords and selects sources in the Next.js UI.
- The frontend sends requests through local API routes in
frontend/src/app/api/*. - Those routes proxy requests to the Flask backend.
- The backend fetches content from enabled sources, ranks it, and returns normalized items.
- Favorite interactions are stored and later reused as lightweight preference signals.
The backend currently queries:
redditstackoverflowmedium
The source list is configurable through the backend environment.
Each result can include:
- lexical relevance
- freshness score
- preference score
The combined ranking is designed to keep the MVP explainable while still feeling personalized.
If MONGODB_URI is configured, FocusFetch uses MongoDB. Otherwise it falls back to a local JSON store, which keeps local development simple.
cd backend
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
python -m app.mainDefault backend URL: http://127.0.0.1:5050
cd frontend
npm install
cp .env.local.example .env.local
npm run devDefault frontend URL: http://localhost:3000
The frontend expects BACKEND_API_URL in frontend/.env.local. The example file points to the default local Flask server.
To run the full stack with Docker Compose:
docker compose -f docker/docker-compose.yml up --buildThis starts:
- frontend on
http://localhost:3000 - backend on
http://localhost:5050 - MongoDB on
mongodb://localhost:27017
Example file: backend/.env.example
Common settings:
PORTMONGODB_URIDB_NAMEENABLED_SOURCESREQUEST_TIMEOUTSOURCE_LIMITMAX_CONTENT_LENGTHFRESHNESS_HALF_LIFE_DAYSENABLE_BERT_RERANKBERT_MODELSEMANTIC_TOP_N
Example file: frontend/.env.local.example
Common setting:
BACKEND_API_URL
The Flask backend exposes these main routes under /api:
GET /api/healthGET /api/sourcesPOST /api/searchPOST /api/user/interactGET /api/content/<content_id>
The Next.js app also exposes proxy routes for the UI:
GET /api/sourcesPOST /api/searchPOST /api/interactions
cd backend
python -m pytestcd frontend
npm run typecheck
npm run lint
npm run build- Semantic reranking is present behind configuration but is not the primary default path.
- Source adapters are intentionally modular so more providers can be added later.
- The app is optimized for a readable MVP workflow rather than a production search cluster.