Contributor: Tejas-Santosh-Nalawade
Domain: FullStack
Difficulty: Intermediate
Tech Stack: React.js, Node.js, Express.js, MongoDB, JWT Authentication
A complete full-stack task management application with user authentication, CRUD operations, and real-time updates. Features a modern React frontend, RESTful Express backend, MongoDB database, and JWT-based authentication.
- ✅ User registration and login
- ✅ JWT token-based authentication
- ✅ Create, read, update, delete tasks
- ✅ Mark tasks as complete/incomplete
- ✅ Filter tasks (All/Active/Completed)
- ✅ Search functionality
- ✅ Responsive design
- ✅ Loading states and error handling
- ✅ Protected routes
- ✅ RESTful API architecture
- ✅ User authentication with JWT
- ✅ Password hashing with bcrypt
- ✅ MongoDB database integration
- ✅ Input validation
- ✅ Error handling middleware
- ✅ CORS enabled
- ✅ Environment configuration
- React.js 18 - UI library
- React Router - Navigation
- Axios - HTTP client
- CSS3 - Styling
- Node.js - Runtime environment
- Express.js - Web framework
- MongoDB - Database
- Mongoose - ODM
- JWT - Authentication
- bcrypt - Password hashing
- dotenv - Environment variables
- Node.js 14+ and npm
- MongoDB installed and running
- Git
-
Navigate to backend directory
cd Domains/FullStack/MiniProjects/TaskManagerApp/backend -
Install dependencies
npm install
-
Create .env file
PORT=5000 MONGODB_URI=mongodb://localhost:27017/taskmanager JWT_SECRET=your_super_secret_key_change_this_in_production NODE_ENV=development
-
Start MongoDB
# On Windows net start MongoDB # On Mac/Linux sudo systemctl start mongod
-
Run backend server
npm run dev
Server will run on
http://localhost:5000
-
Navigate to frontend directory (new terminal)
cd Domains/FullStack/MiniProjects/TaskManagerApp/frontend -
Install dependencies
npm install
-
Start frontend
npm start
App will open on
http://localhost:3000
TaskManagerApp/
├── backend/
│ ├── server.js # Entry point
│ ├── config/
│ │ └── db.js # Database connection
│ ├── models/
│ │ ├── User.js # User schema
│ │ └── Task.js # Task schema
│ ├── routes/
│ │ ├── auth.js # Auth routes
│ │ └── tasks.js # Task routes
│ ├── middleware/
│ │ └── auth.js # JWT verification
│ ├── controllers/
│ │ ├── authController.js
│ │ └── taskController.js
│ ├── package.json
│ └── .env.example
├── frontend/
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── App.js # Main component
│ │ ├── App.css
│ │ ├── components/
│ │ │ ├── Login.js
│ │ │ ├── Register.js
│ │ │ ├── TaskList.js
│ │ │ ├── TaskItem.js
│ │ │ └── TaskForm.js
│ │ ├── services/
│ │ │ └── api.js # API calls
│ │ └── utils/
│ │ └── auth.js # Token management
│ ├── package.json
│ └── .env
└── README.md
POST /api/auth/register - Register new user
POST /api/auth/login - Login user
GET /api/auth/me - Get current user
GET /api/tasks - Get all user tasks
POST /api/tasks - Create new task
PUT /api/tasks/:id - Update task
DELETE /api/tasks/:id - Delete task
PATCH /api/tasks/:id/toggle - Toggle task completion
{
name: String (required),
email: String (required, unique),
password: String (required, hashed),
createdAt: Date
}{
title: String (required),
description: String,
completed: Boolean (default: false),
priority: String (low/medium/high),
dueDate: Date,
user: ObjectId (ref: User),
createdAt: Date,
updatedAt: Date
}-
Registration
- User submits name, email, password
- Password is hashed with bcrypt
- User saved to database
- JWT token generated and returned
-
Login
- User submits email, password
- Password verified against hash
- JWT token generated and returned
-
Protected Routes
- Token sent in Authorization header
- Middleware verifies token
- User ID extracted from token
- Request proceeds if valid
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { login } from '../services/api';
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const data = await login(email, password);
localStorage.setItem('token', data.token);
navigate('/tasks');
} catch (error) {
alert('Login failed');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
);
}import { useState, useEffect } from 'react';
import { getTasks, createTask, deleteTask } from '../services/api';
import TaskItem from './TaskItem';
function TaskList() {
const [tasks, setTasks] = useState([]);
const [filter, setFilter] = useState('all');
useEffect(() => {
loadTasks();
}, []);
const loadTasks = async () => {
const data = await getTasks();
setTasks(data);
};
const filteredTasks = tasks.filter(task => {
if (filter === 'active') return !task.completed;
if (filter === 'completed') return task.completed;
return true;
});
return (
<div>
<div>
<button onClick={() => setFilter('all')}>All</button>
<button onClick={() => setFilter('active')}>Active</button>
<button onClick={() => setFilter('completed')}>Completed</button>
</div>
{filteredTasks.map(task => (
<TaskItem key={task._id} task={task} onUpdate={loadTasks} />
))}
</div>
);
}const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
password: {
type: String,
required: true
}
}, { timestamps: true });
// Hash password before saving
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 10);
next();
});
// Method to compare passwords
userSchema.methods.comparePassword = async function(password) {
return bcrypt.compare(password, this.password);
};
module.exports = mongoose.model('User', userSchema);const jwt = require('jsonwebtoken');
const User = require('../models/User');
const auth = async (req, res, next) => {
try {
// Get token from header
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'No authentication token' });
}
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Find user
const user = await User.findById(decoded.userId);
if (!user) {
return res.status(401).json({ error: 'User not found' });
}
// Attach user to request
req.user = user;
req.userId = user._id;
next();
} catch (error) {
res.status(401).json({ error: 'Please authenticate' });
}
};
module.exports = auth;const Task = require('../models/Task');
exports.getTasks = async (req, res) => {
try {
const tasks = await Task.find({ user: req.userId })
.sort({ createdAt: -1 });
res.json(tasks);
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
};
exports.createTask = async (req, res) => {
try {
const task = new Task({
...req.body,
user: req.userId
});
await task.save();
res.status(201).json(task);
} catch (error) {
res.status(400).json({ error: error.message });
}
};
exports.updateTask = async (req, res) => {
try {
const task = await Task.findOneAndUpdate(
{ _id: req.params.id, user: req.userId },
req.body,
{ new: true, runValidators: true }
);
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.json(task);
} catch (error) {
res.status(400).json({ error: error.message });
}
};
exports.deleteTask = async (req, res) => {
try {
const task = await Task.findOneAndDelete({
_id: req.params.id,
user: req.userId
});
if (!task) {
return res.status(404).json({ error: 'Task not found' });
}
res.json({ message: 'Task deleted' });
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
};- ✅ React hooks (useState, useEffect)
- ✅ Component-based architecture
- ✅ React Router navigation
- ✅ State management
- ✅ API integration with Axios
- ✅ Form handling
- ✅ Protected routes
- ✅ RESTful API design
- ✅ Express.js routing
- ✅ MongoDB & Mongoose
- ✅ JWT authentication
- ✅ Password hashing
- ✅ Middleware patterns
- ✅ Error handling
- ✅ Client-server communication
- ✅ Token-based authentication
- ✅ CORS configuration
- ✅ Environment variables
- ✅ API security
- ✅ Database modeling
- Task Categories - Organize tasks by category
- Due Date Reminders - Email/push notifications
- Team Collaboration - Share tasks with others
- File Attachments - Upload files to tasks
- Dark Mode - Theme switching
- Task Priority - Color-coded priorities
- Search & Filters - Advanced filtering
- Analytics Dashboard - Task statistics
- Drag & Drop - Reorder tasks
- Export/Import - CSV/JSON export
npm testnpm testdescribe('Task API', () => {
it('should create a new task', async () => {
const res = await request(app)
.post('/api/tasks')
.set('Authorization', `Bearer ${token}`)
.send({ title: 'Test Task' });
expect(res.status).toBe(201);
expect(res.body.title).toBe('Test Task');
});
});# Check if MongoDB is running
mongosh# Kill process on port 5000
npx kill-port 5000- Default: 7 days
- Update in auth controller
MIT License - Free to use and modify!
This is a sample project for ProjectHive. Feel free to:
- Fork and enhance
- Add new features
- Report issues
- Use as learning material
Happy Full-Stack Development! 🚀