A full-stack “ContextCV” platform where users author their portfolio in Markdown, publish a public profile, and visitors can chat with an AI that answers strictly from the portfolio content.
- User registration and login (JWT)
- Markdown portfolio editor with live preview
- Public profile page rendering Markdown
- Real-time chat with owner’s AI (answers only from portfolio context)
- Swagger API docs
- Pinecone vector storage for portfolio context
- CORS configured for local dev (React 3000 → API 5000)
- Backend: Node.js, Express, Socket.io, Mongoose, JWT, Swagger, Google Generative AI, Pinecone
- Frontend: React, Axios, socket.io-client, react-markdown, lucide-react
- Install dependencies:
cd backend-node
npm install- Environment variables: create
.envinbackend-node:
PORT=5000
MONGODB_URI=mongodb://localhost:27017/livingcv
JWT_SECRET=replace_with_a_strong_secret
# Google Gemini
GEMINI_API_KEY=your_gemini_api_key
# Pinecone
PINECONE_API_KEY=your_pinecone_api_key
# IMPORTANT: keep names consistent; set BOTH to the same index name
PINECONE_INDEX=my-livingcv-index
PINECONE_INDEX_NAME=my-livingcv-index- Start backend:
npm start- Swagger docs available at: http://localhost:5000/api-docs
- Auth
- POST /api/auth/register
- POST /api/auth/login → returns
{ token }
- Portfolio (private)
- GET /api/portfolio → requires
Authorization: Bearer <token> - PUT /api/portfolio → save markdown (syncs to Pinecone), requires
Bearer
- GET /api/portfolio → requires
- Portfolio (public)
- GET /api/portfolio/:userId → public view of portfolio markdown
- Socket.io
- Client emits:
chat_with_bot{ targetUserId, question } - Server emits:
bot_streamchunks of AI answer
- Client emits:
- The user’s portfolio markdown is embedded (Pinecone Llama v2) and stored as a single vector per user with metadata
{ text: <markdown> }. - Chat fetches the full text directly via
index.fetch([userId])to ensure accurate context. - Prompt enforces strict persona: first-person answers, use ONLY provided context; if missing, respond: “I haven’t included that in my portfolio yet.”
- Install dependencies:
cd frontend
npm install- Start frontend:
npm start- Auth/Dashboard: http://localhost:3000/
- Public profile: http://localhost:3000/profile/
- Register → Login → Edit your Markdown portfolio → Save → Click “View Public”
- Share the public URL
/profile/<userId>with anyone - Visitors ask questions in the chat; AI answers from your portfolio only
- Register
curl -X POST http://localhost:5000/api/auth/register ^
-H "Content-Type: application/json" ^
-d "{\"email\":\"dev@example.com\",\"password\":\"SuperSecret!123\"}"- Login
curl -X POST http://localhost:5000/api/auth/login ^
-H "Content-Type: application/json" ^
-d "{\"email\":\"dev@example.com\",\"password\":\"SuperSecret!123\"}"- Save portfolio (replace TOKEN)
curl -X PUT http://localhost:5000/api/portfolio ^
-H "Authorization: Bearer TOKEN" ^
-H "Content-Type: application/json" ^
-d "{\"content\":\"# Jane Doe\\n\\n## Skills\\n- Node.js\\n- React\"}"- Get public portfolio
curl http://localhost:5000/api/portfolio/<userId>- Pinecone index should match embedding dimension: 768 (llama-text-embed-v2)
- Ensure both
PINECONE_INDEXandPINECONE_INDEX_NAMEreference the same index name (the code reads both in different places) - CORS is enabled in
server.jsfor development
- “No chat response”
- Check backend logs (console) for socket events and Gemini errors
- Confirm
GEMINI_API_KEYandPINECONE_API_KEYare valid - Ensure portfolio has been saved at least once (so Pinecone has content)
- “Portfolio not found”
- The user hasn’t saved yet; save a portfolio in Dashboard first
- Swagger shows no routes
- Verify
swagger-ui-expressandswagger-jsdocare installed - Check
apis: ['./routes/*.js']and JSDoc comments exist
- Verify
MIT