Skip to content

Latest commit

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

🧠 LinkMind — Personal Knowledge Management System

Save anything from the internet. AI organizes, connects, and resurfaces it for you.

LinkMindNodeReactMongoDB


📖 Table of Contents


Overview

LinkMind is a full-stack personal knowledge management app where users save articles, tweets, YouTube videos, and PDFs. The system automatically tags, summarizes, clusters, and resurfaces saved content using AI.


Features

FeatureDescription
🔗 Save AnythingArticles, YouTube, Tweets, PDFs via URL paste or browser extension
🤖 AI TaggingGemini auto-generates 3-7 tags per item
📝 AI Summary2-3 sentence summary generated automatically
🔍 Semantic SearchSearch by meaning using Atlas Vector Search
🕸️ Knowledge Graphd3.js visualization of item relationships
🧩 Topic ClusteringItems grouped by dominant AI tags
🧠 Memory ResurfacingDaily cron resurfaces forgotten items
📁 CollectionsNested collections with item counts
🖊️ HighlightsSave text highlights with color + notes
🔌 Browser ExtensionChrome + Firefox one-click save

Tech Stack

Backend

  • Runtime — Node.js (ESM)
  • Framework — Express.js
  • Database — MongoDB Atlas + Mongoose
  • Cache/Queue — Redis + BullMQ
  • AI — Google Gemini API (gemini-2.5-flash + gemini-embedding-001)
  • Vector Search — MongoDB Atlas Vector Search
  • Auth — JWT + bcrypt + email verification
  • Email — Nodemailer
  • Scheduler — node-cron

Frontend

  • Framework — React 19 + Vite
  • Styling — SCSS modules
  • State — Zustand
  • Graph — d3.js
  • HTTP — Axios
  • Routing — React Router v6

Browser Extension

  • Manifest — v3 (Chrome + Firefox)
  • Storage — chrome.storage.local

Project Structure

LinkMind/
├── backend/
│ └── src/
│ ├── ai/
│ │ ├── ai.queue.js # BullMQ queue setup
│ │ └── ai.worker.js # Job processor
│ ├── config/
│ │ ├── database.js # MongoDB connection
│ │ ├── logger.js # Winston logger
│ │ └── redis.js # Redis connection
│ ├── controllers/
│ │ ├── auth.controller.js
│ │ ├── clustering.controller.js
│ │ ├── collection.controller.js
│ │ ├── graph.controller.js
│ │ ├── item.controller.js
│ │ ├── resurfacing.controller.js
│ │ └── search.controller.js
│ ├── jobs/
│ │ └── cron.js # Daily resurfacing cron
│ ├── middleware/
│ │ ├── auth.middleware.js
│ │ ├── error.middleware.js
│ │ └── validate.middleware.js
│ ├── models/
│ │ ├── auth.model.js
│ │ ├── collection.model.js
│ │ ├── graph.model.js # GraphEdge schema
│ │ └── item.model.js
│ ├── resurfacing/
│ │ └── resurfacing.job.js
│ ├── routes/
│ │ ├── auth.routes.js
│ │ ├── clustering.routes.js
│ │ ├── collection.routes.js
│ │ ├── graph.routes.js
│ │ ├── index.routes.js
│ │ ├── item.routes.js
│ │ ├── resurfacing.routes.js
│ │ └── search.routes.js
│ ├── services/
│ │ ├── ai.service.js # Gemini API wrapper
│ │ ├── auth.service.js
│ │ ├── clustering.service.js
│ │ ├── collection.service.js
│ │ ├── graph.service.js
│ │ ├── item.service.js
│ │ ├── mail.service.js
│ │ ├── resurfacing.service.js
│ │ └── search.service.js
│ ├── utils/
│ │ ├── apiResponse.js
│ │ ├── asyncHandler.js
│ │ ├── metadata.fetcher.js # Auto-fetch URL metadata
│ │ └── storage.js
│ └── app.js
├── frontend/
│ └── src/
│ ├── api/ # All API call functions
│ ├── components/ # Reusable UI components
│ ├── hooks/ # Custom React hooks
│ ├── pages/ # Route-level pages
│ ├── routes/ # AppRouter + ProtectedRoute
│ ├── store/ # Zustand stores
│ ├── styles/ # SCSS files
│ └── utils/ # Frontend utilities
└── linkmind-extension/ # Browser extension
├── manifest.json
├── popup/
├── background/
└── content/

Backend Setup

Prerequisites

  • Node.js 18+
  • MongoDB Atlas account
  • Redis (RedisLabs or local)
  • Google AI Studio API key

Installation

cd backend
npm install

Environment Variables

Create .env in the backend/ folder:

# ServerPORT=3000NODE_ENV=development# MongoDBMONGO_URI=mongodb+srv://xxxxxxxx# RedisREDIS_URL=redis://default:password@host:port# JWTJWT_SECRET=your_super_secret_keyJWT_EXPIRES_IN=7d# Google GeminiGEMINI_API_KEY=your_gemini_api_key# Email (Nodemailer)SMTP_HOST=smtp.gmail.comSMTP_PORT=587SMTP_USER=your@gmail.comSMTP_PASS=your_app_passwordFROM_EMAIL=noreply@linkmind.app# Frontend URL (for email links)CLIENT_URL=http://localhost:5173

MongoDB Atlas Vector Search Index

Create a vector search index on the items collection named vector_index:

