This directory contains the backend API for FlashLearn, a RESTful service built with Node.js, Express, and MongoDB.
- Node.js: JavaScript runtime environment
- Express.js: Web application framework
- MongoDB: NoSQL database with Mongoose ODM
- JWT: JSON Web Tokens for authentication
- bcryptjs: Password hashing and security
- RESTful API: Clean, resource-oriented endpoint design
- JWT Authentication: Secure, stateless authentication flow
- Data Validation: Input validation for all API requests
- MongoDB Integration: Optimized schema design with indexing
- Error Handling: Consistent error responses and logging
The backend follows a structured MVC pattern:
backend/
├── controllers/ # Request handlers
│ ├── authController.js # Authentication logic
│ ├── userController.js # User management
│ ├── setController.js # Flashcard sets operations
│ └── flashcardController.js # Flashcard operations
├── models/ # Database schemas
│ ├── User.js # User model
│ ├── FlashcardSet.js # Set model
│ └── Flashcard.js # Flashcard model
├── middleware/ # Express middleware
│ ├── auth.js # JWT verification
│ └── ...
├── routes/ # API route definitions
│ ├── auth.js # Auth endpoints
│ ├── users.js # User endpoints
│ ├── sets.js # Set endpoints
│ └── flashcards.js # Flashcard endpoints
├── utils/ # Helper functions
│ ├── generateToken.js # JWT utility
│ └── ...
└── server.js # Application entry point
-
POST /auth/register - Register a new user
// Request body { "name": "User Name", "email": "user@example.com", "phone": "1234567890", // optional "password": "securepassword" } // Response { "_id": "user_id", "name": "User Name", "email": "user@example.com", "phone": "1234567890", "token": "jwt_token" }
-
POST /auth/login - Login and get JWT token
// Request body { "email": "user@example.com", "password": "securepassword" } // Response { "_id": "user_id", "name": "User Name", "email": "user@example.com", "phone": "1234567890", "token": "jwt_token" }
- GET /users/:id - Get user profile
- PUT /users/:id - Update user profile
- GET /users/:id/stats - Get user statistics
- GET /users/:id/sets - Get all sets for a user
- GET /sets/public - Get all public sets
- GET /sets/:id - Get a set by ID
- POST /sets - Create a new set
- PUT /sets/:id - Update a set
- DELETE /sets/:id - Delete a set and its flashcards
- GET /sets/:setId/flashcards - Get all flashcards for a set
- POST /flashcards - Create a new flashcard
- DELETE /flashcards/:id - Delete a flashcard
{
name: {
type: String,
required: [true, 'Name is required'],
trim: true
},
email: {
type: String,
required: [true, 'Email is required'],
unique: true,
trim: true,
lowercase: true,
match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, 'Please enter a valid email']
},
phone: {
type: String,
trim: true
},
password: {
type: String,
required: [true, 'Password is required'],
minlength: [6, 'Password must be at least 6 characters long']
}
}{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: [true, 'Set must belong to a user']
},
title: {
type: String,
required: [true, 'Title is required'],
trim: true
},
description: {
type: String,
trim: true,
default: ''
},
tags: {
type: [String],
default: []
},
isPublic: {
type: Boolean,
default: false
}
}{
setId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'FlashcardSet',
required: [true, 'Flashcard must belong to a set'],
index: true
},
front: {
type: String,
required: [true, 'Front content is required'],
trim: true
},
back: {
type: String,
required: [true, 'Back content is required'],
trim: true
}
}The authentication system uses JWT tokens with middleware protection:
// Middleware to protect routes
const protect = async (req, res, next) => {
let token;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
try {
// Extract token
token = req.headers.authorization.split(' ')[1];
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Find user and add to request
req.user = await User.findById(decoded.id).select('-password');
if (!req.user) {
return res.status(401).json({ message: 'Not authorized, user not found' });
}
next();
} catch (error) {
console.error(error);
res.status(401).json({ message: 'Not authorized, token failed' });
}
}
if (!token) {
res.status(401).json({ message: 'Not authorized, no token provided' });
}
};The backend implements several performance optimizations:
-
Database Indexing:
// Create index for faster querying by setId flashcardSchema.index({ setId: 1 }); // Create index for faster querying by userId flashcardSetSchema.index({ userId: 1 }); // Create index for faster querying public sets flashcardSetSchema.index({ isPublic: 1 });
-
Error Handling: Centralized error handling for consistent responses
-
Request Validation: Validate inputs before database operations
-
Password Security: bcrypt hashing with pre-save hooks
-
Resource Ownership: Middleware checks for resource access rights
- Node.js (v14+)
- MongoDB instance (local or Atlas)
Create a .env file in the backend directory with:
PORT=5000
MONGODB_URI=mongodb://localhost:27017/flashlearn
JWT_SECRET=your_super_secret_key
NODE_ENV=development
# Install dependencies
npm install
# Run in development mode with nodemon
npm run dev
# Run in production mode
npm startSee the root README for Docker setup instructions. The backend is containerized for consistent environments.
You can test the API using tools like Postman or curl:
# Example: Login
curl -X POST https://api.aimablem.dev/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password123"}'
# Example: Get user sets (with authentication)
curl -X GET https://api.aimablem.dev/users/123/sets \
-H "Authorization: Bearer YOUR_JWT_TOKEN"The API provides standardized error responses:
// Example error response
{
"message": "Resource not found",
"status": 404,
"error": "Not Found"
}The backend is deployed using Docker containers on AWS. See the root README for detailed deployment information.