A full-stack todo application with JWT authentication, built with React, Express, and MySQL.
-
User Authentication
- Register/Login with username & password
- JWT-based authentication with refresh tokens
- Password reset functionality
- Secure cookie storage for tokens
-
Todo Management
- Create, read, update, and delete todos
- Mark todos as complete/incomplete
- Filter todos by status (all/active/completed)
- Real-time statistics and progress tracking
-
Security
- Password hashing with bcrypt
- HTTPS with SSL certificates
- CORS configuration for cross-origin requests
- SQL injection prevention with parameterized queries
- React 19 - UI library
- Vite - Build tool
- Tailwind CSS - Styling
- React Router - Navigation
- Axios - HTTP client
- React Hot Toast - Notifications
- Express.js - Node.js framework
- MySQL - Database (Aiven hosted)
- JWT - Authentication tokens
- bcryptjs - Password hashing
- CORS - Cross-origin resource sharing
├── backend/
│ ├── config/ # Database & JWT configuration
│ ├── controllers/ # Route controllers
│ ├── models/ # Database models
│ ├── routes/ # API routes
│ ├── middlewares/ # Authentication middleware
│ └── server.js # Main server file
├── frontend/
│ ├── src/
│ │ ├── api/ # API client configuration
│ │ ├── auth/ # Authentication context
│ │ ├── components/ # Reusable UI components
│ │ ├── lib/ # Utility functions
│ │ ├── pages/ # Page components
│ │ └── router/ # Route protection
│ └── vite.config.js # Vite configuration
- Node.js (v18+)
- MySQL database (Aiven recommended)
-
Clone the repository
git clone <repository-url> cd todo-app
-
Backend Setup
cd backend npm install cp .env.example .env # Configure environment variables npm run dev
-
Frontend Setup
cd frontend npm install cp .env.example .env # Set API URL npm run dev
-
Database Setup
cd backend node config/db-setup.js
Backend (.env)
PORT=5005
CORS_ORIGINS=http://localhost:5173
JWT_ACCESS_SECRET=your_access_secret
JWT_REFRESH_SECRET=your_refresh_secret
db_host=your_db_host
db_port=your_db_port
db_user=your_db_user
db_password=your_db_password
db_name=your_db_nameFrontend (.env)
VITE_API_URL=http://localhost:5005POST /api/auth/register- Register new userPOST /api/auth/login- User loginPOST /api/auth/logout- User logoutPOST /api/auth/refresh- Refresh access tokenPOST /api/auth/reset-password- Reset passwordGET /api/auth/me- Get current user
GET /api/todos- Get all todos for userPOST /api/todos- Create new todoPUT /api/todos/:id- Update todoPUT /api/todos/:id/toggle- Toggle todo completionDELETE /api/todos/:id- Delete todo
- User logs in with credentials
- Server generates:
- Access token (15min expiry) - stored in secure cookie
- Refresh token (7 days expiry) - stored in database & cookie
- Frontend includes cookies automatically in requests
- Access token expires → Frontend automatically refreshes using refresh token
- User logs out → Both tokens are invalidated
Both frontend and backend are configured for Vercel deployment:
- Push code to GitHub
- Import projects to Vercel
- Configure environment variables
- Deploy
- Backend: Node.js server with PM2
- Frontend: Build with
npm run buildand serve with Nginx - Database: Aiven MySQL with SSL
users: id, username, password, created_at, updated_at
todos: id, user_id, todo, completed, created_at, updated_at
refresh_tokens: id, user_id, token, expires_at, created_atMIT License - see LICENSE file for details
Common issues:
- CORS errors: Check
CORS_ORIGINSenvironment variable - Database connection: Verify SSL certificates and credentials
- Token issues: Clear browser cookies and re-login
- Build errors: Ensure Node.js version is 18+
Built with ❤️ using modern web technologies