{
"fields": [
{
"type": "vector",
"path": "embedding.vector",
"numDimensions": 3072,
"similarity": "cosine"
},
{ "type": "filter", "path": "user" },
{ "type": "filter", "path": "isArchived" },
{ "type": "filter", "path": "type" }
]
}

Run

# Development
npm run dev
# Production
npm start

Frontend Setup

Prerequisites

  • Node.js 18+

Installation

cd frontend
npm install

Environment Variables

Create .env in the frontend/ folder:

VITE_API_URL=http://localhost:3000/api

Run

npm run dev

App runs at http://localhost:5173


Browser Extension Setup

Install in Chrome

  1. Open chrome://extensions
  2. Enable Developer Mode (top right)
  3. Click Load unpacked
  4. Select the linkmind-extension/ folder
  5. The LinkMind icon appears in your toolbar

Install in Firefox

  1. Open about:debugging
  2. Click This Firefox
  3. Click Load Temporary Add-on
  4. Select linkmind-extension/manifest.json

Update API URL

In linkmind-extension/popup/popup.js and background/background.js:

constAPI_BASE="http://localhost:3000/api";// change for production

API Reference

Auth

MethodEndpointDescription
POST/api/auth/registerRegister new user
POST/api/auth/loginLogin
POST/api/auth/logoutLogout
GET/api/auth/verify-email/:tokenVerify email
POST/api/auth/resend-verificationResend verification email

Items

MethodEndpointDescription
POST/api/itemsSave new item
GET/api/itemsGet items (with filters)
GET/api/items/statsGet item stats
GET/api/items/:idGet single item
PATCH/api/items/:idUpdate item
DELETE/api/items/:idDelete item
PATCH/api/items/:id/readMark as read
POST/api/items/:id/highlightsAdd highlight
DELETE/api/items/:id/highlights/:hidRemove highlight

Collections

MethodEndpointDescription
POST/api/collectionsCreate collection
GET/api/collectionsGet all collections
GET/api/collections/:idGet collection + items
PATCH/api/collections/:idUpdate collection
DELETE/api/collections/:idDelete collection
POST/api/collections/:id/items/:itemIdAdd item to collection
DELETE/api/collections/:id/items/:itemIdRemove item from collection

Search

MethodEndpointDescription
GET/api/search?q=...&mode=hybridSearch items
GET/api/search/similar/:itemIdFind similar items

Graph

MethodEndpointDescription
GET/api/graphGet graph nodes + edges
POST/api/graph/buildBuild/update graph
DELETE/api/graphRebuild graph from scratch
GET/api/graph/statsGraph statistics
GET/api/graph/item/:itemIdItem connections (backlinks)

Clusters

MethodEndpointDescription
GET/api/clustersGet topic clusters
GET/api/clusters/:tagGet items in a cluster

Resurfacing

MethodEndpointDescription
GET/api/resurfacingGet resurfaced items
POST/api/resurfacing/seenMark items as seen
GET/api/resurfacing/statsResurfacing stats

Architecture

How an item gets saved

User pastes URL
↓
POST /api/items
↓
metadata.fetcher.js → auto-fetches title, thumbnail, author
↓
Item saved to MongoDB (aiProcessingStatus: "pending")
↓
BullMQ job queued → "ai-process-item"
↓
ai.worker.js picks up job
↓
Gemini API runs 3 tasks in parallel:
├── generateEmbedding() → 3072-dim vector
├── generateTags() → ["javascript", "react", ...]
└── generateSummary() → 2-3 sentence summary
↓
Item updated (aiProcessingStatus: "done")
↓
graph.service.js builds edges automatically

How semantic search works

User types query
↓
generateEmbedding(query) → 3072-dim vector
↓
MongoDB Atlas $vectorSearch
↓
Cosine similarity against all item embeddings
↓
Returns items sorted by semantic relevance score

How resurfacing works

Daily at 8:00 AM (node-cron)
↓
queueResurfacingForAllUsers()
↓
For each user → score all candidate items:
- Days since saved (older = boost)
- Surface count (less surfaced = boost)
- Read status (unread = boost)
- Random factor (variety)
↓
Top 5 items returned with context message:
"You saved this 47 days ago — you haven't read this yet"

Frontend State Architecture

API Layer Store (Zustand) Hook Component
───────── ─────────────── ──── ─────────
auth.api → auth.store → useAuth → LoginPage
items.api → items.store → useItems → LibraryPage
search.api → search.store → useSearch → SearchPage
graph.api → graph.store → useGraph → GraphPage
clusters.api → clusters.store → useClusters → ClustersPage
resurfacing.api → resurfacing.store → useResurfacing → Dashboard
collections.api → collections.store → useCollections → CollectionsPage
→ ui.store → useToast → Any component

Scripts

Backend

npm run dev # nodemon development server
npm start # production server

Frontend

npm run dev # Vite dev server
npm run build # Production build
npm run preview # Preview production build

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Commit your changes: git commit -m 'Add my feature'
  4. Push to branch: git push origin feature/my-feature
  5. Open a Pull Request

License

MIT License — feel free to use this project for learning and personal use.


Built with ❤️ using Node.js, React, MongoDB Atlas, and Google Gemini AI.

About

LinkMind is a full-stack personal knowledge management app where you save articles, tweets, YouTube videos, and PDFs. Powered by Gemini AI, it automatically tags, summarizes, and clusters your content. It features MongoDB semantic search, a knowledge graph, daily memory resurfacing, and a browser extension for seamless one-click saving

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages