Develop a full‑stack web application using Next.js that integrates a user’s resume and Google Scholar profile to suggest suitable projects based on their skills, education, and academic work. The app will:
- Parse the resume to extract key details (name, contact, skills, experience, education).
- Fetch the Google Scholar profile to gather research interests, publications, citations, and h‑index.
- Run a recommendation engine that suggests projects categorized by the user’s skills and academic expertise.
- Frontend Specifications
- Backend Specifications
- State Management & Async Patterns
- Security Considerations
- Design Patterns
- Testing
- Linting & Tooling
- Framework: Next.js (App Router, SSR/SSG)
- Language: TypeScript
- Styling: Tailwind CSS + shadcn/ui components
- State Management: Redux Toolkit (with Thunks)
- Animations: Framer Motion
-
ResumeUploader:
- Drag & drop or click to upload PDF/DOCX
- Shows upload progress, file metadata
- “Analyze Resume” button
-
ScholarProfileInput:
- URL input field for Google Scholar
- Validates URL format, shows loader on fetch
- Displays researcher name, affiliation, citations, h‑index, interests, recent publications
-
ProjectSuggestions:
- Lists recommended projects with title, description, match score badge
- Tags for matched skills & research areas
- “Refine Analysis” & “Save Results” buttons
-
ResultsPage:
- Summary cards for resume & scholar data
- Grid of suggested projects with dynamic gradients and hover effects
- Route:
POST /api/parse-resume - Implementation: Next.js API Route
- Parser:
pdf-parse(PDF) andmammoth.js(DOCX) - Output:
{ "name": "John Doe", "emails": ["john@example.com"], "phone": "+1-555-123-4567", "skills": ["JavaScript","React","AWS",…], "education": ["B.Sc. Computer Science 2020",…], "experience": ["Frontend Intern – XYZ Corp (2021–22)",…] }
- Route:
POST /api/scrape-scholar - Implementation: Next.js API Route using Puppeteer
- Data Extracted:
name(selector#gsc_prf_in)affiliation(selector.gsc_prf_il)interests(selector.gsc_prf_ila)citations,hIndex(fromtd.gsc_rsb_std)publications(first 20 rows, selector.gsc_a_tr)
- Route:
POST /api/suggest-projects - Input: Parsed resume JSON + scholar JSON
- Engine:
- Embeddings: Sentence‑Transformers
all‑mpnet‑base‑v2served via a FastAPI microservice (embed-engine/) - Matcher: Cosine similarity between the concatenated profile embedding and each project’s embedding
- Fallback: If no high‑score matches are found, return the top 3 generic projects with a forced 50% match score
- Embeddings: Sentence‑Transformers
- Storage: Supabase table
resultswith columns:idUUID (primary key)created_atTIMESTAMPresume_dataJSONBscholar_dataJSONBproject_suggestionsJSONB
- resumeSlice — stores parsed resume data
- scholarSlice — stores Google Scholar profile data
- suggestionSlice — stores project suggestions
- fetchResume — calls
/api/parse-resume - fetchScholar — calls
/api/scrape-scholar - fetchSuggestions — invokes the embedding engine, then saves to Supabase
Promise.all()— run resume parse and scholar scrape in parallelPromise.race()— optionally fallback to the fastest parser if multiple are configured- Sequential chaining — resume ⟶ scholar ⟶ embed ⟶ database save
- File type & size checks on resume uploads
- URL pattern validation for Scholar profile endpoint
- Rate limiting on
/api/scrape-scholarto prevent abuse - Secrets (Supabase keys, service roles) stored exclusively in environment variables
- Supabase Row‑Level Security (RLS) with a policy allowing only the service role to insert
- Strip any HTML from parsed text to prevent XSS
- Use
dangerouslySetInnerHTMLonly on sanitized strings - Configure a strict CSP via Next.js’s
headers()API
- ResumeUploader renders and fires API calls correctly
- scholarSlice reducers and async thunks
- matcher.ts scoring logic with mocked embeddings
- Next.js API routes tested via
supertestor Next’s built‑in test utils - Mock Puppeteer &
pdf-parseto simulate edge cases
- Full upload → analyze → results workflow
- Test with a variety of resume files (different formats, missing sections)
- Validate error handling on invalid Google Scholar URLs
-
ESLint + Prettier
- Configured for TypeScript, React, and Next.js
- Rules enforced via
.eslintrc.jsonand.prettierrc - Automatically fixes formatting and lint errors on save or via CLI
-
Husky Pre‑commit Hooks
- Runs
eslint --fixandprettier --writeon staged files - Ensures code style consistency before commits
- Defined in
package.jsonunder"husky"scripts
- Runs
-
EditorConfig
.editorconfigenforces consistent indentation, line endings, and charset- Shared across IDEs to standardize developer environment
-
TypeScript
- Strict mode enabled (
"strict": true) intsconfig.json - No implicit
any, strict null checks, and path aliases configured
- Strict mode enabled (
-
Gitignore
- Ignores build artifacts (
.next/,node_modules/,venv/, etc.) - Keeps repository clean and reduces merge conflicts
- Ignores build artifacts (
Prerequisite: Node.js v18+, Python 3.10+, and Git
git clone https://github.com/your-username/scholarsync.git
cd scholarsynccd scholar-sync
npm installcd embed-engine
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtIf missing, install manually:
pip install fastapi uvicorn sentence-transformers torchCreate .env.local in scholar-sync/:
NEXT_PUBLIC_SUPABASE_URL=https://<your-project>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-keyRun embedding engine:
cd embed-engine
uvicorn app:app --reload --port 8001Run Next.js frontend:
cd scholar-sync
npm run dev