Production-grade Node.js backend for AI Interview & Career Intelligence SaaS platform.
This backend follows service-based architecture:
- Backend API (this service) - Handles business logic, data persistence, authentication
- ML Service (Python/FastAPI) - Handles AI/ML inference (ATS scoring, interview evaluation)
- Frontend (React) - User interface
- Runtime: Node.js 18+
- Framework: Express.js
- Database: MongoDB with Mongoose
- Authentication: JWT (access + refresh tokens)
- Security: Helmet, CORS
- File Upload: Multer
- Logging: Morgan
- Validation: Express-validator
backend/
βββ src/
β βββ config/ # Configuration files
β β βββ env.js # Environment variables
β β βββ database.js # MongoDB connection
β βββ middlewares/ # Express middlewares
β β βββ errorHandler.js
β β βββ requestLogger.js
β βββ routes/ # Route definitions
β β βββ health.routes.js
β βββ controllers/ # Request handlers
β β βββ health.controller.js
β βββ models/ # Mongoose schemas
β βββ modules/ # Feature modules (auth, resume, interview)
β βββ utils/ # Helper functions
β βββ app.js # Express app configuration
β βββ server.js # Server entry point
βββ package.json
βββ .env.example
βββ README.md
- Node.js >= 18.0.0
- npm >= 9.0.0
- MongoDB (local or cloud)
-
Clone and navigate to backend directory
cd backend -
Install dependencies
npm install
-
Configure environment variables
cp .env.example .env
Then edit
.envwith your configuration:MONGODB_URI- Your MongoDB connection stringJWT_ACCESS_SECRET- Secret key for access tokensJWT_REFRESH_SECRET- Secret key for refresh tokens- Other optional configurations
-
Start MongoDB (if running locally)
# Using Docker docker run -d -p 27017:27017 --name mongodb mongo:latest # Or start your local MongoDB service sudo systemctl start mongod
-
Run the application
# Development mode (with auto-restart) npm run dev # Production mode npm start
Basic service health check
Response:
{
"success": true,
"message": "Career AI SaaS Backend is running",
"data": {
"status": "healthy",
"uptime": 123.456,
"timestamp": "2026-01-25T14:00:00.000Z",
"environment": "development",
"version": "1.0.0"
}
} Database connectivity check
Response:
{
"success": true,
"message": "Database is healthy",
"data": {
"status": "healthy",
"database": "career-ai-saas",
"connected": true,
"responseTime": "5ms"
}
}POST /api/v1/resume/upload- Upload resume for analysisPOST /api/v1/interview/start- Start interview sessionPOST /api/v1/interview/:id/answer- Submit and evaluate answerPOST /api/v1/interview/:id/complete- Complete with summary
Register a new user
Request:
{
"email": "john@example.com",
"password": "password123",
"name": "John Doe"
}Response (201):
{
"success": true,
"message": "User registered successfully",
"data": {
"user": {
"id": "...",
"email": "john@example.com",
"name": "John Doe",
"profileCompleteness": 30
},
"tokens": {
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"expiresIn": "15m"
}
}
}Login existing user
Request:
{
"email": "john@example.com",
"password": "password123"
}Response (200): Same as register
Get current user profile (requires authentication)
Headers:
Authorization: Bearer <accessToken>
Response (200):
{
"success": true,
"data": {
"user": {
"id": "...",
"email": "john@example.com",
"name": "John Doe",
"currentRole": "Software Engineer",
"targetRole": "Senior Engineer",
"experienceYears": 3,
"profileCompleteness": 50,
"hasUploadedResume": false
}
}
}Update user profile (requires authentication)
Request:
{
"name": "John Smith",
"currentRole": "Software Engineer",
"targetRole": "Senior Software Engineer",
"experienceYears": 3,
"phone": "+1234567890"
}Refresh access token
Request:
{
"refreshToken": "eyJ..."
}Response (200):
{
"success": true,
"message": "Tokens refreshed successfully",
"data": {
"tokens": {
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"expiresIn": "15m"
}
}
}Logout user (invalidate refresh token)
Request:
{
"refreshToken": "eyJ..."
}Upload and parse resume (PDF/DOCX)
Headers:
Authorization: Bearer <token>Content-Type: multipart/form-data
Body:
resume: File object
Response (201):
{
"success": true,
"data": {
"resume": {
"id": "...",
"fileName": "my_cv.pdf",
"textLength": 1250,
"status": "uploaded"
}
}
}List all uploaded resumes
Response (200):
{
"success": true,
"data": {
"count": 2,
"resumes": [...]
}
}Analyze resume against job description
Body:
{
"jobDescription": "We are looking for..."
}Response (200):
{
"success": true,
"data": {
"score": 85.5,
"matchedKeywords": ["python", "fastapi"],
"missingKeywords": ["docker"],
"summary": null
}
}Start new interview session
Body:
{
"jobRole": "Senior Full Stack Developer",
"jobDescription": "Looking for a developer with JavaScript, React, Node.js experience...",
"resumeId": "optional-resume-id"
}Response (201):
{
"success": true,
"message": "Interview session started successfully",
"data": {
"interviewId": "...",
"jobRole": "Senior Full Stack Developer",
"totalQuestions": 8,
"extractedSkills": ["javascript", "react", "nodejs"],
"currentQuestion": {...},
"questions": [...]
}
}Get interview session details
Response (200):
{
"success": true,
"data": {
"interviewId": "...",
"status": "in_progress",
"progress": 37,
"questions": [...],
"answers": [...],
"nextQuestion": {...}
}
}Get user's interview history with pagination
Query params: status, limit, page
Submit answer for evaluation
Body:
{
"questionId": "q-123...",
"answerText": "Detailed answer here..."
}Response (200):
{
"success": true,
"data": {
"evaluation": {
"score": 85,
"feedback": "Excellent answer!",
"strengths": ["Includes specific examples"],
"improvements": ["Add more metrics"]
},
"progress": {...},
"hasMoreQuestions": true,
"nextQuestion": {...}
}
}Complete interview and get summary
Response (200):
{
"success": true,
"data": {
"summary": {
"overallScore": 78,
"readinessLevel": "Medium",
"strongAreas": ["Technical questions"],
"weakAreas": ["Behavioral questions"],
"categoryScores": {...},
"recommendations": [...]
}
}
}See INTERVIEW_TESTING.md for full API documentation.
- Helmet: Secure HTTP headers
- CORS: Configurable cross-origin resource sharing
- JWT: Secure token-based authentication
- Password Hashing: Bcrypt for password encryption
- Input Validation: Express-validator for request validation
- Rate Limiting: Protection against brute force attacks
| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Environment (development/production) | development |
PORT |
Server port | 5000 |
MONGODB_URI |
MongoDB connection string | mongodb://localhost:27017/career-ai-saas |
JWT_ACCESS_SECRET |
JWT access token secret | - |
JWT_REFRESH_SECRET |
JWT refresh token secret | - |
JWT_ACCESS_EXPIRES_IN |
Access token expiry | 15m |
JWT_REFRESH_EXPIRES_IN |
Refresh token expiry | 7d |
CORS_ORIGIN |
Allowed CORS origin | http://localhost:5173 |
ML_SERVICE_URL |
ML service endpoint | http://localhost:8000 |
# Run tests (to be added)
npm test
# Run linting
npm run lint
# Format code
npm run format- Modular Architecture: Keep features in separate modules
- Error Handling: Always use try-catch and proper error responses
- Validation: Validate all user inputs
- Logging: Log important events and errors
- Security: Never commit secrets, use environment variables
- Documentation: Comment complex logic, update README
Request β Middleware Stack β Route β Controller β Service β Database
β
Response β Error Handler β Controller β Service β Database
- Middleware Stack: Logger, Helmet, CORS, Body Parser
- Route: Matches URL pattern to controller
- Controller: Handles request, calls services
- Service: Business logic (to be added)
- Database: Data persistence via Mongoose
- Error Handler: Catches and formats all errors
Coming in Step 7 (DevOps)
- Step 1: Backend Foundation β
- Step 2: Authentication System β
- Step 3: Resume Intelligence (Upload, parsing, ML integration) β
- Step 4: ML Service (ATS scoring, skill extraction) β
- Step 5: Interview Intelligence (Questions, evaluation, summary) β
- Step 6: Frontend (React + Tailwind)
- Step 7: DevOps (Docker, Nginx, deployment)
This is a production-grade SaaS project, not a college mini project. Code quality matters!
MIT